¿Es posible hacer un convertidor de ROM?

Jack Kasbrack 11/01/2018. 5 answers, 4.011 views
emulation nes compilers turbografx-16

Según mi entendimiento, es necesario un emulador porque la máquina con el emulador (por ejemplo, Windows) no ejecuta el mismo código de máquina que la plataforma de destino (6502, por ejemplo). Entonces, lo que hace un emulador es que interpreta el código línea por línea y lo ejecuta de manera similar a como funciona un intérprete.

Teniendo esto en cuenta, ¿sería posible crear el equivalente de un compilador, que convertiría (por ejemplo) un archivo .PCE en un archivo .exe, para que pueda ejecutarse en Windows sin un emulador?

5 Answers


NobodyNada 11/01/2018.

Nota: esta respuesta se centra principalmente en la NES, ya que eso es con lo que estoy más familiarizado.

Sí; Esto se denomina recompilación estática o traducción binaria estática , y es teóricamente posible: Jamulator, de Andrew Kelly, lo hace . Sin embargo, la recompilación puede ser increíblemente difícil (hasta el punto de que en algunos casos puede ser necesario recurrir a la interpretación en el tiempo de ejecución). Además, el hardware sin CPU del sistema (como gráficos y hardware de sonido) todavía debe ser emulado.


La compilación estática del código de la máquina es increíblemente difícil; determinar el comportamiento de un programa analizando su código antes de tiempo es, en algunos casos, probadamente imposible . Algunos de los problemas que surgen al compilar estáticamente una ROM de videojuegos retro incluyen:

¿Cómo determinamos qué partes de la ROM son código ejecutable y qué partes son datos?

La forma "obvia" de recompilar una ROM de NES es tomar una sola pasada, leer una secuencia de instrucciones 6502 y generar una secuencia de instrucciones x86. Sin embargo, la ROM también incluye bytes de datos, que producirán basura si se interpretan como instrucciones. Estas instrucciones de basura nunca deben ejecutarse, ya que el programa nunca saltará a esa dirección, pero la presencia de datos sin instrucción plantea dos problemas:

1) El programa debe poder leer su propia ROM. Esto no es realmente un problema difícil en absoluto; solo necesitamos incluir una copia no compilada de la ROM en el programa binario compilado para leer los bytes de datos.

2) No podemos escribir un simple compilador de un solo paso. Las instrucciones pueden tener varios bytes de ancho, por lo que si intentamos recompilar un bloque de datos no ejecutables, podríamos terminar desalineados al compilar las instrucciones subsiguientes. (Como un ejemplo simple (algo artificial), en el código de máquina 6502, la secuencia de bytes 69 09 0A es ADC #09; ASL , mientras que la secuencia de bytes A5 69 09 0A es LDA $69; ORA #0A . El punto en el cual Empezamos a ejecutar afectando drásticamente nuestros resultados.)

Entonces, esto significa que tenemos que realizar un análisis de código mucho más complejo para determinar los bloques básicos del programa y compilarlos individualmente. jamulator hace esto comenzando en los vectores de interrupción y siguiendo todas las ramas posibles desde allí. Sin embargo, este enfoque still tiene problemas con:

Saltos dinámicos

Aquí es donde la dirección para ejecutar se calcula en tiempo de ejecución. En algunos casos, la dirección calculada en tiempo de ejecución se puede buscar y se puede encontrar el código x86 correspondiente. Sin embargo, si la only forma de acceder a un bloque básico es a través de un salto indirecto, el recompilador probablemente habría asumido que el bloque no era un código ejecutable y, por lo tanto, no lo había compilado.

jamulator mitiga este problema usando un hack: soporte codificado en el recompilador para reconocer implementaciones de tablas de salto en juegos específicos . Esto funciona, pero claramente no es una solución de propósito general.

Cambio de banco

Aunque Jamulator solo admite juegos NROM, muchos juegos NES con mapeadores más complicados podrían cambiar regiones de código y datos dentro y fuera del espacio de direcciones accesible. Esto significa que cada salto podría ir a docenas de ubicaciones diferentes en la ROM, dependiendo de qué banco se asigna a esa dirección en tiempo de ejecución.

Código generado dinámicamente / código auto-modificable

Aunque esto no era común en los juegos de NES debido a la pequeña cantidad de RAM, si recuerdo correctamente, el software C64 ocasionalmente generaría y ejecutaría código en tiempo de ejecución, o modificaría el código durante la ejecución. Esto sería casi imposible de predecir estáticamente.

Otro hardware como gráficos y audio.

La unidad de procesamiento de imágenes NES y la unidad de procesamiento de audio aún deben estar emuladas. jamulator incluye un emulador para el hardware sin CPU en una biblioteca de tiempo de ejecución, y el código x86 generado llama a una función de biblioteca para manejar escrituras en direcciones de memoria asignadas a operaciones de E / S.

Muchos juegos de NES se basaron en la sincronización precisa entre la CPU y la PPU, por lo que el código de la CPU generado debe contar la cantidad de 6502 ciclos de reloj que toma el código ejecutado. jamulator implementa esto de manera relativamente simple : después de cada instrucción NES, llama a una biblioteca de tiempo de ejecución que ejecuta el resto del hardware durante un número específico de ciclos. Este enfoque es simple de implementar, pero tiene algunas desventajas:

  • Las escrituras de la CPU no ocurren exactly el ciclo exactly correcto en relación con el resto del hardware. La sincronización solo es precisa para la instrucción más cercana, no para el ciclo más cercano.
  • La emulación de la PPU y la APU después de cada instrucción de la CPU perjudica en gran medida el rendimiento, ya que el recompilador pierde oportunidades para eliminar, combinar o reordenar las instrucciones para un mejor rendimiento. El cambio frecuente entre las operaciones también perjudica el rendimiento de la memoria caché de la CPU x86 y la precisión de la predicción de ramificación.

Un enfoque más eficiente (pero mucho más complejo) es predecir los momentos en que se necesita una sincronización precisa entre la CPU y el resto del hardware, y usar estas predicciones para cambiar entre los modos de emulación rápidos y precisos según el ciclo, según sea necesario.


Aunque la recompilación estática es a menudo posible, puede ser extremadamente difícil. El jamulator a veces recurre a la interpretación cuando el juego hace algo que el recompilador estático no maneja adecuadamente.

La precisión de la recompilación estática podría mejorarse ejecutando el juego dentro de algo como el registrador de datos de código de FCEUX, que emula al juego mientras registra los caminos de código que toma. Los datos de una ejecución real del juego se pueden utilizar para mejorar en gran medida la precisión de la recompilación estática. Sin embargo, la "ejecución de prueba" registrada por el registrador de datos de código debe ejercer exhaustivamente las posibles rutas de código tomadas por el juego para que sea útil.

Los emuladores de sistemas más nuevos, como el Dolphin Emulator (que emula a GameCube y Wii) con frecuencia usan compilación justo a tiempo , donde el emulador compila secciones del código del juego at runtime . En general, esto proporciona lo mejor de ambos mundos: obtenemos las mejoras de rendimiento del código compilado, y la visión mejorada de poder analizar el código del juego en tiempo de ejecución.


Michael Kohne 11/01/2018.

El problema es que el emulador está emulando mucho más que solo la CPU. Así que además de transpilar el código 6502 al código Intel (y no crea que eso sea simple, hacer que el tiempo salga bien sería un problema fascinante), también debe proporcionar código (de manera análoga a las bibliotecas estándar que usa cualquier programa) que proporcionan un entorno de E / S emulado que el código 6502 puede manipular.

Sería mucho más fácil simplemente agrupar el emulador y el programa en un binario y enviar eso. Esto es lo que hizo Ian Bogost con Un año lento : el binario 6502 simplemente se envuelve en un binario con el emulador.


DrMeta 11/01/2018.

Si es posible o no, no es el único factor que define el desarrollo. Tenga en cuenta que la calidad de un emulador está muy conectada con su capacidad para crear TAS, Savestate, usar RAMWatch, etc., todo lo cual no sería posible si la ROM se convirtiera en un archivo .EXE. Con esto en mente, los desarrolladores no han estado interesados ​​en crear tal cosa, que es la razón por la que no es "posible" con el conocimiento que probablemente tenga la comunidad.


Jules 11/01/2018.

Compilar las instrucciones de un procesador arbitrario (por ejemplo, un 6502) en un código que se ejecutará en una PC moderna debería ser bastante fácil. Después de todo, no es muy diferente de lo que hace un compilador justo a tiempo para un lenguaje que se distribuye como bytecode (por ejemplo, Java, .NET, etc.) y más simple que un compilador JIT para un lenguaje que necesita no trivial análisis (por ejemplo, Javascript). La forma más fácil sería utilizar un generador de código existente (por ejemplo, LLVM o gcc) y simplemente agregar un extremo muy simple que lea el código de la máquina y genere las instrucciones intermedias apropiadas ...

Hay tres cosas que hacen esto mucho más complejo de lo que parece:

  • Primero, deberá emular el hardware que no sea la CPU, por lo que el sistema de gráficos, el sistema de audio, etc. Junto con esto, deberá proporcionar una versión pre-traducida de cualquier firmware que se espera que esté presente en su Sistema de destino para que se pueda vincular al código que está compilando.

  • En segundo lugar, debe identificar qué partes de la ROM son en realidad instrucciones que deben ejecutarse y qué partes son datos (por ejemplo, sprites, pistas de audio, mapas de nivel de juego, etc.). Las partes de los datos deben manejarse de manera diferente, idealmente, traducidas a un formato de más fácil acceso (especialmente números de múltiples bytes, ya sean enteros o puntos flotantes, que podrían estar fácilmente en un formato que el procesador host no entienda de forma nativa).

  • Tercero, y posiblemente más interesante, todo esto puede ser, de hecho, algo menos legal que el simple uso de la emulación interpretada. Muchos proveedores de software y hardware han otorgado permiso para permitir que su código (ya sea firmware o juegos) se use en emuladores, siempre que permanezcan sin cambios (p. Ej., Sé que esta es la situación con las ROM para el Sinclair ZX Spectrum, que tienen publicado bajo términos como estos por su titular actual de derechos de autor, Amstrad PLC). Pero recompilarlo para un nuevo sistema lo cambia. Incluso cuando no se ha otorgado el permiso de copyright, hay una variedad de excepciones al copyright que permiten realizar una copia mínima (p. Ej., Copiar el contenido de un cartucho ROM en el disco para facilitar el acceso) si es necesario para que funcione, pero la recompilación no es necesaria, por lo que incluso cuando no hay una concesión de licencia explícita disponible, puede ser menos legal compilar para una nueva arquitectura que solo para emular la antigua. (No soy abogado, así que tome esto con una pizca de sal muy grande, pero he pasado una cantidad de tiempo razonable aprendiendo sobre las leyes de derechos de autor, y estoy bastante seguro de esta posición)


lvd 11/01/2018.

No es una respuesta completa; Sin embargo, muchos emuladores de las consolas, como Playstation y similares, en cierto sentido hacen lo mismo sobre lo que están preguntando.

En lugar de ejecutar el código con precisión y emular con precisión el hardware, algunos elementos de código típicos (en su mayoría relacionados con transformaciones y renderización 3D) se reconocen como un todo y el resultado final se inserta simplemente en el estado de la máquina o se procesa utilizando las capacidades 3D del host. La razón para hacerlo es probablemente la falta de información detallada del hardware y la velocidad de la CPU del host, que no es suficiente para emular todo lo necesario.


HighResolutionMusic.com - Download Hi-Res Songs

Related questions

Hot questions

Language

Popular Tags