stringtranslate.com

máquina apiladora

En informática , ingeniería informática e implementaciones de lenguajes de programación , una máquina de pila es un procesador de computadora o una máquina virtual en la que la interacción principal es mover valores temporales de corta duración hacia y desde una pila de inserción . En el caso de un procesador de hardware, se utiliza una pila de hardware . El uso de una pila reduce significativamente el número requerido de registros de procesador . Las máquinas apilables amplían los autómatas de empuje hacia abajo con operaciones adicionales de carga/almacenamiento o apilamientos múltiples y, por lo tanto, son Turing-completas .

Diseño

La mayoría o todas las instrucciones de la máquina de pila suponen que los operandos provendrán de la pila y los resultados se colocarán en la pila. La pila contiene fácilmente más de dos entradas o más de un resultado, por lo que se puede calcular un amplio conjunto de operaciones. En el código de máquina de pila (a veces llamado código p ), las instrucciones con frecuencia tendrán solo un código de operación que ordena una operación, sin campos adicionales que identifiquen una constante, un registro o una celda de memoria, lo que se conoce como formato de dirección cero . [1] Se dice que una computadora que opera de tal manera que la mayoría de sus instrucciones no incluyen direcciones explícitas utiliza instrucciones de dirección cero. [2] Esto simplifica enormemente la decodificación de instrucciones. Las bifurcaciones, los inmediatos de carga y las instrucciones de carga/almacenamiento requieren un campo de argumento, pero las máquinas de pila a menudo organizan que los casos frecuentes de estos todavía encajen junto con el código de operación en un grupo compacto de bits . La selección de operandos a partir de resultados anteriores se realiza implícitamente ordenando las instrucciones. Algunos conjuntos de instrucciones de máquinas de pila están destinados a la ejecución interpretativa de una máquina virtual, en lugar de controlar el hardware directamente.

Los operandos constantes enteros son impulsados ​​por instrucciones Pusho Load Immediate. A menudo se accede a la memoria mediante instrucciones separadas Loadque Storecontienen una dirección de memoria o que calculan la dirección a partir de valores en la pila. Todas las máquinas de pila prácticas tienen variantes de los códigos de operación de carga y almacenamiento para acceder a variables locales y parámetros formales sin cálculos de direcciones explícitos. Esto puede ser mediante compensaciones desde la dirección actual de la parte superior de la pila o mediante compensaciones desde un registro de base de cuadro estable.

El conjunto de instrucciones lleva a cabo la mayoría de las acciones de ALU con operaciones de sufijo ( notación polaca inversa ) que funcionan solo en la pila de expresiones, no en registros de datos ni celdas de memoria principal. Esto puede resultar muy conveniente para ejecutar lenguajes de alto nivel, porque la mayoría de las expresiones aritméticas se pueden traducir fácilmente a notación postfija.

Árbol de sintaxis binaria para la expresión A *( B - C ) + ( D + E )

Por ejemplo, considere la expresión A *( B - C )+( D + E ), escrita en notación polaca inversa como A B C - * D E + +. Compilar y ejecutar esto en una máquina de pila imaginaria simple tomaría la forma:

 # contenido de la pila (más a la izquierda = arriba = más reciente): empujar A # A empujar B# BA empujar C # CBA restar # BC A multiplicar # A*(BC) presione D # DA*(BC) presione E # EDA*(BC) añadir # D+EA*(BC) añadir # A*(BC)+(D+E)

Las operaciones aritméticas 'restar', 'multiplicar' y 'suma' actúan sobre los dos operandos superiores de la pila. La computadora toma ambos operandos de los valores superiores (más recientes) de la pila. La computadora reemplaza esos dos valores con la diferencia, suma o producto calculado. En otras palabras, los operandos de la instrucción se "sacan" de la pila y sus resultados luego se "empujan" nuevamente a la pila, listos para la siguiente instrucción.

Las máquinas apilables pueden tener su pila de expresiones y su pila de devolución de llamadas separadas o como una estructura integrada. Si se separan, las instrucciones de la máquina apilable se pueden canalizar con menos interacciones y menos complejidad de diseño, por lo que normalmente se ejecutará más rápido.

La optimización del código de pila compilado es bastante posible. Se ha demostrado que la optimización back-end de la salida del compilador mejora significativamente el código, [3] [4] y potencialmente el rendimiento, mientras que la optimización global dentro del propio compilador logra mayores beneficios. [5]

Almacenamiento en pila

Algunas máquinas apiladoras tienen una pila de tamaño limitado, implementada como un archivo de registro. La ALU accederá a esto con un índice. Un archivo de registro grande utiliza muchos transistores y, por lo tanto, este método sólo es adecuado para sistemas pequeños. Algunas máquinas tienen una pila de expresiones en la memoria y una pila de registros separada. En este caso, el software o una interrupción pueden mover datos entre ellos. Algunas máquinas tienen una pila de tamaño ilimitado, implementada como una matriz en RAM, que se almacena en caché mediante una cierta cantidad de registros de direcciones "superiores a la pila" para reducir el acceso a la memoria. Excepto por las instrucciones explícitas de "carga desde la memoria", el orden de uso de los operandos es idéntico al orden de los operandos en la pila de datos, por lo que se puede lograr fácilmente una excelente captación previa.

Considerar X+1. Se compila en Load X; Load 1; Add. Con una pila almacenada completamente en RAM, esto realiza escrituras y lecturas implícitas de la pila en memoria:

para un total de 5 referencias de caché de datos.

El siguiente paso es una máquina de pila o intérprete con un único registro en la parte superior de la pila. El código anterior entonces hace:

para un total de 3 referencias de caché de datos, en el peor de los casos. Generalmente, los intérpretes no rastrean el vacío porque no es necesario: cualquier valor debajo del puntero de la pila es un valor no vacío y el registro de caché TOS siempre se mantiene activo. Sin embargo, los intérpretes típicos de Java no almacenan en buffer la parte superior de la pila de esta manera porque el programa y la pila tienen una combinación de valores de datos cortos y anchos.

Si la máquina de pila cableada tiene 2 o más registros de pila superior, o un archivo de registro, en este ejemplo se evita todo acceso a la memoria y solo hay 1 ciclo de caché de datos.

Historia e implementaciones

Robert proporcionó por primera vez en la conferencia una descripción de un método de este tipo que requiere que solo se mantengan dos valores a la vez en los registros, con un conjunto limitado de operandos predefinidos que se pueden ampliar mediante la definición de otros operandos, funciones y subrutinas. S. Barton en 1961. [6] [7]

Máquinas apilables comerciales

Ejemplos de conjuntos de instrucciones de pila ejecutados directamente en hardware incluyen

Máquinas de pila virtuales

Ejemplos de máquinas de pila virtuales interpretadas en software:

Máquinas híbridas

Las máquinas de pila pura son bastante ineficientes para procedimientos que acceden a múltiples campos desde el mismo objeto. El código de máquina de la pila debe recargar el puntero del objeto para cada cálculo de puntero + desplazamiento. Una solución común para esto es agregar algunas características de la máquina de registro a la máquina de pila: un archivo de registro visible dedicado a guardar direcciones e instrucciones de estilo registro para realizar cargas y cálculos de direcciones simples. Es poco común que los registros sean completamente de propósito general, porque entonces no hay una razón sólida para tener una pila de expresiones e instrucciones postfix.

Otro híbrido común es comenzar con una arquitectura de máquina de registro y agregar otro modo de dirección de memoria que emule las operaciones push o pop de máquinas de pila: 'memaddress = reg; reg += instr.displ'. Esto se utilizó por primera vez en la minicomputadora PDP-11 de DEC . [26] Esta característica se implementó en las computadoras VAX y en los microprocesadores Motorola 6800 y M68000 . Esto permitió el uso de métodos de pila más simples en los primeros compiladores. También admitía eficientemente máquinas virtuales que utilizaban intérpretes de pila o código subproceso . Sin embargo, esta característica no ayudó a que el código de la máquina de registro fuera tan compacto como el código de máquina de pila pura. Además, la velocidad de ejecución fue menor que cuando se compilaba bien con la arquitectura de registro. Es más rápido cambiar el puntero de la parte superior de la pila sólo ocasionalmente (una vez por llamada o devolución) en lugar de subirlo y bajarlo constantemente a lo largo de cada instrucción del programa, y ​​es incluso más rápido evitar por completo las referencias a la memoria.

Más recientemente, las llamadas máquinas de pila de segunda generación han adoptado una colección dedicada de registros para que sirvan como registros de direcciones, descargando la tarea de direccionamiento de memoria de la pila de datos. Por ejemplo, MuP21 se basa en un registro llamado "A", mientras que los procesadores GreenArrays más recientes se basan en dos registros: A y B. [23]

La familia de microprocesadores Intel x86 tiene un conjunto de instrucciones de estilo registro (acumulador) para la mayoría de las operaciones, pero usa instrucciones de pila para su x87 , aritmética de punto flotante Intel 8087 , que se remonta al coprocesador iAPX87 (8087) para 8086 y 8088. Es decir, no hay registros de punto flotante accesibles para el programador, sino solo una pila profunda de 8 niveles y 80 bits de ancho. El x87 depende en gran medida de la CPU x86 para recibir asistencia en el desempeño de sus operaciones.

Computadoras que utilizan pilas de llamadas y marcos de pila

La mayoría de las computadoras actuales (de cualquier estilo de conjunto de instrucciones) y la mayoría de los compiladores utilizan una gran pila de devolución de llamadas en la memoria para organizar las variables locales de corta duración y los enlaces de retorno para todos los procedimientos o funciones actualmente activos. Cada llamada anidada crea un nuevo marco de pila en la memoria, que persiste hasta que se completa la llamada. Esta pila de devolución de llamadas puede ser administrada completamente por el hardware a través de registros de direcciones especializados y modos de direcciones especiales en las instrucciones. O puede ser simplemente un conjunto de convenciones seguidas por los compiladores, utilizando registros genéricos y modos de dirección de registro+desplazamiento. O puede ser algo intermedio.

Dado que esta técnica es ahora casi universal, incluso en las máquinas registradoras, no resulta útil referirse a todas estas máquinas como máquinas apiladas. Ese término se reserva comúnmente para máquinas que también utilizan una pila de expresiones e instrucciones aritméticas de solo pila para evaluar las partes de una sola declaración.

Las computadoras comúnmente brindan acceso directo y eficiente a las variables globales del programa y a las variables locales solo del procedimiento o función más interno actual, el marco de pila superior. El direccionamiento de 'nivel superior' del contenido de los marcos de pila de las personas que llaman generalmente no es necesario y no es compatible directamente con el hardware. Si es necesario, los compiladores admiten esto pasando punteros de marco como parámetros ocultos adicionales.

Algunas máquinas apilables de Burroughs admiten referencias de nivel superior directamente en el hardware, con modos de dirección especializados y un archivo de registro de "visualización" especial que contiene las direcciones de trama de todos los ámbitos externos. Actualmente, sólo MCST Elbrus ha hecho esto en hardware. Cuando Niklaus Wirth desarrolló el primer compilador Pascal para el CDC 6000 , descubrió que, en general, era más rápido pasar los punteros de marco como una cadena, en lugar de actualizar constantemente conjuntos completos de punteros de marco. Este método de software tampoco agrega gastos generales para lenguajes comunes como C, que carecen de referencias de nivel superior.

Las mismas máquinas Burroughs también admitían el anidamiento de tareas o subprocesos. La tarea y su creador comparten los marcos de pila que existían en el momento de la creación de la tarea, pero no los marcos posteriores del creador ni los marcos propios de la tarea. Este estaba sostenido por una pila de cactus , cuyo diagrama de disposición se asemejaba al tronco y los brazos de un cactus Saguaro . Cada tarea tenía su propio segmento de memoria que contenía su pila y los fotogramas que posee. La base de esta pila está vinculada a la mitad de la pila de su creador. En máquinas con un espacio de direcciones plano convencional, la pila de creadores y las pilas de tareas serían objetos de montón separados en un solo montón.

En algunos lenguajes de programación, los entornos de datos de alcance externo no siempre están anidados en el tiempo. Estos lenguajes organizan sus procedimientos 'registros de activación' como objetos de montón separados en lugar de marcos de pila añadidos a una pila lineal.

En lenguajes simples como Forth , que carecen de variables locales y de denominación de parámetros, los marcos de pila no contendrían más que direcciones de rama de retorno y gastos generales de gestión de marcos. Por lo tanto, su pila de retorno contiene direcciones de retorno simples en lugar de marcos. La pila de devolución está separada de la pila de valores de datos para mejorar el flujo de configuración de llamadas y devoluciones.

Comparación con máquinas registradoras.

Las máquinas apilables a menudo se comparan con las máquinas de registro, que contienen valores en una serie de registros . Las máquinas registradoras pueden almacenar estructuras similares a pilas en esta matriz, pero una máquina registradora tiene instrucciones que eluden la interfaz de la pila. Las máquinas registradoras superan habitualmente a las máquinas apilables, [27] y las máquinas apilables siguen siendo un actor de nicho en los sistemas de hardware. Pero las máquinas de pila se utilizan a menudo para implementar máquinas virtuales debido a su simplicidad y facilidad de implementación. [28]

Instrucciones

Las máquinas apilables tienen una mayor densidad de código . A diferencia de las instrucciones comunes de las máquinas de pila que pueden caber fácilmente en 6 bits o menos, las máquinas de registro requieren dos o tres campos de números de registro por instrucción ALU para seleccionar operandos; las máquinas de registro más densas promedian alrededor de 16 bits por instrucción más los operandos. Las máquinas de registro también utilizan un campo de compensación más amplio para códigos de operación de almacenamiento de carga. El código compacto de una máquina de pila naturalmente cabe en más instrucciones en la caché y, por lo tanto, podría lograr una mejor eficiencia de la caché , reduciendo los costos de memoria o permitiendo sistemas de memoria más rápidos por un costo determinado. Además, la mayoría de las instrucciones de la máquina de pila son muy simples y están hechas de un solo campo de código de operación o de un campo de operando. Por tanto, las máquinas apilables requieren muy pocos recursos electrónicos para decodificar cada instrucción.

Un programa tiene que ejecutar más instrucciones cuando se compila en una máquina de pila que cuando se compila en una máquina de registro o en una máquina de memoria a memoria. Cada carga variable o constante requiere su propia instrucción Load separada, en lugar de estar incluida dentro de la instrucción que usa ese valor. Las instrucciones separadas pueden ser simples y de ejecución más rápida, pero el recuento total de instrucciones es aún mayor.

La mayoría de los intérpretes de registros especifican sus registros por número. Pero no se puede acceder a los registros de una máquina host en una matriz indexada, por lo que se asigna una matriz de memoria para los registros virtuales. Por lo tanto, las instrucciones de un intérprete de registros deben utilizar memoria para pasar los datos generados a la siguiente instrucción. Esto obliga a los intérpretes de registros a ser mucho más lentos en microprocesadores fabricados con una regla de proceso fina (es decir, transistores más rápidos sin mejorar las velocidades del circuito, como el Haswell x86). Estos requieren varios relojes para acceder a la memoria, pero solo un reloj para acceder a los registros. En el caso de una máquina de pila con un circuito de reenvío de datos en lugar de un archivo de registro, los intérpretes de pila pueden asignar los registros de la máquina principal para los operandos superiores de la pila en lugar de la memoria de la máquina principal.

En una máquina de pila, los operandos utilizados en las instrucciones siempre están en un desplazamiento conocido (establecido en el puntero de la pila), desde una ubicación fija (la parte inferior de la pila, que en un diseño de hardware siempre podría estar en la ubicación de memoria cero), evitando que el valioso almacenamiento en caché o en la CPU se utilice para almacenar tantas direcciones de memoria o números de índice. Esto puede preservar dichos registros y caché para su uso en cálculos sin flujo. [ cita necesaria ]

Valores temporales/locales

Algunos en la industria creen que las máquinas de pila ejecutan más ciclos de caché de datos para valores temporales y variables locales que las máquinas de registro. [29]

En las máquinas de pila, los valores temporales a menudo se derraman en la memoria, mientras que en las máquinas con muchos registros estos temporales generalmente permanecen en los registros. (Sin embargo, estos valores a menudo deben dividirse en "marcos de activación" al final de la definición de un procedimiento, bloque básico o, como mínimo, en un búfer de memoria durante el procesamiento de interrupciones). Los valores derramados en la memoria agregan más ciclos de caché. Este efecto de derrame depende del número de registros ocultos utilizados para almacenar los valores de la parte superior de la pila, de la frecuencia de las llamadas a procedimientos anidados y de las tasas de procesamiento de interrupciones de la computadora host.

En las máquinas de registro que utilizan compiladores de optimización, es muy común que las variables locales más utilizadas permanezcan en los registros en lugar de en las celdas de memoria del marco de pila. Esto elimina la mayoría de los ciclos de caché de datos para leer y escribir esos valores. El desarrollo de la "programación de pila" para realizar análisis de variables en vivo y, por lo tanto, retener variables clave en la pila durante períodos prolongados, ayuda a resolver esta preocupación. [3] [4] [5]

Por otro lado, las máquinas de registro deben derramar muchos de sus registros en la memoria a través de llamadas a procedimientos anidados. La decisión de qué registros derramar y cuándo se toma estáticamente en el momento de la compilación en lugar de en la profundidad dinámica de las llamadas. Esto puede generar más tráfico de caché de datos que en una implementación avanzada de máquina de pila.

Subexpresiones comunes

En las máquinas de registro, una subexpresión común (una subexpresión que se usa varias veces con el mismo valor de resultado) se puede evaluar solo una vez y su resultado se guarda en un registro rápido. Las reutilizaciones posteriores no tienen coste de tiempo ni de código, sólo una referencia de registro. Esta optimización acelera las expresiones simples (por ejemplo, cargar la variable X o el puntero P), así como las expresiones complejas menos comunes.

En las máquinas apilables, por el contrario, los resultados se pueden almacenar de dos maneras. En primer lugar, los resultados se pueden almacenar utilizando una variable temporal en la memoria. El almacenamiento y las recuperaciones posteriores cuestan instrucciones adicionales y ciclos de caché de datos adicionales. Hacer esto solo es una ganancia si el cálculo de la subexpresión cuesta más en tiempo que recuperarlo de la memoria, lo que en la mayoría de las CPU de pila, casi siempre es el caso. Nunca vale la pena buscar variables simples y punteros, porque ya tienen el mismo costo de un ciclo de caché de datos por acceso. Sólo vale la pena marginalmente para expresiones como X+1. Estas expresiones más simples constituyen la mayoría de las expresiones redundantes y optimizables en programas escritos en lenguajes distintos de los lenguajes concatenativos . Un compilador optimizador sólo puede ganar con redundancias que el programador podría haber evitado en el código fuente. [ cita necesaria ]

La segunda forma deja un valor calculado en la pila de datos y lo duplica según sea necesario. Esto utiliza operaciones para copiar entradas de la pila. La pila debe tener una profundidad suficiente para las instrucciones de copia disponibles de la CPU. El código de pila escrito a mano a menudo utiliza este enfoque y alcanza velocidades similares a las de las máquinas de registro de uso general. [30] [9] Desafortunadamente, los algoritmos para una "programación de pila" óptima no se utilizan ampliamente en los lenguajes de programación.

Tubería

En las máquinas modernas, el tiempo para recuperar una variable del caché de datos suele ser varias veces mayor que el tiempo necesario para las operaciones básicas de ALU. Un programa se ejecuta más rápido sin detenerse si sus cargas de memoria pueden iniciarse varios ciclos antes de la instrucción que necesita esa variable. Las máquinas complejas pueden hacer esto con una canalización profunda y una "ejecución desordenada" que examina y ejecuta muchas instrucciones a la vez. Las máquinas de registro pueden incluso hacer esto con hardware "en orden" mucho más simple, una canalización poco profunda y compiladores ligeramente más inteligentes. El paso de carga se convierte en una instrucción separada y esa instrucción se programa estáticamente mucho antes en la secuencia del código. El compilador coloca pasos independientes en el medio.

La programación de accesos a la memoria requiere registros de repuesto explícitos. No es posible en máquinas apiladas sin exponer algún aspecto de la microarquitectura al programador. Para la expresión AB -, B debe evaluarse y presionarse inmediatamente antes del paso Menos. Sin permutación de pila o subprocesos múltiples de hardware, se puede colocar relativamente poco código útil mientras se espera que finalice la carga B. Las máquinas de pila pueden solucionar el retraso de la memoria al tener una canalización de ejecución fuera de orden que cubra muchas instrucciones a la vez o, más probablemente, pueden permutar la pila de modo que puedan trabajar en otras cargas de trabajo mientras se completa la carga, o pueden Puede entrelazar la ejecución de diferentes subprocesos de programa, como en el sistema Unisys A9. [31] Las cargas computacionales cada vez más paralelas de hoy en día sugieren, sin embargo, que esta podría no ser la desventaja que se pensaba que era en el pasado.

Las máquinas apilables pueden omitir la etapa de búsqueda de operandos de una máquina registradora. [30] Por ejemplo, en el microprocesador Java Optimized Processor (JOP), los 2 operandos superiores de la pila ingresan directamente a un circuito de reenvío de datos que es más rápido que el archivo de registro. [32]

Ejecución fuera de orden

El algoritmo Tomasulo encuentra paralelismo a nivel de instrucción emitiendo instrucciones a medida que sus datos están disponibles. Conceptualmente, las direcciones de las posiciones en una pila no son diferentes de los índices de registro de un archivo de registro. Esta vista permite la ejecución desordenada del algoritmo Tomasulo para ser utilizado con máquinas apiladas.

La ejecución fuera de orden en máquinas apiladas parece reducir o evitar muchas dificultades teóricas y prácticas. [33] La investigación citada muestra que una máquina de pila de este tipo puede explotar el paralelismo a nivel de instrucciones, y el hardware resultante debe almacenar en caché los datos de las instrucciones. Estas máquinas evitan eficazmente la mayoría de los accesos a la memoria de la pila. El resultado logra un rendimiento (instrucciones por reloj ) comparable al de las máquinas con arquitectura de carga y almacenamiento , con densidades de código mucho más altas (porque las direcciones de los operandos están implícitas).

Un problema que surgió en la investigación fue que se necesitan alrededor de 1,88 instrucciones de máquina de pila para realizar el trabajo de una instrucción en una máquina con arquitectura de almacén de carga. [ cita necesaria ] Por lo tanto, las máquinas apilables fuera de servicio de la competencia requieren aproximadamente el doble de recursos electrónicos para seguir las instrucciones ("estaciones de emisión"). Esto podría compensarse con ahorros en caché de instrucciones y memoria y circuitos de decodificación de instrucciones.

Oculta una máquina de registro más rápida en su interior.

Algunas máquinas apilables sencillas tienen un diseño de chip totalmente personalizado hasta el nivel de los registros individuales. El registro de dirección de la parte superior de la pila y los buffers de datos de la parte superior de la pila N se construyen a partir de circuitos de registros individuales separados, con sumadores separados y conexiones ad hoc.

Sin embargo, la mayoría de las máquinas apiladas se construyen a partir de componentes de circuitos más grandes donde los N buffers de datos se almacenan juntos dentro de un archivo de registro y comparten buses de lectura/escritura. Las instrucciones de la pila decodificadas se asignan a una o más acciones secuenciales en ese archivo de registro oculto. Las cargas y las operaciones de ALU actúan en algunos registros superiores, y los derrames y rellenos implícitos actúan en los registros inferiores. El decodificador permite que el flujo de instrucciones sea compacto. Pero si el flujo de código tuviera campos explícitos de selección de registros que manipularan directamente el archivo de registro subyacente, el compilador podría hacer un mejor uso de todos los registros y el programa se ejecutaría más rápido.

Las máquinas apilables microprogramadas son un ejemplo de esto. El motor de microcódigo interno es una especie de máquina de registro tipo RISC o una máquina tipo VLIW que utiliza múltiples archivos de registro. Cuando se controla directamente mediante un microcódigo específico de la tarea, ese motor realiza mucho más trabajo por ciclo que cuando se controla indirectamente mediante un código de pila equivalente para esa misma tarea.

Los traductores de código objeto para HP 3000 y Tandem T/16 son otro ejemplo. [34] [35] Tradujeron secuencias de código de pila en secuencias equivalentes de código RISC. Las optimizaciones "locales" menores eliminaron gran parte de la sobrecarga de una arquitectura de pila. Se utilizaron registros de repuesto para descartar cálculos de direcciones repetidos. El código traducido aún conservaba mucha sobrecarga de emulación debido a la falta de coincidencia entre las máquinas originales y de destino. A pesar de esa carga, la eficiencia del ciclo del código traducido coincidió con la eficiencia del ciclo del código de pila original. Y cuando el código fuente se recopiló directamente en la máquina de registro mediante compiladores optimizados, la eficiencia se duplicó. Esto muestra que la arquitectura de la pila y sus compiladores no optimizados estaban desperdiciando más de la mitad de la potencia del hardware subyacente.

Los archivos de registro son buenas herramientas para la informática porque tienen un gran ancho de banda y una latencia muy baja, en comparación con las referencias de memoria a través de cachés de datos. En una máquina simple, el archivo de registro permite leer dos registros independientes y escribir un tercero, todo en un ciclo de ALU con latencia de un ciclo o menos. Mientras que la caché de datos correspondiente puede iniciar solo una lectura o una escritura (no ambas) por ciclo, y la lectura normalmente tiene una latencia de dos ciclos de ALU. Eso es un tercio del rendimiento con el doble del retraso del oleoducto. En una máquina compleja como Athlon que completa dos o más instrucciones por ciclo, el archivo de registro permite leer cuatro o más registros independientes y escribir otros dos, todo en un ciclo ALU con latencia de un ciclo. Mientras que la caché de datos de doble puerto correspondiente puede iniciar solo dos lecturas o escrituras por ciclo, con múltiples ciclos de latencia. Nuevamente, eso es un tercio del rendimiento de los registros. Es muy costoso construir un caché con puertos adicionales.

Dado que una pila es un componente de la mayoría de los programas de software, incluso cuando el software utilizado no es estrictamente una máquina de pila, una máquina de pila de hardware podría imitar más fielmente el funcionamiento interno de sus programas. Los registros del procesador tienen un alto costo térmico y una máquina apilada podría presumir de una mayor eficiencia energética. [22]

Interrumpe

Responder a una interrupción implica guardar los registros en una pila y luego pasar al código del controlador de interrupciones. A menudo, las máquinas apiladas responden más rápidamente a las interrupciones, porque la mayoría de los parámetros ya están en una pila y no es necesario enviarlos allí. Algunas máquinas de registro se ocupan de esto teniendo múltiples archivos de registro que pueden intercambiarse instantáneamente [36] pero esto aumenta los costos y ralentiza el archivo de registro.

Intérpretes

Los intérpretes para máquinas de pila virtuales son más fáciles de construir que los intérpretes para máquinas de registro; la lógica para manejar los modos de dirección de memoria está en un solo lugar en lugar de repetirse en muchas instrucciones. Las máquinas apiladas también tienden a tener menos variaciones de código de operación; un código de operación generalizado manejará tanto casos frecuentes como casos oscuros de referencias de memoria o configuración de llamadas a funciones. (Pero la densidad del código a menudo se mejora agregando formas cortas y largas para la misma operación).

Los intérpretes de máquinas de pila virtual suelen ser más lentos que los intérpretes de otros estilos de máquinas virtuales. [37] Esta desaceleración es peor cuando se ejecuta en máquinas host con canales de ejecución profundos, como los chips x86 actuales.

En algunos intérpretes, el intérprete debe ejecutar un salto de interruptor de N vías para decodificar el siguiente código de operación y pasar a sus pasos para ese código de operación en particular. Otro método para seleccionar códigos de operación es el código subproceso . Los mecanismos de captación previa de la máquina host no pueden predecir ni recuperar el objetivo de ese salto indexado o indirecto. Por lo tanto, el proceso de ejecución de la máquina host debe reiniciarse cada vez que el intérprete alojado decodifica otra instrucción virtual. Esto sucede con más frecuencia en las máquinas de pila virtual que en otros estilos de máquinas virtuales. [38]

Un ejemplo es el lenguaje de programación Java . Su máquina virtual canónica se especifica como una máquina de pila de 8 bits. Sin embargo, la máquina virtual Dalvik para Java utilizada en los teléfonos inteligentes Android es una máquina de registro virtual de 16 bits, una elección realizada por razones de eficiencia. Las instrucciones aritméticas obtienen o almacenan directamente variables locales a través de campos de instrucciones de 4 bits (o más). [39] De manera similar, la versión 5.0 de Lua reemplazó su máquina de pila virtual con una máquina de registro virtual más rápida. [40] [41]

Desde que la máquina virtual Java se hizo popular, los microprocesadores han empleado predictores de rama avanzados para saltos indirectos. [42] Este avance evita la mayoría de los reinicios de canalización a partir de saltos de N vías y elimina gran parte de los costos de recuento de instrucciones que afectan a los intérpretes de pila.

Ver también

Referencias

  1. ^ Beard, Bob (otoño de 1997). "La computadora KDF9: 30 años después". RESURRECCIÓN informática .
  2. ^ Hayes, John P. (1978). Arquitectura y Organización de Computadores . Compañía internacional del libro McGraw-Hill. pag. 164.ISBN _ 0-07-027363-4.
  3. ^ ab Koopman, Jr., Philip John (1994). "Una exploración preliminar de la generación de código de pila optimizada" (PDF) . Revista de aplicaciones e investigaciones de Forth . 6 (3).
  4. ^ ab Bailey, Chris (2000). "Programación entre límites de operandos de pila: un estudio preliminar" (PDF) . Actas de la conferencia Euroforth 2000 .
  5. ^ ab Shannon, Mark; Bailey, Chris (2006). "Asignación global de pilas: asignación de registros para máquinas apilables" (PDF) . Actas de la Conferencia Euroforth 2006 .
  6. ^ Barton, Robert S. (9 de mayo de 1961). "Un nuevo enfoque para el diseño funcional de una computadora digital". Artículos presentados en la conferencia informática conjunta occidental IRE-AIEE-ACM del 9 al 11 de mayo de 1961 . 1961 Conferencia informática conjunta occidental IRE-AIEE-ACM. págs. 393–396. doi :10.1145/1460690.1460736. ISBN 978-1-45037872-7. S2CID  29044652.
  7. ^ Barton, Robert S. (1987). "Un nuevo enfoque para el diseño funcional de una computadora digital". Anales IEEE de la historia de la informática . 9 : 11-15. doi :10.1109/MAHC.1987.10002.
  8. ^ Blaauw, Gerrit Anne ; Brooks, Jr., Frederick Phillips (1997). Arquitectura de ordenadores: Conceptos y evolución . Boston, Massachusetts, EE.UU.: Addison-Wesley Longman Publishing Co., Inc.
  9. ^ ab LaForest, Charles Eric (abril de 2007). "2.1 Lukasiewicz y la primera generación: 2.1.2 Alemania: Konrad Zuse (1910-1995); 2.2 La primera generación de computadoras pila: 2.2.1 Zuse Z4". Arquitectura informática apilada de segunda generación (PDF) (tesis). Waterloo, Canadá: Universidad de Waterloo . pag. 8, 11, etc. Archivado (PDF) desde el original el 2022-01-20 . Consultado el 2 de julio de 2022 .(178 páginas) [1]
  10. ^ Greve, David A.; Wilding, Matthew M. (12 de enero de 1998). "El primer procesador Java del mundo". Tiempos de ingeniería electrónica .
  11. ^ "Principios de funcionamiento del procesador Mesa". Museo de la Computación DigiBarn . Fotocopiadora . Consultado el 20 de septiembre de 2023 .
  12. ^ Diente de león "DigiBarn: Xerox Star 8010""". Museo de la Computación DigiBarn . Consultado el 20 de septiembre de 2023 .
  13. ^ "Hewlett-Packard Journal Vol. 34 No. 8 (1983-08) (Hewlett-Packard)". Agosto de 1983 . Consultado el 5 de febrero de 2024 . {{cite journal}}: Citar diario requiere |journal=( ayuda )
  14. ^ Guía del programador de microcontroladores MARC4 de 4 bits (PDF) . Atmel .
  15. ^ "Cuartas fichas". Colorforth.com . Archivado desde el original el 15 de febrero de 2006 . Consultado el 8 de octubre de 2017 .
  16. ^ "Descripción general del microprocesador F21". Ultratecnología.com . Consultado el 8 de octubre de 2017 .
  17. ^ "Wiki de ForthFreak". GitHub.com . 2017-08-25 . Consultado el 8 de octubre de 2017 .
  18. ^ "Un chip Java disponible, ¡ahora!". Desarrollador.com . 1999-04-08 . Consultado el 7 de julio de 2022 .
  19. ^ "Procesador 4stack". bernd-paysan.de . Consultado el 8 de octubre de 2017 .
  20. ^ "Transferencia del compilador GNU C al microprocesador Thor" (PDF) . 1995-12-04. Archivado desde el original (PDF) el 20 de agosto de 2011 . Consultado el 30 de marzo de 2011 .
  21. ^ "ZPU: la CPU de 32 bits más pequeña del mundo con una cadena de herramientas GCC: descripción general". opencores.org . Consultado el 7 de febrero de 2015 .
  22. ^ ab "Documentos". GreenArrays, Inc. Tecnología F18A . Consultado el 7 de julio de 2022 .
  23. ^ ab "instrucciones colorForth". Colorforth.com . Archivado desde el original el 10 de marzo de 2016 . Consultado el 8 de octubre de 2017 .(Conjunto de instrucciones de los núcleos F18A, denominado colorForth por razones históricas).
  24. ^ "GreenArrays, Inc". Greenarraychips.com . Consultado el 8 de octubre de 2017 .
  25. ^ Randell, Brian ; Russell, Lawford John (1964). Implementación de Algol 60 (PDF) . Londres, Reino Unido: Academic Press . ISBN 0-12-578150-4.
  26. ^ Duncan, Fraser George (1 de mayo de 1977). "Desarrollo de máquinas apilables: Australia, Gran Bretaña y Europa" (PDF) . Computadora . vol. 10, núm. 5. Universidad de Bristol, Bristol, Virginia, Estados Unidos. págs. 50–52. doi :10.1109/MC.1977.315873. eISSN  1558-0814. ISSN  0018-9162. S2CID  17013010. CÓDIGO  CPTRB4. Archivado desde el original (PDF) el 15 de octubre de 2023 . Consultado el 15 de octubre de 2023 .(3 páginas)
  27. ^ Shi, Yunhe; Gregg, David; Beatty, Andrés; Ertl, M. Antón (2005). "Enfrentamiento de máquinas virtuales: pila versus registros". Actas de la 1ª conferencia internacional ACM/USENIX sobre entornos de ejecución virtuales . págs. 153-163. doi :10.1145/1064979.1065001. ISBN 1595930477. S2CID  811512.
  28. ^ Hyde, Randall (2004). Escribe un gran código, vol. 2: Pensar en un nivel bajo, escribir en un nivel alto. vol. 2. Sin prensa de almidón . pag. 391.ISBN _ 978-1-59327-065-0. Consultado el 30 de junio de 2021 .
  29. ^ "Arquitectura informática: un enfoque cuantitativo", John L. Hennessy , David Andrew Patterson ; Vea la discusión sobre máquinas apilables.
  30. ^ ab Koopman, Jr., Philip John. "Stack Computers: la nueva ola". Ece.cmu.edu . Consultado el 8 de octubre de 2017 .
  31. ^ Introducción a los sistemas de la serie A (PDF) . Corporación Burroughs . Abril de 1986 . Consultado el 20 de septiembre de 2023 .
  32. ^ "Diseño e implementación de una máquina apiladora eficiente" (PDF) . Jopdesign.com . Consultado el 8 de octubre de 2017 .
  33. ^ Sinha, Steve; Chatterji, Satrajit; Ravindran, Kaushik. "BOOST: La pila fuera de servicio de Berkeley". Puerta de la investigación . Consultado el 11 de noviembre de 2023 .
  34. ^ Bergh, Arndt; Keilman, Keith; Magenheimer, Daniel; Miller, James (diciembre de 1987). "Emulación HP3000 en computadoras con arquitectura HP Precision" (PDF) . Diario de Hewlett-Packard . Hewlett-Packard : 87–89 . Consultado el 20 de septiembre de 2023 .
  35. ^ Kristy Andrews; Duane Sand (octubre de 1992). "Migración de una familia de computadoras CISC a RISC mediante traducción de código objeto". Actas de ASPLOS-V .
  36. ^ Manual de CPU 8051, Intel, 1980
  37. ^ Shi, Yunhe; Gregg, David; Beatty, Andrés; Ertle, M. Antón. "Enfrentamiento de máquinas virtuales: apilar frente a registrar máquinas" (PDF) . Usenix.org . Consultado el 8 de octubre de 2017 .
  38. ^ Davis, Brian; Beatty, Andrés; Casey, Kevin; Gregg, David; Waldron, Juan. "El caso de las máquinas de registro virtuales" (PDF) . Scss.tcd.ie. _ Consultado el 20 de septiembre de 2023 .
  39. ^ Bornstein, Dan (29 de mayo de 2008). "Presentación de los componentes internos de Dalvik VM" (PDF) . pag. 22 . Consultado el 16 de agosto de 2010 .
  40. ^ "La implementación de Lua 5.0" (PDF) . Lua.org . Consultado el 8 de octubre de 2017 .
  41. ^ "La máquina virtual de Lua 5.0" (PDF) . Inf.puc-rio.br . Consultado el 8 de octubre de 2017 .
  42. ^ "Predicción de ramas y actuación de los intérpretes: no confíe en el folclore". Hal.inria.fr . Consultado el 20 de septiembre de 2023 .

enlaces externos