Puedes descargar la Fe de erratas en formato PDF para imprimirlas y adjuntarlas al libro.
Actualizado el libro en Amazon a la segunda edición, con las erratas corregidas.
Ensamblador ZX Spectrum, fe de erratas
Donde dice
Debe decir
Página
Página
25
25
Es el microprocesador del que dispone el ZX Spectrum en sus todos sus modelos.
Es el microprocesador del que dispone el ZX Spectrum en todos sus modelos.
Donde dice
Debe decir
Página
Página
26
26
Otra característica del Z80, que en ocasiones no nos gustará, es que no es un ortogonal…
Otra característica del Z80, que en ocasiones no nos gustará, es que no es ortogonal…
Donde dice
Debe decir
Página
Página
35
35
– JR NZ, n: salta a la dirección de memoria que está a n bytes si el flag Z está a cero; el resultado de la última operación no es cero. – JP Z, n: salta a la dirección de memoria que está a n bytes si el flag Z está a uno; el resultado de la última operación es cero.
– JR NZ, n: salta a la dirección de memoria que está a n bytes si el flag Z está a cero; el resultado de la última operación no es cero. – JR Z, n: salta a la dirección de memoria que está a n bytes si el flag Z está a uno; el resultado de la última operación es cero.
Donde dice
Debe decir
Página
Página
36
36
Lo valores siempre son registros de 16 bits.
Los valores siempre son registros de 16 bits.
Donde dice
Debe decir
Página
Página
37
37
Editamos a holamundo.asm y llamamos con CALL a rutinas de la ROM; …
Editamos holamundo.asm y llamamos con CALL a rutinas de la ROM; …
Donde dice
Debe decir
Página
Página
39
39
Ya hemos desarrollado nuestro primer programa en ensamblador para ZX Spectrum; comenzamos el desarrollo ZX-Pong.
Ya hemos desarrollado nuestro primer programa en ensamblador para ZX Spectrum; comenzamos el desarrollo de ZX-Pong.
Donde dice
Debe decir
Página
Página
49
49
Vamos a desarrollar una rutina para comprobar si se ha pulsado alguna de las teclas de control, …
Vamos a desarrollar en Controls.asm una rutina para comprobar si se ha pulsado alguna de las teclas de control, …
Donde dice
Debe decir
Página
Página
55
55
Cargamos el valor del color rojo en A, LD A, $02 y escribimos este valor en el puerto $FE (256), OUT ($FE), A.
Cargamos el valor del color rojo en A, LD A, $02 y escribimos este valor en el puerto $FE (254), OUT ($FE), A.
Donde dice
Debe decir
Página
Página
57
57
Una vez realizado esto, incrementa HL y DE. Repite en bucle hasta que BC llegue a cero.
Una vez realizado esto, incrementa HL y DE y decrementa BC. Repite en bucle hasta que BC llegue a cero.
Donde dice
Debe decir
Página
Página
57
57
Como se puede aprecia en la imagen, ya no sale la línea Bytes: PoromPong; …
Como se puede apreciar en la imagen, ya no sale la línea Bytes: PoromPong; …
Donde dice
Debe decir
Página
Página
68
68
Por último, tras de pintar las palas vamos a sustituir RET por JR loop, para quedarnos en un bucle infinito.
Por último, tras pintar las palas vamos a sustituir RET por JR loop, para quedarnos en un bucle infinito.
Donde dice
Debe decir
Página
Página
113
113
getPointSprite_loop: dec a ; Decrementa A ret z ; A = 0, fin de rutina add hl, bc ; Suma 4 a dirección sprite jr getPointSprite_loop ; Bucle hasta que A = 0 ret
getPointSprite_loop: dec a ; Decrementa A ret z ; A = 0, fin de rutina add hl, bc ; Suma 4 a dirección sprite jr getPointSprite_loop ; Bucle hasta que A = 0
Donde dice
Debe decir
Página
Página
114
114
Cargamos los puntos del jugador uno en A, LD A, (points), …
Cargamos los puntos del jugador uno en A, LD A, (p1points), …
Donde dice
Debe decir
Página
Página
118
118
call reprintPoint_print ; Pinta 1er dígito marcador jugador 1
pop hl ; Recupera valor de HL ; 2º dígito del jugador 1 inc hl inc hl ; HL = parte baja dirección 2º dígito ld e, (hl) ; E = (HL) inc hl ; HL = parte alta dirección 2º dígito ld d, (hl) ; D = (HL) ld hl, POINTS_P1 ; HL = dirección memoria donde pintar ; puntos jugador 1 inc l ; HL = dirección donde pintar 2º dígito call reprintPoint_print ; Pinta 2º dígito marcador jugador 1
ld a, (p2points) ; A = puntos jugador 2 call GetPointSprite ; Obtiene sprite a pintar en marcador push hl ; Preserva valor de HL ; 1er dígito del jugador 2 ld e, (hl) ; HL = parte baja dirección 1er dígito ; E = (HL) inc hl ; HL = parte alta dirección 1er dígito ld d, (hl) ; D = (HL) ld hl, POINTS_P2 ; HL = dirección memoria donde pintar ; puntos jugador 2 call reprintPoint_print ; Pinta 1er dígito marcador jugador 2
call reprintPoint_print ; Pinta 1er dígito marcador jugador 1
pop hl ; Recupera valor de HL ; 2º dígito del jugador 1 inc hl inc hl ; HL = parte baja dirección 2º dígito ld e, (hl) ; E = (HL) inc hl ; HL = parte alta dirección 2º dígito ld d, (hl) ; D = (HL) ld hl, POINTS_P1 ; HL = dirección memoria donde pintar ; puntos jugador 1 inc l ; HL = dirección donde pintar 2º dígito call reprintPoint_print ; Pinta 2º dígito marcador jugador 1
ld a, (p2points) ; A = puntos jugador 2 call GetPointSprite ; Obtiene sprite a pintar en marcador push hl ; Preserva valor de HL ; 1er dígito del jugador 2 ld e, (hl) ; HL = parte baja dirección 1er dígito ; E = (HL) inc hl ; HL = parte alta dirección 1er dígito ld d, (hl) ; D = (HL) ld hl, POINTS_P2 ; HL = dirección memoria donde pintar ; puntos jugador 2 call reprintPoint_print ; Pinta 1er dígito marcador jugador 2
Donde dice
Debe decir
Página
Página
127
127
SetBallRight: ld hl, $4d7f ld (ballPos), hl ld a, $ff ld (ballRotation), a ld a, (ballSetting) or $40
SetBallRight: ld hl, $4d7f ld (ballPos), hl ld a, $ff ld (ballRotation), a ld a, (ballSetting) or $40
Donde dice
Debe decir
Página
Página
130
130
La pala que se pinta con el sprite que hemos definido.
La pala no se pinta con el sprite que hemos definido.
Donde dice
Debe decir
Página
Página
131
131
En concreto, tenemos al final del archivo Main.asm, dos JR Main y un JR Loop.
En concreto, tenemos al final del archivo Main.asm, dos JR Z, Main y un JR Loop.
Donde dice
Debe decir
Página
Página
135
135
; Dependiendo del lugar de colisión, inclinación y velocidad ld a, c ; A = penúltimo scanline de pala sub $15 ; A = primero scanline ld c, a ; C = A
; Dependiendo del lugar de colisión, inclinación y velocidad ld a, c ; A = penúltimo scanline de pala sub $15 ; A = primer scanline ld c, a ; C = A
Donde dice
Debe decir
Página
Página
147
147
Y ahora hay cuatro rutinas que tenemos que cambiar en G:
Y ahora hay cuatro rutinas que tenemos que cambiar:
Donde dice
Debe decir
Página
Página
148
148
De la rutina MoveBallY, y modificamos la segunda línea:
Localizamos la rutina MoveBallY, y modificamos la segunda línea:
Donde dice
Debe decir
Página
Página
153
153
Según vemos en la definición de los sprites, cada uno está a 4 bytes del otro, por eso hacemos es un bucle …
Según vemos en la definición de los sprites, cada uno está a 4 bytes del otro, por eso hacemos un bucle …
Donde dice
Debe decir
Página
Página
158
158
Localizamos la etiqueta CheckCrossY en el archivo Video.asm, dieciséis líneas más abajo nos encontramos con esto.
Localizamos la etiqueta CheckCrossY en el archivo Game.asm, dieciséis líneas más abajo nos encontramos con esto.
Donde dice
Debe decir
Página
Página
158
158
Si el resultado en mayor que cero, salimos con el flag Z desactivado (no hay colisión).
Si el resultado es mayor que cero, salimos con el flag Z desactivado (no hay colisión).
Donde dice
Debe decir
Página
Página
169
169
Para lograrlo vamos a aplicar el mismo método que aplicamos en paso 10 siguiendo los comentarios de Spirax; el camino que marcó.
Para lograrlo vamos a aplicar el mismo método que aplicamos en el paso 10 siguiendo los comentarios de Spirax; el camino que marcó.
Donde dice
Debe decir
Página
Página
171
171
printPoint_2_print: … ld hl, POINTS_P2 ; HL = dirección donde dígito call PrintPoint ; Pinta 1er dígito pop hl ; Recupera HL
printPoint_2_print: … ld hl, POINTS_P2 ; HL = dirección donde pintar dígito call PrintPoint ; Pinta 1er dígito pop hl ; Recupera HL
Donde dice
Debe decir
Página
Página
173
173
https://tinyurl.com/2hl6j3uz
https://tinyurl.com/26dfekly
Donde dice
Debe decir
Página
Página
174
174
… el resto de bloques que se van a cargar, y que de esta forma que no borren parte de la pantalla de carga.
… el resto de bloques que se van a cargar, y que de esta forma no borren parte de la pantalla de carga.
Donde dice
Debe decir
Página
Página
191
191
Una vez hecho, al pintar con RST $10 cualquier carácter comprendido entre $90 y $A4, se pintaran los gráficos que hemos definido.
Una vez hecho, al pintar con RST $10 cualquier carácter comprendido entre $90 y $A4, se pintarán los gráficos que hemos definido.
Donde dice
Debe decir
Página
Página
191
191
Lo primero es indicar la dirección en la que se vamos a cargar el programa, ORG $5DAD.
Lo primero es indicar la dirección en la que vamos a cargar el programa, ORG $5DAD.
Donde dice
Debe decir
Página
Página
193
193
En el archivo Var.asm, encima de udgsEnemiesLeve1,vamos a añadir las siguientes líneas:
En el archivo Var.asm, encima de udgsEnemiesLevel1,vamos a añadir las siguientes líneas:
Donde dice
Debe decir
Página
Página
194
194
Cargamos la dirección de la extensión DE, LD DE, udgsExtension, …
Cargamos la dirección de la extensión en DE, LD DE, udgsExtension, …
Donde dice
Debe decir
Página
Página
209
209
Ahora ya tenemos nuestra área de juego.
Ahora ya tenemos nuestro área de juego.
Donde dice
Debe decir
Página
Página
213
213
… siendo más rápido y ocupando menos que si usamos usado la pila.
… siendo más rápido y ocupando menos que usando la pila.
Donde dice
Debe decir
Página
Página
214
214
printFrame_loop: ... inc b ; B = línea siguiente ld a, b ; A = B cp $14 ; ¿A = 21? jr nz, printFrame_loop ; A != 21, sigue con el bucle
printFrame_loop: ... inc b ; B = línea siguiente ld a, b ; A = B cp $14 ; ¿A = 20? jr nz, printFrame_loop ; A != 20, sigue con el bucle
Donde dice
Debe decir
Página
Página
219
219
… (antes de nada añadimos include de Game.asm en Main.asm).
… (antes de nada añadimos el include de Game.asm en Main.asm).
Donde dice
Debe decir
Página
Página
220
220
moveShip_right: ... ld (shipPos), bc
ret
moveShip_right: ... ld (shipPos), bc
moveShip_print: call PrintShip
ret
Donde dice
Debe decir
Página
Página
224
224
Deshabilitamos las interrupciones, DI, cargamos $28 (40) en el registro A, LD A, $28, y lo cargamos I, LD I, A.
Deshabilitamos las interrupciones, DI, cargamos $28 (40) en el registro A, LD A, $28, y lo cargamos en I, LD I, A.
Donde dice
Debe decir
Página
Página
229
229
MoveFire: … ld bc, (shipPos) inc h jr moveFire_print
MoveFire: … ld bc, (shipPos) inc b jr moveFire_print
Donde dice
Debe decir
Página
Página
245
245
ld a, (countEnemy) inc a ld (countEnemy), a sub $02 jr nz, Isr_end ld (countEnemy), a
ld a, (countEnemy) inc a ld (countEnemy), a sub $03 jr nz, Isr_end ld (countEnemy), a set $02, (hl)
Donde dice
Debe decir
Página
Página
252
252
Cargamos en A el número de enemigos que siguen activos, LD A, (enemiesCounter), comprobamos si hemos llegado a cero, CP $00, y saltamos si es así, JR Z, Main_restart.
Cargamos en A el número de enemigos que siguen activos, LD A, (enemiesCounter), comprobamos si hemos llegado a cero, OR A, y saltamos si es así, JR Z, Main_restart.
Donde dice
Debe decir
Página
Página
263
263
Para probar lo implementado abrimos Main.asm, localizamos la rutina Main_restart, y debajo, antes de CALL ChangeLevel, añadimos las siguientes líneas: call FadeScreen call PrintFrame call PrintInfoGame call PrintShip
Para probar lo implementado abrimos Main.asm, localizamos la rutina Main_restart, y sustituimos la línea CALL ChangeLevel por estas:
Seguimos en Print.asm, localizamos la etiqueta PrintFrame y borramos la segunda y añadimos dos después de CALL PrintString.
Seguimos en Print.asm, localizamos la etiqueta PrintFrame y borramos la segunda línea y añadimos dos después de CALL PrintString.
Donde dice
Debe decir
Página
Página
288
288
Buscamos las líneas de carga del vector de interrupciones, desde DI hasta EI, las cortamos y las pegamos encima de MainStart.
Buscamos las líneas de carga del vector de interrupciones, desde DI hasta EI, las cortamos y las pegamos encima de Main_start.
Donde dice
Debe decir
Página
Página
288
288
Cargamos en A en las vidas, LD A, (livesCounter), evaluamos si son cero, OR A, y saltamos de ser así, JR Z, GameOver.
Cargamos en A las vidas, LD A, (livesCounter), evaluamos si son cero, OR A, y saltamos de ser así, JR Z, GameOver.
Donde dice
Debe decir
Página
Página
303
303
... ld a, (pointsCounter + 1) ; A centenas y ud millar adc a, $00 ; A = A+1 con acarreo daa ; Ajuste decimal ld (pointsCounter + 1), a ; Actualiza memoria ld hl, (extraCounter) ; HL = contador vida extra ld bc, $0005 ; BC = 5 add hl, bc ; HL = HL+BC ld (extraCounter), hl ; Actualiza memoria ld bc, $01f4 ; BC = 500 sbc hl, bc ; HL = HL-BC jr nz, checkCrashFire_cont ; 0, salta ld (extraCounter), hl ; No 0, contador vida extra = 0
... ld a, (pointsCounter + 1) ; A = centenas y ud millar adc a, $00 ; A = A+1 con acarreo daa ; Ajuste decimal ld (pointsCounter + 1), a ; Actualiza memoria ld hl, (extraCounter) ; HL = contador vida extra ld bc, $0005 ; BC = 5 add hl, bc ; HL = HL+BC ld (extraCounter), hl ; Actualiza memoria ld bc, $01f4 ; BC = 500 sbc hl, bc ; HL = HL-BC jr nz, checkCrashFire_cont ; No 0, salta ld (extraCounter), hl ; 0, contador vida extra = 0
Donde dice
Debe decir
Página
Página
309
309
Seguimos Game.asm y localizamos la etiqueta MoveEnemies; su aspecto inicial es el siguiente:
Seguimos en Game.asm y localizamos la etiqueta MoveEnemies; su aspecto inicial es el siguiente:
Donde dice
Debe decir
Página
Página
312
312
… limpiamos el primero, LD (HL), $02, limpiamos el resto, LDIR, y salimos, RET.
… limpiamos el primero, LD (HL), $00, limpiamos el resto, LDIR, y salimos, RET.
Donde dice
Debe decir
Página
Página
314
314
; --------------------------------------------------- ; Actualiza la configuración de los disparos enemigos ; ; Altera el valor de los registros AD, BC, HL e IX. ; ---------------------------------------------------
; --------------------------------------------------- ; Actualiza la configuración de los disparos enemigos ; ; Altera el valor de los registros AF, BC, HL e IX. ; ---------------------------------------------------
Donde dice
Debe decir
Página
Página
315
315
Si el enemigo está activo, el segundo byte de la configuración lo cargamos en A, LD A, (HL), nos quedamos con la coordenada X, AND $1F, comparamos con la coordenada X de la nave, CP E, y saltamos si no son la misa, JR NZ, enableEnemiesFire_loopCont.
Si el enemigo está activo, el segundo byte de la configuración lo cargamos en A, LD A, (HL), nos quedamos con la coordenada X, AND $1F, comparamos con la coordenada X de la nave, CP E, y saltamos si no son la misma, JR NZ, enableEnemiesFire_loopCont.
Donde dice
Debe decir
Página
Página
319
319
Si está inactivo se podría salir de la rutina, …
Si no está inactivo se podría salir de la rutina, …
Donde dice
Debe decir
Página
Página
323
323
Si las coordenadas son iguales, cargamos en A la coordenada X del disparo, LD A, (HL), la comparamos la de la nave, CP E, …
Si las coordenadas son iguales, cargamos en A la coordenada X del disparo, LD A, (HL), la comparamos con la de la nave, CP E, …
Donde dice
Debe decir
Página
Página
335
335
… y una contador del número de interrupciones …
… y un contador del número de interrupciones …
Donde dice
Debe decir
Página
Página
336
336
Esta es la forma de onda que podemos ver en el emulador.
Esta es la forma de onda que podemos ver en el emulador (Menu \ Audio \ Waveform).
Donde dice
Debe decir
Página
Página
338
338
Creamos Int3.asm y copiamos dentro todo el código del archivo Int.asm. … En los include sustituimos Var.asm e Int.asm por Var3.asm e Int3.asm, y añadimos una línea de comentario a la etiqueta music.
Creamos Int3.asm y copiamos dentro todo el código del archivo Int2.asm. … En los include sustituimos Var.asm e Int2.asm por Var3.asm e Int3.asm, y añadimos una línea de comentario a la etiqueta music.
Donde dice
Debe decir
Página
Página
355
355
Si localizamos la etiqueta checkCrashShip_endLoop, que está dentro de la rutina CheckCreashShip, …
Si localizamos la etiqueta checkCrashShip_endLoop, que está dentro de la rutina CheckCrashShip, …
Donde dice
Debe decir
Página
Página
360
360
Desactivamos las interrupciones, DI, cambiamos al modo a uno…
Desactivamos las interrupciones, DI, cambiamos el modo a uno…
Donde dice
Debe decir
Página
Página
362
362
res $05, (hl) ; Bit 5 = 5, necesario para futuras ; inspecciones
res $05, (hl) ; Bit 5 = 0, necesario para futuras ; inspecciones
Donde dice
Debe decir
Página
Página
364
364
Cargamos la dificultad en A, LD A, (hardmess), comprobamos si es cuatro, CP $04, y saltamos si no lo es, JR NZ, main_restartCont.
Cargamos la dificultad en A, LD A, (hardness), comprobamos si es cuatro, CP $04, y saltamos si no lo es, JR NZ, main_restartCont.
Donde dice
Debe decir
Página
Página
368
368
Ejecutamos make o make.bat, cargamos emulador y ya tenemos nuestro juego terminado, a no ser queráis cambiar algo…
Ejecutamos make o make.bat, cargamos en el emulador y ya tenemos nuestro juego terminado, a no ser queráis cambiar algo…
Donde dice
Debe decir
Página
Página
372
372
; Sprite línea horizontal Sprite_SLASH: db $18, $18, $18, $18, $18, $18, $18, $18 ; $97
; Sprite línea vertical Sprite_MINUS: db $00, $00, $00, $ff, $ff, $00, $00, $00 ; $98
; Sprite línea vertical Sprite_SLASH: db $18, $18, $18, $18, $18, $18, $18, $18 ; $97
; Sprite línea horizontal Sprite_MINUS: db $00, $00, $00, $ff, $ff, $00, $00, $00 ; $98
Donde dice
Debe decir
Página
Página
379
379
rst $10 ; Imprime 2ª dígito
rst $10 ; Pinta 2º dígito
Donde dice
Debe decir
Página
Página
397
397
ret ; Ultima condición, siempre sale
ret ; Última condición, siempre sale
Donde dice
Debe decir
Página
Página
417
417
ei ; Actualiza interrupciones
ei ; Activa interrupciones
Donde dice
Debe decir
Página
Página
418
418
En Screen.asm vamos implementar la rutina que pinta la cuenta atrás.
En Screen.asm vamos a implementar la rutina que pinta la cuenta atrás.
Donde dice
Debe decir
Página
Página
434
434
Entre esta línea y loop_keyCont vamos añadir el movimiento del Spectrum …
Entre esta línea y loop_keyCont vamos a añadir el movimiento del Spectrum …
Donde dice
Debe decir
Página
Página
444
444
Si tuviéramos problemas de capacidad, que no es así, …
Misma ficha para ambos jugadores Si tuviéramos problemas de capacidad, que no es así, …
Donde dice
Debe decir
Página
Página
446
446
Localizamos en Game.asm printOXO_X y las líneas en las que se carga el UDG en A.
Localizamos en Screen.asm printOXO_X y las líneas en las que se carga el UDG en A.
Donde dice
Debe decir
Página
Página
451
451
ld hl,MaxTies ; HL = valor tiempo
ld hl,MaxTies ; HL = valor tablas
Donde dice
Debe decir
Página
Página
452
452
Por favor, sed benévolos, el arte nunca ha sido lo mío. Veré con buenos ojos que diseñéis vuestra propia pantalla de carga, que seguro que es mejor que está; difícil no debe ser.
Por favor, sed benévolos, el arte nunca ha sido lo mío. Veré con buenos ojos que diseñéis vuestra propia pantalla de carga, que seguro que es mejor que ésta; difícil no debe ser.
Donde dice
Debe decir
Página
Página
453
453
; ---------------------------------------------------------- ; LoadScr.asm ; ; La pantalla de carga se cargará en $5eba, y esta rutina la pasará ; a la VideoRAM para que aparezca de golpe y luego limpiará la zona ; dónde se había cargado inicialmente. ; La limpieza de esa área de memoria no es necesaria, pero lo hacemos ; por si tenemos que depurar, no encontrar código que en realidad ; sean restos de la pantalla de carga. ; ---------------------------------------------------------- org $5e88 ; Dirección de carga
ld hl, $5eba ; HL = dirección dónde está la pantalla ld de, $4000 ; DE = dirección VideoRAM ld bc, $1b00 ; Longitud de la pantalla ldir ; Vuelva la pantalla
; ---------------------------------------------------------- ; LoadScr.asm ; ; La pantalla de carga se cargará en $5eba, y esta rutina la pasará ; a la VideoRAM para que aparezca de golpe y luego limpiará la zona ; dónde se había cargado inicialmente. ; La limpieza de ese área de memoria no es necesaria, pero lo hacemos ; por si tenemos que depurar, no encontrar código que en realidad ; sean restos de la pantalla de carga. ; ---------------------------------------------------------- org $5e88 ; Dirección de carga
ld hl, $5eba ; HL = dirección dónde está la pantalla ld de, $4000 ; DE = dirección VideoRAM ld bc, $1b00 ; Longitud de la pantalla ldir ; Vuelca la pantalla
Donde dice
Debe decir
Página
Página
467
467
Paso a paso por instrucciones (Enter) ejecuta las instrucciones de una a una …
Paso a paso por instrucciones (Enter) ejecuta las instrucciones de una en una …
2 comentarios en «Ensamblador ZX Spectrum – Fe de erratas»
Hola! Utilizo Mac OS, una mac mini con M1, no he podido conseguir hacer funcionar el compilador PASMO. ¿Sabéis si algo similar para mac os? Muchas gracias
Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información.plugin cookies
Hola!
Utilizo Mac OS, una mac mini con M1, no he podido conseguir hacer funcionar el compilador PASMO.
¿Sabéis si algo similar para mac os?
Muchas gracias
Hola
Pásate por el grupo de ASM de Telegram, hay un link en el mensaje fijado con la compilación para M1.