Tutorial de optimización de cintas y ultracargas

Cursos, reparaciones, fichas, tutoriales, etc.

Moderador: Fundadores

Avatar de Usuario
flopping
Fundador
Fundador
Mensajes: 9973
Registrado: 29 Mar 2013, 15:26
Ubicación: Valencia
Been thanked: 124 times
Contactar:

Re: Tutorial de optimización de cintas y ultracargas

Mensaje por flopping »

Ok, esta claro el tema, y entiendo que aunque el juego este metido en una ROM de 16k, no significa que vaya a funcionar en un spectrum de 16k de RAM, ya que según comentas, al descomprimirlo, este ira a buscar sus posiciones de memoria original y si es de 48k, es evidente que no va a caber en uno de 16k, ¿es correcto mi razonamiento?, a no ser que como dices, re ensambles todo el juego, cambiando las direcciones de salto y demás claro.
No me hago responsable de mis post pues estan escritos bajo la influencia del alcohol y drogas psicotropicas, por la esquizofrenia paranoide.
(C) 1982-2024, 42 años de ZX Spectrum.
http://www.va-de-retro.com/ un foro "diferente".

Mi juego, que puedes descargar desde aqui
Avatar de Usuario
antoniovillena
Demonio segundo orden
Demonio segundo orden
Mensajes: 1596
Registrado: 02 Abr 2013, 19:06
Been thanked: 1 time

Re: Tutorial de optimización de cintas y ultracargas

Mensaje por antoniovillena »

El spectrum 48K fue el más extendido con diferencia. El cartucho simplemente reemplaza la ROM de 16K si lo insertas en un interface II, tanto en spectrum 16K como en spectrum 48K.

El problema fue que cuando lo sacaron realmente no se calentaron mucho la cabeza. Lo ideal habría sido crear juegos para cartucho, o hacer una adaptación para estos (suponiendo que tienes 48k de RAM). Es decir, recortar un poco el mapeado y los niveles del juego, pero que éste se ejecute en ROM. Lo que se hicieron son adaptaciones rápidas de juegos para spectrum 16K, son juegos muy simples porque quitando los 7K de memoria de video te quedan 9K para código, variables y buffers y eso no da para mucho.

Lo que hacían era copiarse a sí mismos a RAM y se ejecutaban donde lo hacían en su versión cinta. Lo que yo he hecho son adaptaciones rápidas pero de juegos para 48K (en lugar de copiarse a sí mismos se descomprimen), también respetando el mapa de memoria del juego original en cinta. Algunos juegos de 48K se pueden comprimir en una ROM de 16K, sólo estoy adaptando dichos juegos.

No hay que cambiar direcciones de salto ni reensamblar el juego, de hecho la mayoría de los juegos los he convertido extrayendo los binarios del archivo TAP. La razón de disponer del código fuente es para poder recortar bytes más fácilmente.
Avatar de Usuario
flopping
Fundador
Fundador
Mensajes: 9973
Registrado: 29 Mar 2013, 15:26
Ubicación: Valencia
Been thanked: 124 times
Contactar:

Re: Tutorial de optimización de cintas y ultracargas

Mensaje por flopping »

Ok, y por cierto a colación de este tema, he desarrollado un interface de spectrum, que carga juegos de 64k, algo así como el shadow of unicorn, pero sin tener que cargar de cinta, microdrive o cualquier otro dispositivo exterior, esta todo el juego en el propio interface, en una memoria ( eprom, eeprom o similar) y se pasa a la memoria RAM y se sustituye la ROM por una parte del juego, con lo que conseguimos 64k para juegos, cuando lo tenga mas depurado, lo mostrare y haré un tutoríal sobre ello, de momento solo tengo un juego, pero en el interface se podrían meter muchos mas y así tener varios juegos de 64k en un mismo dispositivo, y bueno, solo espero que a la gente le parezca interesante el tema, jajajajaaj
No me hago responsable de mis post pues estan escritos bajo la influencia del alcohol y drogas psicotropicas, por la esquizofrenia paranoide.
(C) 1982-2024, 42 años de ZX Spectrum.
http://www.va-de-retro.com/ un foro "diferente".

Mi juego, que puedes descargar desde aqui
Avatar de Usuario
wilco2009 !Sinclair 1
Hermano de Lucifer
Hermano de Lucifer
Mensajes: 8155
Registrado: 01 Abr 2013, 23:47
Ubicación: Valencia
Has thanked: 47 times
Been thanked: 107 times

Re: Tutorial de optimización de cintas y ultracargas

Mensaje por wilco2009 »

mmmm, eso suena interesante, flopping.

A ver cuando lo podemos ver.
"Aprender a volar es todo un arte. Aunque sólo hay que cogerle el truco. Consiste en tirarse al suelo y fallar".

Douglas Adams. Guía del autoestopista galáctico.
Avatar de Usuario
flopping
Fundador
Fundador
Mensajes: 9973
Registrado: 29 Mar 2013, 15:26
Ubicación: Valencia
Been thanked: 124 times
Contactar:

Re: Tutorial de optimización de cintas y ultracargas

Mensaje por flopping »

wilco2009 escribió:mmmm, eso suena interesante, flopping.

A ver cuando lo podemos ver.
Pronto, muy pronto, por lo menos el prototipo, las pacas definitivas aun estoy esperando a poder hacerlas por culpa de un usuario malévolo y perverso, que solo quiere arruinar mi reputación y retrasar mis logros, jajajajaja...... :P :P :P ;) ;)
No me hago responsable de mis post pues estan escritos bajo la influencia del alcohol y drogas psicotropicas, por la esquizofrenia paranoide.
(C) 1982-2024, 42 años de ZX Spectrum.
http://www.va-de-retro.com/ un foro "diferente".

Mi juego, que puedes descargar desde aqui
Avatar de Usuario
antoniovillena
Demonio segundo orden
Demonio segundo orden
Mensajes: 1596
Registrado: 02 Abr 2013, 19:06
Been thanked: 1 time

Re: Tutorial de optimización de cintas y ultracargas

Mensaje por antoniovillena »

Lección 3

En esta tercera lección vamos a introducir un poco de teoría. Como ya no vamos a modificar más el manic.asm, partimos del manic.bin de 32768 bytes y comentamos la línea del make.bat que ensambla dicho archivo. Además, en esta lección tampoco vamos a tocar el loader.bin, así que ni siquiera necesitamos el ensamblador:

Código: Seleccionar todo

rem SjAsmPlus loader.asm
rem SjAsmPlus manic.asm
GenTape                     manic.tzx   ^
    basic 'ManicMiner'  10  loader.bin  ^
     data                   manic.scr   ^
     data                   manic.bin
Habréis observado un manic.tzx en lugar del anterior manic.tap. Esto es así porque en esta lección vamos a manejarnos a bajo nivel y el formato TAP no nos vale. Los bloques que ya hemos visto: "basic", "hdata" y "data" son los de más alto nivel, es decir, generan cargas estándar con tiempos estándar. Con estos 3 bloques podemos generar tanto TAPs, como TZXs, como WAVs tan sólo cambiando el nombre del archivo.

Lo que vamos a hacer en un primer momento es generar un archivo TZX equivalente pero con otros componetes de más bajo nivel (que no permiten crear TAPs), para luego hacer ciertos ajustes que acorten el tiempo de carga. Pero antes de introducir estos nuevos bloques, un poco de teoría.

Lo primero de todo es distinguir bloques lógicos de bloques físicos. Un bloque "basic" es un bloque lógico compuesto por 2 bloques físicos (cabecera y datos). Lo mismo pasa con el bloque "hdata". Sin embargo el bloque lógico "data" contiene un único bloque físico de datos. Esto se supone que lo sabíamos de anteriores lecciones pero nunca viene mal darle un repaso.

Un bloque físico contiene 4 partes diferenciadas:
  • Tono guía. En inglés se suele usar la palabra "pilot" en lugar de "leader tone". Es un tono grave de 808Hz que avisa cuando va a comenzar un nuevo bloque. En carga estándar viene indicado por las bandas rojo y cian. Tiene distinta duración dependiendo de si el bloque físico es de cabecera o de datos: si es de cabecera dura unos 5 segundos; si es de datos, 2 segundos. Durante el primer segundo la ROM suele esperar sin hacer nada, aunque esto también lo hace si hay cualquier ruído en la cinta. Luego se asegura de que haya 512 pulsos guía después (unos 320ms) para empezar a detectar el sincronismo. La duración de un pulso (media onda) del tono guía es de 2168 ciclos de reloj. El reloj base que se toma es de 3.5Mhz (modelos 48K), siendo 285.7 nanosegundos la duración de un ciclo.
  • Sincronismo. En inglés "sync". Son dos pulsos cortos de duración 667 y 735 ciclos respectivamente. Sirven para indicar que ya se ha acabado el tono guía y que lo que viene después son los datos. El primero es un pelín más corto por retardos de instrucciones (en la rutina SAVE). La razón de que sean dos es para equilibrar ondas asimétricas. Si el azimut está muy alto (o muy bajo) no resultaría raro tener un tono guía de 1500 ciclos alternado con otro de 2836 ciclos. No habría ningún problema porque la suma es 2*2168 ciclos y se detectan de 2 en 2 (o en onda completa).
  • Datos. Aquí se codifican bit a bit todos los datos del bloque, incluido el byte flag de comienzo y el byte checksum del final. Se envian primero los bits de mayor peso y cuando llegamos al bit 0 pasamos al siguiente byte. En carga estándar se señaliza con bandas azules y amarillas en el borde. El tipo de modulación que se emplea es muy sencilla, se llama FSK, y se trata de codificar el bit 0 con dos pulsos seguidos de 855 ciclos cada uno, y el bit 1 con dos pulsos del doble de duración (1710 ciclos).
  • Pausa. Es un momento de silencio que se incluye al final de cada bloque (o al comienzo según se mire) para dar tiempo al Z80 a que haga lo que tenga que hacer, por ejemplo descomprimir una pantalla o mostrar una pequeña animación. También para que sea más fácil reconocerlos por el oído, si estamos buscando un bloque en concreto. Su duración difiere si el bloque físico es de datos o de cabecera. Tras un bloque de cabecera se inserta una pausa de 1 segundo; si es de datos son 2. La razón: tras una cabecera siempre se ejecuta el mismo código de ROM de duración fija (y pequeña). Con un segundo hay de sobra para el reconocimiento acústico.
Vista ya la teoría entremos en materia. Con GenTape podemos generar bloques físicos con los parámetros de tiempo que queramos, o incluso a más bajo nivel cualquier parte de un bloque físico (las que acabo de explicar) por separado.

Para generar bloques enteros tenemos el comando "turbo", mientras que para generar partes por separado tenemos los comandos "pilot", "pulse", "pure" y "pause" respectivamente. Como tenemos 2 bloque físicos (pantalla de carga y juego) voy a codificar el primer bloque con "turbo", mientras que en el segundo bloque emplearemos todo lo demás.

Una cosa muy importante. Tanto en "turbo" como en "pure" estamos trabajando a bajo nivel, y a diferencia de los tipos anteriores ("basic", "hdata", "data") no se insertan ni el byte flag al comienzo ni el checksum al final. Resumiendo, hay que coger un editor hexadecimal y añadir manualmente esos 2 bytes a los binarios. Para saber cuál es el checksum necesario puedes probar primero con un bloque "data" y ver cuál es el valor correcto (con Tapir o con un editor hexadecimal). Esto lo indico en el binario (que he añadido flag y checksum) añadiendo _flag_chk al final del nombre. Así, a "manic_flag_chk.scr" le he insertado los bytes $FF y $FF al principio y al final, mientras que en "manic_flag_chk.bin" han sido $FF y $19.

Siguiendo el orden que se muestra en la ayuda...

Código: Seleccionar todo

| turbo <pilot_ts> <syn1_ts> <syn2_ts> <zero_ts> <one_ts>
                       <pilot_ms> <pause_ms> <input_file>
...voy introduciendo los datos estándar, que son los mismos que he explicado antes. Al tener el tipo "turbo" una gran cantidad de parámetros yo suelo partir la línea en dos para no hacerme un lío, pero esto ya depende de lo que cada uno considere:

Código: Seleccionar todo

    turbo 2168   667   735                      ^
      855 1710  1980  2000  manic_flag_chk.scr  ^
Con esto ya tenemos un bloque físico idéntico al anterior, pero escrito a bajo nivel. Recuerdo que el bloque anterior se codificaba así:

Código: Seleccionar todo

     data                   manic.scr   ^
Esta es la pantalla de carga. Nos queda el último bloque, el que contiene el juego. Como he avanzado antes aquí vamos a emplear todos los subloques existentes, excepto el "pause", ya que el bloque "pure" te permite añadir una pausa al final.

Veamos primero la ayuda de los tipos que vamos a usar:

Código: Seleccionar todo

| pilot <pilot_ts> <pilot_ms>
| pulse <M> <pulse1_ts> <pulse2_ts> .. <pulseM_ts>
|  pure <zero_ts> <one_ts> <pause_ms> <input_file>
Recuerdo que el bloque a generar es equivalente a este:

Código: Seleccionar todo

     data                   manic.bin
Pues bien, siguiendo los valores de ciclos y duración que he explicado en la teoría, para generar el último bloque lo hacemos de la siguiente manera:

Código: Seleccionar todo

    pilot 2168  1980                            ^
    pulse    2   667   735                      ^
     pure  855  1710  2000  manic_flag_chk.bin
Pues ya está, ya hemos completado el archivo bat. En este caso lo llamaremos make2.bat para diferenciarlo del make.bat en alto nivel.

make2.bat

Código: Seleccionar todo

rem SjAsmPlus loader.asm
rem SjAsmPlus manic.asm
GenTape                     manic2.tzx          ^
    basic 'ManicMiner'  10  loader.bin          ^
    turbo 2168   667   735                      ^
      855 1710  1980  2000  manic_flag_chk.scr  ^
    pilot 2168  1980                            ^
    pulse    2   667   735                      ^
     pure  855  1710  2000  manic_flag_chk.bin
Llegados aquí ya estamos listos para empezar a tunear la carga. Mi idea es acortar la duración lo máximo que pueda sin perder fiabilidad de carga (o en todo caso que se pierda muy poca). Para ello copiamos el make2.bat en un make3.bat y vamos cambiando los valores numéricos. Os recomiendo que probéis vosotros mismos: cambiáis un valor, generáis el tzx y veis si carga bien. Repetís el proceso hasta que estéis satisfechos. No se trata de conseguir grandes mejoras, tened en cuenta que seguimos con carga estándar, no hemos modificado el programa cargador. Para que os hagáis una idea, desde manic2.tzx hasta manic3.tzx hemos pasado de una duración de 3:25 a otra de 2:41.

Código: Seleccionar todo

rem SjAsmPlus loader.asm
rem SjAsmPlus manic.asm
GenTape                     manic3.tzx          ^
    basic 'ManicMiner'  10  loader.bin          ^
    turbo 2168   667   735                      ^
      600 1600  1500     0  manic_flag_chk.scr  ^
    pilot 2168  1500                            ^
    pulse    2   667   735                      ^
     pure  600  1600     0  manic_flag_chk.bin
Dejo como ejercicio convertir a bajo nivel el tipo "basic" y recortar los tiempos de la misma forma que hemos hecho en los dos últimos bloques. Ojo, es un bloque lógico con 2 bloques físicos, os recomiendo que uséis Tapir para dumpear los binarios (tanto la cabecera como los datos).

En la siguiente lección vamos a dar un paso más, que es modificar el cargador para tener distintos colores de borde y una carga más rápida. La carga estándar es de 1500bps, con el cargador turbo de la siguiente lección (repito basado en la misma modulación que la carga estándar) espero poder alcanzar los 3000bps, que era lo habitual en las cargas turbo de la época. No se recomienda mayor velocidad con este tipo de modulación ya que bajaría drásticamente la fiabilidad.

Nos vemos en la siguiente lección.

Pincha aquí para bajar el archivo de la lección
Avatar de Usuario
wilco2009 !Sinclair 1
Hermano de Lucifer
Hermano de Lucifer
Mensajes: 8155
Registrado: 01 Abr 2013, 23:47
Ubicación: Valencia
Has thanked: 47 times
Been thanked: 107 times

Re: Tutorial de optimización de cintas y ultracargas

Mensaje por wilco2009 »

Vas mas deprisa escribiendo tutoriales que a mi me da tiempo a digerirlos. :)) :)) :))

Esta información es oro.
"Aprender a volar es todo un arte. Aunque sólo hay que cogerle el truco. Consiste en tirarse al suelo y fallar".

Douglas Adams. Guía del autoestopista galáctico.
Avatar de Usuario
antoniovillena
Demonio segundo orden
Demonio segundo orden
Mensajes: 1596
Registrado: 02 Abr 2013, 19:06
Been thanked: 1 time

Re: Tutorial de optimización de cintas y ultracargas

Mensaje por antoniovillena »

Lección 3 y media

Esta minilección tiene 2 objetivos. Primero muestro la solución del ejercicio anterior. Segundo, os enseño cómo automatizar un proceso que es repetitivo.

Vamos a lo primero. Para simplificar vamos a pasar a "turbo" el último bloque, así nos queda el archivo BAT más corto y homogéneo. Los dos últimos bloques quedarían así:

Código: Seleccionar todo

    turbo 2168   667   735                  ^
      600 1600  1500     0  manic.scr.fck   ^
    turbo 2168   667   735                  ^
      600 1600  1500     0  manic.bin.fck
Ahora tenemos que pasar a turbo el primer bloque:

Código: Seleccionar todo

    basic 'ManicMiner'  10  loader.bin          ^
Como hemos dicho antes este bloque lógico se corresponde con 2 bloques físicos (cabecera y datos). Además, en la cabecera hay información (longitud) que depende de los datos, por lo que no podemos generar dichos bloques de forma independiente. La solución, ensamblar en loader.asm la información de la cabecera, de tal forma que se generen 2 archivos: el antiguo loader.bin con los datos, y un nuevo archivo llamado header.bin con la cabecera. Este sería el contenido del nuevo loader.asm:

Código: Seleccionar todo

; Bloque cabecera
        output  header.bin
        db      0               ; tipo: 0=cabecera, 1=array numérico
                                ; 2=array alfanumérico, 3=código máquina
        db      'ManicMiner'    ; Nombre del archivo (hasta 10 letras)
        block   11-$, 32        ; Relleno el resto con espacios
        dw      fin-ini         ; Longitud del bloque basic
        dw      10              ; Autoejecución en línea 10
        dw      fin-ini         ; Longitud del bloque basic

; Bloque datos (Basic con código máquina incrustado)
        output  loader.bin
        org     $5ccb
ini     ld      sp, $7530
        di
        db      $de, $c0, $37, $0e, $8f, $39, $96 ;OVER USR 7 ($5ccb)
        ld      hl, $5800
        ld      de, $5801
        ld      bc, $2ff
        ld      (hl), l
        ldir
        scf
        sbc     a, a
        ld      ix, $4000
        ld      de, $1b00
        call    $0556
        scf
        sbc     a, a
        ld      ix, $8000
        ld      de, $8000
        call    $0556
        jp      $8400
fin
Pues bien, ya tenemos los binarios de los 2 primeros bloques físicos (header.bin y loader.bin). El siguiente paso es añadirle el byte flag y el byte checksum. Esto antes lo hacíamos de forma manual con un editor hexadecimal. A medida que creemos varios TZXs con esta técnica, el proceso resulta tedioso y aburrido. La solución, hacer un programa que se encargue de esto por nosotros. Lo he llamado FlagCheck y está incluído en el fichero de la lección (tanto el código fuente en C como el ejecutable). Básicamente añade el flag que le especificamos (ó $FF si no lo hacemos) al principio y el checksum calculado del archivo al final. También he cambiado la nomeclatura: ahora en lugar de nombrearchivo_flag_chk.bin pasan a llamarse nombrearchivo.bin.fck, que es más sencillo.

Mostramos pues el make.bat solución:

Código: Seleccionar todo

SjAsmPlus loader.asm
rem SjAsmPlus manic.asm
FlagCheck header.bin 0
FlagCheck loader.bin
FlagCheck manic.scr
FlagCheck manic.bin
GenTape                     manic.tzx       ^
    turbo 2168   667   735                  ^
      600 1600  1500     0  header.bin.fck  ^
    turbo 2168   667   735                  ^
      600 1600  1500     0  loader.bin.fck  ^
    turbo 2168   667   735                  ^
      600 1600  1500     0  manic.scr.fck   ^
    turbo 2168   667   735                  ^
      600 1600  1500     0  manic.bin.fck
Pincha aquí para bajar el archivo de la lección
Avatar de Usuario
tacha Uruguay
Hermano de Lucifer
Hermano de Lucifer
Mensajes: 3167
Registrado: 04 Abr 2013, 20:22
Ubicación: Montevideo, Uruguay
Has thanked: 52 times
Been thanked: 35 times
Contactar:

Re: Tutorial de optimización de cintas y ultracargas

Mensaje por tacha »

antoniovillena, se me hace hagua la boca y me babeo... en cuanto tenga un rato me pongo a rockear con este tuto, que está de maravilla por cierto. Tb estoy copado con esos cartuchos IF2, eso de comprimir juegos de 48k en 16kb y ese de 64k que menciona flopping; capos!

:D

a ver floppis :-] , tengo mas TK90 para cambiarte por esos cartichos :P
66 6C 6F 70 70 69 6E 67 20 6D 61 73 63 61 20 50 30 6C 6C 34 / 6D 61 73 20 63 6F 74 69 6C 6C 61 20 73 65 72 E1 73 20 74 75 20 49 7A 61 72 6F 20 3A 70
Avatar de Usuario
antoniovillena
Demonio segundo orden
Demonio segundo orden
Mensajes: 1596
Registrado: 02 Abr 2013, 19:06
Been thanked: 1 time

Re: Tutorial de optimización de cintas y ultracargas

Mensaje por antoniovillena »

Lo de los cartuchos IF2 es más complejo. Este tutorial sin embargo es asequible, también tengo en mente una lección sobre compresión, que seguro os viene bien para el tema cartuchos.
Responder

Volver a “Cursos y Tutoriales”