Acceso a disco desde código máquina con Spectrum +3

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

Moderador: Sir Cilve Sinclair

Responder
Avatar de Usuario
Nat
Herbert
Mensajes: 95
Registrado: Lun Mar 25, 2019 9:31 am

Acceso a disco desde código máquina con Spectrum +3

Mensaje por Nat » Mar May 21, 2019 11:36 pm

No estoy teniendo suerte buscando documentación específica sobre cómo acceder al disco en un Spectrum +3 utilizando código máquina, es decir, hacer las operaciones comunes de carga, grabación, borrado, catálogo del disco, etc. llamando directamente a las funciones de la ROM.

¿Es muy rebuscado o está disponible? Gracias.
Saludos,
Nat

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

Re: Acceso a disco desde código máquina con Spectrum +3

Mensaje por zup » Mié May 22, 2019 7:13 am

Está todo en el capítulo 8, sección 27 del manual del +3. Salvo un pequeño error en fopen, está todo ahí.

Personalmente, he usado las funciones típicas (open, close, read, write, seek), pero no he utilizado las de catálogo ni borrado.
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
Nat
Herbert
Mensajes: 95
Registrado: Lun Mar 25, 2019 9:31 am

Re: Acceso a disco desde código máquina con Spectrum +3

Mensaje por Nat » Mié May 22, 2019 1:08 pm

Muy bueno. Gracias.

No tengo experiencia más que con el gomas 48 pero es suficiente para empezar aunque esperaba algo más trabajado con ejemplos de uso para agilizar el desarrollo. Con mil sitios así para cualquier tarea con el gomas, me ha extrañado encontrarme con este desierto de resultados.

El manual lo encontré en WOS, una versión muy primitiva en texto entre tags <pre> que parece proceder de un escaneo con OCR, con infinidad de typos y errores HTML, como confundir a<b con a<b y que al intentar arreglarlo con búsquedas y reemplazos desde el editor les ha liado sin que se den cuenta unas bien gordas en varios capítulos. La sorpresa es la leonina defensa que hacen del manual que hace casi imposible descargarlo offline. He intentado con wget pero he tenido que ir completando con más y más headers y otros switches hasta conseguir evitar el terrible Error 403 Forbidden.

Después de corregirlo parcialmente tomando como fuente para la comparación el manual en PDF del ZX Spectrum +2 os facilito el texto completo en una cuenta de Dropbox que acabo de crear para el manual.

Encontré también esta versión en español del manual en Archive.org y otra versión del manual en inglés en
Spectrum Computing.

Edit: Miro ahora en RetrocodingUK que parecen tener algo de este tema.
Saludos,
Nat

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

Re: Acceso a disco desde código máquina con Spectrum +3

Mensaje por zup » Mié May 22, 2019 3:33 pm

Si quieres te posteo un cargador de un juego. Yo he aprendido todo lo que sé con ese manual, desensamblar o el cargador del Camión Bubble y probando burradas con ZX Spin.
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
Nat
Herbert
Mensajes: 95
Registrado: Lun Mar 25, 2019 9:31 am

Re: Acceso a disco desde código máquina con Spectrum +3

Mensaje por Nat » Mié May 22, 2019 5:31 pm

Estoy haciendo alguna cosa con el manual, de momento he conseguido grabar el contenido de la pantalla en el disco.

Código: Seleccionar todo

STACK:      equ     $9FFF                   ; arbitrary value picked to be below BFE0h and above 4000h
BANKM:      equ     $5B5C                   ; system variable that holds the last value output to 7FFDh
BANKP:      equ     $7FFD                   ; address of ROM/RAM switching port in I/O map
DOS_WRITE:  equ     $0115
DOS_OPEN:   equ     $0106
DOS_CLOSE:  equ     $0109
DOS_REFHEAD:equ     $010F

CDOSCREATE: equ     1                       ; Create action
CDOSOPEN:   equ     3                       ; Open action

DOSTB_TYPE: equ     0                       ; Byte: File type (0=BASIC, 1=Array...)
DOSTB_SIZE: equ     1                       ; Word: Length
DOSTB_LINE  equ     3                       ; Word: $8000 OR BASIC LINE
DOSTB_LDAD: equ     3                       ; Word: Load address
DOSTB_OFFP: equ     5                       ; Word: Offset to prog

CDOSTCODE:  equ     3                       ; File type CODE/SCREEN$

CDOSSRCBUF: equ     5                       ; Source buffer page 5 $4000...$7FFF

CDOSFILEn:  equ     1                       ; File # 1

DATASTART:  equ     $4000
DATASIZE:   equ     $1B00


            org     $8000
_START_:    di                              ; disable interrupts before switching RAM/ROM
            ld      (SPBASICv+1),SP         ; save BASIC's stack pointer
            ld      BC,BANKP                ; the horizontal ROM switch/RAM switch I/O address
            ld      A,(BANKM)               ; system variable that holds current switch state
            res     4,A                     ; move right to left in horizontal ROM switch (ROM 3 to ROM 2)
            or      7                       ; switch in RAM page 7
            ld      (BANKM),A               ; must keep system variable up to date (very important!)
            out     (C),A                   ; make the switch
            ld      SP,STACK                ; make sure stack is above 4000h and below BFE0h
            ei                              ; interrupts can now be enabled

            ; Open file

            ld      HL,FILENAME             ; filename CANNOT include wildcards
            ld      B,CDOSFILEn             ; file number set to one
            ld      C,0                     ; zero C reg
            set     1,C                     ; bit set (on)

            ld      D,CDOSCREATE            ; Create action on
            ld      E,CDOSOPEN              ; Open action on
            call    DOS_OPEN                ; call to +DOS

            ; Header

            ld      B,CDOSFILEn             ; file number set to 1
            call    DOS_REFHEAD             ; get pointer to header

            ld      HL,DATASTART            ; fill header data
            ld      DE,DATASIZE
            ld      (IX+DOSTB_TYPE),CDOSTCODE ; file type CODE/SCREEN$
            ld      (IX+DOSTB_SIZE),E       ; set file length
            ld      (IX+DOSTB_SIZE+1),D
            ld      (IX+DOSTB_LDAD),L       ; set load address
            ld      (IX+DOSTB_LDAD+1),H

            ; Write file

            ld      B,CDOSFILEn             ; file number set to 1
            ld      HL,DATASTART
            ld      DE,DATASIZE
            ld      C,5
            call    DOS_WRITE               ; write it

            ; Close file

            ld      B,CDOSFILEn             ; file number set to 1
            call    DOS_CLOSE

            di                              ; disable interrupts before switching RAM/ROM
            push    BC                      ; save number of files
            ld      BC,BANKP                ; I/O address of horizontal ROM/RAM switch
            ld      A,(BANKM)               ; get current switch state
            set     4,A                     ; move left to right (ROM 2 to ROM 3)
            and     $F8                     ; also want RAM page 0
            ld      (BANKM),A               ; update the system variable (very important!)
            out     (C),A                   ; make the switch
            pop     BC                      ; get back the saved number of files in catalog
SPBASICv:   ld      SP,000                  ; put BASIC's stack back (placeholder for BASIC's stack)
            ret                             ; return to BASIC, value in BC is returned to USR


FILENAME:   db      "SCREEN",$FF            ; the file name, must be terminated with $FF

_END_
Funciona sin problemas pero como mi objetivo es pasar juegos del 48 al +3 cuando intento después grabar grandes bloques de memoria, desde mi desconocimiento del +3, veo cosas raras como que al cargar lo grabado hay parte que no está. Creo que se deberá a algo relacionado con la paginación y demás, quizás para cargar bloques muy grandes -y algunos juegos de 48 tenían toda la memoria desde 16384 hasta 65535- haya que usar técnicas más específicas para +3. Por otra parte, con el manual delante advierto que la zona de variables de sistema se ha ampliado, comiéndose toda la zona reservada para el buffer de impresión y hay muchos juegos de 48 que hacen uso de esa zona de memoria para datos o variables. A saber qué ocurre si algún programa machaca el contenido de BANKM (05B5Ch).

Acabo de empezar y tengo que dedicarle bastante más tiempo pero no me vendrá mal ver ese cargador por si me da ideas porque cargadores son lo que justamente estoy escribiendo. Gracias.

PD: En Pluma veo el código perfectamente tabulado pero al pegarlo al foro, la fuente escogida para el BBCode code no lo muestra bien alineado. Mis disculpas.
Saludos,
Nat

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

Re: Acceso a disco desde código máquina con Spectrum +3

Mensaje por zup » Mié May 22, 2019 7:31 pm

natohara escribió:Estoy haciendo alguna cosa con el manual, de momento he conseguido grabar el contenido de la pantalla en el disco.
Cuidado con el número de fichero, yo suelo empezar en 5. Creo que los más bajos están "cogidos" por el sistema y pueden dar problemas.
natohara escribió:Funciona sin problemas pero como mi objetivo es pasar juegos del 48 al +3 cuando intento después grabar grandes bloques de memoria, desde mi desconocimiento del +3, veo cosas raras como que al cargar lo grabado hay parte que no está. Creo que se deberá a algo relacionado con la paginación y demás
Cuatro cosas cosas:
- Lo que apuntaba del número de fichero, aunque puede que no de problemas.
- En ningún momento compruebas que haya habido errores. Carry a 0 significa error, carry a 1 significa OK. Te recomendaría que pongas breakpoints tras las llamadas... puede que tu problema sea algún error no controlado.
- Hay un error en el manual del +3, en la llamada dos open todos los números están corridos una unidad. Es decir, donde pone "2. Open the file read..." debería poner "1. Open the file read...". No sé la documentación que tienes tú está corregida.
- Cuidado con las cabeceras y las acciones asociadas. Hay dos modos de crear/usar un fichero: con y sin cabecera. Si hay cabecera, los primeros 128 bytes del fichero son la cabecera. El tema es que si creas un fichero con cabecera y luego lo abres SIN cabecera o le indicas a +3DOS que ignore la cabecera, los primeros 128 bytes que vas a leer son la cabecera en sí... lo que puede llevarte a confusión.

Las cabeceras son informativas y son las que permiten cargar desde BASIC sin demasiados problemas. Un fichero sin cabecera se puede copiar usando COPY, pero a la hora de cargarlo suele dar errores del estilo "Invalid File Type" o algo así. Personalmente, yo guardo y cargo todo SIN cabecera... así nunca me confundo ;)
natohara escribió:Por otra parte, con el manual delante advierto que la zona de variables de sistema se ha ampliado, comiéndose toda la zona reservada para el buffer de impresión y hay muchos juegos de 48 que hacen uso de esa zona de memoria para datos o variables. A saber qué ocurre si algún programa machaca el contenido de BANKM (05B5Ch).
¡BUM! El sistema se cuelga. Te acabas de cargar las rutinas de paginación del Spectrum. Es algo que pasa en los 128k en general. Y te preguntarás... ¿por qué no se cuelga al cargar (p.ej.) el Humphrey que carga casi toda la RAM? Pues porque el problema lo vas a tener si retornas a BASIC. En esos juegos, el cargador salta directamente al c/m del juego, así que no tienes problemas.

Lo que yo hago en esos casos es cargar la pantalla y toda la RAM desde 24576 hacia arriba normalmente. Los 1280 bytes que van desde 23296 hasta 24575 los cargo en la RAM 3 junto con una rutina que los reubique a su posición original, ponga la página 0 y salte al c/m del juego. Cuando termino con el disco (ya no hay riesgo de reventar nada), pagino la RAM 3 y llamo a la rutina en cuestión.
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
Nat
Herbert
Mensajes: 95
Registrado: Lun Mar 25, 2019 9:31 am

Re: Acceso a disco desde código máquina con Spectrum +3

Mensaje por Nat » Mié May 22, 2019 10:07 pm

zup escribió:Cuidado con el número de fichero, yo suelo empezar en 5. Creo que los más bajos están "cogidos" por el sistema y pueden dar problemas.
Es una simple prueba de concepto, nada serio ni que vaya a acabar funcionando en un sistema real. Empiezo de esta forma para verificar que me entiendo con el +3DOS, que hace lo que se supone que debe hacer y que no he interpretado mal la documentación. Igual con la inexistente gestión de errores, no compensa dedicarle tiempo si hay un error de concepto y el código va a ser desechado. Todo eso lo dejo para las versiones finales más estables.
zup escribió:- Hay un error en el manual del +3, en la llamada dos open todos los números están corridos una unidad. Es decir, donde pone "2. Open the file read..." debería poner "1. Open the file read...". No sé la documentación que tienes tú está corregida.
En cuanto a las acciones no hay problema en mi documentación, por eso probé el crear el fichero de forma que si existía generase automáticamente el .BAK así verifiqué la combinación 1/3 con una única comprobación. En el modo de acceso no estoy tan seguro, aún no he probado si exclusive-read o exclusive-write están intercambiados.
zup escribió:- Cuidado con las cabeceras y las acciones asociadas. Hay dos modos de crear/usar un fichero: con y sin cabecera. Si hay cabecera, los primeros 128 bytes del fichero son la cabecera. El tema es que si creas un fichero con cabecera y luego lo abres SIN cabecera o le indicas a +3DOS que ignore la cabecera, los primeros 128 bytes que vas a leer son la cabecera en sí... lo que puede llevarte a confusión.
No son necesarias y siguiendo tu sistema tampoco pienso usarlas.
zup escribió:Lo que yo hago en esos casos es cargar la pantalla y toda la RAM desde 24576 hacia arriba normalmente. Los 1280 bytes que van desde 23296 hasta 24575 los cargo en la RAM 3 junto con una rutina que los reubique a su posición original, ponga la página 0 y salte al c/m del juego. Cuando termino con el disco (ya no hay riesgo de reventar nada), pagino la RAM 3 y llamo a la rutina en cuestión.
Algo muy parecido haré con la página 0 que no hay forma de cargar nada en ella porque +3DOS hace un uso intensivo de la página 7 pero aún tengo todo muy en el aire y solo hago pruebas y más pruebas.

Gracias por tu colaboración.
Última edición por Nat el Jue May 23, 2019 10:26 am, editado 1 vez en total.
Saludos,
Nat

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

Re: Acceso a disco desde código máquina con Spectrum +3

Mensaje por zup » Jue May 23, 2019 7:03 am

natohara escribió:Igual con la inexistente gestión de errores, no compensa dedicarle tiempo si hay un error de concepto y el código va a ser desechado.
No se trata de hacer una gestión de errores "completa", sino de que quede evidente cuando ha habido un error. Por ejemplo, hacer una minirutina que ponga el borde rojo y bloquee el equipo (dos instrucciones) y meter un jr nc a la rutina cada vez que haces una operación. Los errores de disco son bastante silenciosos, y te ayudará a ver rápidamente qué está bien hecho y qué mal (eso, o cada vez que metas algo nuevo tendrás que tirar de depurador).
natohara escribió:No son necesarias y siguiendo tu sistema tampoco pienso usarlas.
Te lo comentaba porque el código de muestra (leído de manera muy rápida) parece que si las usaba.
natohara escribió:Algo muy parecido haré con la página 0 que no hay forma de cargar nada en ella porque +3DOS hace un uso intensivo de la página 7 pero aún tengo todo muy en el aire y solo hago pruebas y más pruebas.
Las problemáticas son la página 1 y la 7, la cero no da problemas para nada. Las funciones read y write tienen un parámetro para indicar la página que quieres cargar (va en c). De manera que (aunque para acceder a +3DOS tengas paginada ROM2/RAM7) para cargar 1280 bytes en la página 3 el código sería algo de este estilo:

Código: Seleccionar todo

ld b,5
ld c,3
ld hl,49152
ld de,1280
call dos_read
Para cargar un bloque desde 24576 hasta el final de la RAM, el código sería este (evidentemente, solo funcionará si la pila está por debajo de 24575):

Código: Seleccionar todo

ld b,5
ld c,0
ld hl,24576
ld de,40960
call dos_read
Las problemáticas (como digo), son la página 1 y la 7. La 7 está bastante claro (ahí está todo el +3DOS), aunque hay una serie de áreas que puedes usar sin problemas (p.ej: los primeros 6912 bytes).

La página 1 está algo menos claro. El problema es que los primeros 4k de esta página se emplean para la caché de disco, así que cualquier cosa que pongas ahí será sobreescrita sin piedad. Si tienes planeado usar este área, no hay mucho problema... solo hay que decirle al sistema que NO emplee caché de disco. Para ello, hay que usar la función dos_set_1346 (en $013f), poniendo de y hl a 0.
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: Acceso a disco desde código máquina con Spectrum +3

Mensaje por zup » Jue May 23, 2019 7:10 am

Tocho de código 1: un cargador para Mad Mix Game y Pepsi Challenge. Se usan tres ficheros separados (ahora no recuerdo si tienen o no cabecera) para las pantallas y los datos.

Código: Seleccionar todo

dos_init	equ 256
dos_open	equ 262
dos_close	equ 265
dos_abandon	equ 268
dos_read	equ 274
dos_write	equ 277
dos_set_drive	equ 301
dos_set1346	equ 319
dos_free_space	equ 289
dos_set_pos	equ 310
dd_l_off_motor	equ 412
BANK678		equ 23399
BANKM		equ 23388

ini_pant	equ 16384
lon_pant	equ 6912

ini_madmix	equ 24576
lon_madmix	equ 36790
lon_pepsi	equ 36800
juego		equ 24576

inicio equ 24400

org inicio

  di

; cargar la pantalla
  ld ix,ini_pant
  ld de,lon_pant
  ld a,0
  ld hl,fich_pant
  call cargar

; cargar el juego
  ld ix,ini_madmix
  ld de,lon_madmix
  ld hl,fich_madmix

; Si 24576=0, se carga Mad Mix
;   si no, se carga Pepsi Challenge

  ld a,(juego)
  or a
  jr z, carga_juego

  ld de,lon_pepsi
  ld hl,fich_pepsi

carga_juego:
  ld a,0
  call cargar

; parar el disco y lanzar el juego
  call parar_disco
  ei
  jp 24576

paginar:
  ld bc,32765
  ld (BANKM),a
  out (c),a
  ret

cargar:
; Esta rutina carga ficheros con +3DOS
; a=página donde se va a cargar
; ix=dirección inicial
; de=longitud de datos
; Si hay error -> reset
  push af
  push ix
  push de

; poner ROM2/RAM7 para usar +3DOS
  di
  ld a,$07
  call paginar

; abrir el fichero apuntado por hl
  ld bc,$0501
  ld de,$0001
  call dos_open
  jp nc,0

; Se cargan los datos
  pop de
  pop hl
  pop af
  ld b,5
  ld c,a
  call dos_read
  jp nc,0

; se cierra el fichero

  ld b,5
  call dos_close
  jp nc,0

; se vuelve a poner ROM0/RAM0
  ld a,$10
  call paginar
  ret

parar_disco:
  ld a,$07
  call paginar
  call dd_l_off_motor
  ld a,$10
  call paginar
  ret

fich_pant:
  db 'MADMIX.$',$ff

fich_madmix:
  db 'MADMIX.C',$ff

fich_pepsi:
  db 'PEPSI.C',$ff
Tocho de código 2: algo un poquito más avanzado. Los mismos juegos, pero con todo (pantalla y código) en un único fichero.

Código: Seleccionar todo

dos_init	equ 256
dos_open	equ 262
dos_close	equ 265
dos_abandon	equ 268
dos_read	equ 274
dos_write	equ 277
dos_set_drive	equ 301
dos_set1346	equ 319
dos_free_space	equ 289
dos_set_pos	equ 310
dd_l_off_motor	equ 412
BANK678		equ 23399
BANKM		equ 23388

ini_pant	equ 16384
lon_pant	equ 6912

ini_madmix	equ 24576
lon_madmix	equ 36790
lon_pepsi	equ 36800
juego		equ 24576

inicio equ 24400

org inicio

  di

; poner ROM2/RAM7 para usar +3DOS
  di
  ld a,$07
  call paginar

; abrir el fichero del juego
  ld hl,fich_juego
  ld bc,$0501
  ld de,$0001
  call dos_open
  jp nc,0

; Se cargan la pantalla de presentación
  ld hl,ini_pant
  ld de,lon_pant
  ld bc,$500
  call dos_read
  jp nc,0

  ld hl,ini_madmix
  ld de,lon_madmix

; Si 24576=0, se carga Mad Mix Game
;   si no, se carga The Pepsi Challenge
  ld a,(juego)
  or a
  jr z,carga_bloque_juego

; Nos saltamos el bloque de Mad Mix Game
  ld b,5
  ld e,0
  ld hl,lon_pant+lon_madmix
  call dos_set_pos
  jp nc,0

  ld hl,ini_madmix
  ld de,lon_pepsi

carga_bloque_juego:
  ld bc,$500
  call dos_read
  jp nc,0

; se cierra el fichero
  ld b,5
  call dos_close
  jp nc,0

; se detiene el disco
  call dd_l_off_motor

; se vuelve a poner ROM0/RAM0
  ld a,$10
  call paginar

; se ejecuta el juego
  jp 24576

paginar:
  ld bc,32765
  ld (BANKM),a
  out (c),a
  ret

fich_juego:
  db 'MADMIX.BIN',$ff
A ver si luego encuentro algo de 128k, o algo que se lleve por delante casi toda la RAM...
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
Nat
Herbert
Mensajes: 95
Registrado: Lun Mar 25, 2019 9:31 am

Re: Acceso a disco desde código máquina con Spectrum +3

Mensaje por Nat » Jue May 23, 2019 10:18 am

zup escribió:No se trata de hacer una gestión de errores "completa",...
...
Te lo comentaba porque el código de muestra (leído de manera muy rápida) parece que si las usaba.
Como te decía era una prueba con la única intención de familializarme con el interfaz del +3DOS, habrás visto también que el código escribe en disco (el contenido de la pantalla) y de hecho para el cargador final no he necesitado escribir para nada porque los bloques definitivamente los he generado desde PC que me es más cómodo.
zup escribió:Las problemáticas son la página 1 y la 7, la cero no da problemas para nada.
El problema en mi caso viene porque la parte libre de la RAM del Spectrum 48 está en la página 0, en la que está el cargador original y que además inicializa SP a 0 ¿Es posible ejecutar el cargador desde esa página? Imagino que solo la pila de retorno supone un obstáculo.

Las funciones read y write tienen un parámetro para indicar la página que quieres cargar (va en c). De manera que (aunque para acceder a +3DOS tengas paginada ROM2/RAM7) para cargar 1280 bytes en la página 3 el código sería algo de este estilo:
zup escribió:La página 1 está algo menos claro.
Muchas gracias zup, por la explicación y por el código (que me lo guardo), esto es muy interesante y sin duda supera las necesidades que tenía para este cargador pero, quién sabe, es más que posible que lo aproveche en el futuro.
Saludos,
Nat

Avatar de Usuario
Nat
Herbert
Mensajes: 95
Registrado: Lun Mar 25, 2019 9:31 am

Re: Acceso a disco desde código máquina con Spectrum +3

Mensaje por Nat » Dom May 26, 2019 1:11 pm

Encontré más información sobre el acceso a disco en estos artículos de Juan Carlos Jaramago, Carlos Enrique Alcántara y Pedro José Rodríguez Larrañaga en MHoogle en este enlace:

http://mhoogle.speccy.org/mhoogle.php?b ... bajo+nivel

o para leerlos offline en este otro:

https://mega.nz/#!fzZglS4Q!ihuOErrLTsAM ... ONevohpze0
Saludos,
Nat

Responder

¿Quién está conectado?

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