ZX81 escribió:ZX-81 escribió:ZX81 escribió:
Ahora sólo me quedaría buscar porque se cuelga el emulador en algunos programas, implementar el sonido (BEEPs) y añadir los t-states, porque todo va super rápido
Saludos.
Si quieres ver algo más, siempre puedes mirar el código de mi emulador,
JSpeccy, que también está escrito en Java. En mis repos también tienes el código del core Z80 que gasta el emulador en Java y en C++, y que implementan una Z80 completa, con (casi) todos los bells & whistles.
Eso sí, te deseo buena suerte con él, si es que se te ocurre publicarlo. El 90% de la gente directamente odia Java, aunque no tienen ni idea de qué va la fiesta. Desde el 2011, me he encontrado con montones de personas que rajan del emulador sin siquiera haberlo probado.
Vamos, que si lo haces para aprender, cohonúo, pero como lo publiques, temo que te llevarás un chasco desagradable. Es lo que hay.
He visto que en tu emulador los T-States no los vas añadiendo en cada instrucción. Pones que en cada búsqueda de instrucción sumas 4 T-States, para cada lectura y escritura de memoria sumas 3 T-States y para cada IN y OUT sumas 4 T-States. Luego pones que en algunas instrucciones es necesario añadir algunos T-States más. Si no es mucha molestia, de qué instrucciones de tratarían?
Gracias.
Efectivamente, no los añado instrucción a instrucción simplemente porque eso no vale para emular un Spectrum al 100%, ya que para emular la memoria en contienda necesitas que las cosas sucedan exactamente, o lo suficientemente cerca, a como las haría la CPU. En otros emuladores puedes tomarte "licencias" que aceleran la ejecución, pero no en el Spectrum. Por ejemplo, si te vas al Z80.java, línea 1935, tienes la instrucción DJNZ. Todas las instrucciones comienzan leyendo el opcode de RAM (3 ciclos) y luego un ciclo más de decodificación, durante el cual se pone el contenido del par IR en el bus de direcciones para que la RAM haga su refresco.
Pero en DJNZ hay un quinto ciclo más y ese se genra llamando al método
addressOnBus. En cualquier otro ordenador eso no importaría mucho, pero en el Spectrum es fundamental. En la línea 1941 tienes otra llamada al mismo método que añade 5 ciclos durante los cuales la CPU real calcula la dirección del salto para DJNZ, pero mientras que en el primer caso lo que causará la contención será el contenido de IR, en el siguiente es el contenido del registro PC en ese preciso momento y ciclo a ciclo. Y cada uno de esos ciclos provocará una contención diferente, dependiendo de donde se encuentre.
Una optimización podría ser que solo leyera el byte de desplazamiento si B != 0, si no, añades a capón los 3 ciclos que costaría la lectura y no lees nada. De nuevo, con ese tipo de emulación no te sale un Spectrum ni de broma.
Por otro lado, estrictamente hablando, la CPU nada sabe de contar ciclos, para ella todos los ciclos son iguales, nunca está a principio de cuadro, ni al final, de modo que estructuralmente no me parece muy correcto que la CPU cuente nada. Mejor que lo haga una clase Clock, que además te puede avisar de eventos en determinados momentos.
Espero no liarte mucho.