Como hacer tus cambios en la ROM del Spectrum

Aquí solo proyectos que incluyan el código fuente

Moderador: Fundadores

Reglas del Foro
Si no se incluyen los fuentes, se debe usar el foro de proyectos de software generales
Avatar de Usuario
flopping
Fundador
Fundador
Mensajes: 9971
Registrado: 29 Mar 2013, 15:26
Ubicación: Valencia
Been thanked: 122 times
Contactar:

Re: Como hacer tus cambios en la ROM del Spectrum

Mensaje por flopping »

Pues de momento esto se pone muy interesante, sigue así que al final aprenderemos y todo, jejejeje. :D :D
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: Como hacer tus cambios en la ROM del Spectrum

Mensaje por antoniovillena »

Hoy vamos a insertar el script tokenizador. Está compuesto por 4 trozos pequeños más la rutina principal. Empezamos con el trozo 1:

Trozo 1, en MAIN-2

Código: Seleccionar todo

;; MAIN-2
L12AC:  LD      A,$00           ; select channel 'K' the keyboard

        CALL    L1601           ; routine CHAN-OPEN opens it

      IFDEF easy
        call    NEWED           ;+ Call the New Editor.
      ELSE
        CALL    L0F2C           ; routine EDITOR is called.
                                ; Note the above routine is where the Spectrum
                                ; waits for user-interaction. Perhaps the
                                ; most common input at this stage
                                ; is LOAD "".
      ENDIF
Como veis, de lo que se trata es de sustituir la etiqueta del salto L02F a NEWED. Las instrucciones que he puesto antes son para que localicéis el fragmento, ya que el archivo 48.asm es enorme. Se puede hacer sin ensamblado condicional (cambiando el valor de la etiqueta), pero prefiero hacerlo de esta forma ya que así podemos combinar snippets y tener distintas variantes de ROM.

El segundo trozo está en MAIN-3

Código: Seleccionar todo

;; MAIN-3
L12CF:  
      IFDEF easy
        nop
        nop
        ld      (iy+$07), 0     ;+ Set MODE to 'KLC' ( not extended or graph)
      ELSE
        LD      HL,($5C59)      ; fetch the edit line address from E_LINE.

        LD      ($5C5D),HL      ; system variable CH_ADD is set to first
                                ; character of edit line.
                                ; Note. the above two instructions are a little
                                ; inadequate. 
                                ; They are repeated with a subtle difference 
                                ; at the start of the next subroutine and are 
                                ; therefore not required above.
      ENDIF
El tercer trozo en OUT-LINE3

Código: Seleccionar todo

;; OUT-LINE3
L1881:  PUSH    DE              ; save flag E for a return value.
        EX      DE,HL           ; save HL address in DE.
        RES     2,(IY+$30)      ; update FLAGS2 - signal NOT in QUOTES.

      IFDEF easy
        call    IMPOSE
        jp      L1894
        nop
        nop
        nop
        nop
        nop
        nop
        nop
      ELSE
        LD      HL,$5C3B        ; point to FLAGS.
        RES     2,(HL)          ; signal 'K' mode. (starts before keyword)
        BIT     5,(IY+$37)      ; test FLAGX - input mode ?
        JR      Z,L1894         ; forward to OUT-LINE4 if not.

        SET     2,(HL)          ; signal 'L' mode. (used for input)
      ENDIF
El cuarto trozo en OUT-CHAR

Código: Seleccionar todo

;; OUT-CHAR
L1937:  CALL    L2D1B           ; routine NUMERIC tests if it is a digit ?
        JR      NC,L196C        ; to OUT-CH-3 to print digit without
                                ; changing mode. Will be 'K' mode if digits
                                ; are at beginning of edit line.

        CP      $21             ; less than quote character ?
        JR      C,L196C         ; to OUT-CH-3 to output controls and space.

      IFDEF easy
        call    IMPOSE
        nop
      ELSE
        RES     2,(IY+$01)      ; initialize FLAGS to 'K' mode and leave
                                ; unchanged if this character would precede
                                ; a keyword.
      ENDIF
Por último, la rutina principal irá donde tengamos un hueco libre. Como hemos dicho antes, a partir de L386E está todo a $FF así que lo ponemos ahí, aunque también podríamos haberla puesto justo antes del mapa de caracteres ($3d00) o en un punto intermedio.

Código: Seleccionar todo

;; spare
L386E:
      IFDEF easy
; -------------------------------------------------------------------------
;  Impose flags on secondary flags. It is OK to use HL register. (20 bytes)
; -------------------------------------------------------------------------

IMPOSE: ld      hl, $5c3b       ; point to FLAGS. (IY+$01)
        set     3, (hl)         ; permant flag 'L' mode
        set     2, (hl)         ; temporary flag built up by line
        bit     5, (iy+$30)     ; Test NEW FLAG
        ret     z               ; Leave as 'L'
        jp      z, $ffff
        bit     5, (iy+$37)     ; test FLAGX - input mode ?
        ret     nz              ; Leave as 'L' if in input state
        res     3,(hl)          ; set permanent flag to 'K'
        res     2,(hl)          ; set transient flag to 'K'
        ret                     ; Return
; -----
; NEWED
; -----
;   The new editor sets flags that allow the old editor to be called to enter
;   lower-case text.

NEWED:  res     3, (iy+$02)     ;
        call    IMPOSE          ; Set flags. HL addresses System Variable FLAGS
        dec     l               ; Points to ERR_NR
        ld      (hl), $ff       ; Set to 'OK'
        call    L0F2C           ; Original EDITOR prepares line
        bit     5, (iy+$30)     ; Test NEW FLAG
        ret     nz              ; Return if not set

;   Otherwise continue into the tokenizer that converts text to tokens.

; ---------------
; THE 'TOKENIZER'
; ---------------
;   Note the tokenizer should not tokenize anything after rem
;   Also no keywords within quotes although this is normally permissible.
;   keywords in any order e.g. 'AT', 'ATTR', 'ATN'
;   print pi is taken as the constant and not a variable pi
;   REM is treated separately first.
;   Then COPY down to RND.
;   REM is done again as its easier to just process than avoid.
;   Spaces in goto and deffn are optional.

        ld      de, REMTO       ; Start of 'REM' in ROM token table.
        xor     a               ; A zero detects first pass for 'REM'
NEWTOK: push    de              ; The same token may be repeated many times.
        pop     ix              ; Save token table position in IX
        ld      hl, ($5C59)     ; Get edit line start from E_LINE.
CHAR0:  ld      b, 0
        push    af              ; Preserve the token number on the stack.
        ld      c, b
CHAR1:  push    ix              ; Transfer the start of current token
        pop     de              ; to the DE register.
L3:     ld      a, (hl)         ; Get edit line character.
L4:     cp      $0d             ; Carriage return?
        jr      z, EOL          ; End of edit line - next token
        cp      $EA             ; Is token REM ?
        jr      z, EOL          ; Treat same as end of line - no more tokens.
        cp      $22             ; Is this quote character
        jr      nz, NOQ         ; Skip if not to no quotes
        inc     c               ; Increment quotes flag toggling bit 0.
NOQ:    bit     0, c            ; Within quotes?
        jr      nz, SKIP        ; Forward if so to repeat loop
        call    UCASE           ; Make uppercase sets carry if alpha
        jr      nc, NOT_AZ      ; Forward if not A-Z

;   If this is alpha then previous must not be to avoid 'INT' in 'PRINT' etc.

        bit     7, b            ; Is previous alpha?
        jr      nz, SKIP        ; Forward if previous is alpha to ignore
NOT_AZ: ex      de, hl          ; Switch in first character of token
        cp      (hl)            ; Is there a match
        ex      de, hl          ; Switch out.
        jr      z, MATCH1       ; Forward if first character matches.
SKIP:   inc     hl              ; Address next character in edit line
        jr      L3              ; Back - check next character against 1st char.

;   The first characters match.
                
MATCH1: ld      ($5cac), hl     ; Store position within 
INTRA:  inc     hl              ; Increment edit line pointer.
        ld      a, (hl)         ; Next BASIC character.
        call    UCASE           ; Make uppercase.
        ex      af, af'         ; Create an entry point.
INTRA2: ex      af, af'         ; Start of loop for internal characters
        inc     de              ; Point to next character in token
        ex      de, hl          ; 
        cp      (hl)            ; compare with token - intra?
        ex      de, hl          ;
        jr      z, INTRA        ; loop while token characters match

;   If DE is a space then allow to be skipped now e.g. 'goto' and 'GO TO'

        ex      af, af'         ; Save the edit line character.
        ld      a, (de)         ; Fetch the token character to A.
        cp      $20             ; Is it a space?
        jr      z, INTRA2       ; Consider next token character if so.

;   First check for a '.' which indicates an abbreviated keyword.  
;   as suggested by Andrew Owen 18-OCT-2004 

        ex      af, af'         ; Retrieve the edit line character.
        cp      $2e             ; Is it an abbreviation i.e. '.' ?
        jr      z, CHKSP        ; substitute straight away

;   The only possibility now is the terminating character of token.

        ex      de, hl          ; Switch in token
        or      $80             ; Set bit 7
        cp      (hl)            ; Is character inverted?
        ex      de, hl          ; Switch out.

;   If not go back and reset pointer (DE) to the start of the current token
;   and continue until the end of this line.

        jr      nz, CHAR1       ; Back to start at char 1 again
                
;   All the characters matched including the final inverted one.
;   Examine the last character for a valid non-alpha as in 'val$a$'

        cp      $40+$80         ; Is it <> or STR$ or OPEN # etc.
        jr      c, SUBST        ; Good enough - skip the alpha test

;   A full match - but check the next character and reclaim if space.
;   Note. do not remove! This prevents hidden spaces in listing!
;   Also don't substitute if next is alpha. e.g. 'AT' in 'ATN'.
;   Also FOR in FORMAT.  Also no substitution if next is '$' 
;   e.g. VAL in VAL$ credit. Andrew Owen.

CHKSP:  inc     hl              ; Advance to next character in edit line.
        ld      a, (hl)         ; Get following character in A.
        cp      $20             ; Is it a space ?
        jr      z, SUBST        ; Forward, if so, replacing letters AND space.
        dec     hl              ; points to last character of token.
        cp      $24             ; is it '$' ? e.g. VAL within VAL$
        jr      z, CHAR1        ; abandon as could be token within token.
        call    L2C8D           ; Call ROM routine ALPHA
        jr      c, CHAR1        ; Start again if next char is alpha
                                ; e.g. 'AT' in 'ATN'

;   A full match - accumulator on stack gives token.
;   For convenience we will not reclaim the last character as the new token
;   which is a single character can go there.

SUBST:  ld      de, ($5cac)     ; First character of token in edit line
BAKT:   dec     de              ; Harvest any leading spaces
        ld      a, (de)
        cp      $20
        jr      z, BAKT
        inc     de              ; Back to first character of keyword.
        call    L19E5           ; Use ROM routine RECLAIM-1

;   HL points to empty cell, token (AF) is on stack.

        pop     af              ; Retrieve token
        push    ix              ; Transfer address within token table
        pop     de              ; to the DE register.

;   The next two lines apply only when parsing the special REM table.
;   The normal table is at the start of ROM, the secondary table is at the end.

        bit     5, d            ; Test high byte of table address.
        ret     nz              ; Return if not standard keywords to NEWREM
        ld      (hl), a         ; Insert the token and test it.
        and     a               ; Will be zero if on first pass for REM
        jp      nz, CHAR0       ; Else look for more of the same token

;  There can only be one token REM in a line.

        ld      (hl), $ea       ; Substitute the REM token. No more tokenization 
        push    af              ; After the 'REM' token don't loop back.

; End of BASIC line - do next token down in table.

EOL:    ld      de, CPYTO       ; set to  START of COPY in case first REM pass.
        pop     af              ; Restore token.
        sub     $01             ; Decrement but set carry if originally zero.
        jr      c, NXTTOK       ; Will point to new token cluster so go.
        cp      $a4             ; RND -1 
        ret     z               ; Finished if so
        push    ix              ; Have to work down to find the start of the previous token
        pop     hl
NXTT:   dec     hl              ; Known inverted end of previous
LLOOP:  dec     hl              ;
        bit     7, (hl)         ; inverted?
        jr      z, LLOOP        ;
        inc     hl              ; point to first char.
        ex      de, hl          ; token position to DE
NXTTOK: jp      NEWTOK          ; back to process next token
UCASE:  call    L2C8D           ;+ ROM routine ALPHA.
        ld      b, c            ;+ prev to B
        ld      c, 0            ;+ set flag to non-alpha initially
        ret     nc              ;+ return with >= etc.
        res     5, a            ;+ make uppercase alpha.
        set     7, c            ;+ invert flag if alpha
        ret                     ;+ Return.
      ENDIF
También tenemos que definir la constante de compilación condicional "easy" al principio del archivo:

Código: Seleccionar todo

        DEFINE  easy

        OUTPUT  48.rom

;************************************************************************
;** An Assembly File Listing to generate a 16K ROM for the ZX Spectrum **
;************************************************************************
Y poner etiquetas justo donde empieza el texto de las instrucciones REM y COPY:

Código: Seleccionar todo

        DEFM    "DI"
        DEFB    'M'+$80
REMTO:  DEFM    "RE"
        DEFB    'M'+$80
...
        DEFM    "RETUR"
        DEFB    'N'+$80
CPYTO:  DEFM    "COP"
        DEFB    'Y'+$80
Ahora ensamblamos y vemos que la ROM funciona perfectamente. Sin embargo hay un último paso que debemos hacer siempre para asegurarnos de que la compatibilidad de la ROM con los juegos sea la máxima. El área sin usar la emplean algunos juegos para suministrar el puntero para interrupciones IM 2. La dirección se calcula con el registro I más lo que se lea del bus de datos que, a no ser que tengamos un dispositivo específico, será $FF. En resumen, que tenemos que asegurarnos que en las direcciones $38FF, $39FF, $3AFF y $3BFF existan dos bytes consecutivos a $FF. Con un editor hexadecimal (yo uso HxD) vemos que esto no ocurre:
cambiosrom.png
Hay muchas formas de arreglarlo, la más sencilla es quizás con un salto jr para que no se ejecuten los bytes $FF (ya que colgarían el sistema). Como las instrucciones del Z80 tienen distinto tamaño, en algunos casos habrá que hacer algún relleno después del jr y antes de los dos $FF. Pero con un poco de dominio en ensamblador seguro que se os ocurren otras fórmulas para que los bytes que se pierdan sean los mínimos:

Código: Seleccionar todo

        cp      $24             ; is it '$' ? e.g. VAL within VAL$
        jr      z, CHAR1        ; abandon as could be token within token.

        jp      z, $ffff

        call    L2C8D           ; Call ROM routine ALPHA
        jr      c, CHAR1        ; Start again if next char is alpha
En este caso sólo perdemos un byte. Como sabemos que el flag Z está desactivado en ese punto, la instrucción JP Z nunca saltará, con lo que hemos encontrado otra forma válida de evitar los 2 bytes a $ff.

Ensamblamos para asegurarnos y como podemos comprobar, ahora sí tenemos que los dos bytes que apuntan a $38FF están a $FF, $FF.
cambiosrom2.png
Ya hemos acabado. Os dejo el código fuente aunque recomiendo que lo intentéis hacer vosotros mismos siguiendo las instrucciones, y comparar los binarios para comprobar si os habéis equivocado.

Os adelanto que el próximo día pondré un snippet que permite pokear en tiempo real dentro de cualquier juego y sin hardware específico. Tan sólo necesitaréis tener un botón NMI y pulsarlo en el momento de aplicar el POKE.
No tiene los permisos requeridos para ver los archivos adjuntos a este mensaje.
Avatar de Usuario
antoniovillena
Demonio segundo orden
Demonio segundo orden
Mensajes: 1596
Registrado: 02 Abr 2013, 19:06
Been thanked: 1 time

Re: Como hacer tus cambios en la ROM del Spectrum

Mensaje por antoniovillena »

Voy a acabar este tutorial con el pokeador. Tenía pensado meter también la rutina Reset & Play, pero es más de lo mismo y además siguiendo el tutorial no sería muy difícil hacerlo a partir del código de CargandoLeches.

Este pokeador es una versión reducida del pokemon: no tiene la función de reseteo, ni de salto a rutina, ni la de transfer. Una vez estemos jugando dentro del juego (a ser posible en el menú o en un sitio donde no importe la corrupción de la parte baja de la pantalla) pulsamos el botón NMI (F5 si lo pruebas en emulador) y aparece un recuadro con 5 caracteres en azul en la esquina superior izquierda. Pues bien, primero introducimos la dirección del poke, y en cuanto le demos a intro nos aparecerá el antiguo valor de byte. Cambiando el valor y pulsando intro se produce el poke. Lo siguiente puede ser un byte (3 o menos caracteres) o una dirección (5 caracteres). Si escribimos lo primero haremos un poke en una dirección consecutiva a la anterior, si hacemos lo segundo introducimos una nueva dirección para un segundo poke. Para salir (volver al juego) hay que pulsar intro 2 veces.

El snippet principal va en la dirección $3948, justo después de donde acaba el tokenizador. Y acaba en $3aa0, dejando libres 608 bytes para los snippets que queramos. Como ya hemos dicho, se puede combinar con la activación del tokenizador, teniendo 4 posibles configuraciones:

ROM del 48K original

Código: Seleccionar todo

;        DEFINE  easy
;        DEFINE  pokemon
Sólo tokenizador

Código: Seleccionar todo

        DEFINE  easy
;        DEFINE  pokemon
Sólo pokeador

Código: Seleccionar todo

;        DEFINE  easy
        DEFINE  pokemon
Ambas cosas a la vez

Código: Seleccionar todo

        DEFINE  easy
        DEFINE  pokemon
En el caso del pokeador sólo hay 2 fragmentos de código. El código principal que va en $3948, y la rutina NMI en la dirección $0066. Esta vez no escribo el código porque es más de lo mismo. Eso sí, dejo el archivo final para que os lo descarguéis.
No tiene los permisos requeridos para ver los archivos adjuntos a este mensaje.
Avatar de Usuario
stratotrasto
Hermano de Lucifer
Hermano de Lucifer
Mensajes: 2494
Registrado: 20 Feb 2014, 17:23
Ubicación: Abula

Re: Como hacer tus cambios en la ROM del Spectrum

Mensaje por stratotrasto »

Gracias de nuevo, uff! Con esto tengo para tiempo. Ya voy diciendo cosas....
Si me muero no dejéis a mi mujer vender mis cacharros por lo que le dije que me costaron...
Avatar de Usuario
neuro_999
El infierno es su lugar
El infierno es su lugar
Mensajes: 161
Registrado: 18 Mar 2015, 19:03

Re: Como hacer tus cambios en la ROM del Spectrum

Mensaje por neuro_999 »

Estoy intentando descargarme los ejemplos de las ROMs, pero todas me dan error al intentar descomprimirlas. Me dice que el zip esta corrupto. He probado con el nativo de windows y con el 7zip y nada. ¿Cual puede ser el problema? El fichero lo he probado a bajar con el firefox y el chrome. y hasta en el tlf. y nada.
¿Algun sitio donde me la pudiera bajar? es que la modificacion del POKEador es lo que habia estado buscando.

Muchas gracias. Eres un makina Antonio, yo es que flipo en la de proyectos interesantes en los que estas metido y todos me interesan. :) el bacteria para la pi, el zx-uno... ahora esto. Eres mi idolo.
Avatar de Usuario
antoniovillena
Demonio segundo orden
Demonio segundo orden
Mensajes: 1596
Registrado: 02 Abr 2013, 19:06
Been thanked: 1 time

Re: Como hacer tus cambios en la ROM del Spectrum

Mensaje por antoniovillena »

Pues debe ser un error en la base de datos del foro porque todos los archivos se han corrompido, incluyendo las imágenes. Desgraciadamente no tengo backup, puesto que una vez escribí el tutorial borré todos los archivos de mi disco duro. La única solución es que alguien que haya seguido el tutorial (posiblemente stratotrasto sea el único candidato posible) se haya bajado los archivos cuando estos funcionaban y los mantenga. Si al final no conseguimos restaurar los archivos me temo que habría que borrar el hilo, ya que sin archivos no tiene mucho sentido.
Avatar de Usuario
antoniovillena
Demonio segundo orden
Demonio segundo orden
Mensajes: 1596
Registrado: 02 Abr 2013, 19:06
Been thanked: 1 time

Re: Como hacer tus cambios en la ROM del Spectrum

Mensaje por antoniovillena »

He podido recuperar de mi disco sólo el último archivo, que adjunto. Haciendo comparaciones binaria parece que filtra todos los bytes con el valor $0D, posiblemente sea una forma de convertir los CR/LF en sólo LF pero sólo debería aplicarse a archivos ASCII.
No tiene los permisos requeridos para ver los archivos adjuntos a este mensaje.
Avatar de Usuario
neuro_999
El infierno es su lugar
El infierno es su lugar
Mensajes: 161
Registrado: 18 Mar 2015, 19:03

Re: Como hacer tus cambios en la ROM del Spectrum

Mensaje por neuro_999 »

Muchas Gracias, este si que lo abre bien.
Tambien he estado viendo los hilos donde hiceste el pokemon :) esta genial.

Animo con los proyectos, y ojala podamos ver comercializado pronto el zxuno (o al menos una version kit con los componentes soldados, aunque solo sea el SMD) que le tengo unas ganas....

Salu2. de un RetroViejuno.
Avatar de Usuario
antoniovillena
Demonio segundo orden
Demonio segundo orden
Mensajes: 1596
Registrado: 02 Abr 2013, 19:06
Been thanked: 1 time

Re: Como hacer tus cambios en la ROM del Spectrum

Mensaje por antoniovillena »

neuro_999 escribió:Muchas Gracias, este si que lo abre bien.
Tambien he estado viendo los hilos donde hiceste el pokemon :) esta genial.

Animo con los proyectos, y ojala podamos ver comercializado pronto el zxuno (o al menos una version kit con los componentes soldados, aunque solo sea el SMD) que le tengo unas ganas....

Salu2. de un RetroViejuno.
Me alegro de que te guste. Estaría bien que flopping diera con el error y así recuperar el resto de archivos del hilo, y otros posibles hilos que se hayan visto afectados.

Este pokeador funciona en un spectrum real, lo único que necesitas es un botón NMI y posibilidad de cambiar la ROM (interface 2+cartucho, reemplazo de chip si tiene zócalo o algún otro interface que te lo permita). A diferencia de otros pokeadores de la época no necesita circuitería adicional.

Respecto al ZX-Uno, cuando lo comercialicemos tendría que ser con la placa completamente soldada y programada.
Avatar de Usuario
neuro_999
El infierno es su lugar
El infierno es su lugar
Mensajes: 161
Registrado: 18 Mar 2015, 19:03

Re: Como hacer tus cambios en la ROM del Spectrum

Mensaje por neuro_999 »

Me ha funcionado perfecto. le he metido los cambios que lleva el smartcard para el manejo de cintas a tu rom y ya tengo la funcion pokeador en el cacharrilo. que gozada.
Si alguien tiene el smartcard y lo quiere, que me lo diga y lo pongo por aqui.

Por cierto, seria muy complicado modificar la rom del shadow of the unicorn para que funcionara con joystick kempston en lugar de interface2?. X donde deberia empezar a buscar en la rom desensamblada?.
Muchas gracia x todo. Me esta gustando volver al ensanblador. Aunque yo era de 68000 y de 8086. jeje. el del zx nunca lo toque, no pase del basic.
Responder

Volver a “Proyectos de software abiertos”