Aprender algunas cosillas sobre emulación

Pues el caso es que me gustaría empezar un proyecto para emular una NES el 6502 para implementarlo en un ARM Cortex, el caso es que me apetece hacerlo como pasatiempo y ya de paso aprender algo, ya que imagino que de ahí seguro que aprendo variadas cosas.
Mis conocimientos son básicos, se programar algo en VHDL,C, C++ y ASM en PIC he tocado, sin ser ningún fiera me defiendo por así decirlo a nivel básico.

Tenia pensado empezar intentando emular el 8080 o el Z80 para romper mano, creéis que es buen comienzo o empiezo por otro sitio, ando un poco perdido si sabéis de material de ayuda os lo agradezco.
Buenas,

yo empezaría por una cpu lo mas sencilla posible y muy bien documentada a nivel de arquitectura, asi que tiraria entre el z80 o 6502, tirando por un interprete que conceptualmente es mas sencillo, es mas si te fijas en el core del z80 de mame, es bastante sencillo y entendible.

https://github.com/mamedev/mame/blob/ma ... 80/z80.cpp

Me imagino que gente como @theelf te podrá dar mejores consejos.
Igual me estoy metiendo en camisa de once barras pero como proyecto a largo-medio plazo lo veo muy interesante.
WTF, un archivo de 3700 lineas. A ver quien depura eso [mad]

Lo normal sería partirlo en 10-20 ficheros. No hacer un fichero tan brutal como ese.

Y la maldita palabra "inline", que en los compiladores modernos es ignorada. Pero la gente sigue poniendola cawento
Buenas, como me ha mencionado @nu_kru, comento un poco mis experiencias, en base a haber escrito varios emuladores, en su mayoria de CPU para integrarse a otro emulador/programa, aunque si he echo algun proyecto completo, un emulador de Atari ST y alguna cosilla mas algun tiempo atras


Lo primero es simplemente recopilar informacion de como funciona lo que quieras emular, a estas alturas da igual el lenguaje que quieras usar, lo primero es entender perfectamente como funciona la maquina

La NES tiene un 6502, es un cpu low-endian, por ejemplo si no sabes bien el concepto, es buscar informacion de como funciona ese tipo de cpus. Si sabes te saltas este paso, y al siguiente

Yo que se, si podes identificar el porque de este codigo, tal vez podes ahorrarte estudiar como funciona el cpu

#include <stdio.h>
#include <stdint.h>

int main(void)
{
   int16_t a = 1;
   int8_t *p = (int8_t *) &a;

   if (p[0] != 1)
   printf("big-endian");
   else           
   printf("little-endian ");
   
   return 0;
}



Cuando tengas estudiada la maquina, te podes plantear el tipo de emulacion, interprete o recompilacion. Lo mas comun para emular hardware poco potente como la nes, sera interprete, que tambien requiere menos conocimientos (o nulos) de ensamblador

Un codigo tipico para interprete es

      while(CPUactivo)
      {
        buscar opcode
        Interpretar opcode
      }



Basicamente una vez tengas estudiado el CPU a emular, es interceptar las llamadas, interpretarlas, y devolver un valor esperado. Parece facil en papel, un dolor de huevos delante del notepad (o lo q uses para tipear codigo)...




Una vez que tengas identificado todo sobre papel, y decidido el tipo de emulacion, recien podes plantearte el lenguaje, plataforma a programar, etc


No se en que estado esta tu "proyecto" como para dar otros consejos realmente





Para darte un ejemplo del tema practico, hace unos tres años atras, me pille una PSP GO para remplazar a la PSP FAT que ya molestaba en el bolsillo

Cuestion que mi principal objetivo era jugar a la neogeo pocket en la PSP, consola que me gusta muchisimo. Cual fue mi sorpresa al darme cuenta que el unico emulador existente para PSP de NeoGeoPocket *decente*, era realmente un desastre

Dejemos de lado que tenia filtro bilinear, fallos a doquier... etc etc el principal problema era que no llegaba ni al 50% de la velocidad en la mayoria de los juegos , y solo se podia mantener la velocidad usando frameskip , un jodido desastre, asi no se disfruta......


Me baje el codigo del emulador, y despues de analizarlo, llege a la conclusion que el problema era que el emulador del CPU central, un TLCS-900H era extremadamente ineficiente. Escrito en C


Asi que me puse a escribir mi propio emulador de TLCS-900H en ensamblador, pero en vez de estudiarme el TLCS-900H de arriba a abajo (que tambien lo estudie) lo que hice fue basarme en los resultados que daba el core en C, viendo los opcodes, memoria, etc, pero principalmente tratando de mantener la estructura original


Resultado? ademas de lograr 100% de velocidad, es que pude escribir el emulador en unos pocos 3 meses, y lo logre integrar al resto del codigo existente de manera facil, ya que no hice cambios significativos a la estructura


http://www.elotrolado.net/hilo_emulador-neogeo-pocket-para-psp_2043905



Realmente no se que ventajas puede dar estudiar el codigo de un emulador ya existente, no puedo aconsejarte sobre ese tema, pero si que puedo aconsejarte que comienzes por algun lenguaje facil, no ensamblador, a menos, que te pase como a mi, que estas muy ajustado por el hardware, y no queda otra


Por eso tal vez echar un vistazo a algun emu ya existente en C, pueda darte alguna idea. Pero solo, solo, despues que te estudiaras la teoria. No sirve de nada meter mano al codigo sin conocer el hardware





@amchacon hombre, para ser un emulador de un CPU, 3700 lineas es relativamente simple y poco. El emulador original en C del TLCS-900H que comento arriba, andaba por las 20mil lineas

Cual es el problema de los inline? yo los veo constantemente en codigo de emuladores, aunque programo muy poco en C, suelo usarlos tambien
Por complementar, hace tiempo tengo este blog en favoritos que va precisamente sobre el tema, y lo explica todo bastante clarito y desde cero, seguramente te sirva:
http://www.emulator101.com/welcome.html

amchacon escribió:Y la maldita palabra "inline", que en los compiladores modernos es ignorada. Pero la gente sigue poniendola cawento


A no ser...

#define INLINE                  inline __attribute__((always_inline))
#define NOINLINE                __attribute__((noinline))
theelf escribió:@amchacon hombre, para ser un emulador de un CPU, 3700 lineas es relativamente simple y poco. El emulador original en C del TLCS-900H que comento arriba, andaba por las 20mil lineas

El problema no es la longitud del código, el problema esque lo ha metido todo dentro de un solo archivo.

Lo ideal sería haberlo partido en 10-20 archivos pequeños.

theelf escribió:Cual es el problema de los inline? yo los veo constantemente en codigo de emuladores, aunque programo muy poco en C, suelo usarlos tambien

Pues que los compiladores actuales ya hacen las funciones inline cuando es óptimo. Por lo que en realidad, esa palabra lo único que hace es ocupar espacio.

Korso10 escribió:
amchacon escribió:Y la maldita palabra "inline", que en los compiladores modernos es ignorada. Pero la gente sigue poniendola cawento

A no ser...

#define INLINE                  inline __attribute__((always_inline))
#define NOINLINE                __attribute__((noinline))

Solo en el compilador gcc. Y no siempre (funciones en distintos archivos no se puede hacer inline, salvo que las implementes en el header).

Por otro lado es mala idea. En ocasiones el inline puede bajar el rendimiento, creo que es mejor activar las optimizaciones del compilador y dejar que él decida.
@amchacon

mm.. yo prefiero todo en un bloque que en varios archivos la verdad, si hablamos de codigo de lo mismo

Sobre inline, dejarle toda la tarea al compilador me parece algo arriesgado, todo lo que se pueda hacer manual es mucho mejor a menos que no estes seguro de lo q estas escribiendo

Desconozco los pormenores de los compiladores actuales, pero a mi me parece que los inline siguen siendo validos
theelf escribió:@amchacon mm.. yo prefiero todo en un bloque que en varios archivos la verdad, si hablamos de codigo de lo mismo

Pues hombre, como tengas que buscar algo ahí te puedes morir [mad]

A mí las clases/módulos pequeñitos se hacen muchos más fáciles de depurar y de entender.

theelf escribió:Sobre inline, dejarle toda la tarea al compilador me parece algo arriesgado, todo lo que se pueda hacer manual es mucho mejor a menos que no estes seguro de lo q estas escribiendo

Inline es solo un consejo al compilador, el estándar no te garantiza que la función se haga inline.

La mayoría de la gente no es mejor que un compilador en estas micro-optimizaciones puesto que no tiene en cuenta tantas variables como hace el compilador.

Por ejemplo, si una función es muy larga o se llama muchas veces en distintas partes del código. Hacerla inline podría perjudicar el rendimiento, pues el código "inlinizado" se haría muy largo, lo que haría aumentar los fallos de caché.
theelf escribió:Desconozco los pormenores de los compiladores actuales, pero a mi me parece que los inline siguen siendo validos

Los compiladores actuales suelen ignorarlos. Como ya comenté, el inline solo es un consejo.
Muchas gracias @theelf grandes consejos y mas viniendo de alguien con experiencia, @Korso10 gracias por el enlace.

Lo de big-endian lo he leído en wikipedia y me ha quedado claro, el código se entiende, en principio pues con C me sentiría cómodo he hecho algunos pinitos con micro-controladores,poca cosa algún juego de naves en ARM y C++ .
Tambien, puedes mirar esta pagina, que ha mi entender, es la mas depurada que hay en toda la red con respecto a la emulacion de NES. Tambien, contiene muchos enlaces a tutoriales.
http://wiki.nesdev.com/w/index.php/Nesdev_Wiki
@desal

Tambien podes pasar por clasicas, justo ayer se abrio un hilo de un homebrew para la NES

http://www.elotrolado.net/hilo_vigilante-para-nes-port-sms_2174926


Programar para una consola no es lo mismo que hacer un emulador de esa consola, pero muchos conocimientos son los mismos, lo que seguro algunas preguntas que hagas tendran respuesta
11 respuestas