Cargador genérico para +3/+3e

Todo sobre la creación, diseño y programación de nuevo software para
nuestro Spectrum

Moderador: Sir Cilve Sinclair

Responder
zup
Freddy Hardest
Mensajes: 666
Registrado: Vie Ago 15, 2008 2:43 pm

Cargador genérico para +3/+3e

Mensaje por zup » Jue Dic 05, 2013 8:44 am

Ahí va un cargador genérico para juegos para el +3/+3e.

Código: Seleccionar todo

dos_open equ 262
dos_close equ 265
dos_read equ 274
dos_write equ 277
dos_set1346 equ 319
inicio equ 24576

; inicio

org inicio
ld iy,tabla

; paginar DOS
ld a,(23388)
ld bc,32765
res 4,a
or 7
di
ld (23388),a
out (c),a
ei

; deshabilitar cache
ld de,0
ld hl,128
call dos_set1346
jp nc,0

; abrir fichero
ld bc,$0501
ld de,$0002 ; debería ser 3?
ld hl,fichero
call dos_open
jp nc,0

; repetir
bucle:

;   leer tabla
ld a,(iy+0)

;     si no he terminado de leer entonces
bit 7,a
jr nz,cerrar

;       leer bloque
and 7
ld c,a
ld b,5
ld l,(iy+1)
ld h,(iy+2)
ld e,(iy+3)
ld d,(iy+4)
call dos_read
jp nc,0

;     finsi
ld hl,5
push iy
pop bc
add hl,bc
push hl
pop iy
jr bucle

; fin del bucle

; cerrar fichero
cerrar:
ld b,5
call dos_close

; paginar BASIC
di
ld a,$10
ld bc,32765
ld (23388),a
out (c),a
ei

; retornar
retornar:
ld iy,23610
ret

; variables

fichero:
db 'GOKUMAL.BIN',$ff

tabla:
db 0
dw 16384
dw 6912
db 1
dw 49152
dw 14729
db 3
dw 49152
dw 14819
db 4
dw 49152
dw 14555
db 6
dw 49152
dw 9497
db 0
dw 24200
dw 35187
db $FF


Este cargador está preparado para cargar el juego "Goku Mal" y no está optimizado para que sea más claro trabajar con él. Ocupa algo más de 150 bytes y no tiene un control de errores... salvo que si algo va mal, bloquea el equipo. Supuestamente debería funcionar tanto para disquetes como para disco duro/flash.

El código viene a ser algo así:

Código: Seleccionar todo

INICIALIZAR
ABRIR FICHERO
REPETIR
     LEER TABLA
     SI PAGINAS>128
          LEER BLOQUE
     FINSI
HASTA PAGINAS>128
CERRAR FICHERO


El formato de la tabla es el siguiente:

Código: Seleccionar todo

1 byte  - Flags
            bit 7 - Marcador de fin
            bits 2..0 - Página a colocar en $c000~$ffff
2 bytes - Dirección inicial del bloque
2 bytes - Longirud del bloque


Para generar el fichero GOKUMAL.BIN, he extraído los bloques de datos, después los he unido a lo burro con copy /b gokumal.scr+gokumal.1+gokumal.3+gokumal+4+gokumal.6+gokumal.c GOKUMAL.BIN y por último he metido ese fichero a un disquete con P3Explorer. El resultado es un fichero headerless con todos los datos del juego unidos.

He definido el primer byte como flags, de manera que (ampliando la rutina) sea posible hacer calls al cargar algunos bloques o usar bloques comprimidos.

Comentarios (y posibles mejoras/tratamiento de errores):
- La rutina paginar DOS puede comprimirse algo... dado que sabemos que vamos a la ROM2/RAM7 y que al final vamos a volver a la ROM3/RAM0, no es necesario comprobar el valor de BANKM (aunque sí que es necesario actualizarlo).
- Si la rutina deshabilitar caché falla, la página 1 se corromperá al cargar. Si no utilizamos la página 1, podemos quitarla y ahorrar 9 bytes.
- Si abrir fichero falla, es de suponer que el fichero no se ha abierto y podríamos retornar al BASIC.
- Se utiliza el fichero número 5 porque (a veces) los 3 primeros pueden estar ya abiertos.
- Si falla leer_bloque, se podría intentar saltar a cerrar fichero y retornar al BASIC.
- Estoy seguro de que se pueden optimizar todos esos (IY+x), y el código que avanza IY 5 bytes.
- Si falla cerrar fichero, la forma ideal de tratar este error es llamar a dos_abandon.
- Hubiera sido un detalle apagar la disquetera, bien usando dd_l_off_motor o con los puertos.
- Como hemos estado mangoneando con IY, hay que restaurarlo antes de volver a BASIC. Si no tenemos intención de volver a BASIC, en retornar podríamos poner el stack en su sitio y saltar con un jp.
- Tengo que averiguar si hay alguna manera de crear REMs de una longitud arbitraria (para esconder este tipo de códigos en el BASIC). Hacerlos a mano es un coñazo.

El fichero de muestra se puede descargar aquí.
I have traveled across the universe and through the years to find Her. Sometimes going all the way is just a start...

Avatar de Usuario
antoniovillena
Nonamed
Mensajes: 1164
Registrado: Dom Ene 09, 2011 8:55 am

Re: Cargador genérico para +3/+3e

Mensaje por antoniovillena » Jue Dic 05, 2013 10:32 am

Para incrementar iy en 5 has usado esta rutina:

Código: Seleccionar todo

        ld      hl, 5
        push    iy
        pop     bc
        add     hl, bc
        push    hl
        pop     iy


Es más fácil hacerlo así:

Código: Seleccionar todo

        ld      de, 5
        add     iy, de
Imagen

zup
Freddy Hardest
Mensajes: 666
Registrado: Vie Ago 15, 2008 2:43 pm

Re: Cargador genérico para +3/+3e

Mensaje por zup » Jue Dic 05, 2013 10:43 am

Me concentré buscando un add hl,NN y resulta que no ví se podía hacer add iy,registro. Entre eso y la "pifia" de paginar DOS, se pueden ahorrar como una docena de bytes.
I have traveled across the universe and through the years to find Her. Sometimes going all the way is just a start...

zup
Freddy Hardest
Mensajes: 666
Registrado: Vie Ago 15, 2008 2:43 pm

Re: Cargador genérico para +3/+3e

Mensaje por zup » Vie Dic 06, 2013 10:26 am

Ahora la siguiente pregunta... ¿hay algún atajo que permita reducir considerablemente el tamaño de estas rutinas?

Imaginemos que quisiera parchear un juego (ejemplo: Elecciones Generales) para cargar/grabar los saves en disco. En el peor de los casos (peor para mí, se entiende), la rutina de carga se va a llevar una docena de bytes, mientras que necesito entre 80 y 100 para meter la de disco.

He pensado en alojar esas rutinas en la RAM7, y en el hueco de la rutina de carga original poner una rutina que pagine ROM2/RAM7 y salte a mi rutina. Luego desde mi rutina, cargar el fichero. Esto tiene dos inconvenientes:

- El stack debe estar obligatoriamente por debajo de 49152 (o debo buscarle un hueco en alguna otra parte).
- El juego debe poder funcionar en modo 128k o, como último recurso, modo USR0 (si tengo que bloquear la paginación, se acabó la historia).

¿Alguna opinión?
I have traveled across the universe and through the years to find Her. Sometimes going all the way is just a start...

zup
Freddy Hardest
Mensajes: 666
Registrado: Vie Ago 15, 2008 2:43 pm

Re: Cargador genérico para +3/+3e

Mensaje por zup » Lun Dic 16, 2013 10:53 am

Después de discutirlo algo en WOS y gracias a la colaboración de la gente de allá, ahí va una nueva versión del cargador. La antigua funciona, pero esta debería hacerlo mejor.

Código: Seleccionar todo

dos_open   equ 262
dos_close   equ 265
dos_abandon   equ 268
dos_read   equ 274
dos_write   equ 277
dos_set1346   equ 319
dos_free_space   equ 289
BANK678      equ 23399
BANKM      equ 23388
; estas definiciones pueden usarse en otras rutinas

inicio      equ 23760

; inicio

org inicio

; paginar DOS
ld a,$07
call paginar   ; poner ROM2/RAM7 (configuración para +3DOS)

; deshabilitar cache
ld de,0
ld hl,128
call dos_set1346
jp nc,0

; abrir fichero
ld bc,$0501
ld de,$0002
ld hl,fichero
call dos_open
jp nc,0

ld hl,tabla   ; hl apunta a nuestra tabla de direcciones
; repetir
bucle:

; leer tabla
ld a,(hl)
bit 7,a      ; es el marcador de final?
jr nz,cerrar   ; si lo es, saltamos a cerrar el fichero

; leer bloque
inc hl
ld c,(hl)
inc hl
ld b,(hl)   ; leo la dirección inicial y la meto en bc
inc hl
ld e,(hl)
inc hl
ld d,(hl)   ; datos a leer
inc hl
push hl      ; el indice apunta al siguiente bloque, lo preservo
push bc
pop hl      ; Cambio la dirección de inicio de bc a hl
and 7
ld c,a      ; página donde vamos a leer
ld b,5
call dos_read   ; se lee el bloque
pop hl      ; recupero el indice
jp nc,0

; finsi
jr bucle   ; y cerramos el bucle

; hasta marcador de final

; cerrar fichero
cerrar:
ld b,5
call dos_close   ; se cierra el fichero

; paginar ROM BASIC
ld a,$10
call paginar
; retornar al BASIC
ret

; rutina de paginación
; necesita la página a establecer en a
paginar:
di
ld bc,32765
ld (BANKM),a   ; actualizamos BANKM
out (c),a   ; paginamos
ei
ret

; variables

fichero:
; es el nombre del fichero con los datos
db 'GOKUMAL.BIN',$ff

tabla:
; contiene la lista de bloques que tiene el juego
; El formato es el siguiente:
;   1 byte FLAGS
;   0..2   Página a colocar en $c000
;   6..3   Reservado
;   7   a 1 para marcar el final de la tabla
;   2 bytes dirección inicial de carga
;   2 bytes longitud de datos
db 0      ; screen$
dw 16384
dw 6912
db 1      ; página 1
dw 49152
dw 14729   
db 3      ; página 3
dw 49152
dw 14819
db 4      ; página 4
dw 49152
dw 14555
db 6      ; página 6
dw 49152
dw 9497
db 0      ; código principal (en las páginas 5+2+0)
dw 24200
dw 35187
db $ff      ; fin de tabla


Los cambios:
- El +3DOS habilita las interrupciones después de cada llamada, he tenido que mover los di/ei a la rutina de paginación.
- No se utiliza para nada el registro IY. Aunque las rutinas de +3DOS no lo utilizan, la interrupción de BASIC si que lo hace, así que puede intentar actualizar lo que cree que es la variable FRAMES o LAST_K y corromper memoria.
- Como consecuencia, la rutina es algo más corta. Los opcodes del estilo ld r,(IY+nn) ocupan bastante más que los ld r,(HL).
- Ya no se suman 5 bytes para avanzar el puntero a la tabla de bloques, sino que se usan varios inc (hl). Esto es (en parte) debido a que no hay opcode para ld r,(HL+nn). También se ha movido la carga de bc al final (para permitir usar bc como almacenamiento temporal de la dirección de inicio).
- Esta rutina ahora ocupa 131 bytes (la original medía casi 150). De esos 131 bytes hay que descontar los que corresponden a la tabla de bloques (5 por entrada).
- Existe una versión modificada de esta rutina (pendiente de recibir los cambios) que permite usar compresión zx7. De momento, quiero exprimir esta antes de que la otra reciba estos cambios y publicarla (aunque la modificación no es gran cosa).
I have traveled across the universe and through the years to find Her. Sometimes going all the way is just a start...

BCH
Jack The Nipper
Mensajes: 170
Registrado: Mié Ago 19, 2009 10:26 pm

Re: Cargador genérico para +3/+3e

Mensaje por BCH » Lun Ene 27, 2014 1:23 pm

Esta es la rutina que he usado para algunas convesiones, en particular esta es para cargar el bloque principal del Sonic Boom. Como veras hay partes del codigo que no son esenciales para la carga en si. Mi idea fue tener multiples bloques numerados (SONICBOO.1, SONICBOO.2, SONICBOO.3) y cargarlos uno detras de otro con un loop. El largo y la direccion de destino de cada bloque la leo directamente desde la cabecera de +3DOS, y utilizo una pequeña tabla con la paginacion que cada bloque necesita.

Código: Seleccionar todo

org 23808

bankm      EQU 23388
DOS_EST_1346    equ $13F
DOS_OPEN    equ $106
DOS_READ    equ $112
DOS_CLOSE   equ $109 
DOS_MOTOR_OFF   equ $19c


start   ld hl, 25000
   ld de, 23808
   ld bc, 196
   ldir
   jp 23808+14

   ld sp, 24575
   di
   
   ld a,7      
   call paging
   


   ld hl, 0
   ld de, 0
   call DOS_EST_1346; kill ramdisk-cache

   ld a, 1
   push af 
open   
   ld hl, pageseq
   add a, l
   ld l, a
   ld a, (hl)
   ld (pages+1),a
   pop af

   add a, 48
   ld (filename+9), a

file   LD HL, filename      ; file name
   LD DE, 2             ; E=2 open mode
   LD BC, 5             ; C=5 shared read mode
   CALL DOS_OPEN        ; DOS OPEN           
       
read_fileLenght

   LD HL, 16      ; set position after first 16 bytes
   LD E, 0
   LD B, 0         ; file 0
   call 310      ; DOS SET POSITION
       
   LD HL, lenghtstart   ; target addr
   LD DE, 4             ;
   LD BC, 0      ; file 1, page 0
    CALL DOS_READ        ; read block´s lenght and target address to memory

   LD HL, 128      ; set position after header
   LD E, 0
   LD B, 0         ; file 0
   call 310      ; DOS SET POSITION


   LD HL, (lenghtstart+2)   
   ld de, (lenghtstart)   
   ld B, 0
pages   ld c, 0         ;select target page to load to
   call DOS_READ      ;read level   
      
   ld b, 0         ; Close file 0
   call DOS_CLOSE   
   
   ld a, (filename+9)   ;increases the block number
   sub 48
   add a, 1
   cp 6         ;controls loading loop
   jp nc, exit
   
   push af
   jp open

exit   call DOS_MOTOR_OFF

   ld hl, 23296      ;preserve var area
   ld de, 50000
   ld bc, 436
   ldir   

   ld hl, 49152
   ld de, 23296
   ld bc, 511
   ldir
      
   ld a, 16
   call paging   

   jp 48940

paging:
   di
   ld bc, 32765
   out (c),a      ; execute paging
   ld (bankm),a
   ei         ;
   ret

      
filename:      defm "SONICBOO.1  ", 255
pageseq:      defb 0,0,0,0,0,7

lenghtstart:      defb 0,0,0,0


Responder

¿Quién está conectado?

Usuarios navegando por este Foro: Bing [Bot] y 19 invitados