Aprendiendo a programar un Emulador (DCPU-16)

Foro dedicado a la programación en todo tipo de sistemas clásicos.
jepalza

Re: Aprendiendo a programar un Emulador (DCPU-16)

Mensajepor jepalza » 02 Oct 2012, 20:21

Parte de código de mi emulador basic del 6809. Es la parte de las IRQ y la ejecución de INS. Verás la rutina que lee la INS para "inyectarla" al emulador de CPU, las dos IRQ que tiene (FIRQ e IRQ), el código de reset de la CPU (que pone a cero los contadores y las IRQ) y la rutina que ejecuta la INS, enviando la ejecución a la rutina que le corresponde. (se me olvida, y la NMI, la interrupción hardware no enmascarable, o sea, no interrumpible, siempre se ejecuta si por ejemplo, el teclado, la pide)

Código: Seleccionar todo


Function m6809_execute() As Integer


  vd = get_byte() ' cogemos la instruccion (e incrementamos PC en +1)
 
  cicloscpu = opcycles(vd) ' cogemos los ciclos empleados
  addrmode  = addrmod(vd)  ' cogemos el modo de direccionamiento
 
   m6809_RunINS(vd)
   
  return cicloscpu

end Function


' funciones de reset, interrupciones y testeo de BIT's
sub m6809_reset()
   
  ra = 0
  rb = 0
  rDP = 0
     
  rx = 0
  ry = 0
  ru = 0
  rs = 0
 
  set_CC(0)
 
  ' estado de interrupciones IRQ y FIRQ deshabilitados
  ccf = 1
  cci = 1
 
  PC = peekw(&hfffe) ' rom

End Sub


sub m6809_firq()

  if ccf=0 Then
      cce = 0
    Push(rs, ru, &h81)
    rs=d1temp
    cci = 1
    ccf = 1
    PC = peekw(&hfff6) ' rom
    cicloscpu = 12
  End If
 
End Sub
 
sub m6809_irq()

  if cci=0 Then
      cce = 1
    Push(rs, ru, &hff)
    rs=d1temp
    cci = 1
    PC = peekw(&hfff8) 'rom
    cicloscpu = 21
  End If
 
End Sub

sub m6809_NMI()

      cce = 1
    Push(rs, ru, &h81)
    rs=d1temp
    cci = 1
    ccf = 1
    PC = peekw(&hfffc) 'rom
    cicloscpu = 21
 
End Sub

Sub m6809_RunINS(vr As Integer)
   
 Select Case vr
  Case 1
     Cintas()   ' saltamos al lector de cintas, al trampear la rom del Mo5
  Case 0,96,112
    neg ()
  Case 3,99,115
    com ()
  Case 4,100,116
    lsr ()

........
aqui van un porrón de lladas, una para cada INS que tiene la cpu 6809, pero son todas básicamente iguales.
........

    cmpu()
  Case 652,668
    cmps()
  Case else
    nulo()
 End Select
 
End Sub

Avatar de Usuario
Hark0
Amiga 1200
Amiga 1200
Mensajes: 1695
Registrado: 11 Jul 2012, 23:44
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
consola_favorita: (Otro)
Primera consola: (Otro)
Ubicación: Cornellà de Llobregat - Barcelona
Contactar:

Re: Aprendiendo a programar un Emulador (DCPU-16)

Mensajepor Hark0 » 02 Oct 2012, 21:11

Muchas gracias por los listados, mañana mismo me los imprimo... y repaso ;)

De antemano decirte que me has aclarado más cosas en dos hilos que en no pocos sitios de la red... se tiende a explicar el funcionamiento de los emuladores muchas veces entrando en cosas tan tecnicas que uno se pierde...

Perdón de antemano por el taladro de preguntas, has despertado un monstruo con tus exlicaciones... si consigo esto, prometo transcribilo a un ebook/pdf bien detalladito... ;)

Recapitulando a ver si no me he perdido:

1- Inicio las variables de registro a 0. PC también a 0.
2- Declaración de tipos de IRQ (básicas). Digamos 0 reset, 1 video, 2 teclado
2a- Declaración de instrucciones y número de bytes a leer según instrucción leida:

Instrucciones: (bytes a leer). Puede ser una tabla tipo Bytes_Ins[n] que contiene los bytes a leer tras lee la instrucción.
0 NOP (0) -> No hace nada, el bucle principal continúa.
1 SUMA A,B (2) -> A=A+B
2 RESTA A,B (2) -> A=A-B

3- Creación de espacio para memoria. DIM memoria%[cantidad de bytes].
4- Variables de control del emulador como contadores y demases a 0.

5- Empiezo (continúo) el mainloop leyendo la posición de memoria.
6- PC=PC+1
7- Según la instrucción leida, salto a una rutina u otra (select case instruccion)
7a- Leo en la tabla de instrucciones cuantos bytes debo leer y sumo a PC.
7b- Almaceno en las variables A y B los valores de las posiciones en el orden que leo memoria%[PC].

8- Se ejecuta la rutina 0,1 ó 2 y actualizo los registros según resultados de las operaciones nohacernada,suma a+b y resta a-b.

8a- Sumo +1 los contadores para IRQ1 y RQ2.
8b- Vuelvo a 5.
----------------------------

Tema IRQ:

IRQ 0 (reset) - reinicio la app. Tosco de momento...
IRQ 1 (video) - Pongamos que hay un contador 0 - 59, suma en cada loop, cuando alcanza 60, la pongo a 0 y dibujo la pantalla. Vuelve a la posición PC y sigue el main loop.
IRQ 2 (teclado) - Igual que Video, pero con su contador propio. Vuelve a PC...

Entiendo según lo que dices:

- IRQ 0 es NO enmascarable, osea, para el loop... ¿en que paso hago RESET?

a) ¿en el punto 5?, ANTES de tocar el contador PC y leer ninguna inst. Espero a terminar las operaciones de intrs de turno...
b)¿ paro toda operación (aunque esté sumando/restando) y ejecuto la rutina IRQ 0? a saco!

- Pero y ¿para las otras 2 IRQ? Una se encarga de pintar la pantalla, y la otra de leer el teclado... aunque de momento no sirva para nada. (En mis pruebas monté una rutina que copiaba el valor de la tecla pulsada a una posición de la RAM, tipoVariables del Sistema del ZX. ¿Es correcto?)

¿Cuando las ejecuto?
¿como he comentado en IRQ 0?
¿ha de ir en funcion de los ciclos de cada operacion? ¿como se decide la cantidad de ciclos de una operación? Siempre he leido que esto viene declarado por el fabricante... lees tal operación son X ciclos... ¿porque esa cantidad?
http://www.zxuno.com
ZX-Uno · Clon de ordenador ZX Spectrum basado en FPGA.

jepalza

Re: Aprendiendo a programar un Emulador (DCPU-16)

Mensajepor jepalza » 02 Oct 2012, 21:57

Veamos:
Las IRQ no se definen como "teclado", "video" y demas. No. Las IRQ son solo pausas en la CPU, y las genera la CPU. Y no porque el teclado o el vídeo las llame. Lo que ocurre, es que, por hard o soft, puedes hacer que al pulsar una tecla, se detenga la CPU mediante una IRQ que tú has programado (bueno, el fabricante del ordenador).
Tu escribes una rutina de tratamiento de IRQ (o dos, o tres o las que IRQ que lleve). En el ejemplo que te he puesto del 6809, hay 3: IRQ, FIRQ, y NMI. La IRQ es la normal, la FIRQ es una IRQ Rápida (de ahí la "F" de Fast), y es para pararse sin hacer preguntas, y ahorrar algún ciclo de reloj, tan necesario en muchas situaciones, como juegos muy complejos. Y la NMI es la Hardware, que se activa externamente por una patilla de la CPU que puede ir colocada en el teclado, de ahí, que el teclado genere una NMI (que es una IRQ no enmascarable o en ingles "Not Maskered IRQ" o algo así).

Así que, tu programa llevará "x" rutinas de IRQ, una para cada tipo que lleve la CPU. Y no una para el teclado, otra para el video, etc. No, solo una general. Al llegar a esa IRQ, es donde miras si ha side el teclado, o el vídeo o el reset el que la ha llamado, y entonces sí que saltas a la rutina de teclado o la que sea.

Los puntos 1 y 2a es "ma o meno" como dices, pero ojo con el PC, que no todas las CPU empiezan en "0". El Z80 sí empieza en la "0", pero el 6809, empieza en la FFFE (dos bytes antes del final), lee esa dirección y salta al código. Tu CPU debes mirar dónde empieza, y el PC apuntará ahí.

La tabla de bytes de INS, eso a gusto del usuario. Yo por ejemplo, (bueno, y el 100% de los programadores) metemos en un Array del tamaño de la ROM (por ejemplo, 16k) todo el código de la ROM, y vamos cogiendo de byte en byte desde ahí, según donde apunte el PC. Al leer ese primer byte, actuas en consecuencia, y saltas a la rutina que corresponde a ese byte, y desde ahi, vuelves a leer otro byte (si es NOP, simplemente, no haces nada, o sino lo has hecho antes, pues incrementas PC, decrementas pulsos de IRQ, y vuelves)

En el punto 7a, es como dices, en una tabla tienes, la INS (su nº e incluso, para depuracion, su nombre real, el del ASM, aunque luego no lo uses) su nº de bytes trás ella, el nº de ciclos que gasta, y si es un modo especial o no (como las INS extendidas del Z80)

El punto 8a, generalmente, se descuenta, no se suma. Creo que es mas limpio el código, si vas restando hasta llegar a "0", que si vas sumando hasta alcanzar "x".

El final, no te entiendo bien, pero las llamadas a video y teclado pueden ser cuando a ti te venga en gana, o cuando el creador del ordenador lo programara.
Si haces muchas llamadas a video y teclado, cada poco tiempo, enlenteces el emulador, pero se verá fluido, si llamas cada muuuucho tiempo, irá a saltos, y verás cada pocos FPS.

Lo del bucle principal, es la vida del emulador, el corazón.
Primero, inicializas todo a "0" (o al valro que sea, por que una IRQ, según que CPU, puede que vaya activada desde el principio, no tiene que ser "0")
Luego, entras en el bucle principal, ahí lees el primer byte al que apunta el PC, saltas a la rutina que emula ese byte, vuelves al bucle principal
y entonces,decrementas contador de IRQ, o miras teclado, o refrescas vídeo, etc, pero no todo al mismo tiempo, ni todo en cada INS, por que entonces, el emulador no va a poder con todo. Digamos que lees el estado del teclado cada 100ins, y refrescas el vídeo cada 200ins. Es por poner un ejemplo, pero esos valores te los dicta el hardware, el cómo se ha diseñado ese ordenador.
Ahí entramos ya en un mundo mas complejo: el refresco del vídeo se hace cada "x" mhz del ordenador, para lo cual, debes saber cuando saltar la IRQ. AHora no recuerdo la fórmula, pero era algo así como dividir los MHZ por los HZ del pais, ejemplo un equipo de 2mhz de velocidad, son 2000000 de hz, dividido entre los 60hz del estándar de la tele, quedan 33333 ciclos, o sea, que cada 33333 ciclos de INS ejecutadas, se genera una IRQ de vídeo. (esto, a groso modo)
Pero eso es liarse, lo mejor, es ir probando hasta lograr tu propio ciclo de IRQ.

Y por ahora, dejo de escribir, que me duelen los dedos.

jepalza

Re: Aprendiendo a programar un Emulador (DCPU-16)

Mensajepor jepalza » 02 Oct 2012, 22:06

Seguro que te lio mas, pero te pongo un trozo de código de mi "viejo" emulador en C++ del Mr.Do!

Código: Seleccionar todo


void initFM();
void resetFM();
byte SN7649(byte val, byte chip);

extern byte CPURunning;
word IPeriod=30000;

byte Operiodo,periodo;
byte *rom;  // rom de cpu
byte *roms; // rom de sprites
byte *romg1; // rom de graficos 1 (fondos)
byte *romg2; // rom de graficos 2 (textos)
byte *ramp;
byte rst38=1;
byte AND;
byte bytet[]={0,2,1,3};
byte bytes[]={0,3,1,2};

char *vga = (char *)MK_FP(0xa000,0);

static reg R;
int tipodebug;

void modo_X(void);

void M_WRMEM(register word a,register byte v)
{
  rom[a]=v;
  if (a==(word)0x9801) SN7649(v,0);
  if (a==(word)0x9802) SN7649(v,1);
}

byte M_RDMEM(register word A)
{

 rst38=0;
 if (A>(word)0x156) {rst38=0;return *P;}
 if (A==(word)0x38) {rst38=0;return *P;}
 if ((A>(word)0x133)||(A<(word)0x157)) rst38=1;
 if (A<(word)0x157) rst38=1;

 return *(rom+A);
}


word Interrupt(void)
{
  char *pp,*g;
  register byte col,fil,bucleg;
  register byte buclef;
  register char *dirg,*dirinig;
  byte color1,color2,bytea,byteb;
  word x,y,dirinip,carac1,carac2;
  word key;

periodo-=1;
if (!periodo)
{
 periodo=Operiodo;

 
 // tratamiento de pantalla, actualizacion
    pp=rom+0x8080; // graficos
    g=(char *)0xb8000000L;
    for (fil=0;fil<24;fil++)
       {
         for (col=0;col<32;col++)
           {
            if (tipodebug>0)
              {
               *g=*(pp+0x400);*(g+1)=*pp;
               *(g+80)=*(pp+0xc00);*(g+80+1)=*(pp+0x800);
               pp+=1;g+=2;
               //*g++=*(pp+0x400);
              }
              else
              {
 

   bla, bla, bla,

                     if((bucleg=bytet[((bytea &32)>>5)+((byteb &32)>>4)])!=0) *(dirg+5)=bucleg+color2;
                     if((bucleg=bytet[((bytea &64)>>6)+((byteb &64)>>5)])!=0) *(dirg+6)=bucleg+color2;
                     if((bucleg=bytet[((bytea &128)>>7)+((byteb &128)>>6)])!=0) *(dirg+7)=bucleg+color2;
                     dirinip+=320; dirg=(char *)ramp+32+dirinip;
                  }
nomascolor:;
              }
           }
         g+=96;
       }
nosprite:;
   }

//   memcpy(0xa0000000,ramp,61440);

   for (x=0;x<256;x++)
    {
     pp=ramp+(288-x);
     for (y=0;y<192;y++)
      {
       vga[x*256+y+32]=*(pp+y*320);
      }
    }



} //fin bucle de operiodo

if (periodo==1)
  {

   *(rom+0xa000)=0xff; // joystick
   *(rom+0xa001)=0xff; // botones de start

    if (tecla)
      {
        if (tecla&1  ) *(rom+0xa000)^=0x01; //izqui  1p
        if (tecla&2  ) *(rom+0xa000)^=0x04; //dere   1p
        if (tecla&4  ) *(rom+0xa000)^=0x08; //arriba 1p
        if (tecla&8  ) *(rom+0xa000)^=0x02; //abajo  1p
        if (tecla&16 ) *(rom+0xa000)^=0x10; //disparo    1p (CTRL)
        if (tecla&64 ) *(rom+0xa000)=0xdf; //start      1p (1)
        if (tecla&128) *(rom+0Xa001)=0x7f; //coin right 1p (2)
        if (tecla==255) CPURunning=0;
ya:;
        //if (tecla&32 ) goto ya; //disparo    1p (CTRL)
      }
   }

if (rst38==1) return 0x38; else return 0xffff;
}



int main(int argc,char *argv[])
{

      creamos matriz de ROM y de RAM (o solo de espacio de

      Operiodo=3;
      if (argc==2) Operiodo=c-48; tipodebug=0; // solo para enviarlo a WEB
      periodo=Operiodo;

      if (tipodebug==0) modo_X();


      R.PC.W=0x0;
      if ( (*(rom+0)==0) && (*(rom+1)==0) ) R.PC.W=0x17; // direccion de inicio del pirata es la 0x17
      halt=0x5c01;    // direccion hasta donde ejecuta sin parar


      if (tipodebug<1) {saveirq9=_dos_getvect(9); _dos_setvect(9,teclado);}
      initFM();
      Z80(R,tipodebug,halt);
      resetFM();
      hfree(rom);
      free(romg1);
      free(romg2);
      free(roms);
      hfree(ramp);
      if (tipodebug<1) _dos_setvect(9,saveirq9);
      _setvideomode(_TEXTC80);
      printf("Beta 2.1 (6-Enero-97)\n");
      printf("Joseba Epalza <jepalza@arrakis.es>\n");
      exit(1);
}


a ver si mirándolo te ayuda o te lia. Ahí veras el contador de IRQ, el tratamiento de las mismas, y las llamadas a video y teclado, todo en uno, dentro de la misma rutina de IRQ.
Vas a ver como decremento el IPERIOD y al llegar a "0", salto a la rutina de IRQ a mirar si debo leer teclado (joystick en este caso) y pantalla. El Iperiod, ("periodo" en el decremento) empieza siendo 30000 que es el valor que en su día calculé para la velocidad de esa máquina arcade.

Avatar de Usuario
Hark0
Amiga 1200
Amiga 1200
Mensajes: 1695
Registrado: 11 Jul 2012, 23:44
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
consola_favorita: (Otro)
Primera consola: (Otro)
Ubicación: Cornellà de Llobregat - Barcelona
Contactar:

Re: Aprendiendo a programar un Emulador (DCPU-16)

Mensajepor Hark0 » 02 Oct 2012, 23:31

Voy a imprimir todo y a echarle un vistazo,mluego a teclear...

Gracias por toda la info... y la paciencia ;)


TENGO CURRO PA UN MES!

Postearé resultados, etc..... :D
http://www.zxuno.com
ZX-Uno · Clon de ordenador ZX Spectrum basado en FPGA.

Avatar de Usuario
Joss
Atari 1040 STf
Atari 1040 STf
Mensajes: 930
Registrado: 17 Jul 2012, 20:07
Gracias dadas: 14 veces
Gracias recibidas: 2 veces

Re: Aprendiendo a programar un Emulador (DCPU-16)

Mensajepor Joss » 03 Oct 2012, 00:09

Hark0 escribió:Gracias por toda la info... y la paciencia ;)

Me uno al agradecimiento =D>

Hark0 escribió:TENGO CURRO PA UN MES!


Osea, que hasta Navidades tienes tiempo de sobra p'a terminarlo :mrgreen: (<----- es broma, no te lo tomes a mal .....)

Avatar de Usuario
Hark0
Amiga 1200
Amiga 1200
Mensajes: 1695
Registrado: 11 Jul 2012, 23:44
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
consola_favorita: (Otro)
Primera consola: (Otro)
Ubicación: Cornellà de Llobregat - Barcelona
Contactar:

Re: Aprendiendo a programar un Emulador (DCPU-16)

Mensajepor Hark0 » 03 Oct 2012, 11:23

Primer "intento" de mainloop funcional de CPU.

Por favor maestro... espero correcciones. ;)

Escrito en GLBasic, las primeras líneas son para preparar el entorno, la typo etc... si quieres, subo el ZIP con la typo a mi dropbox, etc.
GLBasic se puede bajar (demo) aqui: http://www.glbasic.com/main.php?lang=en&site=download

Espero haber entendido todo OK.... :P

Gracias de antemano. ;)

Código: Seleccionar todo

//-------------------------------------------------------------------- Preparando GLBasic
CLEARSCREEN
SETSCREEN 640,480,0
SYSTEMPOINTER TRUE
SETTRANSPARENCY RGB(255,0,255)   
SETCURRENTDIR("Media")

LOADFONT "font/Terminal_10x18_Blanco.png",0
SETFONT 0


//-------------------------------------------------------------------- Declaración Variables
GLOBAL Estado_CPU%
GLOBAL memoria%[]
GLOBAL PC%
GLOBAL Instruccion%
GLOBAL Instruccion_bytes%[]
GLOBAL Contador_para_IRQ%
GLOBAL Registro_IRQ%
GLOBAL A%
GLOBAL B%


//-------------------------------------------------------------------- Inicio Variables
DIM memoria[0]                   // Vaciamos RAM
DIM memoria[1024]                // Asignamos RAM 1Kb
DIM Instruccion_bytes[0]         // Tabla Cantidad de bytes a leer (ciclos)
DIM Instruccion_bytes[3]         // segun Instruccion
Instruccion_bytes[0]=0             // NOP - No leemos ningun byte.
Instruccion_bytes[1]=2             // ADD A,B - Leemos A y B
Instruccion_bytes[2]=2             // RES A,B - Leemos A y B
A=0                            // Registro A
B=0                           // Registro B
PC=0                         // Iniciamos PC
Contador_para_IRQ=100            // Cada 100 ciclos generamos IRQ
Registro_IRQ=0                  // Especifica IRQ a usar (0 Video - 1 Teclado)
Estado_CPU=1                   // Activamos mainloop


//- INYECTAMOS PROGRAMA EN RAM
memoria[0]=1   // Instruccion ADD A,B
memoria[1]=4   // A
memoria[2]=6   // B

            //Deberiamos tener 10 en A al ejecutar



//-------------------------------------------------------------------- Bucle Principal
WHILE Estado_CPU=1            

   Instruccion=memoria[PC]                     // Leemos Instruccion en memoria, posicion PC
   PC=PC+1                                 // Avanzamos el puntero PC

   SELECT Instruccion                         // Mnemónico:         Ciclos:

      CASE 0    // Nop                         // NOP               1
         PC=PC+Instruccion_bytes[Instruccion]   // Aumentamos PC el numero de ciclos x Instruccion segun tabla
         
      
      CASE 1    // Suma A=A+B                  // ADD A,B            2
         A=memoria[PC]                     // Leemos en PC y lo "metemos" en A      
         B=memoria[PC+1]                     // Leemos en PC+1 y lo "metemos" en B
         A=A+B                           // Hacemos la operación
         PC=PC+Instruccion_bytes[Instruccion]   // Aumentamos PC el numero de ciclos x Instruccion segun tabla


      CASE 2    // Resta A=A-B                   // RES A,B            2
         A=memoria[PC]                     // Leemos en PC y lo "metemos" en A      
         B=memoria[PC+1]                     // Leemos en PC+1 y lo "metemos" en B
         A=A-B                           // Hacemos la operación
         PC=PC+Instruccion_bytes[Instruccion]   // Aumentamos PC el numero de ciclos x Instruccion segun tabla
         
   ENDSELECT


   // IRQ
   Contador_para_IRQ=Contador_para_IRQ-Instruccion_bytes[Instruccion]
   
   IF Contador_para_IRQ<=0                     // Alacanzamos 0 en contador Contador_para_IRQ
      
      SELECT Registro_IRQ                     // Hacemos la IRQ durante Tiempo_IRQ ciclos
      
         CASE 0                           // Video
            Pintar_Pantalla()
                  
         CASE 1                           // Teclado
            //Capturamos Teclas
            //Pausa de XXXX ciclos   (lo que tardariamos en capturar teclado e intrepretar tecla)
      ENDSELECT
      
      Contador_para_IRQ=Contador_para_IRQ+100      // Volvemos a poner el contador Contador_para_IRQ= que al empezar
   ENDIF



   // CONTROL DESBORDAMIENTO PC
   IF PC>=1024   // Nos salimos de la RAM, DE MOMENTO REINICIO (temporal)
      A=0                            // Registro A
      B=0                           // Registro B
      PC=0                         // Iniciamos PC
      Contador_para_IRQ=100            // Cada 1000 ciclos generamos IRQ
      Registro_IRQ=0                  // Especifica IRQ a usar (0 Video - 1 Teclado)
   ENDIF
   
   
   
   // DEBUG - A ver que estamos haciendo (temporal)
   Pintar_Pantalla()
WEND

END

//////////////////////////////////////////////////////
FUNCTION Pintar_Pantalla: // Driver video cutre

   PRINT "PC: "+PC,0,0
   PRINT "Contador_para_IRQ: "+Contador_para_IRQ,0,15
   PRINT "Reg. A: "+A,0,30
   PRINT "Reg. B: "+B,0,45
   SHOWSCREEN
   
   //Pausa de XXXX ciclos   (lo que tardariamos en pintar pantalla, que se declara PARA CADA IRQ UN VALOR DIFERENTE)

ENDFUNCTION
http://www.zxuno.com
ZX-Uno · Clon de ordenador ZX Spectrum basado en FPGA.

jepalza

Re: Aprendiendo a programar un Emulador (DCPU-16)

Mensajepor jepalza » 03 Oct 2012, 11:51

¡Exactly!
Por ahí van los tiros.
Dos comentarios, por ahora: el contador de la IRQ, una vez agotado, deberías ponerlo a "100", no a "100+contador", por que puede ocurrir que nunca sea 100 exactos, sino 99, o 97, y aunque es una minucia como la copa de un pino, en una emulación real, pierdes unos ciclos muy valiosos, y haces un funcionamiento aleatorio, una veces salta en 100, otras en 97, etc. En la vida real, no se va a notar, pero sí en un equipo real.

Y luego, te faltaría una pila de datos (según avances la emulación), para guardar allí las direcciones de saltos y demas, de modo que el PC no siempre sería "PC=PC+1", sino que dependería de si una rutina le obliga a saltar a la 100, y luego, al retornar, vuelve a ser 1 por ejemplo.

Y lo de la IRQ, el contador, que lo has pillado, debes mirar el hardware, como lo interpreta, si es por ciclos consumidos, o por instrucciones consumidas. Si es por intrucciones, lo tienes bien, si es por ciclos, debes mirar y meter en las variables de instrucciones, el apartado de ciclos a usar, y emplearlos para descontar al contador, en lugar de descontar nº de ins leídas.

Se me olvida: sigues con la idea, de que las IRQ deben ir nombradas, 0 para pantalla, 1 para teclado, pero no es así. Si lo quieres ver así, no pasa nada, funciona igualmente, pero debes entender que la IRQ es única. Simplemente, se ha generado, bien por agotamiento del tiempo establecido en la CPU, bien por que un dispositivo la ha llamado. Simplemente, se ha activado la IRQ, y nada mas. Una vez activada y en la rutina, tu no sabes si ha sido el teclado o la pantalla, solo sabes que has llegado por uno de los motivos citados antes. Lo que ocurre, es que en esta rutina, estudias cada caso. Por ejemplo, la pantalla es casi obligatorio refrescarla, asi que vas a ello sin preguntar, como mucho, miras que el refresco de la pantalla (el sincronismo vertical), este fuera del marco visible, para evitar parpadeos y evitar dibujar en medio del rayo (así es en el hardware real, en la emulación no pasa eso, pero es una emulación, osea, que debe ser fiel a la realidad). El teclado, idem, ya que estas en la rutina de la IRQ, lo miras por si hay tecla pulsada.

El caso de una IRQ activada externamente, como puede ser un teclado, es diferente, y en ese caso, no te queda mas remedio que meterte con la multitarea, o sea, con una rutina aparte que se llama continuamente al márgen de como vaya la CPU y dónde se encuentre. Si una vez en la multitarea del teclado, se pulsa una tecla, entonces se genera una IRQ (NMI) y la CPU, al seguir su curso, ve que alguien ha puesto la NMI a "1", y para lo que esté haciendo, pone la IRQ igualmente a "1" y salta a la rutina. Como ya tienes NMI y IRQ a "1" ambos, sabes que alguien externo, en este caso el teclado, ha pedido saltar ahí.
Pero este caso es mas raro que se emplee en micros viejos, por que detienes a la CPU en un punto que no se esperaba, y se pueden producir parpadeos de la pantalla, por poner un ejem,plo.

Avatar de Usuario
Hark0
Amiga 1200
Amiga 1200
Mensajes: 1695
Registrado: 11 Jul 2012, 23:44
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
consola_favorita: (Otro)
Primera consola: (Otro)
Ubicación: Cornellà de Llobregat - Barcelona
Contactar:

Re: Aprendiendo a programar un Emulador (DCPU-16)

Mensajepor Hark0 » 03 Oct 2012, 12:02

OLÉ!!!!!!

No te digo a que hora me acosté, releyendo todo.... ;)

Voy a ir "añadiendo" cosas... y ver el "sincronizar" las IRQ etc...
http://www.zxuno.com
ZX-Uno · Clon de ordenador ZX Spectrum basado en FPGA.

Avatar de Usuario
mentalthink
Amiga 2500
Amiga 2500
Mensajes: 2840
Registrado: 11 Abr 2010, 15:06
Gracias dadas: 45 veces
Gracias recibidas: 14 veces

Re: Aprendiendo a programar un Emulador (DCPU-16)

Mensajepor mentalthink » 03 Oct 2012, 12:46

Que interesante los emus que has puesto en Basic Jepalza... Intentaré hacer una conversión a GLbasic...

Por lo que veo Hark0 ya ha empezado a hacer un Emulador, no sé si basado en alguno de los de Basic de más arriba... pero por lo poco que he leído en general, y el código de Jepalza, no parece demasiado complejo de entender... Lo poco que he visto y me ha parecido realmente chulo, es el tema de las direcciones de memoria, con un Array, ni me imaginaba que se haría de esa forma...

Pues gracias a esté hilo me parece que van a salir algunas cosillas...

De nuevo gracias por estos hilos como ya se ha comentado, pero por uno más no "pasa ná" la mar de interesantes...

Saludos!!!


Volver a “Programación”

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 2 invitados