;=== 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 (pero ocupa 3 bytes) ; ; ENTRADA: A = caracter a imprimir por pantalla ;----------------------------------------------------------------------- PrintChar EQU $0010 ; $0010 = RST $10 = RST 16 ; Podriamos llamar a $15E6 en su lugar ; que es donde llama internamente $0010. ;----------------------------------------------------------------------- ; 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, SALIDA, MODIFICA: NADA ;----------------------------------------------------------------------- Wait_For_Key: CALL Wait_For_No_Key PUSH AF wait_for_key_loop: XOR A ; A = 0 IN A, (254) OR 224 INC A JR Z, wait_for_key_loop LD A, ($5C08) ; Devolver Variable LAST-K en A POP AF 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 224 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