Karoshi MSX Community
06 de Julio de 2021, 12:03:53 am *
Bienvenido(a), Visitante. Por favor, ingresa o regístrate.

Ingresar con nombre de usuario, contraseña y duración de la sesión
Noticias:
 
   Inicio   Ayuda Buscar Ingresar Registrarse  
Páginas: [1] 2
  Imprimir  
Autor Tema: La rutina de transferencia "refinitiva"  (Leído 12188 veces)
0 Usuarios y 1 Visitante están viendo este tema.
Darth_Fistro
Karoshi Hero
*****
Mensajes: 507


Email
« : 24 de Mayo de 2007, 10:20:54 am »

Hello!  Smiley

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:

Código:
; 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:

Código:
ld a,l
di
out ($99),a
ld a,h
and $3F
or $40
out ($99),a
ei

por:

Código:
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í.

Código:
; 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)  Grin

« Ú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

Código:
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   Cheesy  )
En línea
Darth_Fistro
Karoshi Hero
*****
Mensajes: 507


Email
« 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  Wink

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  Cheesy ¡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
Karoshi Forum's Guru
*******
Mensajes: 1812


« 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
Karoshi Hero
*****
Mensajes: 507


Email
« Respuesta #4 : 24 de Mayo de 2007, 12:39:03 pm »

Gracias a ambos Smiley

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
Karoshi Hero
*****
Mensajes: 507


Email
« 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  Huh
En línea

MSX FOREVER (hasta que saquen un ZX81 con TMS, PSG y 64K de RAM)
jltursan
Karoshi Forum's Guru
*******
Mensajes: 1516


¿Que es lo que has aprendido hoy?


WWW Email
« 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 Wink) 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.

Código:
;
; 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
Karoshi Hero
*****
Mensajes: 507


Email
« Respuesta #7 : 24 de Mayo de 2007, 03:12:01 pm »

Gracias por la lección magistral, como siempre  Cheesy

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.  Huh

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
Karoshi Hero
*****
Mensajes: 507


Email
« 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
Karoshi Hero
*****
Mensajes: 507


Email
« 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
Karoshi Forum's Guru
*******
Mensajes: 1516


¿Que es lo que has aprendido hoy?


WWW Email
« Respuesta #10 : 24 de Mayo de 2007, 03:58:45 pm »

Citar
-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... Roll Eyes

Citar
¿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é... Grin

Citar
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 Sad), 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.

Citar
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
Karoshi Hero
*****
Mensajes: 507


Email
« Respuesta #11 : 24 de Mayo de 2007, 04:28:29 pm »

¡Gracias!

Citar
¿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é... Grin


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...)  Wink
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:

Código:
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
Karoshi Hero
*****
Mensajes: 507


Email
« Respuesta #13 : 29 de Mayo de 2007, 03:29:21 pm »

¡Joder, es que esto de ser matemático te da gran ventaja!  Cheesy

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!  Cheesy

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  Smiley Genial para inicializar todo, como dices  Cheesy

¡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!  Cheesy

Según para que cosas... Roll Eyes Roll Eyes

Citar
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!  Cheesy

Hombre, si le mandas para acá le pediré un autógrafo para todos los del foro Grin Grin Grin Grin En cuanto tenga algo de tiempo enchufo el portátil y copio la rutina aquí.

Citar
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  Smiley Genial para inicializar todo, como dices  Cheesy

Pos si, y si no es así, que alguien me corrija Tongue

Saludos
--
Sph.
En línea
Páginas: [1] 2
  Imprimir  
 
Ir a:  

Impulsado por MySQL Impulsado por PHP Powered by SMF 1.1.21 | SMF © 2013, Simple Machines XHTML 1.0 válido! CSS válido!