;=== Libreria utils.asm: Funciones utiles varias para pruebas de === ;=== lenguaje ensamblador Z80 en Spectrum === ;----------------------------------------------------------------------- ; PrintNum: Imprime en la pantalla un valor en decimal usando la ROM. ; ; ENTRADA: BC = valor a imprimir por pantalla ; SALIDA, MODIFICA: NADA ;----------------------------------------------------------------------- PrintNum: push af push bc push de push hl call $2d2b ; ROM_STACK_BC call $2de3 ; ROM_PRINT_FP pop hl pop de pop bc pop af ret ;----------------------------------------------------------------------- ; CLS: Borrado de la pantalla con el color indicado en (CLS_COLOR) ; CLSCOLOR: Direccion de memoria de ATTR_P (atributo para CLS) ; BORDER: Cambio del color del borde ; PAUSE: Realiza una pausa de BC/50 segundos ; MULT_HLDE: Calcula HL=HL*DE ; PIXEL_ADDR2: Devuelve en HL/A direccion de pixel BC (YX) ; PrintNum4digits: Imprime el numero en BC (0-9999). ;----------------------------------------------------------------------- CLS EQU $0daf ; ROM_CLS CLS_COLOR EQU $5c8d ; Variable del Sistema ATTR_P BORDER EQU $229b ; Rutina del borde PAUSE EQU $1f3d ; PAUSAR BC/50 segundos (50 => 1s) MULT_HLDE EQU $30a9 ; Multiplica HL*DE => HL=HL*DE PIXEL_ADDR2 EQU $22b1 ; Devuelve direccion de pixel BC PrintNum4digits EQU $1a1b ; Imprime valor de BC (0-9999) ;----------------------------------------------------------------------- ; PrintChar: Hacer desde nuestro programa "call PrintChar", es el ; equivalente a hacer un "call $0010", es decir, rst 16. ; Es un simple envoltorio de abreviatura para preservar AF. ; ; ENTRADA: A = caracter a imprimir por pantalla ;----------------------------------------------------------------------- PrintChar: push af rst 16 pop af ret ;----------------------------------------------------------------------- ; PrintSpace y PrintCR: para abreviar codigo, imprimen SPACE o ENTER. ; ; ENTRADA, SALIDA, MODIFICA: NADA ;----------------------------------------------------------------------- PrintSpace: push af ld a, ' ' rst 16 pop af ret PrintCR: push af ld a, 13 rst 16 pop af ret ;----------------------------------------------------------------------- ; CursorAt: Mueve el cursor a la posicion indicada por DE (XY) ; ENTRADA: DE = XY (D=X, E=Y) ; SALIDA, MODIFICA: NADA ;----------------------------------------------------------------------- CursorAt: push af ld a, _AT ; Codigo control "AT Y,X" rst 16 ld a, e ; Y rst 16 ld a, d ; X rst 16 pop af ret ;----------------------------------------------------------------------- ; PrintString: Imprime en la pantalla una cadena acabada en un byte de ; valor $ff usando rst 16. ; ; ENTRADA: DE = Dirección de la cadena a imprimir. ; SALIDA: NADA ; MODIFICA: El valor de DE no se preserva (se incrementa) ;----------------------------------------------------------------------- PrintString: push af print_string_loop: ld a, (de) ; Leemos el caracter apuntado por DE CP _EOS ; chequeamos si es $ff (fin de cadena) jr z, end_print_string ; Si lo es, se activa el ZEROFLAG => SALIR rst 16 ; No lo es, no hemos saltado, imprimirlo inc de ; Avanzar al siguiente caracter de la cadena jr print_string_loop ; Repetir hasta que alguno sea 0 y salgamos end_print_string: pop af ret ;----------------------------------------------------------------------- ; PrintBin: Imprime en la pantalla un valor en binario usando rst 16. ; Añade el prefijo '%' delante del numero impreso. ; ; ENTRADA: A = valor a imprimir por pantalla en binario ; SALIDA, MODIFICA: NADA ;----------------------------------------------------------------------- PrintBin: push af push bc ; Preservamos los registros que se usaran ld c, a ; Guardamos en C copia de A ld b, 8 ; Imprimiremos el estado de los 8 bits ld a, '%' rst 16 ; Imprimir prefijo printbin_loop: ld a, '1' ; Para bit = 1, imprimiremos '1' bit 7, c ; Chequeamos el estado del bit 7 jr nz, printbin_es_uno ; Dejamos A = 255 ld a, '0' ; A = '0' printbin_es_uno: rst 16 ; Imprimimos (A): contiene '0' o '1' rlc c ; Rotamos C a la izq para que podamos ; usar de nuevo el BIT 7 en el bucle djnz printbin_loop ; Repetimos 8 veces pop bc pop af ret ;----------------------------------------------------------------------- ; PrintHex: Imprime en la pantalla un numero de 1 byte en hexadecimal. ; Para ello convierte el valor numérico en una cadena llamando a ; Byte2ASCII_Hex y luego llama a rst 16 para imprimir cada caracter por ; separado. Imprime un $ delante y ESPACIO detrás. ; ; ENTRADA: A = valor a imprimir por pantalla en hexadecimal ; ; SALIDA, MODIFICA: NADA ;----------------------------------------------------------------------- PrintHex: push hl ld h, a ; Guardamos A ld a, '$' rst 16 ; Imprimimos un "$" ld a, h ; Recuperamos A push af push de call Byte2ASCII_Hex ; Convertimos A en Cadena HEX ld hl, Byte2ASCII_output ; HL apunta a la cadena ld a, (hl) rst 16 ; Imprimimos primer valor HEX inc hl ; Avanzar en la cadena ld a, (hl) rst 16 ; Imprimimos segundo valor HEX pop de pop af pop hl ret ;----------------------------------------------------------------------- ; PrintHex16: Imprime en la pantalla un numero de 2 bytes en hexadecimal. ; ; ENTRADA: BC = valor a imprimir por pantalla en hexadecimal ; SALIDA, MODIFICA: NADA ;----------------------------------------------------------------------- PrintHex16: push af push hl ld a, '$' rst 16 ; Imprimimos un "$" ld h, b call Byte2ASCII_Hex ; Convertimos A en Cadena HEX ld hl, Byte2ASCII_output ; HL apunta a la cadena ld a, (hl) rst 16 ; Imprimimos primer valor HEX inc hl ; Avanzar en la cadena ld a, (hl) rst 16 ; Imprimimos segundo valor HEX ld h, c call Byte2ASCII_Hex ; Convertimos A en Cadena HEX ld hl, Byte2ASCII_output ; HL apunta a la cadena ld a, (hl) rst 16 ; Imprimimos primer valor HEX inc hl ; Avanzar en la cadena ld a, (hl) rst 16 ; Imprimimos segundo valor HEX pop hl pop af ret ;----------------------------------------------------------------------- ; Byte2ASCII_Hex: Convierte el valor del registro H en una cadena ; de texto de max. 2 caracteres hexadecimales, para poder imprimirla. ; Rutina adaptada de Num2Hex en http://baze.au.com/misc/z80bits.html . ; ; ENTRADA: H = Numero a convertir ; SALIDA: [Byte2ASCII_output] = Espacio de 2 bytes con los ASCIIs ; MODIFICA: NADA ;----------------------------------------------------------------------- Byte2ASCII_Hex: push af push de push hl ld de, Byte2ASCII_output ld a, h call B2AHex_Num1 ld a, h call B2AHex_Num2 jp B2AHex_Exit B2AHex_Num1: rra rra rra rra B2AHex_Num2: or $f0 daa add a, $a0 adc a, $40 ld (de), a inc de ret B2AHex_Exit: pop hl pop de pop af ret Byte2ASCII_output DB 0, 0 ;----------------------------------------------------------------------- ;----------------------------------------------------------------------- ; PrintNum2digits: Imprime en la pantalla un numero de 1 byte en ; base 10, pero solo los 2 últimos digitos (0-99). Para ello convierte ; el valor numerico en una cadena llamando a Byte2ASCII_2Dig y luego ; llama a rst 16 para imprimir cada caracter por separado. ; ; ENTRADA: A = valor a "imprimir" en 2 digitos de base 10. ; SALIDA: NADA ; MODIFICA: NADA ;----------------------------------------------------------------------- PrintNum2digits: push af push de call Byte2ASCII_Dec2Digits ; Convertimos A en Cadena Dec 0-99 ld a, d rst 16 ; Imprimimos primer valor HEX ld a, e rst 16 ; Imprimimos segundo valor HEX pop de pop af ret ;----------------------------------------------------------------------- ; Byte2ASCII_Dec2Digits: Convierte el valor del registro H en una ; cadena de texto de max. 2 caracteres (0-99) decimales. ; ; ENTRADA: A = Numero a convertir ; SALIDA: DE = 2 bytes con los ASCIIs ; MODIFICA: A, FLAGS ; ; Basado en rutina dtoa2d de: ; http://99-bottles-of-beer.net/language-assembler-%28z80%29-813.html ;----------------------------------------------------------------------- Byte2ASCII_Dec2Digits: ld d, '0' ; Starting from ASCII '0' dec d ; Because we are inc'ing in the loop ld e, 10 ; Want base 10 please and a ; Clear carry flag dtoa2dloop: inc d ; Increase the number of tens sub e ; Take away one unit of ten from A jr nc, dtoa2dloop ; If A still hasn't gone negative, do another add a, e ; Decreased it too much, put it back add a, '0' ; Convert to ASCII ld e, a ; Stick remainder in E ret ;----------------------------------------------------------------------- ; PrintFlags: Imprime en la pantalla en binario el registro F (flags). ; ; ENTRADA: F = registro de Flags ; SALIDA, MODIFICA: NADA ;----------------------------------------------------------------------- PrintFlags: push af push bc push af ; Metemos AF en al pila pero sacamos BC pop bc ; Ahora C contiene el valor de F ld a, c call PrintBin pop bc pop af ret ;----------------------------------------------------------------------- ; PrintFlag: Imprime en la pantalla en binario el flag indicado. ; ; ENTRADA: F = registro de Flags ; A = FLAG a imprimir, con constantes como "FLAG_Z". ; SALIDA, MODIFICA: NADA ;----------------------------------------------------------------------- PrintFlag: push af push bc push af ; Metemos AF en al pila pero sacamos BC pop bc ; Ahora C contiene el valor de F ; y B contiene el antiguo valor A ld a, c loopPrintFlag: rlc a ; rotamos A veces el bit djnz loopPrintFlag and %00000001 ; Borramos todos los bits menos bit 0 add a, '0' ; Sumamos '0' para obtener ASCII rst 16 pop bc pop af ret ;----------------------------------------------------------------------- ; Wait_For_Key: Pausa la ejecución hasta que pulse alguna tecla. ; Devuelve el ASCII de la tecla pulsada en A. ; ; ENTRADA: NADA ; SALIDA: ASCII de la tecla pulsada sacado de LAST_K ;----------------------------------------------------------------------- Wait_For_Key: call Wait_For_No_Key push af wait_for_key_loop: xor a ; A = 0 in a, ($FE) or %11100000 inc a jr z, wait_for_key_loop pop af ld a, ($5c08) ; Devolver Variable LAST-K en A ret ;----------------------------------------------------------------------- ; Wait_For_No_Key: Espera a que no haya ninguna tecla pulsada (para ; poder poner como condicion que el usuario suelte la tecla). ; ; ENTRADA, SALIDA, MODIFICA: NADA ;----------------------------------------------------------------------- Wait_For_No_Key: push af wait_for_no_key_loop: xor a in a, ($fe) or %11100000 inc a jr nz, wait_for_no_key_loop pop af ret ;----------------------------------------------------------------------- ; Constantes definidas para usar con cadenas o RST ;----------------------------------------------------------------------- _EOS EQU $ff _CR EQU 13 _INK EQU 16 _PAPER EQU 17 _FLASH EQU 18 _BRIGHT EQU 19 _INVERSE EQU 20 _OVER EQU 21 _AT EQU 22 _TAB EQU 23 _BLACK EQU 0 _BLUE EQU 1 _RED EQU 2 _MAGENTA EQU 3 _GREEN EQU 4 _CYAN EQU 5 _YELLOW EQU 6 _WHITE EQU 7 _FLAG_S EQU 1 _FLAG_Z EQU 2 _FLAG_H EQU 4 _FLAG_PV EQU 6 _FLAG_N EQU 7 _FLAG_C EQU 8