¿Cómo ejecuta una CPU el código de otra con el que no es compatible?

Todos nosotros tenemos un dispositivo PostPC y un PC siendo utilizados al mismo tiempo, ambos tipos de dispositivos tienen software incompatible. ¿No sería ideal que un dispositivo PC o PostPC pudiese hacer una traducción de una ISA a otra? De este tema os vamos a hablar en este artículo, de la forma más detallada y accesible posible

El mundo de la informática esta dividido en dos mitades en estos momentos, por un lado los programas que funcionan en la ISA x86 y por el otro los programas que lo hacen bajo la ISA x86. Pero en algunos casos es importante que un PC o un PostPC ejecute programas x86 y AMD al mismo tiempo.

Software para la traducción de una ISA a otra

Sistema binario

Las soluciones por software para que una CPU con un set de registros e instrucciones entienda a otro son principalmente tres, ninguna de ellas son soluciones no requieren de ningún hardware en el sistema para hacer el trabajo de traducción, pero ninguna de ellas es lo suficientemente efectiva como para garantizar el mismo rendimiento que las soluciones basadas en hardware, las cuales veremos más adelante en este mismo artículo.

Emulación del hardware del que se pretende ejecutar el software

emulación traslado ISA

La más simple es la emulación, la cual consiste en un programa que a tiempo real traduce el código fuente en binario para una arquitectura en código que la máquina huésped puede entender. ¿La contrapartida de ello? Debido a que la traducción se hace a tiempo real nos encontramos con que hay una perdida de rendimiento que depende de la dificultad de la emulación.

Además en algunos sistemas no solo se emula la CPU sino todo el hardware accesorio, añadiendo un nivel dificultad extra en la misma y la necesidad de un hardware para emular que suele ser un par de ordenes de magnitud que el sistema que pretende que emular.

Es por ello que pese a que el PC es técnicamente superior a las consolas de videojuegos nos encontramos que se tarda un largo tiempo, a veces hasta más de una década, en poder emular de manera correcta a una consola de videojuegos recién lanzada al mercado.

Traducción de una ISA a otra vía compilación

Compilación Código

La forma más fácil de hacer que una ISA se haga pasar por otra es obviamente traducir todas las instrucciones de una ISA a instrucciones de otra ISA durante la instalación de una aplicación.

¿Y como se consigue esto? Pues haciendo un desempaquetado de instrucciones, esto significa coger línea del código del programa una por una con un programa que funciona en segundo plano durante la instalación, el cual analiza y traduce las instrucciones del programa para la ISA en origen en una o varias instrucciones de la ISA objetivo.

Este método es el que ha utilizado Apple en su M1 para ejecutar el código x86, no obstante el código obtenido no es del todo eficiente en comparación con la compilación directa de la aplicación generando desde el código fuente del programa un binario nativo para el nuevo conjunto de registros e instrucciones.

Fat Binaries

Fat Binaries

Un Fat Binary es un código fuente ya compilado que tiene diferentes secciones para diferentes arquitecturas, de tal manera que cuando empieza el programa primero pregunta cual es la ISA del procesador y luego deriva a la dirección de memoria donde empieza el código binario para dicho conjunto de registros e instrucciones.

La consecuencia es que el código fuente del programa es mucho más grande que en un binario para una sola arquitectura, pero, al mismo tiempo es la forma más fácil de asegurar una transición a una nueva ISA en una plataforma, ya que con los Fat Binaries te aseguras que la aplicación llegue al nuevo mercado sin muchas complicaciones.

Hardware para la traducción de una ISA a otra

Pero lo que realmente nos interesa son las opciones a nivel de hardware, principalmente por el hecho que no queremos encontrarnos con la falta de velocidad de la emulación, la imprecisión del código generado por los traductores a tiempo de instalación y queremos que el código para otra ISA que nuestra CPU no puede ejecutar no ese ahí ocupando capacidad de la memoria.

¿Es posible hacer esto? Si, pero para poder entender como es posible antes tenemos que entender una serie de conceptos básicos.

CISC vs RISC, dos formas de diseñar el conjunto de instrucciones de un procesador

RISC vs CISC

Para entender la diferencia entre CISC y RISC lo primero que hemos de imaginarnos que un programa no es más que una lista de instrucciones, imaginad por un momento que dejáis una lista de instrucciones en un papal, tenéis toda la libertad para usar el lenguaje para escribir dicha lista.

Ahora bien, imaginad que os dicen que solo podéis utilizar una serie limitada de verbos. ¿La consecuencia? Vuestra lista se hará mucho más grande por el hecho que tendréis que componer acciones a través de otras. Pues bien, ese concepto es la diferencia entre instrucciones CISC e instrucciones RISC, la diferencia es que en un procesador, sea una CPU, una GPU o del tipo que sea, cada una de estas instrucciones ha de estar codificada en el hardware y tiene su camino de datos en las etapas de descodificación y ejecución del ciclo de instrucción.

La consecuencia es que los procesadores con conjuntos de instrucciones RISC son mucho más simples que los procesadores CISC en lo que a su composición se refiere, pero este planteamiento de RISC vs CISC lleva años estando anticuado, pero se ha de entender que una aplicación CISC ocupará menos espacio en memoria al requerir menos instrucciones, pero un procesador RISC es más fácil de ejecutar.

La importancia de las micro-instrucciones

CPU comunicación

A finales de los 80 el mercado lo dominaban dos procesadores, por un lado los x86 de Intel donde el 80286 y el 80386 eran los reyes y por el otro el Motorola 68000. ¿La particularidad de ambos? Eran procesadores CISC y la segmentación de estos de cara a aumentar la velocidad era difícil.

Pero, ¿qué es la segmentación? Es el hecho de dividir la ejecución de una instrucción en varios ciclos de reloj, de tal manera que cuando una instrucción esta en una etapa n, entonces la instrucción que viene después estará en la n-1 y la anterior en la etapa n+1, pero esto que les permitió aumentar considerablemente las velocidades de reloj en un principio se convirtió en un problema y vieron que las ISAs tal y como estaban creadas no podían escalar mucho más, sean estas RISC o CISC.

Microcódigo y microinstrucciones

La solución vino de la mano de utilizar micro-instrucciones, estas son instrucciones muy básicas que se utilizan para crear otras instrucciones más complejas en combinaciones de estas en diferentes ordenes. La idea de cara al aumento de la velocidad de reloj es que si tu subdivides en una mayor cantidad de etapas entonces la velocidad de reloj que puedes alcanzar es lo que tarda en ejecutarse cada una de dichas etapas.

Al final la mayoría de procesadores desde mediados de los 90 se diseñan siendo aparentemente una ISA en concreto de cara al software pero realmente están disfrazados, ya que internamente añaden una fase de descodificación adicional donde las instrucciones a través de una unidad especial son traducidas en micro-instrucciones.

Las micro-instrucciones también son importantes porque les permiten a los ingenieros de hardware dos cosas, por un lado aprovechar los patrones de diseño de unas instrucciones a otras y por otro hacer que en el caso de que el presupuesto sea limitado se puedan aprovechar partes de una instrucción en otra. Por lo que de cara al traslado de una ISA a otra tiempo real en cuanto a hardware lo importante pasa a ser que la traducción se haga a micro-instrucciones, ya que con ello nos ahorramos la doble traducción.

Hardware de función fija para la traducción de una ISA a otra a tiempo real

Hardware Traducción ISA diagrama

La imagen de arriba corresponde a una patente de VIA Technologies que se titula traducido al español en lo siguiente:

Microprocesador que ejecuta instrucciones de programa para la ISA ARM y la ISA x86 a través de un hardware de traducción en micro-instrucciones en un pipeline de ejecución común.

No vamos a entrar en la explicación de la patente punto por punto, solo que este tipo de unidad no es un imposible a nivel de hardware, pero, ¿no sería mejor trasladar el código fuente de una ISA a otra de manera directa a través de hardware? El motivo de ello no es otro que el de simplificar el hardware de traducción, una ISA puede tener decenas de instrucciones distintas y una correlación 1:1 puede llevar a un hardware sumamente complejo, en cambio la traducción en micro-instrucciones mucho más simple.

El hardware de traducción tiene una tabla interna en el que cada instrucción se traduce en una serie de micro-instrucciones, la ventaja de ello es que ni tan siquiera es necesario soportar el set de instrucciones al completo en una relación de 1:1 y es posible añadir nuevas instrucciones para la ISA de origen en futuras actualizaciones del firmware del hardware de la traducción.

Inteligencia Artificial para la traducción de instrucciones a tiempo real

Inteligencia Artificial

El problema de los traductores por hardware es que pese a que un conjunto de procesadores de diferente arquitectura pueden compartir una ISA externa, nos encontramos con que cada arquitectura dentro de cada ISA puede tener variaciones en el conjunto de micro-instrucciones interno, de tal manera que obliga a crear un nuevo traductor con cada nueva arquitectura que se lanza al mercado.

La solución para evitar este dolor de cabeza es tirar de inteligencia artificial, a base de entrenar una IA para que esta aprenda los patrones para traducir una ISA en otra, en el fondo esto no sería otra cosa que entrenar una IA para trasladar de un lenguaje natural a otro, pero esta solución es más bien una solución mixta ya que combina la compilación o emulación por software con el hardware para la IA que es que el aprende los patrones que luego aplicará para generar el código.

Debido a que estamos viendo el añadido de unidades de hardware para acelerar algoritmos de inteligencia artificial y el coste en cuanto a hardware es nulo, ya que no requiere la creación de hardware adicional. El uso de algoritmos de inteligencia artificial junto al hardware para acelerarlos será clave para el traslado a tiempo real de una ISA a otra.