En arquitectura informática , una arquitectura activada por transporte ( TTA ) es un tipo de diseño de procesador en el que los programas controlan directamente los buses de transporte internos de un procesador. El cálculo se produce como un efecto secundario de los transportes de datos: escribir datos en un puerto de activación de una unidad funcional activa la unidad funcional para iniciar un cálculo. Esto es similar a lo que ocurre en una matriz sistólica . Debido a su estructura modular, TTA es una plantilla de procesador ideal para procesadores de conjuntos de instrucciones específicos de la aplicación ( ASIP ) con ruta de datos personalizada pero sin la inflexibilidad y el costo de diseño de los aceleradores de hardware de función fija.
Por lo general, un procesador activado por transporte tiene múltiples buses de transporte y múltiples unidades funcionales conectadas a los buses, lo que brinda oportunidades para el paralelismo a nivel de instrucción . El paralelismo lo define estáticamente el programador. En este sentido (y obviamente debido al gran ancho de palabra de instrucción), la arquitectura TTA se asemeja a la arquitectura de palabra de instrucción muy larga (VLIW). Una palabra de instrucción TTA se compone de múltiples ranuras, una ranura por bus, y cada ranura determina el transporte de datos que tiene lugar en el bus correspondiente. El control de grano fino permite algunas optimizaciones que no son posibles en un procesador convencional. Por ejemplo, el software puede transferir datos directamente entre unidades funcionales sin usar registros.
La activación de transporte expone algunos detalles de la microarquitectura que normalmente están ocultos para los programadores. Esto simplifica enormemente la lógica de control de un procesador, porque muchas decisiones que normalmente se toman en tiempo de ejecución se fijan en tiempo de compilación . Sin embargo, también significa que un binario compilado para un procesador TTA no se ejecutará en otro sin recompilación si hay incluso una pequeña diferencia en la arquitectura entre los dos. El problema de incompatibilidad binaria, además de la complejidad de implementar un cambio de contexto completo, hace que los TTA sean más adecuados para sistemas integrados que para la informática de propósito general.
De todas las arquitecturas informáticas de un solo conjunto de instrucciones , la arquitectura TTA es una de las pocas que ha tenido procesadores basados en ella, y la única que tiene procesadores basados en ella vendidos comercialmente.
Las TTA pueden considerarse arquitecturas VLIW de "ruta de datos expuesta". Mientras que VLIW se programa mediante operaciones, TTA divide la ejecución de la operación en múltiples operaciones de movimiento . El modelo de programación de bajo nivel permite varios beneficios en comparación con el VLIW estándar. Por ejemplo, una arquitectura TTA puede proporcionar más paralelismo con archivos de registro más simples que con VLIW. Como el programador tiene el control de la sincronización de los transportes de datos de operandos y resultados, la complejidad (la cantidad de puertos de entrada y salida) del archivo de registro (RF) no necesita escalarse de acuerdo con el peor escenario de emisión/finalización de las múltiples instrucciones paralelas.
Una importante optimización de software única que permite la programación de transporte se llama bypass de software . En el caso del bypass de software, el programador evita la reescritura del archivo de registro moviendo los datos directamente a los puertos de operando de la siguiente unidad funcional. Cuando esta optimización se aplica agresivamente, el movimiento original que transporta el resultado al archivo de registro se puede eliminar por completo, reduciendo así tanto la presión del puerto del archivo de registro como liberando un registro de propósito general para otras variables temporales. La presión de registro reducida , además de simplificar la complejidad requerida del hardware de RF, puede conducir a un ahorro significativo de energía de la CPU , un beneficio importante especialmente en sistemas integrados móviles. [1] [2]
Los procesadores TTA están formados por unidades de funciones independientes y archivos de registro , que están conectados con buses de transporte y sockets .
Cada unidad de función implementa una o más operaciones , que implementan funciones que van desde una simple suma de números enteros hasta un cálculo específico de la aplicación, complejo y arbitrario, definido por el usuario. Los operandos para las operaciones se transfieren a través de los puertos de la unidad de función .
Cada unidad de función puede tener una canalización independiente . En caso de que una unidad de función esté completamente canalizada , se puede iniciar una nueva operación que tarde varios ciclos de reloj en finalizar en cada ciclo de reloj. Por otro lado, una canalización puede ser tal que no siempre acepte nuevas solicitudes de inicio de operación mientras una antigua aún se esté ejecutando.
El acceso a la memoria de datos y la comunicación con el exterior del procesador se gestionan mediante unidades de función especiales. Las unidades de función que implementan operaciones de acceso a la memoria y se conectan a un módulo de memoria suelen denominarse unidades de carga/almacenamiento .
La unidad de control es un caso especial de unidad de función que controla la ejecución de programas. La unidad de control tiene acceso a la memoria de instrucciones para obtener las instrucciones que se van a ejecutar. Para permitir que los programas ejecutados transfieran la ejecución (salten) a una posición arbitraria en el programa ejecutado, la unidad de control proporciona operaciones de flujo de control. Una unidad de control normalmente tiene una secuencia de instrucciones , que consta de etapas para obtener, decodificar y ejecutar instrucciones de programa.
Los archivos de registro contienen registros de propósito general , que se utilizan para almacenar variables en los programas. Al igual que las unidades de función, los archivos de registro también tienen puertos de entrada y salida. La cantidad de puertos de lectura y escritura, es decir, la capacidad de poder leer y escribir múltiples registros en un mismo ciclo de reloj, puede variar en cada archivo de registro.
La arquitectura de interconexión consta de buses de transporte que se conectan a los puertos de las unidades funcionales mediante conectores . Debido al coste de la conectividad, es habitual reducir el número de conexiones entre unidades (unidades funcionales y archivos de registro). Se dice que una TTA está completamente conectada si existe una ruta desde cada puerto de salida de la unidad a los puertos de entrada de cada unidad.
Los sockets proporcionan medios para programar procesadores TTA al permitir seleccionar qué conexiones de bus a puerto del socket están habilitadas en cualquier instante de tiempo. De este modo, los transportes de datos que tienen lugar en un ciclo de reloj se pueden programar definiendo la conexión de puerto/socket de origen y destino que se habilitará para cada bus.
Algunas implementaciones de TTA admiten la ejecución condicional .
La ejecución condicional se implementa con la ayuda de guardias . Cada transporte de datos puede ser condicionalizado por un guardia, que está conectado a un registro (a menudo un registro condicional de 1 bit ) y a un bus. En caso de que el valor del registro protegido evalúe como falso (cero), el transporte de datos programado para el bus al que está conectado el guardia se comprime , es decir, no se escribe en su destino. Los transportes de datos incondicionales no están conectados a ningún guardia y siempre se ejecutan.
Todos los procesadores, incluidos los procesadores TTA, incluyen instrucciones de flujo de control que alteran el contador del programa, que se utilizan para implementar subrutinas , if-then-else , for-loop , etc. El lenguaje ensamblador para procesadores TTA generalmente incluye instrucciones de flujo de control como ramas incondicionales (JUMP), ramas relativas condicionales (BNZ), llamada a subrutina (CALL), retorno condicional (RETNZ), etc. que tienen el mismo aspecto que las instrucciones de lenguaje ensamblador correspondientes para otros procesadores.
Al igual que todas las demás operaciones en una máquina TTA, estas instrucciones se implementan como instrucciones de "movimiento" a una unidad de función especial.
Las implementaciones de TTA que admiten la ejecución condicional, como sTTAck y el primer prototipo MOVE, pueden implementar la mayoría de estas instrucciones de flujo de control como un movimiento condicional al contador del programa. [3] [4]
Las implementaciones de TTA que sólo admiten transportes de datos incondicionales, como Maxim Integrated MAXQ, [5] suelen tener una unidad de función especial conectada estrechamente al contador de programa que responde a una variedad de direcciones de destino. Cada una de estas direcciones, cuando se utiliza como destino de un "movimiento", tiene un efecto diferente en el contador de programa: cada instrucción de "bifurcación relativa <condición>" tiene una dirección de destino diferente para cada condición; y se utilizan otras direcciones de destino para CALL, RETNZ, etc.
En las arquitecturas de procesadores más tradicionales, un procesador suele programarse definiendo las operaciones ejecutadas y sus operandos. Por ejemplo, una instrucción de adición en una arquitectura RISC podría tener el siguiente aspecto.
suma r3, r1, r2
Esta operación de ejemplo suma los valores de los registros de propósito general r1 y r2 y almacena el resultado en el registro r3. En términos generales, la ejecución de la instrucción en el procesador probablemente resulte en la traducción de la instrucción a señales de control que controlan las conexiones de la red de interconexión y las unidades de función. La red de interconexión se utiliza para transferir los valores actuales de los registros r1 y r2 a la unidad de función que es capaz de ejecutar la operación de suma, a menudo llamada ALU (unidad aritmético-lógica). Finalmente, una señal de control selecciona y activa la operación de suma en la ALU, cuyo resultado se transfiere de vuelta al registro r3.
Los programas TTA no definen las operaciones, sino solo los transportes de datos necesarios para escribir y leer los valores de los operandos. La operación en sí se activa al escribir datos en un operando de activación de una operación. Por lo tanto, una operación se ejecuta como un efecto secundario del transporte de datos de activación. Por lo tanto, la ejecución de una operación de adición en TTA requiere tres definiciones de transporte de datos, también llamadas movimientos . Un movimiento define puntos finales para un transporte de datos que tiene lugar en un bus de transporte. Por ejemplo, un movimiento puede indicar que un transporte de datos desde la unidad de función F, puerto 1, al archivo de registro R, índice de registro 2, debe tener lugar en el bus B1. En caso de que haya varios buses en el procesador de destino, cada bus se puede utilizar en paralelo en el mismo ciclo de reloj. Por lo tanto, es posible explotar el paralelismo a nivel de transporte de datos programando varios transportes de datos en la misma instrucción.
Una operación de suma se puede ejecutar en un procesador TTA de la siguiente manera:
r1 -> ALU.operando1r2 -> ALU.add.triggerResultado ALU -> r3
El segundo movimiento, una escritura en el segundo operando de la unidad de función denominada ALU, activa la operación de suma. Esto hace que el resultado de la suma esté disponible en el puerto de salida 'result' después de la latencia de ejecución de 'add'.
Los puertos asociados con la ALU pueden actuar como un acumulador , lo que permite la creación de macroinstrucciones que abstraen el TTA subyacente:
lda r1 ; "cargar ALU": mover valor al operando 1 de la ALU add r2 ; add: mover valor al disparador de adición sta r3 ; "almacenar ALU": mover valor desde la ALU result
La filosofía principal de los TTA es trasladar la complejidad del hardware al software. Debido a esto, se introducen varios peligros adicionales para el programador. Uno de ellos son las ranuras de retardo , la latencia de operación visible para el programador de las unidades de función. La sincronización es completamente responsabilidad del programador. El programador tiene que programar las instrucciones de tal manera que el resultado no se lea demasiado pronto ni demasiado tarde. No hay detección de hardware para bloquear el procesador en caso de que un resultado se lea demasiado pronto. Considere, por ejemplo, una arquitectura que tiene una operación add con latencia de 1 y una operación mul con latencia de 3. Al activar la operación add , es posible leer el resultado en la siguiente instrucción (próximo ciclo de reloj), pero en el caso de mul , uno tiene que esperar dos instrucciones antes de que se pueda leer el resultado. El resultado está listo para la tercera instrucción después de la instrucción de activación.
Si se lee un resultado demasiado pronto, se leerá el resultado de una operación activada previamente o, en caso de que no se haya activado ninguna operación previamente en la unidad de función, el valor de lectura no estará definido. Por otro lado, el resultado debe leerse con la suficiente antelación para asegurarse de que el resultado de la siguiente operación no sobrescriba el resultado aún no leído en el puerto de salida.
Debido a la abundancia de contexto de procesador visible para el programador, que prácticamente incluye, además de los contenidos de los archivos de registro, también los contenidos de los registros de la canalización de la unidad de función y/o los puertos de entrada y salida de la unidad de función, los guardados de contexto necesarios para la compatibilidad con interrupciones externas pueden resultar complejos y costosos de implementar en un procesador TTA. Por lo tanto, los procesadores TTA normalmente no admiten interrupciones, pero su tarea se delega a un hardware externo (por ejemplo, un procesador de E/S) o se evita su necesidad mediante el uso de un mecanismo alternativo de sincronización/comunicación, como el sondeo.
Una arquitectura basada en registros y activada por transporte permite que todas las instrucciones se codifiquen como operaciones de transferencia simples. Todas las instrucciones se reducen a escribir un valor inmediato en un registro de destino o una ubicación de memoria o a mover datos entre registros y/o ubicaciones de memoria.