Consultas técnicas ensamblador Z80 (para AGD)
- pser1
- Mensajes: 4094
- Registrado: 08 Dic 2012 18:34
- Agradecido : 1352 veces
- Agradecimiento recibido: 1118 veces
Consultas técnicas ensamblador Z80 (para AGD)
Hola compañeros,
como amenacé antes, me decido a abrir un 'hilo' para ir incorporando consultas sobre partes del código
del juego FOGGY que no entienda suficientemente como para poder convertirlas a código 6809
El primer tema para ir abriendo boca es el sonido. ¿Cómo no?
Os adjunto aquí tanto el listado en ensamblador del juego FOGGY completo para Z80
como un listado comentado de la parte que genera sonidos ...
En el próximo mensaje os explico mis dudas al respecto
saludos
pere
como amenacé antes, me decido a abrir un 'hilo' para ir incorporando consultas sobre partes del código
del juego FOGGY que no entienda suficientemente como para poder convertirlas a código 6809
El primer tema para ir abriendo boca es el sonido. ¿Cómo no?
Os adjunto aquí tanto el listado en ensamblador del juego FOGGY completo para Z80
como un listado comentado de la parte que genera sonidos ...
En el próximo mensaje os explico mis dudas al respecto
saludos
pere
- pser1
- Mensajes: 4094
- Registrado: 08 Dic 2012 18:34
- Agradecido : 1352 veces
- Agradecimiento recibido: 1118 veces
Re: Consultas técnicas ensamblador Z80 (para AGD)
En el mensaje anterior os he adjuntado en un solo documento el código generador de sonidos en ensamblador de Z-80 comentado tal
como lo descargué del grupo AGD, algunos comentarios los he modificado para aclararme mejor, otros los he añadido sobre la marcha
Como, a pesar de los comentarios, no me hago una idea clara de como funciona, veréis en la columna de la izquierda un 'trazado' manual
con los valores que adquieren los registros al ir ejecutando la rutina ...
Cosas que entiendo que deben (deberían) suceder:
- Hay que llamar a la rutina una vez para que se le ponga valor a la variable 'clock' o en vsync4 siempre serán diferentes y no se emitirá sonido
- Cuando se llama a la rutina para que emita un sonido debe cumplirse que clock tenga el valor de (23672) o no habrá sonido
Y no veo como lo hace el programa FOGGY ya que NO pone valor alguno a 'clock' antes de llamar a esta rutina
A menos de que sea llamada con valor cero cada 'frame' y por tanto se cumplan los requisitos que acabo de decir ... ojalá sea esto!
Entiendo que (23672) es el byte bajo del contador de cuadros (frames) que supongo irá a razón de uno cada 20mseg (50Hz -> = 0,02seg) PAL
Asumiendo que se haya enviado el valor 'bajo' (5) al altavoz lo mantendrá un número de veces (20 en el caso imaginado), tras lo cual
enviará el valor máximo (253) también 20 veces. Esto completaría un ciclo de señal en onda cuadrada pasando de cero a tope
Si ahora el contador (que tiene el mismo valor 20) no ha bajado a cero, se repite la historia enviando un valor bajo y luego uno alto, o sea que obtendríamos
En este caso la cifra 20 sería el número de ciclos que se habrían generado de una duración de 20 bucles vsync3 cada semiperíodo.
Me parece raro que la cifra "sndtyp" esté determinando al mismo tiempo el número de ciclos a emitir y la anchura de cada semiciclo.
Para elucubrar un poco un bucle comparador en 6809 podría ser
lda clock ; obtener valor anterior
Bucle1 cmpa ,x ; siendo x puntero a valor 'cambiante'
beq Bucle1
El bucle utilizaría: 5+3 = 8 ciclos de CPU
Si lo hacemos 20 veces (regalando los ciclos de otros controles) serán 160 digamos 200 ciclos
El reloj en Dragón va a 0,89Mhz así que esto nos daría: 200*1/0,89 MHz = 0,225 mseg x semiciclo
Realizado 20 veces (20 cambios de nivel) = 4,5 mseg
Con lo cual parece que hay tiempo de sobra dentro de los 20 mseg de un cuadro
Vaya latazo os estoy pegando, para variar
Estoy convencido de que algo se me está escapando.
Espero que alguno de vosotros mucho mas versado en Z-80 pueda aclararme los puntos que me están patinando
Muchísimas gracias por anticipado
saludos
pere
como lo descargué del grupo AGD, algunos comentarios los he modificado para aclararme mejor, otros los he añadido sobre la marcha
Como, a pesar de los comentarios, no me hago una idea clara de como funciona, veréis en la columna de la izquierda un 'trazado' manual
con los valores que adquieren los registros al ir ejecutando la rutina ...
Cosas que entiendo que deben (deberían) suceder:
- Hay que llamar a la rutina una vez para que se le ponga valor a la variable 'clock' o en vsync4 siempre serán diferentes y no se emitirá sonido
- Cuando se llama a la rutina para que emita un sonido debe cumplirse que clock tenga el valor de (23672) o no habrá sonido
Y no veo como lo hace el programa FOGGY ya que NO pone valor alguno a 'clock' antes de llamar a esta rutina
A menos de que sea llamada con valor cero cada 'frame' y por tanto se cumplan los requisitos que acabo de decir ... ojalá sea esto!
Entiendo que (23672) es el byte bajo del contador de cuadros (frames) que supongo irá a razón de uno cada 20mseg (50Hz -> = 0,02seg) PAL
Asumiendo que se haya enviado el valor 'bajo' (5) al altavoz lo mantendrá un número de veces (20 en el caso imaginado), tras lo cual
enviará el valor máximo (253) también 20 veces. Esto completaría un ciclo de señal en onda cuadrada pasando de cero a tope
Si ahora el contador (que tiene el mismo valor 20) no ha bajado a cero, se repite la historia enviando un valor bajo y luego uno alto, o sea que obtendríamos
Código: Seleccionar todo
(253) Alto ---------- ---------- ----------
| | | | | |
| | | | | |
| | | | | |
(005) Bajo ---------- ---------- ---------- ----------
de 20 a 0 de 20 a 0 de 20 a 0 de 20 a 0 de 20 a 0 de 20 a 0 de 20 a 0
Contador = 20 19 18 17 ... 2 1 0
En este caso la cifra 20 sería el número de ciclos que se habrían generado de una duración de 20 bucles vsync3 cada semiperíodo.
Me parece raro que la cifra "sndtyp" esté determinando al mismo tiempo el número de ciclos a emitir y la anchura de cada semiciclo.
Para elucubrar un poco un bucle comparador en 6809 podría ser
lda clock ; obtener valor anterior
Bucle1 cmpa ,x ; siendo x puntero a valor 'cambiante'
beq Bucle1
El bucle utilizaría: 5+3 = 8 ciclos de CPU
Si lo hacemos 20 veces (regalando los ciclos de otros controles) serán 160 digamos 200 ciclos
El reloj en Dragón va a 0,89Mhz así que esto nos daría: 200*1/0,89 MHz = 0,225 mseg x semiciclo
Realizado 20 veces (20 cambios de nivel) = 4,5 mseg
Con lo cual parece que hay tiempo de sobra dentro de los 20 mseg de un cuadro
Vaya latazo os estoy pegando, para variar
Estoy convencido de que algo se me está escapando.
Espero que alguno de vosotros mucho mas versado en Z-80 pueda aclararme los puntos que me están patinando
Muchísimas gracias por anticipado
saludos
pere
-
- Mensajes: 1669
- Registrado: 03 Ago 2011 23:07
- Ubicación: Aluche, Madrid
- Agradecido : 29 veces
- Agradecimiento recibido: 523 veces
Re: Consultas técnicas ensamblador Z80 (para AGD)
Este tema está relacionado más con cómo funciona el sonido en el ZX Spectrum 16/48K que con el procesador Z80 en sí. Tenemos que tener en cuenta que en los ordenadores Spectrum originales, el sonido venía de un zumbador piezoeléctrico que tenía únicamente 2 estados (supongo que electrónicamente serían 2 voltajes) y los sonidos se conseguían cambiando muy rápidamente entre ellos. El código de la ROM contiene una tabla de cuántos T-states debemos mantener cada estado para conseguir una determinada nota musical pura, lo que no quiere decir que en ensamblador podamos utilizar otros valores intermedios con fragmentos de tiempo mínimos, para conseguir hacer "efectos" especiales. Pero es eso, tú imagina simplemente que es un dispositivo biestado, con el que te comunicas a base de OUTs.
No tiene nada que ver con el sonido en los Spectrum a partir del 128K, que incorporan ya un chip independiente generador de ondas de 3 canales+ruido, con volumen y envolvente ADSR (Attack/Decay/Sustain/Release) que no tiene nada que ver con el proceso del zumbador antiguo, que se tomaba el 100% del tiempo de CPU al tener que controlar minuciosamente los bucles de tiempo para generar las frecuencias.
Claro, si lo quieres traducir al sistema que pueda llevar el Dragon, lo primero tendrás que saber exactamente cómo produce sonido el Dragon, algo que yo desconozco. Si lleva un copro independiente para sonido, todos los cálculos de los bucles del Z80 de poco te sirven seguirlos al pie de la letra, sin hacer una interpretación más abstracta del proceso.
No tiene nada que ver con el sonido en los Spectrum a partir del 128K, que incorporan ya un chip independiente generador de ondas de 3 canales+ruido, con volumen y envolvente ADSR (Attack/Decay/Sustain/Release) que no tiene nada que ver con el proceso del zumbador antiguo, que se tomaba el 100% del tiempo de CPU al tener que controlar minuciosamente los bucles de tiempo para generar las frecuencias.
Claro, si lo quieres traducir al sistema que pueda llevar el Dragon, lo primero tendrás que saber exactamente cómo produce sonido el Dragon, algo que yo desconozco. Si lleva un copro independiente para sonido, todos los cálculos de los bucles del Z80 de poco te sirven seguirlos al pie de la letra, sin hacer una interpretación más abstracta del proceso.
- pser1
- Mensajes: 4094
- Registrado: 08 Dic 2012 18:34
- Agradecido : 1352 veces
- Agradecimiento recibido: 1118 veces
Re: Consultas técnicas ensamblador Z80 (para AGD)
BlackHole escribió:Este tema está relacionado más con cómo funciona el sonido en el ZX Spectrum 16/48K que con el procesador Z80 en sí. Tenemos que tener en cuenta que en los ordenadores Spectrum originales, el sonido venía de un zumbador piezoeléctrico que tenía únicamente 2 estados (supongo que electrónicamente serían 2 voltajes) y los sonidos se conseguían cambiando muy rápidamente entre ellos. El código de la ROM contiene una tabla de cuántos T-states debemos mantener cada estado para conseguir una determinada nota musical pura, lo que no quiere decir que en ensamblador podamos utilizar otros valores intermedios con fragmentos de tiempo mínimos, para conseguir hacer "efectos" especiales. Pero es eso, tú imagina simplemente que es un dispositivo biestado, con el que te comunicas a base de OUTs.
No tiene nada que ver con el sonido en los Spectrum a partir del 128K, que incorporan ya un chip independiente generador de ondas de 3 canales+ruido, con volumen y envolvente ADSR (Attack/Decay/Sustain/Release) que no tiene nada que ver con el proceso del zumbador antiguo, que se tomaba el 100% del tiempo de CPU al tener que controlar minuciosamente los bucles de tiempo para generar las frecuencias.
Claro, si lo quieres traducir al sistema que pueda llevar el Dragon, lo primero tendrás que saber exactamente cómo produce sonido el Dragon, algo que yo desconozco. Si lleva un copro independiente para sonido, todos los cálculos de los bucles del Z80 de poco te sirven seguirlos al pie de la letra, sin hacer una interpretación más abstracta del proceso.
Muchas gracias por la rápida respuesta y la aclaración técnica.
Verás el Dragón dispone de una salida DAC de 6 bits a la cual se le puede enviar cualquier valor comprendido entre 0 y 63, por lo que
puedes generar ondas con esta 'definición', no está restringido a 2 niveles o sea alto y bajo, pero puede funcionar así también!
Mi problema es que no veo claro que un solo valor (sndtyp) se emplee para determinar el periodo de la señal a emitir (bucle de
retardo una vez enviado un nivel) y además que determine el número de inversiones de dicho valor (semiperíodos) ...
a menos que esto sea lo que realmente deseara quien programó la rutina de sonido para el motor del AGD para Spectrum
saludos
pere
- pser1
- Mensajes: 4094
- Registrado: 08 Dic 2012 18:34
- Agradecido : 1352 veces
- Agradecimiento recibido: 1118 veces
Re: Consultas técnicas ensamblador Z80 (para AGD)
buff,
ha llovido mucho desde la conversión del Hobbit ...
Intentaré trazar la ejecución del FOGGY y ver valores de registros y variables del sistema a cada llamada a la rutina de sonido.
A ver si me aclaro de nuevo con el SpecEmu ... ya he olvidado como funciona a pesar de la cantidad de sesiones de trazado/depuración
que tuve que realizar
A ver su puedo 'demostrarme' que se llama, a cada cuadro, dicha rutina lo cual garantizaría que se pueda emitir sonido cada vez que haga falta
Si detecto algo 'raro' o imprevisto os lo contaré
saludos
pere
ha llovido mucho desde la conversión del Hobbit ...
Intentaré trazar la ejecución del FOGGY y ver valores de registros y variables del sistema a cada llamada a la rutina de sonido.
A ver si me aclaro de nuevo con el SpecEmu ... ya he olvidado como funciona a pesar de la cantidad de sesiones de trazado/depuración
que tuve que realizar
A ver su puedo 'demostrarme' que se llama, a cada cuadro, dicha rutina lo cual garantizaría que se pueda emitir sonido cada vez que haga falta
Si detecto algo 'raro' o imprevisto os lo contaré
saludos
pere
- pser1
- Mensajes: 4094
- Registrado: 08 Dic 2012 18:34
- Agradecido : 1352 veces
- Agradecimiento recibido: 1118 veces
Re: Consultas técnicas ensamblador Z80 (para AGD)
Buenos dias a todos,
ayer probé a debugar el FOGGY utilizando el SpecEmu v2.8 como hice en tantas ocasiones con The Hobbit
Pero el tiempo ha pasado y he olvidado algunos puntos importantes sobre como utilizar el SpecEmu
Lo arranco y a continuación cargo el fichero FOGGY.TAP usando opción File/OpenFile. Adjunto .tap por si alguien lo quiere probar.
El program aarranca y se para en la pantalla de menú donde el usuario debe seleccionar teclado o tipo de Joystick
En este punto abro el Debugge pulsando tecla Escape y me aparecen las ventanas del debugger tal como las había configurado
cuando convertí el Hobbit. Veo la ventana de código, registros, area de memoria y breakpoints.
A´ñado un breakpoint en #7F5E que es la parte de código que empieza a tratar de sonido y quiero debugarlo paso a paso
o bien saltarlo y esperar a la próxima vez que sea llamado ... y ésto es lo que NO soy capaz de hacer
Puedo seguir el programa paso a paso (Step / Next), pero Leave no devuelve control al programa para seleccionar 1 (teclado)
Y lo peor es que NO puedo cerrar el debugger ni el SpecEmu
Si alguien puede refrescarme la memoria o tiene un manual del mismo se lo agradeceré muchísmimo
En el zip adjunto he incluido el listado de la compilación que permite ver la posición en memoria del programa
saludos
pere
ayer probé a debugar el FOGGY utilizando el SpecEmu v2.8 como hice en tantas ocasiones con The Hobbit
Pero el tiempo ha pasado y he olvidado algunos puntos importantes sobre como utilizar el SpecEmu
Lo arranco y a continuación cargo el fichero FOGGY.TAP usando opción File/OpenFile. Adjunto .tap por si alguien lo quiere probar.
El program aarranca y se para en la pantalla de menú donde el usuario debe seleccionar teclado o tipo de Joystick
En este punto abro el Debugge pulsando tecla Escape y me aparecen las ventanas del debugger tal como las había configurado
cuando convertí el Hobbit. Veo la ventana de código, registros, area de memoria y breakpoints.
A´ñado un breakpoint en #7F5E que es la parte de código que empieza a tratar de sonido y quiero debugarlo paso a paso
o bien saltarlo y esperar a la próxima vez que sea llamado ... y ésto es lo que NO soy capaz de hacer
Puedo seguir el programa paso a paso (Step / Next), pero Leave no devuelve control al programa para seleccionar 1 (teclado)
Y lo peor es que NO puedo cerrar el debugger ni el SpecEmu
Si alguien puede refrescarme la memoria o tiene un manual del mismo se lo agradeceré muchísmimo
En el zip adjunto he incluido el listado de la compilación que permite ver la posición en memoria del programa
saludos
pere
-
- Mensajes: 1669
- Registrado: 03 Ago 2011 23:07
- Ubicación: Aluche, Madrid
- Agradecido : 29 veces
- Agradecimiento recibido: 523 veces
Re: Consultas técnicas ensamblador Z80 (para AGD)
Hola pser1,
Ayer solo aporté con prisas un pequeño comentario, porque tenía que irme. Acabo de venir de rehabilitación y ya tengo más o menos todo el día libre. He intentado echar un vistazo al código en TrazadoManualSonidoZX.zip, pero en su estado actual con todos los comentarios que has puesto a la izquierda, es bastante ilegible (por eso la gente pone los comentarios a la derecha tras los puntos y coma, hehehe) porque cada instrucción tiene una tabulación diferente y no me consigo aclarar. ¿Podrías pegarlo en su estado original, por favor?
De todas formas, creo que lo primero es necesario que sepas cómo funciona el puerto 254 en el Spectrum en modo salida, ya que solo 1 bit genera sonido, mientras que otros 3 cambian el color del borde, que tiene que mantenerse mientras se genera el sonido. Tienes una referencia en https://www.worldofspectrum.org/faq/reference/48kreference.htm#PortFE
Edito: Ya lo he recuperado yo en un editor de texto:
Una de las cosas que quizás tendrías que saber, es que en la posición 23672 ($5C78), el BASIC del Spectrum guarda un contador de 24 bits como variable del sistema FRAMES, que se incrementa una vez cada 1/50 segundos en la rutina de interrupción llamando a una rutina de la ROM situada en la posición 56 ($0038). Ese es el valor que creo que se compara con el contador "clock" definido en el programa. Ignoro si el AGD tiene las interrupciones del sistema habilitadas o tiene una rutina de interrupción propia, pero sea lo que sea, parece que el contador FRAMES se incrementa.
En la posición 23624 ($5C48) el Spectrum guarda otra variable del sistema BORDCR, que almacena en los bits 5/4/3 el color del borde, por eso tiene que rotarlos con RRA 3 veces hasta que queden en los bits 2/1/0, que son los esperados en el comando OUT para el puerto 254. El bit del sonido va a estar en el bit 4 de ese puerto, como ves el DAC solo tiene 1 bit de resolución, por eso tantísimo jaleo.
Otra característica del Spectrum que quizás no estés al tanto, es que la interrupción se ejecuta cada VBLANK (Vertical Blank), no pudiéndose lanzar en otra posición del barrido de pantalla como en Amstrad o Commodore 64. Por eso siempre va a haber una única interrupción cada cincuentavo de segundo (1/60 en los Spectrum americanos) si éstas están habilitadas.
Otra cosita: supongo que lo sabías, pero por tus comentarios del texto, me preguntaba si estás al tanto que la orden DJNZ lo que hace es decrementar el registro B y saltar si no ha llegado a cero.
Ayer solo aporté con prisas un pequeño comentario, porque tenía que irme. Acabo de venir de rehabilitación y ya tengo más o menos todo el día libre. He intentado echar un vistazo al código en TrazadoManualSonidoZX.zip, pero en su estado actual con todos los comentarios que has puesto a la izquierda, es bastante ilegible (por eso la gente pone los comentarios a la derecha tras los puntos y coma, hehehe) porque cada instrucción tiene una tabulación diferente y no me consigo aclarar. ¿Podrías pegarlo en su estado original, por favor?
De todas formas, creo que lo primero es necesario que sepas cómo funciona el puerto 254 en el Spectrum en modo salida, ya que solo 1 bit genera sonido, mientras que otros 3 cambian el color del borde, que tiene que mantenerse mientras se genera el sonido. Tienes una referencia en https://www.worldofspectrum.org/faq/reference/48kreference.htm#PortFE
Edito: Ya lo he recuperado yo en un editor de texto:
Código: Seleccionar todo
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
vsync ld a,(sndtyp) ; sound to play
and a ; any sound?
jp z,vsync1 ; no, Skip sound section
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ld b,a ; save A into B
ld a,(23624) ; get border colour (*8+attr lower half screen)
rra ; divide
rra ; by 8 to
rra ; put border bits into b0-1-2
ld c,a ; save first value to send to speaker (border colour)
ld a,b ; restore received value
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
and a ; test it
jp m,vsync6 ; if negative, go play white noise
vsync2 ld a,c ; get value to send to speaker
out (254),a ; write to speaker
xor 248 ; toggle all except the border bits (b0-1-2)
ld c,a ; store value for next time
ld d,b ; store loop counter (received in A) into D
vsync3 ld hl,clock ; get previous clock setting address
ld a,(23672) ; current clock setting (frame counter, incremented every 20 mseg)
cp (hl) ; subtract last reading
jp nz,vsync4 ; if not equal skip next (exit loop)
djnz vsync3 ; loopback
ld b,d ; restore loop counter
djnz vsync2 ; continue noise
vsync4 ld a,d ; get loop counter
vsynca ld (sndtyp),a ; save for next time
; synchronize to clock
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
vsync1 ld a,(23672) ; get clock low byte
rra ; rotate bit0 into carry
call c,vsync5 ; if carry set,time to do shrapnel/ticker stuff
ld hl,clock ; get last clock reading address
vsync0 ld a,(23672) ; get current clock reading
cp (hl) ; are they the same?
jr z,vsync0 ; yes, wait until clock changes (20 mseg)
ld (hl),a ; set new clock reading into variable clock
ret ; return
vsync5 call plsnd ; play sound
vsync5 jp proshr ; shrapnel and stuff
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Play white noise. A and B arrive both Negative with same value
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
vsync6 ld a,b ; 128 - 255
sub 127 ; 001 - 128
ld b,a ; pass value to B
ld hl,clock ; get previous clock setting address
vsync7 ld a,r ; get random value
and 248 ; retain only the speaker/earphone bits (b3-7)
or c ; merge with border colour
out (254),a ; write to speaker
ld a,(23672) ; current clock setting
cp (hl) ; subtract last reading
jp nz,vsync8 ; different, no more processing please
ld a,b ; restore received value
and 127 ; reset bit7 (-> positive)
inc a ; to test
vsync9 dec a ; for zero
jr nz,vsync9 ; loopback if not zero
djnz vsync7 ; continue noise
vsync8 xor a ; A = zero
jr vsynca ; back to vsynca (no sound)
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; sndtyp defb 0 ; maybe frequency? - can have these values:
; ; 20,35,40,45,50,60,70,80 (maybe others)
; clock defb 0 ; last clock reading.
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Una de las cosas que quizás tendrías que saber, es que en la posición 23672 ($5C78), el BASIC del Spectrum guarda un contador de 24 bits como variable del sistema FRAMES, que se incrementa una vez cada 1/50 segundos en la rutina de interrupción llamando a una rutina de la ROM situada en la posición 56 ($0038). Ese es el valor que creo que se compara con el contador "clock" definido en el programa. Ignoro si el AGD tiene las interrupciones del sistema habilitadas o tiene una rutina de interrupción propia, pero sea lo que sea, parece que el contador FRAMES se incrementa.
En la posición 23624 ($5C48) el Spectrum guarda otra variable del sistema BORDCR, que almacena en los bits 5/4/3 el color del borde, por eso tiene que rotarlos con RRA 3 veces hasta que queden en los bits 2/1/0, que son los esperados en el comando OUT para el puerto 254. El bit del sonido va a estar en el bit 4 de ese puerto, como ves el DAC solo tiene 1 bit de resolución, por eso tantísimo jaleo.
Otra característica del Spectrum que quizás no estés al tanto, es que la interrupción se ejecuta cada VBLANK (Vertical Blank), no pudiéndose lanzar en otra posición del barrido de pantalla como en Amstrad o Commodore 64. Por eso siempre va a haber una única interrupción cada cincuentavo de segundo (1/60 en los Spectrum americanos) si éstas están habilitadas.
Otra cosita: supongo que lo sabías, pero por tus comentarios del texto, me preguntaba si estás al tanto que la orden DJNZ lo que hace es decrementar el registro B y saltar si no ha llegado a cero.
- pser1
- Mensajes: 4094
- Registrado: 08 Dic 2012 18:34
- Agradecido : 1352 veces
- Agradecimiento recibido: 1118 veces
Re: Consultas técnicas ensamblador Z80 (para AGD)
BlackHole escribió:Hola pser1,
Ayer solo aporté con prisas un pequeño comentario, porque tenía que irme. Acabo de venir de rehabilitación y ya tengo más o menos todo el día libre. He intentado echar un vistazo al código en TrazadoManualSonidoZX.zip, pero en su estado actual con todos los comentarios que has puesto a la izquierda, es bastante ilegible (por eso la gente pone los comentarios a la derecha tras los puntos y coma, hehehe) porque cada instrucción tiene una tabulación diferente y no me consigo aclarar. ¿Podrías pegarlo en su estado original, por favor?
Bueno, los comentarios están *realmente* a la derecha del código.
Lo que ves a la izquierda es un trazado sobre papel linea a linea. Si te molesta para leer el código, no tienes mas que eliminarlo
con un editor de texto. Yo uso TextPad y marcando 'bloque' puedes eliminarlo fácilmente. NOTA: Veo que ya lo hiciste, perfecto!
De todas formas, creo que lo primero es necesario que sepas cómo funciona el puerto 254 en el Spectrum en modo salida, ya que solo 1 bit genera sonido, mientras que otros 3 cambian el color del borde, que tiene que mantenerse mientras se genera el sonido. Tienes una referencia en https://www.worldofspectrum.org/faq/reference/48kreference.htm#PortFE
Mas o menos lo entiendo, en el fondo lo que hace el generador de sonido es enviar un valor y luego aplicar un xor a los bits que no son del color del borde, por lo que va invirtiendo el nivel de salida, produciendo la forma de onda que indiqué en mi post. Gracias por el enlace!
Una de las cosas que quizás tendrías que saber, es que en la posición 23672 ($5C78), el BASIC del Spectrum guarda un contador de 24 bits como variable del sistema FRAMES, que se incrementa una vez cada 1/50 segundos en la rutina de interrupción llamando a una rutina de la ROM situada en la posición 56 ($0038). Ese es el valor que creo que se compara con el contador "clock" definido en el programa. Ignoro si el AGD tiene las interrupciones del sistema habilitadas o tiene una rutina de interrupción propia, pero sea lo que sea, parece que el contador FRAMES se incrementa.
Me pareció que se limita a comparar el contenido de la variable clock con el byte bajo del contador de frames.
Y al finalizar el sonido actualiza dicha variable
Creo que esto lo indiqué por un lado en los comentarios y además en el mensaje en el que pinté la forma de onda. Hasta aquí me parece claro.
Otra característica del Spectrum que quizás no estés al tanto, es que la interrupción se ejecuta cada VBLANK (Vertical Blank), no pudiéndose lanzar en otra posición del barrido de pantalla como en Amstrad o Commodore 64. Por eso siempre va a haber una única interrupción cada cincuentavo de segundo (1/60 en los Spectrum americanos) si éstas están habilitadas.
Exactamente igual que en Dragón donde podemos configurar si queremos la interrupción al inicio del frame o justo al final cuando empieza
el borrado vertical con lo que se trabaja 'fuera' de pantalla. Entiendo que en Spectrum es justo el segundo, o sea el borrado vertical.
De todas formas no he visto código relacionado con interrupciones o no he sabido verlo en FOGGY.
Por si acaso adjunté el fuente completo por si alguien puede o quiere echarle una ojeada mas a fondo ...
Muchas gracias por todo
pere
-
- Mensajes: 5619
- Registrado: 20 Sep 2011 13:59
- Ubicación: Madrid
- Agradecido : 990 veces
- Agradecimiento recibido: 2040 veces
- Contactar:
Re: Consultas técnicas ensamblador Z80 (para AGD)
Por defecto y si no me equivoco el ZX opera en IM1; así que si nadie redefine una interrupción IM2, así debe funcionar el juego.
- pser1
- Mensajes: 4094
- Registrado: 08 Dic 2012 18:34
- Agradecido : 1352 veces
- Agradecimiento recibido: 1118 veces
Re: Consultas técnicas ensamblador Z80 (para AGD)
jltursan escribió:Por defecto y si no me equivoco el ZX opera en IM1; así que si nadie redefine una interrupción IM2, así debe funcionar el juego.
O sea asumo que por defecto las interrupciones leen teclado, actualizan el contador de frames y algunas variables del sistema en IM1
Se parece al sistema por defecto en Dragón aunque no hace las mismas cosas (actualiza la variable TIMER)
muchas gracias
pere
- pser1
- Mensajes: 4094
- Registrado: 08 Dic 2012 18:34
- Agradecido : 1352 veces
- Agradecimiento recibido: 1118 veces
Re: Consultas técnicas ensamblador Z80 (para AGD)
NUEVO TEMA:
¿Podría alguien decirme que hacen exactamente estas líneas de código Z80 en el Spectrum 48k?
ld a,71
and 7
No he encontrado información sobre un posible puerto 71 ($47) así que no tengo la mas remota idea
de que información recupera y que significan los tres bits mas bajos ...
Muchas gracias de antemano
pere
¿Podría alguien decirme que hacen exactamente estas líneas de código Z80 en el Spectrum 48k?
ld a,71
and 7
No he encontrado información sobre un posible puerto 71 ($47) así que no tengo la mas remota idea
de que información recupera y que significan los tres bits mas bajos ...
Muchas gracias de antemano
pere
- pser1
- Mensajes: 4094
- Registrado: 08 Dic 2012 18:34
- Agradecido : 1352 veces
- Agradecimiento recibido: 1118 veces
Re: Consultas técnicas ensamblador Z80 (para AGD)
entiendo que simplemente le mete el valor decimal 71, pero para hacerle un AND luego
se habrían haber ahorrado un byte y hacer directamente
ld a,7
Si es otra cosa agradeceré me lo digáis
Muchas gracias
pere
se habrían haber ahorrado un byte y hacer directamente
ld a,7
Si es otra cosa agradeceré me lo digáis
Muchas gracias
pere
- explorer
- Mensajes: 695
- Registrado: 10 Ene 2016 18:43
- Ubicación: Valladolid, España
- Agradecido : 24 veces
- Agradecimiento recibido: 680 veces
- Contactar:
Re: Consultas técnicas ensamblador Z80 (para AGD)
En efecto, primero mete el valor 71 (0b01000111) en el acumulador y luego le hace un and con el valor 7 (0b00000111). El resultado es, desde luego, 7, pero... ¿por qué no lo hace en un solo paso?
Pues... no lo hace porque podría estar usando código automodificable.
Quiero decir que el valor 71 sigue al opcode de ld a,N. Si el código está en RAM, otra parte del código podría referirse a la dirección de memoria de ese valor 71, y cambiarlo. Entonces, cuando la CPU vuelva a ejecutar esa parte del código, el resultado del and será distinto.
Este tipo de trucos se usaba mucho en la época, para ahorrar memoria. En este caso, te ahorras tener un byte reservado aparte para almacenar una variable global. Usas el propio código del programa para guardar el valor.
Pues... no lo hace porque podría estar usando código automodificable.
Quiero decir que el valor 71 sigue al opcode de ld a,N. Si el código está en RAM, otra parte del código podría referirse a la dirección de memoria de ese valor 71, y cambiarlo. Entonces, cuando la CPU vuelva a ejecutar esa parte del código, el resultado del and será distinto.
Este tipo de trucos se usaba mucho en la época, para ahorrar memoria. En este caso, te ahorras tener un byte reservado aparte para almacenar una variable global. Usas el propio código del programa para guardar el valor.
JF^D - Calendario de Retroinformática - Telegram Retro Spain - RetroDev ES
- pser1
- Mensajes: 4094
- Registrado: 08 Dic 2012 18:34
- Agradecido : 1352 veces
- Agradecimiento recibido: 1118 veces
Re: Consultas técnicas ensamblador Z80 (para AGD)
explorer escribió:En efecto, primero mete el valor 71 (0b01000111) en el acumulador y luego le hace un and con el valor 7 (0b00000111). El resultado es, desde luego, 7, pero... ¿por qué no lo hace en un solo paso?
Pues... no lo hace porque podría estar usando código automodificable.
Quiero decir que el valor 71 sigue al opcode de ld a,N. Si el código está en RAM, otra parte del código podría referirse a la dirección de memoria de ese valor 71, y cambiarlo. Entonces, cuando la CPU vuelva a ejecutar esa parte del código, el resultado del and será distinto.
Este tipo de trucos se usaba mucho en la época, para ahorrar memoria. En este caso, te ahorras tener un byte reservado aparte para almacenar una variable global. Usas el propio código del programa para guardar el valor.
Muchísimas gracias,
me ha quedado clarísimo.
He revisado el código por si se utilizaba la etiqueta que precede al ld a,71 en alguna otra parte
y parece que no, así que voy a imaginar que al ser código creado automáticamente por el generador AGD
simplemente no es tan eficiente como sería deseable.
saludos
pere
- explorer
- Mensajes: 695
- Registrado: 10 Ene 2016 18:43
- Ubicación: Valladolid, España
- Agradecido : 24 veces
- Agradecimiento recibido: 680 veces
- Contactar:
Re: Consultas técnicas ensamblador Z80 (para AGD)
La dirección del 71 debería ser "etiqueta+1", cuidado. Pero si es código generado... es muy probable que sea un fallo de optimización.
JF^D - Calendario de Retroinformática - Telegram Retro Spain - RetroDev ES
- pser1
- Mensajes: 4094
- Registrado: 08 Dic 2012 18:34
- Agradecido : 1352 veces
- Agradecimiento recibido: 1118 veces
Re: Consultas técnicas ensamblador Z80 (para AGD)
explorer escribió:La dirección del 71 debería ser "etiqueta+1", cuidado. Pero si es código generado... es muy probable que sea un fallo de optimización.
Tampoco existe ninguna referencia a etiqueta+1
Digamos que simplemente *no* se ha optimizado la salida del generador de código Z-80
Esta combinación de ld a,NN seguida de and 7 la he encontrado en bastantes partes del código
Y muchas veces *no* tiene ninguna etiqueta por las cercanías ...
Resulta ser el paso previo a llamar a la rutina que colorea los sprites.
El código que le pasan va en el registro A y solo admite 8 valores, de ahí el AND ...
Como en el 6809 no tendremos 'cambios' de colores en los sprites, de entrada, me he limitado a no
convertir el código de estas partes.
Muchas gracias
saludos
pere
¿Quién está conectado?
Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 3 invitados