Diferencias
Muestra las diferencias entre dos versiones de la página.
Ambos lados, revisión anteriorRevisión previaPróxima revisión | Revisión previa | ||
cursos:ensamblador:gfx4_fuentes [06-01-2024 16:37] – [Impresión de caracteres con estilos] sromero | cursos:ensamblador:gfx4_fuentes [19-01-2024 08:23] (actual) – sromero | ||
---|---|---|---|
Línea 3: | Línea 3: | ||
En prácticamente cualquier programa o juego nos encontraremos con la necesidad de imprimir en pantalla texto y datos numéricos en diferentes posiciones de pantalla: los menúes, los nombres de los niveles, los marcadores y puntuaciones, | En prácticamente cualquier programa o juego nos encontraremos con la necesidad de imprimir en pantalla texto y datos numéricos en diferentes posiciones de pantalla: los menúes, los nombres de los niveles, los marcadores y puntuaciones, | ||
- | La impresión de fuentes de texto es una aplicación directa de las rutinas de impresión de sprites en baja resolución que creamos en el capítulo anterior. Cada carácter es un sprite de 8x8 píxeles a dibujar en coordenadas (c,f) de baja resolución. | + | La impresión de fuentes de texto es una aplicación directa de las rutinas de impresión de sprites en baja resolución que creamos en el capítulo anterior. Cada carácter es un sprite de 8x8 píxeles a dibujar en coordenadas (COLUMNA, FILA) de baja resolución. |
| | ||
Línea 49: | Línea 49: | ||
Como hay un total de 96 caracteres de texto imprimibles (desde el 32 al 127), para disponer de un juego de caracteres suficiente con minúsculas, | Como hay un total de 96 caracteres de texto imprimibles (desde el 32 al 127), para disponer de un juego de caracteres suficiente con minúsculas, | ||
- | | + | |
Si tenemos problemas de espacio en nuestro programa también podemos utilizar un set de caracteres más reducido que acaben en el ASCII ' | Si tenemos problemas de espacio en nuestro programa también podemos utilizar un set de caracteres más reducido que acaben en el ASCII ' | ||
Línea 77: | Línea 77: | ||
charset1: | charset1: | ||
- | DEFB | + | |
- | | + | DEFB |
- | | + | DEFB |
- | | + | DEFB 56, 0, 76, 56, |
- | | + | DEFB 0, 24, 0, 48, 48, 48, 24, 0, 0, 24, 0, 12, 12, 12, 24, 0 |
- | | + | DEFB |
- | | + | DEFB |
- | | + | DEFB |
- | | + | DEFB 124, 0, |
- | | + | DEFB 124, 0,198, 28, |
- | | + | DEFB 12, 0, 60, |
- | | + | DEFB 60, 0, |
- | | + | DEFB 124, 0, |
- | | + | DEFB |
- | | + | DEFB 246, 6, |
- | | + | DEFB 118, 6, |
- | | + | DEFB 0, 24, 0, 24, 24, 24, 24, 0, 124, 0, |
- | | + | DEFB 252, 0, |
- | | + | DEFB 252, 0, |
- | | + | DEFB 254, 0, |
- | | + | DEFB 198, 0, |
- | | + | DEFB |
- | | + | DEFB 224, 0, |
- | | + | DEFB 198, 0, |
- | | + | DEFB 252, 0, |
- | | + | DEFB 252, 0, |
- | | + | DEFB 254, 0, 56, 56, 56, 56, 56, 0, 198, 0, |
- | | + | DEFB 198, 0, |
- | | + | DEFB 198, 0,124, 56, |
- | | + | DEFB 254, 0, 28, 56, |
- | | + | DEFB |
- | | + | DEFB 60, 0, 70, 12, 24, 0, 24, 0, |
</ | </ | ||
Línea 114: | Línea 114: | ||
==== PrintChar_8x8 ==== | ==== PrintChar_8x8 ==== | ||
- | La rutina de impresión de caracteres debe de recoger el código ASCII a dibujar y realizar el cálculo para posicionar un puntero " | + | La rutina de impresión de caracteres debe de recoger el código ASCII a dibujar y realizar el cálculo para posicionar un puntero " |
<code z80> | <code z80> | ||
Línea 131: | Línea 131: | ||
PrintChar_8x8: | PrintChar_8x8: | ||
- | LD BC, (FONT_X) | + | ld bc, (FONT_X) |
- | EX AF, AF' | + | ex af, af' |
- | ;;; Calculamos las coordenadas destino de pantalla en DE: | + | |
- | LD A, B | + | ld a, b |
- | AND $18 | + | |
- | ADD A, $40 | + | add a, $40 |
- | LD D, A | + | ld d, a |
- | LD A, B | + | ld a, b |
- | AND 7 | + | |
- | RRCA | + | rrca |
- | RRCA | + | rrca |
- | RRCA | + | rrca |
- | ADD A, C | + | add a, c |
- | LD E, A ; DE contiene ahora la direccion destino. | + | ld e, a ; DE contiene ahora la direccion destino. |
- | ;;; Calcular posicion origen (array sprites) en HL como: | + | |
- | | + | ;;; |
- | EX AF, AF' | + | ex af, af' |
- | LD BC, (FONT_CHARSET) | + | ld bc, (FONT_CHARSET) |
- | LD H, 0 | + | ld h, 0 |
- | LD L, A | + | ld l, a |
- | ADD HL, HL | + | add hl, hl |
- | ADD HL, HL | + | add hl, hl |
- | ADD HL, HL | + | add hl, hl |
- | ADD HL, BC ; HL = BC + HL = FONT_CHARSET + (A * 8) | + | add hl, bc ; HL = BC + HL = FONT_CHARSET + (A * 8) |
- | EX DE, HL ; Intercambiamos DE y HL (DE=origen, HL=destino) | + | ex de, hl ; Intercambiamos DE y HL (DE=origen, HL=destino) |
- | ;;; Dibujar 7 scanlines (DE) -> (HL) y bajar scanline (y DE++) | + | |
- | LD B, 7 ; 7 scanlines a dibujar | + | ld b, 7 ; 7 scanlines a dibujar |
drawchar8_loop: | drawchar8_loop: | ||
- | LD A, (DE) ; Tomamos el dato del caracter | + | ld a, (de) ; Tomamos el dato del caracter |
- | LD (HL), A ; Establecemos el valor en videomemoria | + | |
- | INC DE ; Incrementamos puntero en caracter | + | inc de ; Incrementamos puntero en caracter |
- | INC H ; Incrementamos puntero en pantalla (scanline+=1) | + | inc h ; Incrementamos puntero en pantalla (scanline+=1) |
- | DJNZ drawchar8_loop | + | |
- | ;;; La octava iteracion (8o scanline) aparte, para evitar los INCs | + | |
- | LD A, (DE) ; Tomamos el dato del caracter | + | ld a, (de) ; Tomamos el dato del caracter |
- | LD (HL), A ; Establecemos el valor en videomemoria | + | |
- | LD A, H ; Recuperamos el valor inicial de HL | + | ld a, h ; Recuperamos el valor inicial de HL |
- | SUB 7 ; Restando los 7 "INC H"' | + | |
- | ;;; Calcular posicion destino en area de atributos en DE. | + | |
- | ; Tenemos A = H | + | |
- | RRCA ; Codigo de Get_Attr_Offset_From_Image | + | |
- | RRCA | + | rrca |
- | RRCA | + | rrca |
- | AND 3 | + | |
- | OR $58 | + | |
- | LD D, A | + | ld d, a |
- | LD E, L | + | ld e, l |
- | ;;; Escribir el atributo en memoria | + | |
- | LD A, (FONT_ATTRIB) | + | ld a, (FONT_ATTRIB) |
- | LD (DE), A ; Escribimos el atributo en memoria | + | |
- | RET | + | ret |
</ | </ | ||
- | La rutina es muy parecida a las que ya vimos en el capítulo anterior para impresión de sprites 8x8, pero eliminando el cálculo del atributo origen al establecerlo desde la variable FONT_ATTRIB. | + | La rutina es muy parecida a las que ya vimos en el capítulo anterior para impresión de sprites 8x8, pero eliminando el cálculo del atributo origen al establecerlo desde la variable |
- | | + | |
La impresión se realiza por transferencia, | La impresión se realiza por transferencia, | ||
<code z80> | <code z80> | ||
- | LD A, (DE) ; Tomamos el dato del caracter | + | ld a, (de) ; Tomamos el dato del caracter |
- | LD (HL), A ; Establecemos el valor en videomemoria | + | |
</ | </ | ||
Línea 207: | Línea 207: | ||
<code z80> | <code z80> | ||
- | LD A, (DE) ; Tomamos el dato del caracter | + | ld a, (de) ; Tomamos el dato del caracter |
- | OR (HL) ; Hacemos OR entre dato y pantalla | + | |
- | LD (HL), A ; Establecemos el valor en videomemoria | + | |
</ | </ | ||
- | Para llamar a nuestra nueva rutina establecemos los valores de impresión en las variables de memoria y realizamos el CALL correspondiente. Aunque en esta rutina podríamos utilizar el paso por registros, vamos a emplear paso de parámetros por variables de memoria por 2 motivos: | + | Para llamar a nuestra nueva rutina establecemos los valores de impresión en las variables de memoria y realizamos el '' |
* Para que sean utilizables desde BASIC. | * Para que sean utilizables desde BASIC. | ||
Línea 219: | Línea 219: | ||
| | ||
- | En lugar de realizar una resta en cada impresión, podemos establecer el valor de FONT_CHARSET a la dirección del array menos 256 (32*8), con lo que cuando se calcule la dirección origen usando el ASCII real estaremos accediendo al sprite correcto. | + | En lugar de realizar una resta en cada impresión, podemos establecer el valor de '' |
- | Así, asignando a FONT_CHARSET el valor de " | + | Así, asignando a '' |
El código de asignación de variables iniciales y llamada a la función sería pues similar al siguiente: | El código de asignación de variables iniciales y llamada a la función sería pues similar al siguiente: | ||
<code z80> | <code z80> | ||
- | | + | |
- | LD HL, charset1-256 | + | ld hl, charset1-256 |
- | | + | |
- | LD A, 6 | + | ld a, 6 |
- | | + | |
- | | + | |
- | LD A, 15 | + | ld a, 15 |
- | | + | |
- | LD A, 8 | + | ld a, 8 |
- | | + | |
- | LD A, ' | + | ld a, ' |
- | | + | |
</ | </ | ||
- | | + | |
El siguiente ejemplo (donde se ha omitido el código de las funciones ya vistas hasta ahora) muestra el charset 8x8 de 64 caracteres en pantalla, en un bucle de 4 líneas de 16 caracteres cada una: | El siguiente ejemplo (donde se ha omitido el código de las funciones ya vistas hasta ahora) muestra el charset 8x8 de 64 caracteres en pantalla, en un bucle de 4 líneas de 16 caracteres cada una: | ||
Línea 248: | Línea 248: | ||
<code z80> | <code z80> | ||
; Visualizacion del charset de ejemplo | ; Visualizacion del charset de ejemplo | ||
- | ORG 35000 | + | |
- | LD H, 0 | + | ld h, 0 |
- | LD L, A | + | ld l, a |
- | | + | |
- | LD HL, charset1-256 | + | ld hl, charset1-256 |
- | | + | |
- | XOR A | + | xor a |
- | | + | |
- | INC A | + | inc a |
- | | + | |
- | LD A, 6 | + | ld a, 6 |
- | | + | |
- | LD C, 32 ; Empezamos en caracter 32 | + | ld c, 32 ; Empezamos en caracter 32 |
- | | + | |
- | LD E, 4 | + | ld e, 4 |
bucle_y: | bucle_y: | ||
- | | + | |
- | LD B, 16 ; Imprimimos 16 caracteres horiz | + | ld b, 16 ; Imprimimos 16 caracteres horiz |
bucle_x: | bucle_x: | ||
- | LD A, (FONT_X) | + | ld a, (FONT_X) |
- | INC A | + | inc a |
- | | + | |
- | LD A, C | + | ld a, c |
- | PUSH BC | + | push bc |
- | PUSH DE ; Preservamos registros | + | push de ; Preservamos registros |
- | | + | |
- | POP DE | + | pop de |
- | POP BC | + | pop bc |
- | INC C ; Siguiente caracter | + | inc c ; Siguiente caracter |
- | | + | |
- | LD A, (FONT_Y) | + | ld a, (FONT_Y) |
- | INC A | + | inc a |
- | INC A ; Y = Y + 2 | + | inc a ; Y = Y + 2 |
- | | + | |
- | XOR A | + | xor a |
- | | + | |
- | DEC E | + | dec e |
- | JR NZ, bucle_y | + | jr nz, bucle_y |
loop: | loop: | ||
- | JR loop | + | jr loop |
- | RET | + | ret |
; | ; | ||
Línea 310: | Línea 309: | ||
; | ; | ||
- | END 35000 | + | |
</ | </ | ||
+ | Un apunte: en este caso hemos usado '' | ||
\\ | \\ | ||
==== PrintString_8x8 ==== | ==== PrintString_8x8 ==== | ||
- | | + | |
| | ||
Línea 361: | Línea 361: | ||
PrintString_8x8: | PrintString_8x8: | ||
- | ;;; Bucle de impresion de caracter | + | |
pstring8_loop: | pstring8_loop: | ||
- | LD A, (HL) ; Leemos un caracter de la cadena | + | ld a, (hl) ; Leemos un caracter de la cadena |
- | OR A | + | or a |
- | RET Z ; Si es 0 (fin de cadena) volver | + | ret z ; Si es 0 (fin de cadena) volver |
- | INC HL ; Siguiente caracter en la cadena | + | inc hl ; Siguiente caracter en la cadena |
- | PUSH HL ; Salvaguardamos HL | + | push hl ; Salvaguardamos HL |
- | CALL PrintChar_8x8 | + | |
- | POP HL ; Recuperamos HL | + | pop hl ; Recuperamos HL |
- | ;;; Ajustamos coordenadas X e Y | + | |
- | LD A, (FONT_X) | + | ld a, (FONT_X) |
- | INC A ; pero comprobamos si borde derecho | + | inc a ; pero comprobamos si borde derecho |
- | CP 31 ; X > 31? | + | |
- | JR C, pstring8_noedgex | + | jr c, pstring8_noedgex |
- | LD A, (FONT_Y) | + | ld a, (FONT_Y) |
- | CP 23 ; Si ya es 23, no incrementar | + | |
- | JR NC, pstring8_noedgey | + | jr nc, pstring8_noedgey |
- | INC A ; No es 23, cambiar Y | + | inc a ; No es 23, cambiar Y |
- | LD (FONT_Y), | + | |
pstring8_noedgey: | pstring8_noedgey: | ||
- | | + | ld (FONT_Y), |
- | XOR A ; Y ademas hacemos A = X = 0 | + | xor a ; Y ademas hacemos A = X = 0 |
pstring8_noedgex | pstring8_noedgex | ||
- | | + | ld (FONT_X), |
- | JR pstring8_loop | + | |
</ | </ | ||
Línea 396: | Línea 396: | ||
<code z80> | <code z80> | ||
- | | + | |
- | LD HL, charset1-256 | + | ld hl, charset1-256 |
- | | + | |
- | LD A, 64+3 | + | ld a, 64+3 |
- | | + | |
- | LD HL, cadena | + | ld hl, cadena |
- | LD A, 0 | + | ld a, 0 |
- | | + | |
- | LD A, 15 | + | ld a, 15 |
- | | + | |
- | | + | |
- | RET | + | ret |
cadena DB " | cadena DB " | ||
Línea 416: | Línea 416: | ||
\\ | \\ | ||
- | {{ : | + | {{ : |
\\ | \\ | ||
- | La forma más óptima de programar la rutina de impresión consistiría en integrar el código de PrintChar_8x8 dentro de PrintString_8x8 evitando el recálculo de offset en pantalla en cada carácter. Se utilizaría DE como puntero en la fuente y HL como puntero en pantalla. Una vez calculada la posición inicial en pantalla para el primer carácter se variaría HL apropiadamente, | + | La forma más óptima de programar la rutina de impresión consistiría en integrar el código de '' |
| | ||
Línea 425: | Línea 425: | ||
Si vamos a utilizar la impresión de cadenas en la introducción del juego o programa, los menúes, la descripción de las fases, los créditos, la pausa o los mensajes entre nivel y nivel o el final del juego, probablemente será suficiente con la rutina que acabamos de ver. | Si vamos a utilizar la impresión de cadenas en la introducción del juego o programa, los menúes, la descripción de las fases, los créditos, la pausa o los mensajes entre nivel y nivel o el final del juego, probablemente será suficiente con la rutina que acabamos de ver. | ||
- | Las cadenas de texto que se puedan usar en el bucle principal del programa deberían imprimirse como Sprites, y los valores numéricos como impresión tipo "PrintChar_8x8" | + | Las cadenas de texto que se puedan usar en el bucle principal del programa deberían imprimirse como Sprites, y los valores numéricos como impresión tipo '' |
\\ | \\ | ||
Línea 453: | Línea 453: | ||
<code z80> | <code z80> | ||
- | ;;; Guardar en L el valor a convertir y llamar a rutina | + | |
- | LD L, A | + | ld l, a |
- | CALL Dec2String_8 | + | |
- | ;;; Imprimir la cadena resultante de la conversion: | + | |
- | LD HL, conv2string | + | ld hl, conv2string |
- | CALL PrintString_8x8 | + | |
</ | </ | ||
Línea 470: | Línea 470: | ||
La conversión de un valor numérico a una representación binaria se basa en testear el estado de cada uno de los bits del registro " | La conversión de un valor numérico a una representación binaria se basa en testear el estado de cada uno de los bits del registro " | ||
- | En lugar de ejecutar 8 ó 16 comparaciones con el comando BIT, utilizaremos la rotación a la derecha del registro parámetro de forma que el bit a comprobar sea desplazado al Carry Flag y podamos testear su valor con un **JR NC** o **JR C**. | + | En lugar de ejecutar 8 ó 16 comparaciones con el comando |
La rutina de conversión tiene 2 puntos de entrada diferentes según necesitemos convertir un número de 8 bits (valor en registro L) o de 16 bits (valor en registro HL), pero utiliza el mismo core de conversión para ambos casos: | La rutina de conversión tiene 2 puntos de entrada diferentes según necesitemos convertir un número de 8 bits (valor en registro L) o de 16 bits (valor en registro HL), pero utiliza el mismo core de conversión para ambos casos: | ||
Línea 486: | Línea 486: | ||
; | ; | ||
- | Bin2String_16: | + | Bin2String_16: |
- | LD DE, conv2string | + | ld de, conv2string |
- | LD C, H ; C = a convertir (parte alta) | + | ld c, h ; C = a convertir (parte alta) |
- | CALL Bin2String_convert | + | |
- | JR Bin2String_8b | + | |
- | | + | ; saltando el ld de, conv2string |
- | Bin2String_8: | + | Bin2String_8: |
- | LD DE, conv2string | + | ld de, conv2string |
Bin2String_8b: | Bin2String_8b: | ||
- | LD C, L ; C = a convertir (parte baja) | + | ld c, l ; C = a convertir (parte baja) |
- | CALL Bin2String_convert | + | |
- | XOR A | + | xor a |
- | LD (DE), A ; Guardar End Of String | + | |
- | RET | + | ret |
Bin2String_convert: | Bin2String_convert: | ||
- | LD B, 8 ; 8 iteraciones | + | ld b, 8 ; 8 iteraciones |
- | b2string_loop: | + | b2string_loop: |
- | RL C | + | rl c |
- | LD A, ' | + | ld a, ' |
- | JR NC, b2string_noC | + | jr nc, b2string_noC |
- | LD (DE), A ; Lo almacenamos en la cadena | + | |
- | INC DE | + | inc de |
- | DJNZ b2string_loop | + | |
- | RET | + | ret |
b2string_noC: | b2string_noC: | ||
- | DEC A ; A = ' | + | dec a ; A = ' |
- | LD (DE), A | + | |
- | INC DE ; Lo almacenamos y avanzamos | + | inc de ; Lo almacenamos y avanzamos |
- | DJNZ b2string_loop | + | |
- | RET | + | ret |
</ | </ | ||
- | En el área de memoria apuntada por //conv2string// tendremos la representación binaria en ASCII del valor en L o HL, acabado en un carácter 0, lista para imprimir con PrintString_8x8. | + | En el área de memoria apuntada por '' |
\\ | \\ | ||
Línea 541: | Línea 541: | ||
; | ; | ||
Hex2String_16: | Hex2String_16: | ||
- | LD DE, conv2string | + | ld de, conv2string |
- | LD A, H | + | ld a, h |
- | CALL B2AHex_Num1 | + | |
- | LD A, H | + | ld a, h |
- | CALL B2AHex_Num2 | + | |
- | JR Hex2String_8b | + | |
- | Hex2String_8: | + | Hex2String_8: |
- | LD DE, conv2string | + | ld de, conv2string |
Hex2String_8b: | Hex2String_8b: | ||
- | LD A, L | + | ld a, l |
- | CALL B2AHex_Num1 | + | |
- | LD A, L | + | ld a, l |
- | CALL B2AHex_Num2 | + | |
- | XOR A | + | xor a |
- | LD (DE), A ; Guardar End Of String | + | |
- | RET | + | ret |
B2AHex_Num1: | B2AHex_Num1: | ||
- | RRA | + | rra |
- | RRA | + | rra |
- | | + | |
- | RRA ; para poder usar el siguiente bloque | + | |
B2AHex_Num2: | B2AHex_Num2: | ||
- | | + | or $f0 ; Enmascaramos 11110000 |
- | DAA ; Ajuste BCD | + | |
- | ADD A, $A0 | + | add a, $a0 |
- | ADC A, $40 | + | adc a, $40 |
- | LD (DE), A ; Guardamos dato | + | |
- | INC DE | + | inc de |
- | RET | + | ret |
</ | </ | ||
Línea 595: | Línea 595: | ||
; | ; | ||
Int2String_16: | Int2String_16: | ||
- | LD DE, conv2string | + | ld de, conv2string |
- | LD BC, -10000 | + | ld bc, -10000 |
- | CALL Int2Dec_num1 | + | |
- | LD BC, -1000 ; Calcular digito miles | + | ld bc, -1000 ; Calcular digito miles |
- | CALL Int2Dec_num1 | + | |
- | JR Int2String_8b | + | |
- | Int2String_8: | + | Int2String_8: |
- | LD DE, conv2string | + | ld de, conv2string |
- | LD H, 0 ; Parte alta de HL = 0 | + | ld h, 0 ; Parte alta de HL = 0 |
Int2String_8b: | Int2String_8b: | ||
- | LD BC, -100 ; Calcular digito de centenas | + | ld bc, -100 ; Calcular digito de centenas |
- | CALL Int2Dec_num1 | + | |
- | LD C, -10 ; Calcular digito de decenas | + | ld c, -10 ; Calcular digito de decenas |
- | CALL Int2Dec_num1 | + | |
- | LD C, B ; Calcular unidades | + | ld c, b ; Calcular unidades |
- | CALL Int2Dec_num1 | + | |
- | XOR A | + | xor a |
- | LD (DE), A ; Almacenar un fin de cadena | + | |
- | RET | + | ret |
Int2Dec_num1: | Int2Dec_num1: | ||
- | LD A,' | + | ld a,' |
Int2Dec_num2: | Int2Dec_num2: | ||
- | INC A ; Incrementamos el digito (' | + | inc a ; Incrementamos el digito (' |
- | ADD HL, BC ; Restamos " | + | add hl, bc ; Restamos " |
- | JR C, Int2Dec_num2 | + | jr c, Int2Dec_num2 |
- | SBC HL, BC ; Deshacemos el último paso | + | sbc hl, bc ; Deshacemos el último paso |
- | LD (DE), A ; Almacenamos el valor | + | |
- | INC DE | + | inc de |
- | RET | + | ret |
</ | </ | ||
Línea 646: | Línea 646: | ||
; | ; | ||
INC_HL_Remove_Leading_Zeros: | INC_HL_Remove_Leading_Zeros: | ||
- | LD A, (HL) ; Leemos caracter de la cadena | + | ld a, (hl) ; Leemos caracter de la cadena |
- | OR A | + | or a |
- | RET Z ; Fin de cadena -> volver | + | ret z ; Fin de cadena -> volver |
- | CP ' | + | |
- | RET NZ ; Distinto de ' | + | ret nz ; Distinto de ' |
- | INC HL ; ' | + | inc hl ; ' |
- | JR INC_HL_Remove_Leading_Zeros | + | |
</ | </ | ||
Línea 658: | Línea 658: | ||
<code z80> | <code z80> | ||
- | ;;; Imprimir variable de 8 bits (podría ser un registro) | + | |
- | LD A, (variable_8bits) | + | ld a, (variable_8bits) |
- | LD L, A | + | ld l, a |
- | CALL Int2String_8 | + | |
- | LD HL, conv2string | + | ld hl, conv2string |
- | CALL INC_HL_Remove_Leading_Zeros | + | |
- | CALL PrintString_8x8 | + | |
- | ;;; Imprimir variable de 16 bits | + | |
- | LD BC, (variable_16bits) | + | ld bc, (variable_16bits) |
- | PUSH BC | + | push bc |
- | POP HL ; HL = BC | + | pop hl ; HL = BC |
- | CALL Int2String_16 | + | |
- | LD HL, conv2string | + | ld hl, conv2string |
- | CALL INC_HL_Remove_Leading_Zeros | + | |
- | CALL PrintString_8x8 | + | |
</ | </ | ||
Línea 682: | Línea 682: | ||
\\ | \\ | ||
- | | + | |
<code z80> | <code z80> | ||
INC_HL_Justify_Leading_Zeros: | INC_HL_Justify_Leading_Zeros: | ||
- | LD A, (HL) ; Leemos caracter de la cadena | + | ld a, (hl) ; Leemos caracter de la cadena |
- | OR A | + | or a |
- | RET Z ; Fin de cadena -> volver | + | ret z ; Fin de cadena -> volver |
- | CP ' | + | |
- | RET NZ ; Distinto de ' | + | ret nz ; Distinto de ' |
- | INC HL ; ' | + | inc hl ; ' |
- | LD A, ' ' | + | ld a, ' ' |
- | CALL Font_Blank | + | |
- | JR INC_HL_Justify_Leading_Zeros | + | |
</ | </ | ||
De esta forma, podemos tener en pantalla un valor " | De esta forma, podemos tener en pantalla un valor " | ||
- | | + | |
\\ | \\ | ||
Línea 717: | Línea 717: | ||
; | ; | ||
Int2String_8_2Digits: | Int2String_8_2Digits: | ||
- | LD D, ' | + | ld d, ' |
- | DEC D ; Decrementar porque el bucle hace INC | + | dec d ; Decrementar porque el bucle hace INC |
- | LD E, 10 ; Base 10 | + | ld e, 10 ; Base 10 |
- | AND A ; Carry Flag = 0 | + | and a ; Carry Flag = 0 |
dtoa2dloop: | dtoa2dloop: | ||
- | INC D ; Incrementar numero de decenas | + | inc d ; Incrementar numero de decenas |
- | SUB E ; Quitar una unidad de decenas de A | + | sub e ; Quitar una unidad de decenas de A |
- | JR NC, dtoa2dloop | + | jr nc, dtoa2dloop |
- | ADD A, E ; Decrementado demasiado, volver atras | + | add a, e ; Decrementado demasiado, volver atras |
- | ADD A, ' | + | add a, ' |
- | LD E, A ; E contiene las unidades | + | ld e, a ; E contiene las unidades |
- | RET | + | ret |
</ | </ | ||
Línea 737: | Línea 737: | ||
<code z80> | <code z80> | ||
- | LD A, (vidas) | + | ld a, (vidas) |
- | | + | |
- | | + | |
- | LD A, 0 | + | ld a, 0 |
- | | + | |
- | LD A, D | + | ld a, d |
- | | + | |
- | | + | |
- | LD A, 1 | + | ld a, 1 |
- | | + | |
- | LD A, E | + | ld a, e |
- | | + | |
</ | </ | ||
Línea 759: | Línea 759: | ||
===== Fuente estándar 8x8 de la ROM ===== | ===== Fuente estándar 8x8 de la ROM ===== | ||
- | En el Spectrum disponemos de un tipo de letra estándar de 8x8 pregrabado en ROM. Los caracteres imprimibles alojados en la ROM del Spectrum van desde el 32 (espacio) al 127 (carácter de copyright), empezando el primero en $3D00 (15161 decimal) y acabando el último en $3FFF (16383, el último byte de la ROM). | + | En el Spectrum disponemos de un tipo de letra estándar de 8x8 pregrabado en ROM. Los caracteres imprimibles alojados en la ROM del Spectrum van desde el 32 (espacio) al 127 (carácter de copyright), empezando el primero en **$3d00** |
- | | + | |
- | Por defecto, CHARS contiene el valor $3D00 (el tipo de letra estándar) menos 256. El hecho de restar 256 al inicio real de la fuente es porque los caracteres definidos en la ROM empiezan en el 32 y restando 256 (8 bytes por carácter para 32 caracteres = 256 bytes), al igual que hicimos nosotros con nuestro charset personalizado, | + | Por defecto, |
- | El valor por defecto de //CHARS// es, pues, $3D00 - $0100 = $3C00. | + | El valor por defecto de '' |
- | El juego de caracteres estándar es inmutable al estar en ROM. La variable CHARS permitía, en el BASIC del Spectrum, definir un juego de caracteres personalizado en RAM y apuntar CHARS a su dirección en memoria. La definición de los 21 UDGs (19 en el +2A/+3) también está en RAM (desde $FF58 a $FFFF), ya que deben de ser personalizables por el usuario. | + | El juego de caracteres estándar es inmutable al estar en ROM. La variable |
| | ||
Línea 778: | Línea 778: | ||
\\ | \\ | ||
- | El formato en memoria de la fuente de la ROM es idéntico a un spriteset de 8x8 sin atributos, tal y como hemos definido las fuentes de texto personalizadas de nuestras rutinas y ejemplos anteriores. A partir de $3D00 empiezan los 8 bytes de datos (8 scanlines) del carácter 32, a los que siguen los 8 scanlines del carácter 33, etc., así hasta el carácter 127. | + | El formato en memoria de la fuente de la ROM es idéntico a un spriteset de 8x8 sin atributos, tal y como hemos definido las fuentes de texto personalizadas de nuestras rutinas y ejemplos anteriores. A partir de $3d00 empiezan los 8 bytes de datos (8 scanlines) del carácter 32, a los que siguen los 8 scanlines del carácter 33, etc., así hasta el carácter 127. |
- | | + | |
<code z80> | <code z80> | ||
- | LD HL, 15616-256 | + | ld hl, 15616-256 |
- | | + | |
- | | + | |
</ | </ | ||
Línea 798: | Línea 798: | ||
| | ||
- | Ya hemos visto cómo las rutinas PrintChar_8x8 y PrintString_8x8 hacen uso de las variables FONT_X, FONT_Y, FONT_CHARSET y FONT_ATTRIB. En este apartado definiremos más variables, funciones para manipularlas y nuevas funciones de impresión que hagan uso avanzado de ambas. | + | Ya hemos visto cómo las rutinas |
La sección sobre sistemas de gestión de texto se divide en: | La sección sobre sistemas de gestión de texto se divide en: | ||
Línea 816: | Línea 816: | ||
* **FONT_X**, **FONT_Y** : Coordenadas X e Y en baja resolución (comenzando en 0) de la posición actual para la próxima impresión de un carácter (cursor). | * **FONT_X**, **FONT_Y** : Coordenadas X e Y en baja resolución (comenzando en 0) de la posición actual para la próxima impresión de un carácter (cursor). | ||
- | * **FONT_CHARSET** : Apunta al spriteset de la fuente de texto (charset) a utilizar. El valor por defecto es $3D00-256 (la fuente de la ROM). | + | * **FONT_CHARSET** : Apunta al spriteset de la fuente de texto (charset) a utilizar. El valor por defecto es $3d00-256 (la fuente de la ROM). |
* **FONT_ATTRIB** : Almacena el atributo en uso para la impresión de caracteres. | * **FONT_ATTRIB** : Almacena el atributo en uso para la impresión de caracteres. | ||
* **FONT_STYLE** : Almacena un valor numérico que define el estilo de impresión a utilizar. Por defecto es 0 (estilo normal). | * **FONT_STYLE** : Almacena un valor numérico que define el estilo de impresión a utilizar. Por defecto es 0 (estilo normal). | ||
Línea 827: | Línea 827: | ||
<code z80> | <code z80> | ||
- | FONT_CHARSET | + | FONT_CHARSET |
FONT_ATTRIB | FONT_ATTRIB | ||
FONT_STYLE | FONT_STYLE | ||
Línea 845: | Línea 845: | ||
<code z80> | <code z80> | ||
; | ; | ||
- | FONT_CHARSET | + | FONT_CHARSET |
FONT_ATTRIB | FONT_ATTRIB | ||
FONT_STYLE | FONT_STYLE | ||
Línea 857: | Línea 857: | ||
FONT_UNDERSC | FONT_UNDERSC | ||
FONT_ITALIC | FONT_ITALIC | ||
- | |||
; | ; | ||
Línea 864: | Línea 863: | ||
; | ; | ||
Font_Set_Charset: | Font_Set_Charset: | ||
- | | + | ld (FONT_CHARSET), |
- | RET | + | ret |
; | ; | ||
Línea 873: | Línea 871: | ||
; | ; | ||
Font_Set_Style: | Font_Set_Style: | ||
- | | + | ld (FONT_STYLE), |
- | RET | + | ret |
; | ; | ||
Línea 882: | Línea 879: | ||
; | ; | ||
Font_Set_X: | Font_Set_X: | ||
- | | + | ld (FONT_X), |
- | RET | + | ret |
; | ; | ||
Línea 891: | Línea 887: | ||
; | ; | ||
Font_Set_Y: | Font_Set_Y: | ||
- | | + | ld (FONT_Y), |
- | RET | + | ret |
; | ; | ||
Línea 901: | Línea 896: | ||
; | ; | ||
Font_Set_XY: | Font_Set_XY: | ||
- | | + | ld (FONT_X), |
- | RET | + | ret |
; | ; | ||
Línea 911: | Línea 905: | ||
; | ; | ||
Font_Set_Ink: | Font_Set_Ink: | ||
- | PUSH BC ; Preservamos registros | + | push bc ; Preservamos registros |
- | AND 7 ; Borramos bits 7-3 | + | |
- | LD B, A ; Lo guardamos en B | + | ld b, a ; Lo guardamos en B |
- | LD A, (FONT_ATTRIB) | + | ld a, (FONT_ATTRIB) |
- | AND %11111000 | + | |
- | OR B ; Insertamos INK en A | + | or b ; Insertamos INK en A |
- | LD (FONT_ATTRIB), | + | |
- | POP BC | + | pop bc |
- | RET | + | ret |
; | ; | ||
Línea 928: | Línea 921: | ||
; | ; | ||
Font_Set_Paper: | Font_Set_Paper: | ||
- | PUSH BC ; Preservamos registros | + | push bc ; Preservamos registros |
- | AND 7 ; Borramos bits 7-3 | + | |
- | RLCA ; A = 00000XXX -> 0000XXX0 | + | |
- | RLCA ; A = 000XXX00 | + | |
- | RLCA ; A = 00XXX000 <-- Valor en paper | + | |
- | LD B, A ; Lo guardamos en B | + | ld b, a ; Lo guardamos en B |
- | LD A, (FONT_ATTRIB) | + | ld a, (FONT_ATTRIB) |
- | AND %11000111 | + | |
- | OR B ; Insertamos PAPER en A | + | or b ; Insertamos PAPER en A |
- | LD (FONT_ATTRIB), | + | |
- | POP BC | + | pop bc |
- | RET | + | ret |
; | ; | ||
Línea 947: | Línea 939: | ||
; | ; | ||
Font_Set_Attrib: | Font_Set_Attrib: | ||
- | | + | ld (FONT_ATTRIB), |
- | RET | + | ret |
; | ; | ||
Línea 957: | Línea 948: | ||
; | ; | ||
Font_Set_Bright: | Font_Set_Bright: | ||
- | | + | and 1 ; A = solo bit 0 de A |
- | LD A, (FONT_ATTRIB) | + | ld a, (FONT_ATTRIB) |
- | JR NZ, fsbright_1 | + | jr nz, fsbright_1 |
- | RES 6, A ; Seteamos a 0 el bit de flash | + | |
- | LD (FONT_ATTRIB), | + | |
- | RET | + | ret |
fsbright_1: | fsbright_1: | ||
- | | + | set 6, a ; Seteamos a 1 el bit de brillo |
- | LD (FONT_ATTRIB), | + | |
- | RET | + | ret |
; | ; | ||
Línea 975: | Línea 965: | ||
; | ; | ||
Font_Set_Flash: | Font_Set_Flash: | ||
- | | + | and 1 ; A = solo bit 0 de A |
- | LD A, (FONT_ATTRIB) | + | ld a, (FONT_ATTRIB) |
- | JR NZ, fsflash_1 | + | jr nz, fsflash_1 |
- | RES 7, A ; Seteamos a 0 el bit de flash | + | |
- | LD (FONT_ATTRIB), | + | |
- | RET | + | ret |
fsflash_1: | fsflash_1: | ||
- | | + | set 7, a ; Seteamos a 1 el bit de flash |
- | LD (FONT_ATTRIB), | + | |
- | RET | + | ret |
; | ; | ||
Línea 994: | Línea 983: | ||
; | ; | ||
Font_Blank: | Font_Blank: | ||
- | LD A, ' ' | + | ld a, ' ' |
- | PUSH BC | + | push bc |
- | PUSH DE | + | push de |
- | PUSH HL | + | push hl |
- | CALL PrintChar_8x8 | + | |
- | POP HL | + | pop hl |
- | POP DE | + | pop de |
- | POP BC | + | pop bc |
- | CALL Font_Inc_X | + | |
- | RET | + | ret |
- | + | ||
; | ; | ||
Línea 1013: | Línea 1000: | ||
; | ; | ||
Font_Inc_X: | Font_Inc_X: | ||
- | LD A, (FONT_X) | + | ld a, (FONT_X) |
- | INC A ; pero comprobamos si borde derecho | + | inc a ; pero comprobamos si borde derecho |
- | CP FONT_SCRWIDTH-1 | + | |
- | JR C, fincx_noedgex | + | jr c, fincx_noedgex |
- | CALL Font_CRLF | + | |
- | RET | + | ret |
fincx_noedgex: | fincx_noedgex: | ||
- | | + | ld (FONT_X), |
- | RET | + | ret |
; | ; | ||
Línea 1031: | Línea 1017: | ||
; | ; | ||
Font_LF: | Font_LF: | ||
- | LD A, (FONT_Y) | + | ld a, (FONT_Y) |
- | CP FONT_SCRHEIGHT-1 | + | |
- | JR NC, fontlf_noedge | + | jr nc, fontlf_noedge |
- | INC A ; No estamos, avanzar | + | inc a ; No estamos, avanzar |
- | LD (FONT_Y), | + | |
fontlf_noedge: | fontlf_noedge: | ||
- | RET | + | ret |
; | ; | ||
Línea 1046: | Línea 1031: | ||
; | ; | ||
Font_CR: | Font_CR: | ||
- | XOR A | + | xor a |
- | LD (FONT_X), | + | |
- | RET | + | ret |
; | ; | ||
Línea 1056: | Línea 1040: | ||
; | ; | ||
Font_CRLF: | Font_CRLF: | ||
- | | + | call Font_LF |
- | CALL Font_CR | + | |
- | RET | + | ret |
; | ; | ||
Línea 1066: | Línea 1049: | ||
; | ; | ||
Font_Tab: | Font_Tab: | ||
- | PUSH BC | + | push bc |
- | PUSH DE | + | push de |
- | PUSH HL | + | push hl |
- | LD HL, font_tab_string | + | ld hl, font_tab_string |
- | CALL PrintString_8x8 | + | |
- | POP HL | + | pop hl |
- | POP DE | + | pop de |
- | POP BC | + | pop bc |
- | RET | + | ret |
font_tab_string | font_tab_string | ||
- | |||
; | ; | ||
Línea 1085: | Línea 1067: | ||
; | ; | ||
Font_Dec_X: | Font_Dec_X: | ||
- | LD A, (FONT_X) | + | ld a, (FONT_X) |
- | OR A | + | or a |
- | RET Z ; Es cero? no se hace nada (salir) | + | ret z ; Es cero? no se hace nada (salir) |
- | DEC A ; No es cero? Decrementar | + | dec a ; No es cero? Decrementar |
- | LD (FONT_X), | + | |
- | RET ; Salir | + | |
; | ; | ||
Línea 1099: | Línea 1080: | ||
; | ; | ||
Font_Backspace: | Font_Backspace: | ||
- | | + | call Font_Dec_X |
- | LD A, ' ' | + | ld a, ' ' |
- | PUSH BC | + | push bc |
- | PUSH DE | + | push de |
- | PUSH HL | + | push hl |
- | CALL PrintChar_8x8 | + | |
- | POP HL | + | pop hl |
- | POP DE | + | pop de |
- | POP BC | + | pop bc |
- | RET ; Salir | + | |
</ | </ | ||
Línea 1114: | Línea 1095: | ||
<code z80> | <code z80> | ||
- | LD HL, micharset | + | ld hl, micharset |
- | | + | |
- | LD A, 1+(7*8) | + | ld a, 1+(7*8) |
- | Call Font_Set_Attrib | + | Call Font_Set_Attrib |
- | LD A, FONT_NORMAL | + | ld a, FONT_NORMAL |
- | | + | |
- | (...) | + | (...) |
</ | </ | ||
+ | |||
+ | | ||
+ | |||
\\ | \\ | ||
Línea 1129: | Línea 1113: | ||
==== Impresión de caracteres con estilos ==== | ==== Impresión de caracteres con estilos ==== | ||
- | | + | |
| | ||
Línea 1135: | Línea 1119: | ||
Los estilos básicos que podemos conseguir al vuelo son **normal**, **negrita**, | Los estilos básicos que podemos conseguir al vuelo son **normal**, **negrita**, | ||
- | Las rutinas de impresión para los 4 estilos esencialmente iguales salvo por el bucle de impresión, por lo que vamos a utilizar una variable global llamada | + | Las rutinas de impresión para los 4 estilos esencialmente iguales salvo por el bucle de impresión, por lo que vamos a utilizar una variable global llamada |
< | < | ||
;--- Variables de fuente -------------------- | ;--- Variables de fuente -------------------- | ||
- | FONT_CHARSET | + | FONT_CHARSET |
FONT_ATTRIB | FONT_ATTRIB | ||
FONT_STYLE | FONT_STYLE | ||
Línea 1175: | Línea 1159: | ||
PrintChar_8x8: | PrintChar_8x8: | ||
- | LD BC, (FONT_X) | + | ld bc, (FONT_X) |
- | EX AF, AF' | + | ex af, af' |
- | ;;; Calculamos las coordenadas destino de pantalla en DE: | + | |
- | LD A, B | + | ld a, b |
- | AND $18 | + | |
- | ADD A, $40 | + | add a, $40 |
- | LD D, A | + | ld d, a |
- | LD A, B | + | ld a, b |
- | AND 7 | + | |
- | RRCA | + | rrca |
- | RRCA | + | rrca |
- | RRCA | + | rrca |
- | ADD A, C | + | add a, c |
- | LD E, A ; DE contiene ahora la direccion destino. | + | ld e, a ; DE contiene ahora la direccion destino. |
- | ;;; Calcular posicion origen (array sprites) en HL como: | + | |
- | | + | ;;; |
- | EX AF, AF' | + | ex af, af' |
- | LD BC, (FONT_CHARSET) | + | ld bc, (FONT_CHARSET) |
- | LD H, 0 | + | ld h, 0 |
- | LD L, A | + | ld l, a |
- | ADD HL, HL | + | add hl, hl |
- | ADD HL, HL | + | add hl, hl |
- | ADD HL, HL | + | add hl, hl |
- | ADD HL, BC ; HL = BC + HL = FONT_CHARSET + (A * 8) | + | add hl, bc ; HL = BC + HL = FONT_CHARSET + (A * 8) |
- | EX DE, HL ; Intercambiamos DE y HL (DE=origen, HL=destino) | + | ex de, hl ; Intercambiamos DE y HL (DE=origen, HL=destino) |
- | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | + | |
- | | + | ;;; INSERTAR AQUI BUCLES DE IMPRESION SEGUN ESTILO |
- | | + | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
- | ;;; (...) | + | |
- | ;;; Impresion del caracter finalizada | + | |
- | ;;; Impresion de atributos | + | |
- | LD A, H ; Recuperamos el valor inicial de HL | + | ld a, h ; Recuperamos el valor inicial de HL |
- | SUB 8 ; Restando los 8 scanlines avanzados | + | |
- | ;;; Calcular posicion destino en area de atributos en DE. | + | |
- | ; A = H | + | ; A = H |
- | RRCA ; Codigo de Get_Attr_Offset_From_Image | + | |
- | RRCA | + | rrca |
- | RRCA | + | rrca |
- | AND 3 | + | |
- | OR $58 | + | |
- | LD D, A | + | ld d, a |
- | LD E, L | + | ld e, l |
- | ;;; Escribir el atributo en memoria | + | |
- | LD A, (FONT_ATTRIB) | + | ld a, (FONT_ATTRIB) |
- | LD (DE), A ; Escribimos el atributo en memoria | + | |
- | RET | + | ret |
</ | </ | ||
Línea 1240: | Línea 1224: | ||
<code z80> | <code z80> | ||
- | ;;;;;; Estilo NORMAL ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | + | |
- | LD B, 8 ; 8 scanlines a dibujar | + | ld b, 8 ; 8 scanlines a dibujar |
drawchar_loop_normal: | drawchar_loop_normal: | ||
- | LD A, (DE) ; Tomamos el dato del caracter | + | ld a, (de) ; Tomamos el dato del caracter |
- | LD (HL), A ; Establecemos el valor en videomemoria | + | |
- | INC DE | + | inc de |
- | INC H | + | inc h |
- | DJNZ drawchar_loop_normal | + | |
- | JR pchar8_printattr | + | |
</ | </ | ||
Línea 1257: | Línea 1241: | ||
<code z80> | <code z80> | ||
- | ;;;;;; Estilo NEGRITA ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | + | |
- | LD B, 8 ; 8 scanlines a dibujar | + | ld b, 8 ; 8 scanlines a dibujar |
drawchar_loop_bold: | drawchar_loop_bold: | ||
- | LD A, (DE) ; Tomamos el dato del caracter | + | ld a, (de) ; Tomamos el dato del caracter |
- | LD C, A ; Creamos copia de A | + | ld c, a ; Creamos copia de A |
- | RRCA ; Desplazamos A | + | |
- | OR C ; Y agregamos C | + | or c ; Y agregamos C |
- | LD (HL), A ; Establecemos el valor en videomemoria | + | |
- | INC DE | + | inc de |
- | INC H | + | inc h |
- | DJNZ drawchar_loop_bold | + | |
- | JR pchar8_printattr | + | |
</ | </ | ||
Línea 1277: | Línea 1261: | ||
<code z80> | <code z80> | ||
- | ;;;;;; Estilo SUBRAYADO ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | + | |
- | LD B, 7 ; 7 scanlines a dibujar normales | + | ld b, 7 ; 7 scanlines a dibujar normales |
drawchar_loop_undersc: | drawchar_loop_undersc: | ||
- | LD A, (DE) ; Tomamos el dato del caracter | + | ld a, (de) ; Tomamos el dato del caracter |
- | LD (HL), A ; Establecemos el valor en videomemoria | + | |
- | INC DE | + | inc de |
- | INC H | + | inc h |
- | DJNZ drawchar_loop_undersc | + | |
- | ;;; El octavo scanline, una linea de subrayado | + | |
- | LD A, 255 ; Ultima linea = subrayado | + | ld a, 255 ; Ultima linea = subrayado |
- | LD (HL), A | + | |
- | INC H ; Necesario para el SUB A, 8 | + | inc h ; Necesario para el sub a, 8 |
- | JR pchar8_printattr | + | |
</ | </ | ||
Línea 1299: | Línea 1283: | ||
<code z80> | <code z80> | ||
- | ;;;;;; Estilo ITALICA ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | + | |
- | | + | ;;; 3 primeros scanlines, a la derecha, |
- | LD B, 3 | + | ld b, 3 |
drawchar_loop_italic1: | drawchar_loop_italic1: | ||
- | LD A, (DE) ; Tomamos el dato del caracter | + | ld a, (de) ; Tomamos el dato del caracter |
- | SRA A ; Desplazamos A a la derecha | + | sra a ; Desplazamos A a la derecha |
- | LD (HL), A ; Establecemos el valor en videomemoria | + | |
- | INC DE | + | inc de |
- | INC H | + | inc h |
- | DJNZ drawchar_loop_italic1 | + | |
- | ;;; 2 siguientes scanlines, sin tocar | + | |
- | LD B, 2 | + | ld b, 2 |
drawchar_loop_italic2: | drawchar_loop_italic2: | ||
- | LD A, (DE) ; Tomamos el dato del caracter | + | ld a, (de) ; Tomamos el dato del caracter |
- | LD (HL), A ; Establecemos el valor en videomemoria | + | |
- | INC DE | + | inc de |
- | INC H | + | inc h |
- | DJNZ drawchar_loop_italic2 | + | |
- | LD B, 3 | + | ld b, 3 |
drawchar_loop_italic3: | drawchar_loop_italic3: | ||
- | ;;; 3 ultimos scanlines, a la izquierda, | + | |
- | LD A, (DE) ; Tomamos el dato del caracter | + | ld a, (de) ; Tomamos el dato del caracter |
- | SLA A ; Desplazamos A | + | sla a ; Desplazamos A |
- | LD (HL), A ; Establecemos el valor en videomemoria | + | |
- | INC DE | + | inc de |
- | INC H | + | inc h |
- | DJNZ drawchar_loop_italic3 | + | |
- | JR pchar8_printattr | + | |
</ | </ | ||
Línea 1351: | Línea 1335: | ||
PrintChar_8x8: | PrintChar_8x8: | ||
- | LD BC, (FONT_X) | + | ld bc, (FONT_X) |
- | EX AF, AF' | + | ex af, af' |
- | ;;; Calculamos las coordenadas destino de pantalla en DE: | + | |
- | LD A, B | + | ld a, b |
- | AND $18 | + | |
- | ADD A, $40 | + | add a, $40 |
- | LD D, A | + | ld d, a |
- | LD A, B | + | ld a, b |
- | AND 7 | + | |
- | RRCA | + | rrca |
- | RRCA | + | rrca |
- | RRCA | + | rrca |
- | ADD A, C | + | add a, c |
- | LD E, A ; DE contiene ahora la direccion destino. | + | ld e, a ; DE contiene ahora la direccion destino. |
- | ;;; Calcular posicion origen (array sprites) en HL como: | + | |
- | | + | ;;; |
- | EX AF, AF' | + | ex af, af' |
- | LD BC, (FONT_CHARSET) | + | ld bc, (FONT_CHARSET) |
- | LD H, 0 | + | ld h, 0 |
- | LD L, A | + | ld l, a |
- | ADD HL, HL | + | add hl, hl |
- | ADD HL, HL | + | add hl, hl |
- | ADD HL, HL | + | add hl, hl |
- | ADD HL, BC ; HL = BC + HL = FONT_CHARSET + (A * 8) | + | add hl, bc ; HL = BC + HL = FONT_CHARSET + (A * 8) |
- | EX DE, HL ; Intercambiamos DE y HL (DE=origen, HL=destino) | + | ex de, hl ; Intercambiamos DE y HL (DE=origen, HL=destino) |
- | ;;; NUEVO: Verificacion del estilo actual | + | |
- | LD A, (FONT_STYLE) | + | ld a, (FONT_STYLE) |
- | OR A | + | or a |
- | JR NZ, pchar8_estilos_on | + | jr nz, pchar8_estilos_on |
- | ;;;;;; Estilo NORMAL ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | + | |
- | LD B, 8 ; 8 scanlines a dibujar | + | ld b, 8 ; 8 scanlines a dibujar |
drawchar_loop_normal: | drawchar_loop_normal: | ||
- | LD A, (DE) ; Tomamos el dato del caracter | + | ld a, (de) ; Tomamos el dato del caracter |
- | LD (HL), A ; Establecemos el valor en videomemoria | + | |
- | INC DE | + | inc de |
- | INC H | + | inc h |
- | DJNZ drawchar_loop_normal | + | |
- | JR pchar8_printattr | + | |
pchar8_estilos_on: | pchar8_estilos_on: | ||
- | | + | cp FONT_BOLD |
- | JR NZ, pchar8_nobold | + | jr nz, pchar8_nobold |
- | ;;;;;; Estilo NEGRITA ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | + | |
- | LD B, 8 ; 8 scanlines a dibujar | + | ld b, 8 ; 8 scanlines a dibujar |
drawchar_loop_bold: | drawchar_loop_bold: | ||
- | LD A, (DE) ; Tomamos el dato del caracter | + | ld a, (de) ; Tomamos el dato del caracter |
- | LD C, A ; Creamos copia de A | + | ld c, a ; Creamos copia de A |
- | RRCA ; Desplazamos A | + | |
- | OR C ; Y agregamos C | + | or c ; Y agregamos C |
- | LD (HL), A ; Establecemos el valor en videomemoria | + | |
- | INC DE ; Incrementamos puntero en caracter | + | inc de ; Incrementamos puntero en caracter |
- | INC H ; Incrementamos puntero en pantalla (scanline+=1) | + | inc h ; Incrementamos puntero en pantalla (scanline+=1) |
- | DJNZ drawchar_loop_bold | + | |
- | JR pchar8_printattr | + | |
pchar8_nobold: | pchar8_nobold: | ||
- | | + | cp FONT_UNDERSC |
- | JR NZ, pchar8_noundersc | + | jr nz, pchar8_noundersc |
- | ;;;;;; Estilo SUBRAYADO ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | + | |
- | LD B, 7 ; 7 scanlines a dibujar normales | + | ld b, 7 ; 7 scanlines a dibujar normales |
drawchar_loop_undersc: | drawchar_loop_undersc: | ||
- | LD A, (DE) ; Tomamos el dato del caracter | + | ld a, (de) ; Tomamos el dato del caracter |
- | LD (HL), A ; Establecemos el valor en videomemoria | + | |
- | INC DE | + | inc de |
- | INC H | + | inc h |
- | DJNZ drawchar_loop_undersc | + | |
- | ;;; El octavo scanline, una linea de subrayado | + | |
- | LD A, 255 ; Ultima linea = subrayado | + | ld a, 255 ; Ultima linea = subrayado |
- | LD (HL), A | + | |
- | INC H ; Necesario para el SUB A, 8 | + | inc h ; Necesario para el sub a, 8 |
- | JR pchar8_printattr | + | |
pchar8_noundersc: | pchar8_noundersc: | ||
- | | + | cp FONT_ITALIC |
- | JR NZ, pchar8_UNKNOWN | + | jr nz, pchar8_UNKNOWN |
- | ;;;;;; Estilo ITALICA ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | + | |
- | | + | ;;; 3 primeros scanlines, a la derecha, |
- | LD B, 3 | + | ld b, 3 |
drawchar_loop_italic1: | drawchar_loop_italic1: | ||
- | LD A, (DE) ; Tomamos el dato del caracter | + | ld a, (de) ; Tomamos el dato del caracter |
- | SRA A ; Desplazamos A a la derecha | + | sra a ; Desplazamos A a la derecha |
- | LD (HL), A ; Establecemos el valor en videomemoria | + | |
- | INC DE | + | inc de |
- | INC H | + | inc h |
- | DJNZ drawchar_loop_italic1 | + | |
- | ;;; 2 siguientes scanlines, sin tocar | + | |
- | LD B, 2 | + | ld b, 2 |
drawchar_loop_italic2: | drawchar_loop_italic2: | ||
- | LD A, (DE) ; Tomamos el dato del caracter | + | ld a, (de) ; Tomamos el dato del caracter |
- | LD (HL), A ; Establecemos el valor en videomemoria | + | |
- | INC DE | + | inc de |
- | INC H | + | inc h |
- | DJNZ drawchar_loop_italic2 | + | |
- | LD B, 3 | + | ld b, 3 |
drawchar_loop_italic3: | drawchar_loop_italic3: | ||
- | ;;; 3 ultimos scanlines, a la izquierda, | + | |
- | LD A, (DE) ; Tomamos el dato del caracter | + | ld a, (de) ; Tomamos el dato del caracter |
- | SLA A ; Desplazamos A | + | sla a ; Desplazamos A |
- | LD (HL), A ; Establecemos el valor en videomemoria | + | |
- | INC DE | + | inc de |
- | INC H | + | inc h |
- | DJNZ drawchar_loop_italic3 | + | |
- | JR pchar8_printattr | + | |
pchar8_UNKNOWN: | pchar8_UNKNOWN: | ||
- | LD B, 8 ; Lo imprimimos con el normal | + | ld b, 8 ; Lo imprimimos con el normal |
- | JR drawchar_loop_normal | + | |
- | ;;; Impresion de los atributos | + | |
pchar8_printattr: | pchar8_printattr: | ||
- | LD A, H ; Recuperamos el valor inicial de HL | + | ld a, h ; Recuperamos el valor inicial de HL |
- | SUB 8 ; Restando los 8 scanlines avanzados | + | |
- | ;;; Calcular posicion destino en area de atributos en DE. | + | |
- | ; A = H | + | ; A = H |
- | RRCA ; Codigo de Get_Attr_Offset_From_Image | + | |
- | RRCA | + | rrca |
- | RRCA | + | rrca |
- | AND 3 | + | |
- | OR $58 | + | |
- | LD D, A | + | ld d, a |
- | LD E, L | + | ld e, l |
- | ;;; Escribir el atributo en memoria | + | |
- | LD A, (FONT_ATTRIB) | + | ld a, (FONT_ATTRIB) |
- | LD (DE), A ; Escribimos el atributo en memoria | + | |
- | RET | + | ret |
</ | </ | ||
- | Si definimos esta función PrintChar_8x8 en nuestro programa, la función PrintString_8x8 hará uso de ella y podremos imprimir cadenas en diferentes estilos, como en el siguiente ejemplo: | + | Si definimos esta función |
<code z80> | <code z80> | ||
; Ejemplo de estilos de fuente | ; Ejemplo de estilos de fuente | ||
- | ORG 35000 | + | |
- | LD HL, $3D00-256 ; Saltamos los 32 caracteres iniciales | + | ld hl, $3d00-256 ; Saltamos los 32 caracteres iniciales |
- | | + | |
- | LD A, 1+(7*8) | + | ld a, 1+(7*8) |
- | | + | |
- | | + | |
- | LD A, FONT_NORMAL | + | ld a, FONT_NORMAL |
- | | + | |
- | LD HL, cadena1 | + | ld hl, cadena1 |
- | LD A, 4 | + | ld a, 4 |
- | | + | |
- | XOR A | + | xor a |
- | | + | |
- | | + | |
- | | + | |
- | LD A, FONT_BOLD | + | ld a, FONT_BOLD |
- | | + | |
- | LD HL, cadena2 | + | ld hl, cadena2 |
- | LD A, 6 | + | ld a, 6 |
- | | + | |
- | XOR A | + | xor a |
- | | + | |
- | | + | |
- | | + | |
- | LD A, FONT_ITALIC | + | ld a, FONT_ITALIC |
- | | + | |
- | LD HL, cadena3 | + | ld hl, cadena3 |
- | LD A, 8 | + | ld a, 8 |
- | | + | |
- | XOR A | + | xor a |
- | | + | |
- | | + | |
- | | + | |
- | LD A, FONT_UNDERSC | + | ld a, FONT_UNDERSC |
- | | + | |
- | LD HL, cadena4 | + | ld hl, cadena4 |
- | LD A, 10 | + | ld a, 10 |
- | | + | |
- | XOR A | + | xor a |
- | | + | |
- | | + | |
loop: | loop: | ||
- | JR loop | + | jr loop |
- | RET | + | ret |
cadena1 DB " | cadena1 DB " | ||
Línea 1554: | Línea 1537: | ||
cadena3 DB " | cadena3 DB " | ||
cadena4 DB " | cadena4 DB " | ||
- | |||
; | ; | ||
- | FONT_CHARSET | + | FONT_CHARSET |
FONT_ATTRIB | FONT_ATTRIB | ||
FONT_STYLE | FONT_STYLE | ||
Línea 1569: | Línea 1551: | ||
FONT_SCRHEIGHT | FONT_SCRHEIGHT | ||
- | END 35000 | + | |
</ | </ | ||
Línea 1578: | Línea 1560: | ||
\\ | \\ | ||
- | La rutina de impresión PrintChar_8x8 es ahora ligeramente más lenta que la original, pero a cambio nos permite diferentes estilos de texto. Para la impresión de texto con estilo normal, sólo le hemos añadido el siguiente código adicional a ejecutar: | + | La rutina de impresión |
<code z80> | <code z80> | ||
- | LD A, (FONT_STYLE) | + | ld a, (FONT_STYLE) |
- | OR A | + | or a |
- | JR NZ, pchar8_estilos_on | + | jr nz, pchar8_estilos_on |
- | + | + | |
- | | + | jr pchar8_printattr |
</ | </ | ||
- | Son 13 (LD) + 4 (OR) + 7 (JR NZ sin salto) + 12 (JR) = 36 t-estados adicionales por carácter en estilo normal a cambio de la posibilidad de disponer de 4 estilos de texto diferentes para cualquier charset, incluído el de la ROM. | + | Son 13 ('' |
En la rutina se han utilizado operaciones de transferencia LD para imprimir los caracteres, lo que implica que no se respeta el fondo sobre el que se imprime, y se ponen a cero en pantalla todos los píxeles a cero en el charset. Este suele ser el sistema de impresión habitual puesto que el texto, para hacerlo legible, suele imprimirse sobre áreas en blanco de la pantalla, y un caracter impreso sobre otro debe sobreescribir totalmente al primero. | En la rutina se han utilizado operaciones de transferencia LD para imprimir los caracteres, lo que implica que no se respeta el fondo sobre el que se imprime, y se ponen a cero en pantalla todos los píxeles a cero en el charset. Este suele ser el sistema de impresión habitual puesto que el texto, para hacerlo legible, suele imprimirse sobre áreas en blanco de la pantalla, y un caracter impreso sobre otro debe sobreescribir totalmente al primero. | ||
- | No obstante, la rutina PrintChar_8x8 puede ser modificada por el lector, para utilizar operaciones OR en la transferencia a pantalla y por tanto respetar el contenido de pantalla al imprimir el carácter. | + | No obstante, la rutina |
Línea 1608: | Línea 1590: | ||
\\ | \\ | ||
- | El siguiente paso en la escala de la gestión del texto sería la **impresión de cadenas con formato** para que aproveche nuestras nuevas funciones extendidas. Para esto modificaremos la rutina PrinString_8x8 vista al principio del capítulo de forma que haga uso no sólo de FONT_X y FONT_Y sino también de funciones adicionales que especificaremos en la cadena mediante códigos de control o //tokens//. | + | El siguiente paso en la escala de la gestión del texto sería la **impresión de cadenas con formato** para que aproveche nuestras nuevas funciones extendidas. Para esto modificaremos la rutina |
Los códigos de control que vamos a definir y utilizar serán los siguientes: | Los códigos de control que vamos a definir y utilizar serán los siguientes: | ||
Línea 1664: | Línea 1646: | ||
La rutina de impresión de cadenas deberá interpretar cada byte de la misma determinando: | La rutina de impresión de cadenas deberá interpretar cada byte de la misma determinando: | ||
- | * Si es un código ASCII >= 32 -> Imprimir el caracter en FONT_X, FONT_Y (y variar las coordenadas). | + | * Si es un código ASCII >= 32 -> Imprimir el caracter en '' |
- | * Si es un código de control 0 (EOS) -> Fin de la rutina | + | * Si es un código de control 0 ('' |
* Si es un código entre el 1 y el 9 -> Recoger parámetro en cadena (siguiente byte) y llamar a la función apropiada. | * Si es un código entre el 1 y el 9 -> Recoger parámetro en cadena (siguiente byte) y llamar a la función apropiada. | ||
* Si es un código entre el 10 y el 31 -> Llamar a la función apropiada (no hay parámetro). | * Si es un código entre el 10 y el 31 -> Llamar a la función apropiada (no hay parámetro). | ||
Línea 1671: | Línea 1653: | ||
Esto nos permitirá trabajar con cadenas de texto con múltiples formatos sin tener que realizar el posicionamiento, | Esto nos permitirá trabajar con cadenas de texto con múltiples formatos sin tener que realizar el posicionamiento, | ||
- | | + | |
< | < | ||
Línea 1685: | Línea 1667: | ||
;;; Avanzar el puntero FONT_X | ;;; Avanzar el puntero FONT_X | ||
;;; Si HL es menor que 31 : | ;;; Si HL es menor que 31 : | ||
- | ;;; Si es CERO, salir de la rutina con RET Z. | + | ;;; Si es CERO, salir de la rutina con ret z. |
;;; Si es FONT_SET_SETSTYLE (1): | ;;; Si es FONT_SET_SETSTYLE (1): | ||
;;; Coger el siguiente byte de la cadena (el estilo) | ;;; Coger el siguiente byte de la cadena (el estilo) | ||
Línea 1702: | Línea 1684: | ||
;;; Si es FONT_TAB (15): | ;;; Si es FONT_TAB (15): | ||
;;; Llamar a funcion Font_Tab | ;;; Llamar a funcion Font_Tab | ||
- | ;;; Saltar a bucle (se saldrá con el RET Z) | + | ;;; Saltar a bucle (se saldrá con el ret z) |
</ | </ | ||
Línea 1714: | Línea 1696: | ||
; | ; | ||
FONT_CALL_JUMP_TABLE: | FONT_CALL_JUMP_TABLE: | ||
- | | + | |
- | DW Font_Set_Paper, | + | DW Font_Set_Paper, |
- | DW Font_Set_Flash, | + | DW Font_Set_Flash, |
- | DW Font_CR, Font_Backspace, | + | DW Font_CR, Font_Backspace, |
</ | </ | ||
Línea 1725: | Línea 1707: | ||
PrintString_8x8_Format: | PrintString_8x8_Format: | ||
bucle: | bucle: | ||
- | ;;; Coger caracter | + | ;;; Coger caracter |
;;; Incrementar HL | ;;; Incrementar HL | ||
;;; Si HL es mayor que 32 : | ;;; Si HL es mayor que 32 : | ||
Línea 1731: | Línea 1713: | ||
;;; Avanzar el puntero FONT_X | ;;; Avanzar el puntero FONT_X | ||
;;; Si HL es menor que 31 : | ;;; Si HL es menor que 31 : | ||
- | ;;; Si es CERO, salir de la rutina con RET Z. | + | ;;; Si es CERO, salir de la rutina con ret z. |
;;; Calculamos DIR_SALTO = TABLA_SALTOS [ COD_CONTROL ] | ;;; Calculamos DIR_SALTO = TABLA_SALTOS [ COD_CONTROL ] | ||
;;; Como la tabla es de 2 bytes -> DIR_SALTO = TABLA_SALTOS + COD_CONTROL*2 | ;;; Como la tabla es de 2 bytes -> DIR_SALTO = TABLA_SALTOS + COD_CONTROL*2 | ||
Línea 1738: | Línea 1720: | ||
;;; Si es mayor que 10, no requiere recoger parametro | ;;; Si es mayor que 10, no requiere recoger parametro | ||
;;; Saltar a la dirección DIR_SALTO | ;;; Saltar a la dirección DIR_SALTO | ||
- | ;;; Saltar a bucle (se saldrá con el RET Z) | + | ;;; Saltar a bucle (se saldrá con el ret z) |
</ | </ | ||
Línea 1749: | Línea 1731: | ||
; | ; | ||
FONT_CALL_JUMP_TABLE: | FONT_CALL_JUMP_TABLE: | ||
- | | + | |
- | DW Font_Set_Paper, | + | DW Font_Set_Paper, |
- | DW Font_Set_Flash, | + | DW Font_Set_Flash, |
- | DW Font_CR, Font_Backspace, | + | DW Font_CR, Font_Backspace, |
Línea 1771: | Línea 1753: | ||
PrintString_8x8_Format: | PrintString_8x8_Format: | ||
- | ;;; Bucle de impresion de caracter | + | |
pstring8_loop: | pstring8_loop: | ||
- | LD A, (HL) ; Leemos un caracter de la cadena | + | ld a, (hl) ; Leemos un caracter de la cadena |
- | INC HL ; Apuntamos al siguiente caracter | + | inc hl ; Apuntamos al siguiente caracter |
- | | + | cp 32 ; Es menor que 32? |
- | JP C, pstring8_ccontrol | + | jp c, pstring8_ccontrol |
- | PUSH HL ; Salvaguardamos HL | + | push hl ; Salvaguardamos HL |
- | CALL PrintChar_8x8 | + | |
- | POP HL ; Recuperamos HL | + | pop hl ; Recuperamos HL |
- | ;;; Avanzamos el cursor usando Font_Blank, que incrementa X | + | |
- | | + | ;;; y actualiza X e Y si se llega al borde de la pantalla |
- | CALL Font_Inc_X | + | |
- | JR pstring8_loop | + | |
pstring8_ccontrol: | pstring8_ccontrol: | ||
- | OR A ; A es cero? | + | or a ; A es cero? |
- | RET Z ; Si es 0 (fin de cadena) volver | + | ret z ; Si es 0 (fin de cadena) volver |
- | ;;; Si estamos aqui es porque es un codigo de control distinto > 0 | + | |
- | | + | ;;; Ahora debemos calcular la direccion de la rutina que lo atendera. |
- | ;;; Calculamos la direccion destino a la que saltar usando | + | |
- | | + | ;;; la tabla de saltos y el codigo de control como indice |
- | EX DE, HL | + | ex de, hl |
- | LD HL, FONT_CALL_JUMP_TABLE | + | ld hl, FONT_CALL_JUMP_TABLE |
- | RLCA ; A = A * 2 = codigo de control * 2 | + | |
- | LD C, A | + | ld c, a |
- | LD B, 0 ; BC = A*2 | + | ld b, 0 ; BC = A*2 |
- | ADD HL, BC ; HL = DIR FONT_CALL_JUMP_TABLE+(CodControl*2) | + | add hl, bc ; HL = DIR FONT_CALL_JUMP_TABLE+(CodControl*2) |
- | LD C, (HL) ; Leemos la parte baja de la direccion en C... | + | ld c, (hl) ; Leemos la parte baja de la direccion en C... |
- | INC HL ; ... para no corromper HL y poder leer ... | + | inc hl ; ... para no corromper HL y poder leer ... |
- | LD H, (HL) ; ... la parte alta sobre H ... | + | ld h, (hl) ; ... la parte alta sobre H ... |
- | LD L, C ; No hemos usado A porque se usa en el CP | + | ld l, c ; No hemos usado A porque se usa en el CP |
- | ;;; Si CCONTROL> | + | |
- | | + | ;;; Si CCONTROL> |
- | CP 18 ; Comprobamos si (CCONTROL-1)*2 < 18 | + | |
- | JP NC, pstring8_noparam | + | jp nc, pstring8_noparam |
- | ;;; Si CCONTROL < 10 -> recoger parametro: | + | |
- | LD A, (DE) ; Cogemos el parametro en cuestion de la cadena | + | ld a, (de) ; Cogemos el parametro en cuestion de la cadena |
- | INC DE ; Apuntamos al siguiente caracter | + | inc de ; Apuntamos al siguiente caracter |
- | ;;; Realizamos el salto a la rutina con o sin parametro recogido | + | |
pstring8_noparam: | pstring8_noparam: | ||
- | LD BC, pstring8_retaddr | + | ld bc, pstring8_retaddr |
- | PUSH BC ; Hacemos un push de la dir de retorno | + | push bc ; Hacemos un push de la dir de retorno |
- | JP (HL) ; Saltamos a la rutina seleccionada | + | |
- | ;;; Este es el punto al que volvemos tras la rutina | + | |
pstring8_retaddr: | pstring8_retaddr: | ||
- | EX DE, HL ; Recuperamos en HL el puntero a cadena | + | ex de, hl ; Recuperamos en HL el puntero a cadena |
- | JR pstring8_loop | + | |
</ | </ | ||
- | El esqueleto de la rutina y la parte de impresión ya la conocemos, porque es idéntica a PrintString_8x8. El principal añadido es la interpretación de los códigos de control, donde la parte más interesante es la construcción y uso de la tabla de saltos: | + | El esqueleto de la rutina y la parte de impresión ya la conocemos, porque es idéntica a '' |
- | Una vez ubicadas todas las diferentes direcciones de las rutinas en FONT_CALL_JUMP_TABLE, | + | Una vez ubicadas todas las diferentes direcciones de las rutinas en '' |
<code z80> | <code z80> | ||
- | ;;; Calculamos la direccion destino a la que saltar usando | + | |
- | | + | ;;; la tabla de saltos y el codigo de control como indice |
- | EX DE, HL | + | ex de, hl |
- | LD HL, FONT_CALL_JUMP_TABLE | + | ld hl, FONT_CALL_JUMP_TABLE |
- | RLCA ; A = A * 2 = codigo de control * 2 | + | |
- | LD C, A | + | ld c, a |
- | LD B, 0 ; BC = A*2 | + | ld b, 0 ; BC = A*2 |
- | ADD HL, BC ; HL = DIR FONT_CALL_JUMP_TABLE+(CodControl*2) | + | add hl, bc ; HL = DIR FONT_CALL_JUMP_TABLE+(CodControl*2) |
- | LD C, (HL) ; Leemos la parte baja de la direccion en C... | + | ld c, (hl) ; Leemos la parte baja de la direccion en C... |
- | INC HL ; ... para no corromper HL y poder leer ... | + | inc hl ; ... para no corromper HL y poder leer ... |
- | LD H, (HL) ; ... la parte alta sobre H ... | + | ld h, (hl) ; ... la parte alta sobre H ... |
- | LD L, C ; No hemos usado A porque se usa en el CP | + | ld l, c ; No hemos usado A porque se usa en el CP |
- | | + | ; HL = FONT_CALL_JUMP_TABLE+(CodControl*2) |
- | ; (...) ; Codigo de recogida de parametro si procede | + | |
- | LD BC, pstring8_retaddr | + | ld bc, pstring8_retaddr |
- | PUSH BC ; Hacemos un push de la dir de retorno | + | push bc ; Hacemos un push de la dir de retorno |
- | JP (HL) ; Saltamos a la rutina seleccionada | + | |
- | ;;; Este es el punto al que volvemos tras la rutina | + | |
pstring8_retaddr: | pstring8_retaddr: | ||
</ | </ | ||
- | Con el anterior cálculo, por ejemplo, si recibimos un código de control 6, se pondrá en HL la dirección de memoria contenida en FONT_CALL_JUMP_TABLE+(6*2), | + | Con el anterior cálculo, por ejemplo, si recibimos un código de control 6, se pondrá en HL la dirección de memoria contenida en FONT_CALL_JUMP_TABLE+(6*2), |
- | | + | |
- | En el código anterior introducimos en el registro BC la dirección de la etiqueta | + | En el código anterior introducimos en el registro BC la dirección de la etiqueta |
Hemos hecho distinción de 2 tipos de subrutinas de control, ya que las 9 primeras requieren recoger un parámetro de la cadena (apuntado por HL) y las restantes no. El cálculo de la dirección de salto es igual en todos los casos pero para las 9 primeras es necesario obtener el dato adicional al código de control en el registro A antes de saltar. El registro A es el parámetro común en todas las subrutinas de gestión de códigos de control que requieren parámetros, | Hemos hecho distinción de 2 tipos de subrutinas de control, ya que las 9 primeras requieren recoger un parámetro de la cadena (apuntado por HL) y las restantes no. El cálculo de la dirección de salto es igual en todos los casos pero para las 9 primeras es necesario obtener el dato adicional al código de control en el registro A antes de saltar. El registro A es el parámetro común en todas las subrutinas de gestión de códigos de control que requieren parámetros, | ||
Línea 1871: | Línea 1853: | ||
<code z80> | <code z80> | ||
- | ;;; Si CCONTROL> | + | |
- | | + | ;;; Si CCONTROL> |
- | CP 18 ; Comprobamos si (CCONTROL-1)*2 < 18 | + | |
- | JP NC, pstring8_noparam | + | jp nc, pstring8_noparam |
</ | </ | ||
En lugar de volver a dividir el código de control entre 2 (recordemos que se multiplicó por 2 para el cálculo de la dirección de salto) y comprobar si es > 9, podemos comprobar directamente si es > 9*2 = 18. | En lugar de volver a dividir el código de control entre 2 (recordemos que se multiplicó por 2 para el cálculo de la dirección de salto) y comprobar si es > 9, podemos comprobar directamente si es > 9*2 = 18. | ||
- | Tras interpretar el código de control, bastará con volver a saltar al principio de la rutina para continuar con el siguiente carácter. Todo el proceso se repetirá hasta recibir en A un código de control 0 (FONT_EOS, de FONT_END_OF_STRING). | + | Tras interpretar el código de control, bastará con volver a saltar al principio de la rutina para continuar con el siguiente carácter. Todo el proceso se repetirá hasta recibir en A un código de control 0 ('' |
Una vez explicada la rutina, veamos un ejemplo de cómo podríamos utilizarla en nuestros programas: | Una vez explicada la rutina, veamos un ejemplo de cómo podríamos utilizarla en nuestros programas: | ||
Línea 1885: | Línea 1867: | ||
<code z80> | <code z80> | ||
; Ejemplo de gestion de texto | ; Ejemplo de gestion de texto | ||
- | ORG 35000 | + | |
- | LD HL, $3D00-256 ; Saltamos los 32 caracteres iniciales | + | ld hl, $3d00-256 ; Saltamos los 32 caracteres iniciales |
- | | + | |
- | LD A, 1+(7*8) | + | ld a, 1+(7*8) |
- | Call Font_Set_Attrib | + | Call Font_Set_Attrib |
- | | + | |
- | LD A, FONT_NORMAL | + | ld a, FONT_NORMAL |
- | | + | |
- | LD HL, cadena1 | + | ld hl, cadena1 |
- | LD B, 4 | + | ld b, 4 |
- | LD C, 0 | + | ld c, 0 |
- | | + | |
- | | + | |
loop: | loop: | ||
- | JR loop | + | jr loop |
cadena1 DB "SALTO DE", FONT_LF, "LINEA ", FONT_SET_X, 4, FONT_SET_Y, 9 | cadena1 DB "SALTO DE", FONT_LF, "LINEA ", FONT_SET_X, 4, FONT_SET_Y, 9 | ||
Línea 1915: | Línea 1897: | ||
DB FONT_EOS | DB FONT_EOS | ||
- | END 35000 | + | |
</ | </ | ||
Línea 1921: | Línea 1903: | ||
\\ | \\ | ||
- | {{ : | + | {{ : |
\\ | \\ | ||
Línea 1930: | Línea 1912: | ||
| | ||
- | | + | |
En cuanto a las diferencias en tiempo de ejecución de PrintString_8x8_Format vs PrintString_8x8, | En cuanto a las diferencias en tiempo de ejecución de PrintString_8x8_Format vs PrintString_8x8, | ||
<code z80> | <code z80> | ||
- | | + | cp 32 ; Es menor que 32? |
- | JP C, pstring8_ccontrol | + | jp c, pstring8_ccontrol |
</ | </ | ||
- | | + | |
- | En el caso del código de fin de cadena (EOS = 0), ya no se sale de la rutina con un RET Z sino que se pasa por el **CP 32** y se realiza el salto a //pstring8_ccontrol//. | + | En el caso del código de fin de cadena (EOS = 0), ya no se sale de la rutina con un ret z sino que se pasa por el '' |
- | Sí que hay un coste real en la ocupación de memoria, puesto que todas las funciones auxiliares de control que hemos definido seguramente pueden no resultarnos útiles en la programación de un juego donde no se utilice apenas texto. Ese código adicional sumado a la gestión de códigos de control de la rutina y a la tabla de saltos puede ser espacio utilizable por nosotros si empleados la rutina sin formato | + | Sí que hay un coste real en la ocupación de memoria, puesto que todas las funciones auxiliares de control que hemos definido seguramente pueden no resultarnos útiles en la programación de un juego donde no se utilice apenas texto. Ese código adicional sumado a la gestión de códigos de control de la rutina y a la tabla de saltos puede ser espacio utilizable por nosotros si empleados la rutina sin formato |
Donde no hay duda de la gran utilidad de las anteriores rutinas es en cualquier juego basado en texto, donde nos evitamos realizar el formato de los textos en base a programación y llamadas continuadas a las funciones de formato, posicionamiento, | Donde no hay duda de la gran utilidad de las anteriores rutinas es en cualquier juego basado en texto, donde nos evitamos realizar el formato de los textos en base a programación y llamadas continuadas a las funciones de formato, posicionamiento, | ||
Línea 1950: | Línea 1932: | ||
==== Impresión avanzada: datos variables ==== | ==== Impresión avanzada: datos variables ==== | ||
- | | + | |
<code c> | <code c> | ||
Línea 1956: | Línea 1938: | ||
</ | </ | ||
- | Para eso vamos a crear una nueva rutina | + | Para eso vamos a crear una nueva rutina |
Los nuevos códigos de control imitarán el formato de C (símbolo de % seguido de un identificador del tipo de variable) y podrán estar así integrados dentro del propio texto: | Los nuevos códigos de control imitarán el formato de C (símbolo de % seguido de un identificador del tipo de variable) y podrán estar así integrados dentro del propio texto: | ||
Línea 1986: | Línea 1968: | ||
| | ||
- | | + | |
- | La rutina es similar a PrintString_8x8_Format, | + | La rutina es similar a '' |
< | < | ||
Línea 2005: | Línea 1987: | ||
;;; Avanzar el puntero FONT_X | ;;; Avanzar el puntero FONT_X | ||
;;; Si HL es menor que 31 : | ;;; Si HL es menor que 31 : | ||
- | ;;; Si es CERO, salir de la rutina con RET Z. | + | ;;; Si es CERO, salir de la rutina con ret z. |
(...) | (...) | ||
Línea 2024: | Línea 2006: | ||
<code z80> | <code z80> | ||
loop: | loop: | ||
- | LD A, (HL) ; Leemos un caracter de la cadena | + | ld a, (hl) ; Leemos un caracter de la cadena |
- | ;;; (...) | + | |
- | | + | cp ' |
- | JR NZ, pstring8_novar | + | jr nz, pstring8_novar |
- | LD A, (HL) ; Cogemos en A el siguiente char | + | ld a, (hl) ; Cogemos en A el siguiente char |
- | INC HL | + | inc hl |
- | CP ' | + | |
- | JR NZ, pstring8v_var | + | jr nz, pstring8v_var |
- | | + | ; Si, era %, seguir para imprimirlo |
(...) | (...) | ||
- | ;;; Aqui se gestionan los codigos de control con % (tipo = A) | + | |
pstring8v_var: | pstring8v_var: | ||
- | ;;; comprobamos los tipos y saltamos a sus rutinas de gestion | + | |
- | CP ' | + | |
- | JR Z, pstring8v_int8 | + | jr z, pstring8v_int8 |
- | CP ' | + | |
- | JR Z, pstring8v_int8_2d | + | jr z, pstring8v_int8_2d |
- | CP ' | + | |
- | JR Z, pstring8v_int16 | + | jr z, pstring8v_int16 |
- | CP ' | + | |
- | JR Z, pstring8v_string | + | jr z, pstring8v_string |
- | CP ' | + | |
- | JR Z, pstring8v_hex8 | + | jr z, pstring8v_hex8 |
- | CP ' | + | |
- | JR Z, pstring8v_hex16 | + | jr z, pstring8v_hex16 |
- | CP ' | + | |
- | JP Z, pstring8v_bin8 | + | jp z, pstring8v_bin8 |
- | CP ' | + | |
- | JP Z, pstring8v_bin16 | + | jp z, pstring8v_bin16 |
- | JP pstring8_novar | + | |
</ | </ | ||
Línea 2061: | Línea 2043: | ||
<code z80> | <code z80> | ||
- | | + | cp ' |
- | JR Z, pstring8v_int8 | + | jr z, pstring8v_int8 |
(...) | (...) | ||
pstring8v_int8: | pstring8v_int8: | ||
- | PUSH HL | + | push hl |
- | LD L, (IX+0) | + | ld l, (ix+0) |
- | INC IX | + | inc ix |
- | CALL Int2String_8 | + | |
- | LD HL, conv2string | + | ld hl, conv2string |
- | CALL INC_HL_Remove_Leading_Zeros | + | |
- | CALL PrintString_8x8 | + | |
- | POP HL | + | pop hl |
- | JP pstring8v_loop | + | |
</ | </ | ||
Línea 2098: | Línea 2080: | ||
PrintString_8x8_Format_Args: | PrintString_8x8_Format_Args: | ||
- | ;;; Bucle de impresion de caracter | + | |
pstring8v_loop: | pstring8v_loop: | ||
- | LD A, (HL) ; Leemos un caracter de la cadena | + | ld a, (hl) ; Leemos un caracter de la cadena |
- | INC HL ; Apuntamos al siguiente caracter | + | inc hl ; Apuntamos al siguiente caracter |
- | | + | cp 32 ; Es menor que 32? |
- | JP C, pstring8v_ccontrol | + | jp c, pstring8v_ccontrol |
- | | + | cp ' |
- | JR NZ, pstring8_novar | + | jr nz, pstring8_novar |
- | LD A, (HL) ; Cogemos en A el siguiente char | + | ld a, (hl) ; Cogemos en A el siguiente char |
- | INC HL | + | inc hl |
- | CP ' | + | |
- | JR NZ, pstring8v_var | + | jr nz, pstring8v_var |
- | | + | ; Si, era %, seguir para imprimirlo |
pstring8_novar: | pstring8_novar: | ||
- | PUSH HL ; Salvaguardamos HL | + | push hl ; Salvaguardamos HL |
- | CALL PrintChar_8x8 | + | |
- | POP HL ; Recuperamos HL | + | pop hl ; Recuperamos HL |
- | ;;; Avanzamos el cursor usando Font_Blank, que incrementa X | + | |
- | | + | ;;; y actualiza X e Y si se llega al borde de la pantalla |
- | CALL Font_Inc_X | + | |
- | JR pstring8v_loop | + | |
pstring8v_ccontrol: | pstring8v_ccontrol: | ||
- | OR A ; A es cero? | + | or a ; A es cero? |
- | RET Z ; Si es 0 (fin de cadena) volver | + | ret z ; Si es 0 (fin de cadena) volver |
- | ;;; Si estamos aqui es porque es un codigo de control distinto > 0 | + | |
- | | + | ;;; Ahora debemos calcular la direccion de la rutina que lo atendera. |
- | ;;; Calculamos la direccion destino a la que saltar usando | + | |
- | | + | ;;; la tabla de saltos y el codigo de control como indice |
- | EX DE, HL | + | ex de, hl |
- | LD HL, FONT_CALL_JUMP_TABLE | + | ld hl, FONT_CALL_JUMP_TABLE |
- | DEC A ; Decrementamos A (puntero en tabla) | + | dec a ; Decrementamos A (puntero en tabla) |
- | RLCA ; A = A * 2 = codigo de control * 2 | + | |
- | LD C, A | + | ld c, a |
- | LD B, 0 ; BC = A*2 | + | ld b, 0 ; BC = A*2 |
- | ADD HL, BC ; HL = DIR FONT_CALL_JUMP_TABLE+(CodControl*2) | + | add hl, bc ; HL = DIR FONT_CALL_JUMP_TABLE+(CodControl*2) |
- | LD C, (HL) | + | ld c, (hl) |
- | INC HL | + | inc hl |
- | LD H, (HL) | + | ld h, (hl) |
- | LD L, C ; Leemos la direccion de la tabla en HL | + | ld l, c ; Leemos la direccion de la tabla en HL |
- | ;;; Si CCONTROL> | + | |
- | | + | ;;; Si CCONTROL> |
- | CP 18 ; Comprobamos si (CCONTROL-1)*2 < 18 | + | |
- | JP NC, pstring8v_noparam | + | jp nc, pstring8v_noparam |
- | ;;; Si CCONTROL < 10 -> recoger parametro: | + | |
- | LD A, (DE) ; Cogemos el parametro en cuestion de la cadena | + | ld a, (de) ; Cogemos el parametro en cuestion de la cadena |
- | INC DE ; Apuntamos al siguiente caracter | + | inc de ; Apuntamos al siguiente caracter |
- | ;;; Realizamos el salto a la rutina con o sin parametro recogido | + | |
pstring8v_noparam: | pstring8v_noparam: | ||
- | LD BC, pstring8v_retaddr | + | ld bc, pstring8v_retaddr |
- | PUSH BC ; Hacemos un push de la dir de retorno | + | push bc ; Hacemos un push de la dir de retorno |
- | JP (HL) ; Saltamos a la rutina seleccionada | + | |
- | ;;; Este es el punto al que volvemos tras la rutina | + | |
pstring8v_retaddr: | pstring8v_retaddr: | ||
- | EX DE, HL ; Recuperamos en HL el puntero a cadena | + | ex de, hl ; Recuperamos en HL el puntero a cadena |
- | JR pstring8v_loop | + | |
- | ;;; Aqui se gestionan los codigos de control con % (tipo = A) | + | |
pstring8v_var: | pstring8v_var: | ||
- | ;;; comprobamos los tipos y saltamos a sus rutinas de gestion | + | |
- | CP ' | + | |
- | JR Z, pstring8v_int8 | + | jr z, pstring8v_int8 |
- | CP ' | + | |
- | JR Z, pstring8v_int8_2d | + | jr z, pstring8v_int8_2d |
- | CP ' | + | |
- | JR Z, pstring8v_int16 | + | jr z, pstring8v_int16 |
- | CP ' | + | |
- | JR Z, pstring8v_string | + | jr z, pstring8v_string |
- | CP ' | + | |
- | JR Z, pstring8v_hex8 | + | jr z, pstring8v_hex8 |
- | CP ' | + | |
- | JP Z, pstring8v_hex16 | + | jp z, pstring8v_hex16 |
- | CP ' | + | |
- | JP Z, pstring8v_bin8 | + | jp z, pstring8v_bin8 |
- | CP ' | + | |
- | JP Z, pstring8v_bin16 | + | jp z, pstring8v_bin16 |
- | JP pstring8_novar | + | |
; | ; | ||
pstring8v_int8: | pstring8v_int8: | ||
- | PUSH HL | + | push hl |
- | LD L, (IX+0) | + | ld l, (ix+0) |
- | INC IX | + | inc ix |
- | CALL Int2String_8 | + | |
- | LD HL, conv2string | + | ld hl, conv2string |
- | CALL INC_HL_Remove_Leading_Zeros | + | |
- | CALL PrintString_8x8 | + | |
- | POP HL | + | pop hl |
- | JP pstring8v_loop | + | |
; | ; | ||
pstring8v_int8_2d: | pstring8v_int8_2d: | ||
- | PUSH HL | + | push hl |
- | LD A, (IX+0) | + | ld a, (ix+0) |
- | INC IX | + | inc ix |
- | CALL Int2String_8_2Digits | + | |
- | LD A, D ; Resultado conversion en DE | + | ld a, d ; Resultado conversion en DE |
- | PUSH DE | + | push de |
- | CALL PrintChar_8x8 | + | |
- | CALL Font_Inc_X | + | |
- | POP DE | + | pop de |
- | LD A, E | + | ld a, e |
- | CALL PrintChar_8x8 | + | |
- | CALL Font_Inc_X | + | |
- | POP HL | + | pop hl |
- | JP pstring8v_loop | + | |
; | ; | ||
pstring8v_int16: | pstring8v_int16: | ||
- | PUSH HL | + | push hl |
- | LD L, (IX+0) | + | ld l, (ix+0) |
- | INC IX | + | inc ix |
- | LD H, (IX+0) | + | ld h, (ix+0) |
- | INC IX | + | inc ix |
- | CALL Int2String_16 | + | |
- | LD HL, conv2string | + | ld hl, conv2string |
- | CALL INC_HL_Remove_Leading_Zeros | + | |
- | CALL PrintString_8x8 | + | |
- | POP HL | + | pop hl |
- | JP pstring8v_loop | + | |
; | ; | ||
pstring8v_string: | pstring8v_string: | ||
- | PUSH HL | + | push hl |
- | PUSH IX ; HL = IX | + | push ix ; HL = IX |
- | POP HL | + | pop hl |
- | | + | call PrintString_8x8 |
- | POP HL | + | pop hl |
- | pstring8v_strloop: | + | pstring8v_strloop: |
- | LD A, (IX+0) ; de la cadena, recorriendola | + | ld a, (ix+0) ; de la cadena, recorriendola |
- | INC IX ; hasta (IX) = 0 | + | inc ix ; hasta (IX) = 0 |
- | OR A | + | or a |
- | JR NZ, pstring8v_strloop | + | jr nz, pstring8v_strloop |
- | ; De esta forma IX ya apunta al siguiente argumento | + | |
- | JP pstring8v_loop | + | |
; | ; | ||
pstring8v_hex8: | pstring8v_hex8: | ||
- | PUSH HL | + | push hl |
- | LD L, (IX+0) | + | ld l, (ix+0) |
- | INC IX | + | inc ix |
- | LD L, 40 | + | ld l, 40 |
- | CALL Hex2String_8 | + | |
- | LD HL, conv2string | + | ld hl, conv2string |
- | CALL PrintString_8x8 | + | |
- | POP HL | + | pop hl |
- | JP pstring8v_loop | + | |
; | ; | ||
pstring8v_hex16: | pstring8v_hex16: | ||
- | PUSH HL | + | push hl |
- | LD L, (IX+0) | + | ld l, (ix+0) |
- | INC IX | + | inc ix |
- | LD H, (IX+0) | + | ld h, (ix+0) |
- | INC IX | + | inc ix |
- | CALL Hex2String_16 | + | |
- | LD HL, conv2string | + | ld hl, conv2string |
- | CALL PrintString_8x8 | + | |
- | POP HL | + | pop hl |
- | JP pstring8v_loop | + | |
; | ; | ||
pstring8v_bin8: | pstring8v_bin8: | ||
- | PUSH HL | + | push hl |
- | LD L, (IX+0) | + | ld l, (ix+0) |
- | INC IX | + | inc ix |
- | CALL Bin2String_8 | + | |
- | LD HL, conv2string | + | ld hl, conv2string |
- | CALL PrintString_8x8 | + | |
- | POP HL | + | pop hl |
- | JP pstring8v_loop | + | |
; | ; | ||
pstring8v_bin16: | pstring8v_bin16: | ||
- | PUSH HL | + | push hl |
- | LD L, (IX+0) | + | ld l, (ix+0) |
- | INC IX | + | inc ix |
- | LD H, (IX+0) | + | ld h, (ix+0) |
- | INC IX | + | inc ix |
- | CALL Bin2String_16 | + | |
- | LD HL, conv2string | + | ld hl, conv2string |
- | CALL PrintString_8x8 | + | |
- | POP HL | + | pop hl |
- | JP pstring8v_loop | + | |
</ | </ | ||
Línea 2299: | Línea 2281: | ||
<code z80> | <code z80> | ||
; Ejemplo de impresion de texto con argumentos | ; Ejemplo de impresion de texto con argumentos | ||
- | ORG 35000 | + | |
- | LD HL, $3D00-256 | + | ld hl, $3d00-256 |
- | | + | |
- | LD BC, $0400 | + | ld bc, $0400 |
- | | + | |
- | LD HL, cadena1 | + | ld hl, cadena1 |
- | LD IX, args1 | + | ld ix, args1 |
- | | + | |
- | LD HL, cadena2 | + | ld hl, cadena2 |
- | LD IX, args2 | + | ld ix, args2 |
- | | + | |
loop: | loop: | ||
- | JR loop | + | jr loop |
- | RET | + | ret |
- | cadena1 DB "VALOR 8 bits: 40", FONT_CRLF, FONT_CRLF | + | cadena1 DB "Valor 8 bits: 40", FONT_CRLF, FONT_CRLF |
DB " | DB " | ||
DB " | DB " | ||
DB " | DB " | ||
DB FONT_CRLF, FONT_CRLF | DB FONT_CRLF, FONT_CRLF | ||
- | DB "VALOR 16 bits: 1205", FONT_CRLF, FONT_CRLF | + | DB "Valor 16 bits: 1205", FONT_CRLF, FONT_CRLF |
DB " | DB " | ||
DB " | DB " | ||
Línea 2339: | Línea 2321: | ||
args2 DB 2, "cad 1", FONT_EOS, "cad 2", FONT_EOS | args2 DB 2, "cad 1", FONT_EOS, "cad 2", FONT_EOS | ||
- | END 35000 | + | |
</ | </ | ||
\\ | \\ | ||
- | {{ : | + | {{ : |
\\ | \\ | ||
Línea 2349: | Línea 2331: | ||
<code z80> | <code z80> | ||
- | LD HL, cadvidas | + | ld hl, cadvidas |
- | LD IX, vidas ; Variable de argumentos | + | ld ix, vidas ; Variable de argumentos |
- | | + | |
(...) | (...) | ||
Línea 2359: | Línea 2341: | ||
</ | </ | ||
- | Sí que hay que ser especialmente cuidadoso a la hora de definir los parámetros en la variable que apuntamos con IX: es importante que cada parámetro tenga su tamaño adecuado (DB, DW), y que no le falten los End Of String (0) a las cadenas. | + | Sí que hay que ser especialmente cuidadoso a la hora de definir los parámetros en la variable que apuntamos con IX: es importante que cada parámetro tenga su tamaño adecuado ('' |
| | ||
Línea 2382: | Línea 2364: | ||
\\ | \\ | ||
- | A continuación realizamos las modificaciones adecuadas a la rutina PrintString_8x8_Format_Args: | + | A continuación realizamos las modificaciones adecuadas a la rutina |
<code z80> | <code z80> | ||
PrintString_8x8_Format_Args: | PrintString_8x8_Format_Args: | ||
- | ;;; (...) | + | |
- | ;;; Aqui se gestionan los codigos de control con % (tipo = A) | + | |
pstring8v_var: | pstring8v_var: | ||
- | ;;; comprobamos los tipos y saltamos a sus rutinas de gestion | + | |
- | | + | (...) |
- | CP ' | + | |
- | JR Z, pstring8v_int8_zeros | + | jr z, pstring8v_int8_zeros |
- | CP ' | + | |
- | JR Z, pstring8v_int16_zeros | + | jr z, pstring8v_int16_zeros |
- | CP ' | + | |
- | JR Z, pstring8v_int8_justify | + | jr z, pstring8v_int8_justify |
- | CP ' | + | |
- | JR Z, pstring8v_int16_justify | + | jr z, pstring8v_int16_justify |
- | JP pstring8_novar | + | |
; | ; | ||
pstring8v_int8_zeros: | pstring8v_int8_zeros: | ||
- | PUSH HL | + | push hl |
- | LD L, (IX+0) | + | ld l, (ix+0) |
- | INC IX | + | inc ix |
- | CALL Int2String_8 | + | |
- | LD HL, conv2string | + | ld hl, conv2string |
- | CALL PrintString_8x8 | + | |
- | POP HL | + | pop hl |
- | JP pstring8v_loop | + | |
; | ; | ||
pstring8v_int16_zeros: | pstring8v_int16_zeros: | ||
- | PUSH HL | + | push hl |
- | LD L, (IX+0) | + | ld l, (ix+0) |
- | INC IX | + | inc ix |
- | LD H, (IX+0) | + | ld h, (ix+0) |
- | INC IX | + | inc ix |
- | CALL Int2String_16 | + | |
- | LD HL, conv2string | + | ld hl, conv2string |
- | CALL PrintString_8x8 | + | |
- | POP HL | + | pop hl |
- | JP pstring8v_loop | + | |
; | ; | ||
pstring8v_int8_justify: | pstring8v_int8_justify: | ||
- | PUSH HL | + | push hl |
- | LD L, (IX+0) | + | ld l, (ix+0) |
- | INC IX | + | inc ix |
- | CALL Int2String_8 | + | |
- | LD HL, conv2string | + | ld hl, conv2string |
- | CALL INC_HL_Justify_Leading_Zeros | + | |
- | CALL PrintString_8x8 | + | |
- | POP HL | + | pop hl |
- | JP pstring8v_loop | + | |
; | ; | ||
pstring8v_int16_justify: | pstring8v_int16_justify: | ||
- | PUSH HL | + | push hl |
- | LD L, (IX+0) | + | ld l, (ix+0) |
- | INC IX | + | inc ix |
- | LD H, (IX+0) | + | ld h, (ix+0) |
- | INC IX | + | inc ix |
- | CALL Int2String_16 | + | |
- | LD HL, conv2string | + | ld hl, conv2string |
- | CALL INC_HL_Justify_Leading_Zeros | + | |
- | CALL PrintString_8x8 | + | |
- | POP HL | + | pop hl |
- | JP pstring8v_loop | + | |
- | (...) | + | |
</ | </ | ||
- | Lo normal a la hora de utilizar PrintString_Format_Args en nuestro programa es que eliminemos todos aquellos códigos de control (y sus rutinas de chequeo y de gestión) de los cuales no vayamos a hacer uso, con el consiguiente ahorro de memoria (desaparecen las instrucciones de las subrutinas de gestión). | + | Lo normal a la hora de utilizar |
\\ | \\ | ||
Línea 2468: | Línea 2450: | ||
En el artículo dedicado al teclado estudiamos rutinas de lectura del mismo que nos proporcionaban scancodes de las teclas pulsadas. También vimos rutinas de obtención del código ASCII correspondiente a un scancode dado. | En el artículo dedicado al teclado estudiamos rutinas de lectura del mismo que nos proporcionaban scancodes de las teclas pulsadas. También vimos rutinas de obtención del código ASCII correspondiente a un scancode dado. | ||
- | En este caso necesitaremos una rutina | + | En este caso vamos a utilizar para nuestro ejemplo la rutina |
- | Al realizar un CALL a KEY_SCAN se produce una lectura de todas las filas del teclado seguida de una decodificación del resultado de la lectura. La rutina de la ROM coloca entonces en la variable del sistema | + | Al realizar un call a '' |
El desarrollo de la rutina será el siguiente: | El desarrollo de la rutina será el siguiente: | ||
Línea 2499: | Línea 2481: | ||
</ | </ | ||
- | | + | |
<code z80> | <code z80> | ||
LAST_K | LAST_K | ||
- | KEY_SCAN | + | KEY_SCAN |
; | ; | ||
Línea 2516: | Línea 2498: | ||
InputString_8x8: | InputString_8x8: | ||
- | PUSH HL ; Guardamos el puntero a la cadena | + | push hl ; Guardamos el puntero a la cadena |
- | PUSH DE | + | push de |
- | PUSH BC ; Modificados por KEY_SCAN | + | push bc ; Modificados por KEY_SCAN |
- | + | ||
- | LD (inputs_counter), | + | |
- | LD (inputs_limit), | + | |
+ | ld (inputs_counter), | ||
+ | ld (inputs_limit), | ||
inputs_start: | inputs_start: | ||
- | LD A, ' | + | ld a, ' |
- | CALL Font_SafePrintChar_8x8 | + | |
- | XOR A | + | xor a |
- | LD (LAST_K), | + | |
inputs_loop: | inputs_loop: | ||
- | PUSH HL ; KEY_SCAN modifica HL -> preservar | + | push hl ; KEY_SCAN modifica HL -> preservar |
- | CALL KEY_SCAN | + | |
- | POP HL | + | pop hl |
- | LD A, (LAST_K) | + | ld a, (LAST_K) |
- | | + | cp 13 |
- | JR Z, inputs_end | + | jr z, inputs_end |
- | | + | cp 12 |
- | JR Z, inputs_delete | + | jr z, inputs_delete |
- | | + | cp 32 |
- | JR C, inputs_loop | + | jr c, inputs_loop |
- | ;;; Si estamos aqui, ASCII >= 32 -> Es caracter valido -> Guardiar | + | |
- | EX AF, AF' | + | ex af, af' |
- | ;;; Comprobacion de longitud maxima de cadena | + | |
- | LD A, (inputs_counter) | + | ld a, (inputs_counter) |
- | OR A ; Comprobar si es 0 | + | or a ; Comprobar si es 0 |
- | JR Z, inputs_loop | + | jr z, inputs_loop |
- | DEC A | + | dec a |
- | LD (inputs_counter), | + | |
- | EX AF, AF' | + | ex af, af' |
- | LD (HL), A ; Guardamos el caracter leido | + | |
- | INC HL ; Avanzamos al siguiente caracter e imprimir | + | inc hl ; Avanzamos al siguiente caracter e imprimir |
- | CALL Font_SafePrintChar_8x8 | + | |
- | CALL Font_Inc_X | + | |
- | JR inputs_start | + | |
;;; Codigo a ejecutar cuando se pulsa enter | ;;; Codigo a ejecutar cuando se pulsa enter | ||
inputs_end: | inputs_end: | ||
- | LD A, ' ' | + | ld a, ' ' |
- | CALL Font_SafePrintChar_8x8 | + | |
- | XOR A | + | xor a |
- | LD (HL), A ; Almacenamos un FIN DE CADENA en HL | + | |
- | POP BC | + | pop bc |
- | POP DE ; Recuperamos valores de registros | + | pop de ; Recuperamos valores de registros |
- | POP HL ; Recuperamos el inicio de la cadena | + | pop hl ; Recuperamos el inicio de la cadena |
- | RET | + | ret |
;;; Codigo a ejecutar cuando se pulsa DELETE | ;;; Codigo a ejecutar cuando se pulsa DELETE | ||
inputs_delete: | inputs_delete: | ||
- | LD A, (inputs_limit) | + | ld a, (inputs_limit) |
- | LD B, A | + | ld b, a |
- | | + | LD , (inputs_counter) |
- | CP B ; Si char_disponibles-limite == 0 ... | + | cp b ; Si char_disponibles-limite == 0 ... |
- | JR Z, inputs_loop | + | jr z, inputs_loop |
- | INC A ; Si no, si que podemos borrar: | + | inc a ; Si no, si que podemos borrar: |
- | LD (inputs_counter), | + | |
- | DEC HL ; Decrementar puntero en la cadena | + | dec hl ; Decrementar puntero en la cadena |
- | LD A, ' ' | + | ld a, ' ' |
- | CALL Font_SafePrintChar_8x8 | + | |
- | CALL Font_Dec_X | + | |
- | JR inputs_start | + | |
inputs_counter | inputs_counter | ||
Línea 2596: | Línea 2577: | ||
</ | </ | ||
- | InputString_8x8 utiliza una nueva subrutina llamada | + | '' |
<code z80> | <code z80> | ||
Línea 2603: | Línea 2584: | ||
; | ; | ||
Font_SafePrintChar_8x8 | Font_SafePrintChar_8x8 | ||
- | PUSH BC | + | push bc |
- | PUSH DE | + | push de |
- | PUSH HL ; Preservar registros | + | push hl ; Preservar registros |
- | CALL PrintChar_8x8 | + | |
- | POP HL ; Recuperar registros | + | pop hl ; Recuperar registros |
- | POP DE | + | pop de |
- | POP BC | + | pop bc |
- | RET | + | ret |
</ | </ | ||
Línea 2617: | Línea 2598: | ||
<code z80> | <code z80> | ||
; Ejemplo de input de texto | ; Ejemplo de input de texto | ||
- | ORG 35000 | + | |
- | LD HL, $3D00-256 | + | ld hl, $3d00-256 |
- | | + | |
- | | + | |
- | LD HL, cadena1 | + | ld hl, cadena1 |
- | LD B, 4 | + | ld b, 4 |
- | LD C, 0 | + | ld c, 0 |
- | | + | |
- | | + | |
- | | + | |
- | LD HL, input1 | + | ld hl, input1 |
- | LD A, 20 | + | ld a, 20 |
- | | + | |
- | | + | |
- | LD HL, cadena2 | + | ld hl, cadena2 |
- | | + | |
- | LD HL, input1 | + | ld hl, input1 |
- | | + | |
- | RET | + | ret |
cadena1 DB " | cadena1 DB " | ||
Línea 2654: | Línea 2635: | ||
DB 0 | DB 0 | ||
- | END 35000 | + | |
</ | </ | ||
\\ | \\ | ||
- | {{ : | + | {{ : |
\\ | \\ | ||
Línea 2664: | Línea 2645: | ||
\\ | \\ | ||
- | * Permitir edición multilínea. La rutina actual no permite trabajar (al menos en cuanto al borrado) con entrada de texto de múltiples líneas. Se podría editar la rutina para permitir editar más de una línea de texto, realizando una versión especial de Font_Dec_X que decremente el valor de FONT_Y y ponga FONT_X=0 cuando tratemos de borrar desde el margen izquierdo de la pantalla. | + | * Permitir edición multilínea. La rutina actual no permite trabajar (al menos en cuanto al borrado) con entrada de texto de múltiples líneas. Se podría editar la rutina para permitir editar más de una línea de texto, realizando una versión especial de '' |
- | * Habilitar el uso de las teclas de cursor para moverse entre los caracteres de la cadena y así permitir edición avanzada. La rutina debería basarse entonces en un FONT_X y FONT_Y propios y ya no se podría utilizar FONT_BACKSPACE para el borrado. Además, al insertar un carácter en el interior de la cadena habría que mover todos los caracteres en memoria una posición a la derecha y redibujar la cadena completa en pantalla. El cursor podría simularse entonces con FLASH o subrayando la letra actual (por lo que no serviría para editar texto subrayado). | + | * Habilitar el uso de las teclas de cursor para moverse entre los caracteres de la cadena y así permitir edición avanzada. La rutina debería basarse entonces en un '' |
* Permitir llamar a la función con una cadena ya en la zona apuntada por HL. En conjunción con la mejora anterior permitiría editar texto anteriormente introducido. | * Permitir llamar a la función con una cadena ya en la zona apuntada por HL. En conjunción con la mejora anterior permitiría editar texto anteriormente introducido. | ||
\\ | \\ | ||
Línea 2687: | Línea 2668: | ||
\\ | \\ | ||
- | Para utilizar este set de caracteres sólo tendremos que realizar una nueva rutina de impresión llamada | + | Para utilizar este set de caracteres sólo tendremos que realizar una nueva rutina de impresión llamada |
La definición de la fuente de 4x8 píxeles en formato DB es la siguiente: | La definición de la fuente de 4x8 píxeles en formato DB es la siguiente: | ||
Línea 2694: | Línea 2675: | ||
; half width 4x8 font - 384 bytes | ; half width 4x8 font - 384 bytes | ||
charset_4x8: | charset_4x8: | ||
- | DB $00, | + | |
- | | + | DB $00, |
- | | + | DB $00, |
- | | + | DB $00, |
- | | + | DB $00, |
- | | + | DB $00, |
- | | + | DB $00, |
- | | + | DB $00, |
- | | + | DB $00, |
- | | + | DB $00, |
- | | + | DB $00, |
- | | + | DB $00, |
- | | + | DB $00, |
- | | + | DB $00, |
- | | + | DB $00, |
- | | + | DB $00, |
- | | + | DB $00, |
- | | + | DB $00, |
- | | + | DB $00, |
- | | + | DB $00, |
- | | + | DB $00, |
- | | + | DB $00, |
- | | + | DB $00, |
- | | + | DB $00, |
</ | </ | ||
Línea 2745: | Línea 2726: | ||
Al trazar el carácter en pantalla tenemos que hacerlo con OR para respetar otro posible carácter de 4x8 que pueda haber en el mismo bloque, ya lo estemos imprimiendo en la parte izquierda de un bloque (respetar el nibble de la derecha) o en la derecha (respetar el nibble de la izquierda). | Al trazar el carácter en pantalla tenemos que hacerlo con OR para respetar otro posible carácter de 4x8 que pueda haber en el mismo bloque, ya lo estemos imprimiendo en la parte izquierda de un bloque (respetar el nibble de la derecha) o en la derecha (respetar el nibble de la izquierda). | ||
- | | + | |
<code z80> | <code z80> | ||
Línea 2762: | Línea 2743: | ||
PrintChar_4x8: | PrintChar_4x8: | ||
- | | + | rra ; Dividimos A por 2 (resto en CF) |
- | PUSH AF ; Guardamos caracter y CF en A' | + | push af ; Guardamos caracter y CF en A' |
- | ;;; Calcular posicion origen (array fuente) en HL como: | + | |
- | | + | ;;; |
- | LD BC, (FONT_CHARSET) | + | ld bc, (FONT_CHARSET) |
- | LD H, 0 | + | ld h, 0 |
- | LD L, A | + | ld l, a |
- | ADD HL, HL | + | add hl, hl |
- | ADD HL, HL | + | add hl, hl |
- | ADD HL, HL | + | add hl, hl |
- | ADD HL, BC ; HL = Direccion origen de A en fuente | + | add hl, bc ; HL = Direccion origen de A en fuente |
- | ;;; Calculamos las coordenadas destino de pantalla en DE: | + | |
- | LD BC, (FONT_X) | + | ld bc, (FONT_X) |
- | RR C | + | rr c |
- | LD A, B | + | ld a, b |
- | AND $18 | + | |
- | ADD A, $40 | + | add a, $40 |
- | LD D, A | + | ld d, a |
- | LD A, B | + | ld a, b |
- | AND 7 | + | |
- | RRCA | + | rrca |
- | RRCA | + | rrca |
- | RRCA | + | rrca |
- | ADD A, C | + | add a, c |
- | LD E, A ; DE contiene ahora la direccion destino. | + | ld e, a ; DE contiene ahora la direccion destino. |
- | ;;; Calculamos posición en pantalla. Tenemos que dividirla por 2 porque | + | |
- | | + | ;;; en cada columna de pantalla caben 2 caracteres. Usaremos el resto |
- | | + | ;;; (Carry) para saber si va en la izq (CF=0) o der (CF=1) del caracter. |
- | LD A, (FONT_X) | + | ld a, (FONT_X) |
- | RRA ; Dividimos por 2 (posicion X en pantalla) | + | |
- | | + | ; Ademas el carry tiene el resto (par/ |
- | JR NC, pchar4_x_odd | + | jr nc, pchar4_x_odd |
- | ;;; Ahora tenemos que imprimir el caracter en pantalla. Hemos saltado | + | |
- | | + | ;;; a pchar4_x_even o pchar4_x_odd segun si la posicion en pantalla es |
- | | + | ;;; par o impar, pero cada una de estas 2 opciones nos da la posibilidad |
- | | + | ;;; de usar una rutina u otra segun si el caracter ASCII es par o impar |
- | | + | ;;; ya que tenemos que cogerlo de la fuente de una forma u otra |
- | | + | ;;; Posicion de columna en pantalla par: |
pchar4_x_even | pchar4_x_even | ||
- | POP AF ; Restaura A=char y CF=si es char par/impar | + | pop af ; Restaura A=char y CF=si es char par/impar |
- | JR C, pchar4_l_on_l | + | jr c, pchar4_l_on_l |
- | JR pchar4_r_on_l | + | |
pchar4_x_odd: | pchar4_x_odd: | ||
- | POP AF ; Restaura A=char y CF=si es char par/impar | + | pop af ; Restaura A=char y CF=si es char par/impar |
- | JR NC, pchar4_r_on_r | + | jr nc, pchar4_r_on_r |
- | JR pchar4_l_on_r | + | |
pchar4_continue: | pchar4_continue: | ||
Línea 2819: | Línea 2800: | ||
pchar4_printattr: | pchar4_printattr: | ||
- | LD A, D ; Recuperamos el valor inicial de DE | + | ld a, d ; Recuperamos el valor inicial de DE |
- | SUB 8 ; Restando los 8 scanlines avanzados | + | |
- | ;;; Calcular posicion destino en area de atributos en HL. | + | |
- | RRCA ; A ya es = D, listo para rotar | + | |
- | RRCA ; Codigo de Get_Attr_Offset_From_Image | + | |
- | RRCA | + | rrca |
- | AND 3 | + | |
- | OR $58 | + | |
- | LD H, A | + | ld h, a |
- | LD L, E | + | ld l, e |
- | + | ||
- | ;;; Escribir el atributo en memoria | + | |
- | LD A, (FONT_ATTRIB) | + | |
- | LD (HL), A ; Escribimos el atributo en memoria | + | |
- | RET | + | |
+ | ;;; Escribir el atributo en memoria | ||
+ | ld a, (FONT_ATTRIB) | ||
+ | ld (hl), a ; Escribimos el atributo en memoria | ||
+ | ret | ||
;;; | ;;; | ||
Línea 2845: | Línea 2825: | ||
;;; | ;;; | ||
pchar4_l_on_l: | pchar4_l_on_l: | ||
- | LD B, 8 ; 8 scanlines / iteraciones | + | ld b, 8 ; 8 scanlines / iteraciones |
pchar4_ll_lp: | pchar4_ll_lp: | ||
- | LD A, (DE) ; Leer byte de la pantalla | + | ld a, (de) ; Leer byte de la pantalla |
- | AND %11110000 | + | |
- | LD C, A ; Nos lo guardamos en C | + | ld c, a ; Nos lo guardamos en C |
- | LD A, (HL) ; Cogemos el byte de la fuente | + | ld a, (hl) ; Cogemos el byte de la fuente |
- | AND %00001111 | + | |
- | OR C ; Lo combinamos con el fondo | + | or c ; Lo combinamos con el fondo |
- | LD (DE), A ; Y lo escribimos en pantalla | + | |
- | INC D ; Siguiente scanline | + | inc d ; Siguiente scanline |
- | INC HL ; Siguiente dato del " | + | inc hl ; Siguiente dato del " |
- | DJNZ pchar4_ll_lp | + | |
- | JR pchar4_continue | + | |
;;; | ;;; | ||
pchar4_r_on_r: | pchar4_r_on_r: | ||
- | LD B, 8 ; 8 scanlines / iteraciones | + | ld b, 8 ; 8 scanlines / iteraciones |
pchar4_rr_lp: | pchar4_rr_lp: | ||
- | LD A, (DE) ; Leer byte de la pantalla | + | ld a, (de) ; Leer byte de la pantalla |
- | AND %00001111 | + | |
- | LD C, A ; Nos lo guardamos en C | + | ld c, a ; Nos lo guardamos en C |
- | LD A, (HL) ; Cogemos el byte de la fuente | + | ld a, (hl) ; Cogemos el byte de la fuente |
- | AND %11110000 | + | |
- | OR C ; Lo combinamos con el fondo | + | or c ; Lo combinamos con el fondo |
- | LD (DE), A ; Y lo escribimos en pantalla | + | |
- | INC D ; Siguiente scanline | + | inc d ; Siguiente scanline |
- | INC HL ; Siguiente dato del " | + | inc hl ; Siguiente dato del " |
- | DJNZ pchar4_rr_lp | + | |
- | JR pchar4_continue | + | |
;;; | ;;; | ||
pchar4_l_on_r: | pchar4_l_on_r: | ||
- | LD B, 8 ; 8 scanlines / iteraciones | + | ld b, 8 ; 8 scanlines / iteraciones |
pchar4_lr_lp: | pchar4_lr_lp: | ||
- | LD A, (DE) ; Leer byte de la pantalla | + | ld a, (de) ; Leer byte de la pantalla |
- | AND %00001111 | + | |
- | LD C, A ; Nos lo guardamos en C | + | ld c, a ; Nos lo guardamos en C |
- | LD A, (HL) ; Cogemos el byte de la fuente | + | ld a, (hl) ; Cogemos el byte de la fuente |
- | RRCA ; Lo desplazamos 4 veces >> dejando | + | |
- | RRCA ; lo bits 4 al 7 vacios | + | |
- | RRCA | + | rrca |
- | RRCA | + | rrca |
- | AND %11110000 | + | |
- | OR C ; Lo combinamos con el fondo | + | or c ; Lo combinamos con el fondo |
- | LD (DE), A ; Y lo escribimos en pantalla | + | |
- | INC D ; Siguiente scanline | + | inc d ; Siguiente scanline |
- | INC HL ; Siguiente dato del " | + | inc hl ; Siguiente dato del " |
- | DJNZ pchar4_lr_lp | + | |
- | JR pchar4_continue | + | |
;;; | ;;; | ||
pchar4_r_on_l: | pchar4_r_on_l: | ||
- | LD B, 8 ; 8 scanlines / iteraciones | + | ld b, 8 ; 8 scanlines / iteraciones |
pchar4_rl_lp: | pchar4_rl_lp: | ||
- | LD A, (DE) ; Leer byte de la pantalla | + | ld a, (de) ; Leer byte de la pantalla |
- | AND %11110000 | + | |
- | LD C, A ; Nos lo guardamos en C | + | ld c, a ; Nos lo guardamos en C |
- | LD A, (HL) ; Cogemos el byte de la fuente | + | ld a, (hl) ; Cogemos el byte de la fuente |
- | RLCA ; Lo desplazamos 4 veces << dejando | + | |
- | RLCA ; los bits 0 al 3 vacios | + | |
- | RLCA | + | rlca |
- | RLCA | + | rlca |
- | AND %00001111 | + | |
- | OR C ; Lo combinamos con el fondo | + | or c ; Lo combinamos con el fondo |
- | LD (DE), A ; Y lo escribimos en pantalla | + | |
- | INC D ; Siguiente scanline | + | inc d ; Siguiente scanline |
- | INC HL ; Siguiente dato del " | + | inc hl ; Siguiente dato del " |
- | DJNZ pchar4_rl_lp | + | |
- | JR pchar4_continue | + | |
</ | </ | ||
Línea 2925: | Línea 2902: | ||
</ | </ | ||
- | | + | |
<code z80> | <code z80> | ||
Font_Backspace: | Font_Backspace: | ||
- | | + | call Font_Dec_X |
- | LD A, ' ' | + | ld a, ' ' |
- | PUSH BC | + | push bc |
- | PUSH DE | + | push de |
- | PUSH HL | + | push hl |
- | CALL PrintChar_4x8 | + | |
- | POP HL | + | pop hl |
- | POP DE | + | pop de |
- | POP BC | + | pop bc |
- | RET ; Salir | + | |
</ | </ | ||
Línea 2945: | Línea 2922: | ||
<code z80> | <code z80> | ||
; Ejemplo de fuente de 4x8 pixeles (64 caracteres por linea) | ; Ejemplo de fuente de 4x8 pixeles (64 caracteres por linea) | ||
- | ORG 35000 | + | |
- | LD HL, charset_4x8-128 | + | ld hl, charset_4x8-128 |
- | | + | |
- | LD HL, cadena1 | + | ld hl, cadena1 |
- | LD BC, $0400 ; X=00, Y=04 | + | ld bc, $0400 ; X=00, Y=04 |
- | | + | |
- | | + | |
loop: | loop: | ||
- | JR loop | + | jr loop |
- | RET | + | ret |
cadena1 DB " | cadena1 DB " | ||
Línea 2971: | Línea 2948: | ||
DB FONT_EOS | DB FONT_EOS | ||
- | END 35000 | + | |
</ | </ | ||
\\ | \\ | ||
- | {{ : | + | {{ : |
\\ | \\ | ||
- | | + | |
Otro detalle importante es el tema de los atributos: como cada bloque de pantalla contiene 2 caracteres, no podemos establecer atributos diferentes para 2 caracteres del mismo byte. Por esto, hay que ser cauto a la hora de establecer atributos. La solución más sencilla es cambiar las tintas en posiciones donde haya espacios, ya que en ese caso el cambio será efectivo en la letra deseada si ésta es la primera del byte, o en el espacio seguido de la letra deseada si está en la parte derecha. Los cambios de PAPER, BRIGHT o FLASH supondrán problemas si no se realizan siempre en posiciones de pantalla pares. | Otro detalle importante es el tema de los atributos: como cada bloque de pantalla contiene 2 caracteres, no podemos establecer atributos diferentes para 2 caracteres del mismo byte. Por esto, hay que ser cauto a la hora de establecer atributos. La solución más sencilla es cambiar las tintas en posiciones donde haya espacios, ya que en ese caso el cambio será efectivo en la letra deseada si ésta es la primera del byte, o en el espacio seguido de la letra deseada si está en la parte derecha. Los cambios de PAPER, BRIGHT o FLASH supondrán problemas si no se realizan siempre en posiciones de pantalla pares. |