Darth_Fistro
|
|
« : 24 de Mayo de 2007, 10:20:54 am » |
|
Hello! Pues revisando el mogollón de topics que he abierto dando la vara sobre el tema, quiero ir sacando un poco "conclusiones"´para utilizar en juegos spectrumeros (léase tabla de patrones a piñón fijo): He aquí una rutina original cortesía de Mr.Robsy: ; Parameters: ; HL: source address (RAM) ; DE: destiny address (VRAM) ; B: number of 8 byte blocks to be copied RAM2VRAM: ld a,e di out (99h),a ld a,d or a,40h out (99h),a ei ld c,98h LOOP: ld d,b outi ; now only 7xOUTI outi outi outi outi outi outi ld b,d outi jp nz,LOOP ; faster, takes 10T ret
Para empezar, Dioniso sugiere cambiar lo siguiente: ld a,l di out ($99),a ld a,h and $3F or $40 out ($99),a ei
por: ld a,l di out ($99),a ld a,h out ($99),a ei
ahorrándonos unos bytes, teniendo que añadir a la llamada a la rutina, tan sólo el sumar a HL el valor $4000 (si volcamos a la 6144, p.e., pues ld hl,6144+$4000) JL apuntó que para que la rutina funcione en MSX1 debemos intercalar un par de nops en los primeros 6 outis (no me quedó claro por qué en los seis y no en los ocho). La cosa quedaría así. ; Parameters: ; HL: source address (RAM) ; DE: destiny address (VRAM) ; B: number of 8 byte blocks to be copied RAM2VRAM: ld a,l di out ($99),a ld a,h out ($99),a ei ld c,98h LOOP: ld d,b outi ; now only 7xOUTI nop nop outi nop nop outi nop nop outi nop nop outi nop nop outi nop nop outi ld b,d outi jp nz,LOOP ; faster, takes 10T ret
Y por último, JL también propone "desrollar" la rutina si disponemos de memoria suficiente repitiendo el bucle de outis, supongo que el número de bytes a volcar tendrá que ser múltiplo del número de outis dentro del bucle. ¿Alguna nueva sugerencia para lograr una rutina veloz e interrumpible? (al fin y al cabo los resultados los sufriréis vosotros, jeje)
|
|
« Última modificación: 24 de Mayo de 2007, 11:50:35 am por Darth_Fistro »
|
En línea
|
MSX FOREVER (hasta que saquen un ZX81 con TMS, PSG y 64K de RAM)
|
|
|
Dioniso
Visitante
|
|
« Respuesta #1 : 24 de Mayo de 2007, 10:45:24 am » |
|
Lo que yo sugerí no lo he probado en un MSX real (el más perro del planeta), tan sólo en emulador ... pero no sería posible ahorrarte el and $3F or $40 si directamente cargas el valor en HL y le sumas $4000? Por ejemplo: quieres escribir en la VRAM en la dirección $2000 pues haces un LD HL,$6000 ...? Sobre los dos NOPs ... No sé si siempre, pero un LD A,0 creo que también vale y te ahorras 1 t-state (ya sé que parece poco pero en una ristra de NOP, NOP, OUT donde no importa A puede ser mucho )
|
|
|
En línea
|
|
|
|
Darth_Fistro
|
|
« Respuesta #2 : 24 de Mayo de 2007, 11:53:01 am » |
|
Pues no tengo ni idea, Alfonso, en eso estoy pez y si me lo pones en hexa, peor Bueno, lo de los nops que faltan en los dos últimos outi ya lo veo: el ld b,d y el jp nz,loop ya introducen retardo por ellos mismos. Si dices que ld a,0 ahorra un estado y funciona en un MSX real, daríamos un pasito en cuanto a velocidad ¡Hay que exprimir el VDP! (si hace falta, se le puente un chip Fat Agnus)
|
|
|
En línea
|
MSX FOREVER (hasta que saquen un ZX81 con TMS, PSG y 64K de RAM)
|
|
|
pitpan
|
|
« Respuesta #3 : 24 de Mayo de 2007, 12:29:49 pm » |
|
Tened en cuenta que el tema del retardo va en función de si estamos o no dentro de la interrupción de v-blank. Dentro de la interrupción, con un único NOP nos curamos en salud. Fuera de ella, son necesarios 2. La idea de sustituir NOP NOP por una única instrucción, podría ser una buena alternativa.
De todos modos, mis rutinas actuales son bastante más cafres, e incluyen joyas como REPT 1024 | OUTI | ENDR. En fin, felicidad en estado líquido.
|
|
|
En línea
|
|
|
|
Darth_Fistro
|
|
« Respuesta #4 : 24 de Mayo de 2007, 12:39:03 pm » |
|
Gracias a ambos O sea, que si más o menos transfiero 1kb, con un nop va que chuta. Si quiero tansferir 4kbs, le pongo 2 nops y así aseguro que no aparece la imagen distorsionada. Así a bote pronto, con la rutina anterior, ¿cuántos bytes se pueden mandar en un vblank?
|
|
|
En línea
|
MSX FOREVER (hasta que saquen un ZX81 con TMS, PSG y 64K de RAM)
|
|
|
Darth_Fistro
|
|
« Respuesta #5 : 24 de Mayo de 2007, 12:41:16 pm » |
|
Edu, sobre tu bucle a lo cafre, dos cosillas: -¿sólo funciona en emulador? -si no pones nops, tienes entonces siempre que tener cuidado de no mandar más bytes de los convenientes en un solo vblank, ¿verdad? Si no, basura al canto
|
|
|
En línea
|
MSX FOREVER (hasta que saquen un ZX81 con TMS, PSG y 64K de RAM)
|
|
|
jltursan
|
|
« Respuesta #6 : 24 de Mayo de 2007, 01:58:59 pm » |
|
1) Efectivamente, los NOPs son solo necesarios cuando nos encontramos fuera del VBlank. Se puede usar NOP o lo que se quiera; pero se tienen que sumar alrededor de 28T contando los consumidos por el propio OUT. Para saber cual es la cantidad exacta (teórica por supuesto ) de bytes que se pueden transferir sin necesidad de retardos, echa un vistazo por aquí. Fuera de este intervalo te arriesgas a que si no retardas, aparezca basura. 2) Para enviar la dirección de inicio de escritura basta con enviar los dos bytes consecutivamente al VDP a través del puerto de comandos, primero se envía el bajo tal cual y luego el alto. El AND $3F se hace únicamente para asegurar que no vamos a superar los 16Kb y el OR $40 porque ese bit (el 6) tiene que estar a 1 para escritura. Ambas operaciones son superfluas, tal como dice Dioniso basta con construirse una direccion de VRAM un poco "especial" previamente (con $4000 escribiriamos en la $0000). Otra cosa, el EI puede estar por encima del último OUT, las interrupciones se activan a continuación de la instrucción que sigue al EI. La rutina quedaria algo así: 3) La rutina de volcado de Robsy estaba pensada para que se intentarán enviar durante el VBlank todos los bytes posibles sin retardo y a partir de ese punto intercalaba retardos hasta alcanzar el total de bytes que quería enviar. Funciona (o debería) en cualquier emulador y equipo real. ; ; DE: destiny address + $4000 (VRAM) ; ld a,e di out (99h),a ld a,d ei out (99h),a
|
|
|
En línea
|
Doom dee doom dee doom
|
|
|
Darth_Fistro
|
|
« Respuesta #7 : 24 de Mayo de 2007, 03:12:01 pm » |
|
Gracias por la lección magistral, como siempre Veamos, volvamos a un volcado de 6kbs: -vuelco 800 bytes a saco tras un HALT. -luego puedo volcar con dos nops para asegurarme que nada se corrompe. En todo caso, si se puede hacer así entonces, ¿podría forzar a las máquinas de 60Hz a funcionar a 50Hz y así poder volcar 1500 bytes tranquilamente? La mejora es considerable. Muy interesante el tema este del VDP (nunca había pasado de la BIOS)
|
|
|
En línea
|
MSX FOREVER (hasta que saquen un ZX81 con TMS, PSG y 64K de RAM)
|
|
|
Darth_Fistro
|
|
« Respuesta #8 : 24 de Mayo de 2007, 03:13:04 pm » |
|
Otra: si se puede forzar un evío de 1500 bytes, volcar la pantalla en cuatro HALTs como cuatro bloques de 1,5 kbs para evitar las "olas" fuera de sincronismo. Could I?
|
|
|
En línea
|
MSX FOREVER (hasta que saquen un ZX81 con TMS, PSG y 64K de RAM)
|
|
|
Darth_Fistro
|
|
« Respuesta #9 : 24 de Mayo de 2007, 03:14:17 pm » |
|
¿Por qué comentas que la rutina de Edu sigue ese modo de funcionamiento? Por lo que parece en el bucle vuelca OUTIs a saco...
|
|
|
En línea
|
MSX FOREVER (hasta que saquen un ZX81 con TMS, PSG y 64K de RAM)
|
|
|
jltursan
|
|
« Respuesta #10 : 24 de Mayo de 2007, 03:58:45 pm » |
|
-vuelco 800 bytes a saco tras un HALT.
-luego puedo volcar con dos nops para asegurarme que nada se corrompe. Básicamente es así como se hace. El HALT sigue siendo problematico a la hora de sincronizar video; pero bueno, es que es tan cómodo... ¿Por qué comentas que la rutina de Edu sigue ese modo de funcionamiento? Por lo que parece en el bucle vuelca OUTIs a saco... Porque el propio Robsy lo comentó en su día y además yo la desensamblé... En todo caso, si se puede hacer así entonces, ¿podría forzar a las máquinas de 60Hz a funcionar a 50Hz y así poder volcar 1500 bytes tranquilamente? Nunca hagas eso (aunque yo lo hice en el CoT ), si la máquina es un MSX1 a 60Hz, no vas a poder conmutar la frecuencia y por lo tanto tu juego no funcionaría bien en esos modelos. Lo mejor es prepararte para lo peor y hacerlo pensando en 60Hz, si luego le sobra, mejor que mejor. Otra: si se puede forzar un evío de 1500 bytes, volcar la pantalla en cuatro HALTs como cuatro bloques de 1,5 kbs para evitar las "olas" fuera de sincronismo. Could I? El como distribuyas los volcados ya depende de como tengas montado el juego, el tipo de este, lo que quieras conseguir, etc. Simplemente tu sigue la regla de los 800+NOPs y el resto tendrás que imaginarlo tú... ;-) Recuerda que todo esto es simplemente una guía de como sacarle la máxima velocidad al VDP evitando corrupciones. El como evitar parpadeos y tirones ya depende de como te organices.
|
|
|
En línea
|
Doom dee doom dee doom
|
|
|
Darth_Fistro
|
|
« Respuesta #11 : 24 de Mayo de 2007, 04:28:29 pm » |
|
¡Gracias! ¿Por qué comentas que la rutina de Edu sigue ese modo de funcionamiento? Por lo que parece en el bucle vuelca OUTIs a saco Porque el propio Robsy lo comentó en su día y además yo la desensamblé... Me refería a la rutina de Edu que he publicado en este topic, parece que es un bucle mandando 8 outis a saco, a no ser que te refieras a la de algún juego en concreto (jejeje, hacker...)
|
|
|
En línea
|
MSX FOREVER (hasta que saquen un ZX81 con TMS, PSG y 64K de RAM)
|
|
|
SapphiRe_MSX
Visitante
|
|
« Respuesta #12 : 28 de Mayo de 2007, 04:55:33 pm » |
|
Bueno, yo lo que hago es agrupar todas las transferencias de forma que se realicen siempre en el vblank, para lo cual no necesito meter retardos entre outi y outi. Si tengo que hacer transferencias más grandes (normalmente al inicio de un nivel o algo así) desconecto la visualización de la pantalla, lo cual me permite hacer lo mismo durante todo el tiempo. Además, ahorro unos cuantos ciclos extra desenrollando el bucle y aprovechándome de que cada outi realiza un dec b de forma automática, por lo que si en cada bucle hago 16 outi más un djnz, realmente estoy decrementando b un total de 17 veces por bucle. Así, si quiero transferir 320 bytes hago el siguiente cálculo: 320 div 16 = 20 -> tengo que dar 20 vueltas al bucle 20 * 17 = 340 -> he de decrementar b en 340 unidades antes de que llegue a cero, luego 340 mod 256 = 84 -> este es el valor con el que tengo que inicializar b En general, si cada bucle se compone de N instrucciones outi, para transferir L bytes (con L múltiplo de N, por supuesto) habría que inicializar b con la siguiente instrucción: ld b,( (L div N) * (N+1) ) mod 256 y como esas operaciones se realizan en tiempo de compilación, no hay problema alguno y ahorramos unos cuantos ciclos extra que en las rutinas que Darth ha publicado en el primer post se llevan las instrucciones ld d,b y ld b,d. Por si alguien se pregunta si podría darse el caso de que estuviéramos realizando un número incorrecto de transferencias, le diré que se tranquilice, ya que N y N+1 son números primos entre sí, por lo que su mínimo común múltiplo es, precisamente, el producto de ambos y el método funciona para cualesquiera L y N (con L múltiplo de N). Ahora no tengo aquí la rutina, así que si os interesa decídmelo y la pongo aquí para quien quiera utilizarla y optimizarla (cosa que molaría mucho). Saludos -- SapphiRe
|
|
|
En línea
|
|
|
|
Darth_Fistro
|
|
« Respuesta #13 : 29 de Mayo de 2007, 03:29:21 pm » |
|
¡Joder, es que esto de ser matemático te da gran ventaja! Muchas gracias, Sapphire, y además veo que no hace falta enviar a Chuck Norris a tu casa para que publiques esa rutina... ¡ya estás tardando! Entonces, además del genial truco del desglose de outis, cuando se desconecta la pantalla te puedes desentender del vblank y volcar outis a saco, sin nops ni leches Genial para inicializar todo, como dices ¡Gracias de nuevo!
|
|
|
En línea
|
MSX FOREVER (hasta que saquen un ZX81 con TMS, PSG y 64K de RAM)
|
|
|
SapphiRe_MSX
Visitante
|
|
« Respuesta #14 : 29 de Mayo de 2007, 03:41:29 pm » |
|
¡Joder, es que esto de ser matemático te da gran ventaja! Según para que cosas... Muchas gracias, Sapphire, y además veo que no hace falta enviar a Chuck Norris a tu casa para que publiques esa rutina... ¡ya estás tardando! Hombre, si le mandas para acá le pediré un autógrafo para todos los del foro En cuanto tenga algo de tiempo enchufo el portátil y copio la rutina aquí. Entonces, además del genial truco del desglose de outis, cuando se desconecta la pantalla te puedes desentender del vblank y volcar outis a saco, sin nops ni leches Genial para inicializar todo, como dices Pos si, y si no es así, que alguien me corrija Saludos -- Sph.
|
|
|
En línea
|
|
|
|
|