.equ display, 0x20080000 @ Origen de la memoria del display .equ fil, 6 @ Líneas del display .equ col, 40 @ Caracteres por linea .text /********************************************************/ /* sqrt(unsigned int val) */ /********************************************************/ /* Devuelve la parte entera de la raíz cuadrada de un */ /* entero sin signo. Sigue el algoritmo binario que la */ /* calcula bit a bit. (Wikipedia, versión en inglés). */ /* Entrada: */ /* r0: valor */ /* Salida: */ /* r0: raiz entera */ .balign 4 sqrt: ldr r2, = 0x40000000 @ Base para los desplazamientos de bit mov r1, #0 @ Resultado, se inicia a 0 cmp r0, r2 @ Mientras el radicando sea menor que bcs sqalg @ el bit desplazado, buc_s: lsr r2, r2, #2 @ desplazamos a la derecha de 2 en 2 bits cmp r0, r2 bcc buc_s sqalg: tst r2, r2 @ Si el bit desplazado llega a 0 se acaba beq fin buc_s2: add r3, r1, r2 @ Se compara el radicando con el resultado cmp r0, r3 @ parcial más el bit bcc else @ Si es mayor se le resta tal suma sub r0, r0, r3 @ y se actualiza el resultado como lsr r1, r1, #1 @ como res = (res >>l 1) + bit add r1, r1, r2 b finsi else: lsr r1, r1, #1 @ Si no, se desplaza el resultado finsi: lsr r2, r2, #2 @ Desplazamos el bit hasta que llegue a 0 bne buc_s2 fin: mov r0, r1 @ Se pone el resultado en r0 y se termina mov pc, lr /********************************************************/ /* sdivide(int dividendo, int divisor) */ /********************************************************/ /* Realiza una division con signo. */ /* Devuelve el resto en r1 y el cociente en r0. */ /* Si el divisor es 0 devuelve 0x7FFFFFFF en ambos. */ /* Utiliza la divión entera por lo que el resto tiene */ /* signo del divisor. */ /* Entrada: */ /* r0: dividendo */ /* r1: divisor */ /* Salida: */ /* r0: cociente */ /* r1: resto */ .balign 4 sdivide: push {r4-r5, lr} cmp r1, #0 @ Si el divisor es 0 damos error bne s_hazdiv s_error: sub r1, r1, #1 @ para ello ponemos resto y cociente lsr r1, r1, #1 @ al mayor valor positivo 0x7FFFFFFF mov r0, r1 @ y salimos bne s_final s_hazdiv: mov r4, #0 @ Se ponen a 0 las marcas de negativo mov r5, #0 tst r1, r1 @ Si el divisor es negativo bpl s_dos @ se marca en r5 y se le cambia el signo mov r5, #1 neg r1, r1 s_dos: @ Si el dividendo es negativo tst r0, r0 @ se marca en r4 y se le cambia el signo bpl s_call mov r4, #1 neg r0, r0 s_call: bl divide @ Se dividen los valores positivos cmp r5, r4 @ Si los signos de dividendo y divisor son distintos beq s_resto neg r0, r0 @ se cambia el signo al cociente s_resto: cmp r4, #1 @ Si el cociente es negativo bne s_final neg r1, r1 @ se cambia el signo al resto s_final: pop {r4-r5, pc} @ Y se vuelve /********************************************************/ /* divide(unsigned int dividendo, unsigned int divisor) */ /********************************************************/ /* Realiza una division sin signo. */ /* Devuelve el resto en r1 y el cociente en r0. */ /* Si el divisor es 0 devuelve 0xFFFFFFFF en ambos. */ /* Entrada: */ /* r0: dividendo */ /* r1: divisor */ /* Salida: */ /* r0: cociente */ /* r1: resto */ .balign 4 divide: mov r2, #0 @ En r2 tenemos el contador de desplazamientos orr r1, r1 @ Vemos si el divisor es 0 bne a_hazdiv @ y en caso afirmativo sub r0, r2, #1 @ ponemos 0xFFFFFFFF (-1) mov r1, r0 @ en cociente y resto b a_final a_hazdiv: @ Empezamos a dividir mov r3, #0 @ r3 es el cociente parcial and r1, r1 @ Si el msb del cociente es 1 bmi a_itera @ evitamos los desplazamientos a_compara: cmp r0, r1 @ Comparamos el dividendo con el divisor bcc a_itera @ desplazado, y seguimos desplazando hasta add r2, r2, #1 @ que sea menor. Obtenemos en r2 el numero lsl r1, r1, #1 @ de bits del cociente bpl a_compara @ Evitamos el desbordamiento a_itera: lsl r3, r3, #1 @ Desplazamos el cociente cmp r0, r1 @ Vemos si cabe a 1 bcc a_finresta @ Si no cabe vamos a finresta add r3, r3, #1 @ si cabe sumamos 1 en el cociente sub r0, r0, r1 @ y restamos a_finresta: lsr r1, r1, #1 @ Desplazamos el dividendo sub r2, #1 @ Seguimos si quedan iteraciones bpl a_itera a_findiv: mov r1, r0 @ El resto esta en r0 mov r0, r3 @ y el cociente en r3 a_final: mov pc, lr /********************************************************/ /* printString(int col, int fil, char *cad) */ /********************************************************/ /* Imprime la cadena dada en el display a partir de la */ /* coordenada dada. No realiza verificaciones. */ /* */ /* Entrada: */ /* r0: Columna (0...col - 1) */ /* r1: Fila (0...fil - 1) */ /* r2: Cadena ASCIIZ a imprimir */ /* */ /* Salida: */ /* r0: Numero de caracteres impresos (strlen) */ .balign 4 printString: ldr r3, =col @ Se calcula en r0 la dirección de inicio según las mul r1, r1, r3 @ coordenadas, multiplicando el numero de fila add r1, r1, r0 @ por las colúmnas y sumando el de columna. ldr r0, =display @ Al resultado se suma la dirección base del display. add r0, r0, r1 mov r3, #0 @ Se pone a 0 el contador de caracteres buc_1: ldrb r1, [r2] @ Se lee un caracter y si es 0 cmp r1, #0 @ se termina beq end_1 strb r1, [r0] @ Si no, se deja en memoria y se incrementan add r3, r3, #1 @ el contador de caracteres add r0, r0, #1 @ la dirección en el display add r2, r2, #1 @ y la dirección en la cadena en memoria b buc_1 @ y se vuelve al bucle end_1: mov r0, r3 @ El número de caracteres se pone en r0 mov pc, lr @ y se termina /********************************************************/ /* printUInt(int col, int fil, unsigned int val) */ /********************************************************/ /* Imprime en el display a partir de las coordenadas */ /* dadas el entero sin signo en decimal. No realiza */ /* verificaciones. */ /* */ /* Entrada: */ /* r0: Columna (0...col - 1) */ /* r1: Fila (0...fil - 1) */ /* r2: Entero a imprimir */ /* */ /* Salida: */ /* r0: Numero de caracteres impresos */ .balign 4 printUInt: push {r5-r7, lr} @ Se va a crear en la pila una cadena con el número mov r5, sp @ en decimal, por eso ponemos r5 apuntando a sub r5, r5, #4 @ SP + 4 y reservamos espacio para 12 caracteres. sub sp, #12 mov r6, r0 @ Se guardan las coordenadas en r6 y r7 mov r7, r1 mov r0, r2 @ y se copia el número en r0 mov r1, #0 @ Ponemos el final de cadena en r5. Al ir dividiendo entre strb r1, [r5] @ 10 la cadena se va a crear de la cifra menos significativa buc_2: @ hacia la más, es decir de arriba a abajo en memoria sub r5, r5, #1 @ Se decrementa r5 para el siguiente caracter mov r1, #10 @ y se divide el número entre 10 bl divide add r1, #48 @ Se pasa el resto a carácter strb r1, [r5] @ y se escribe en la cadena cmp r0, #0 @ Si el cociente es 0 se ha terminado bne buc_2 @ en otro caso se continúa mov r0, r6 @ Recuperamos las coordenadas mov r1, r7 mov r2, r5 @ y ponemos en r2 la dirección de la cadena bl printString @ Se imprime y pone en r0 su longitud add sp, #12 @ Se ajusta la pila pop {r5-r7, pc} @ y se termina. /********************************************************/ /* printInt(int col, int fil, int val) */ /********************************************************/ /* Imprime en el display a partir de las coordenadas */ /* dadas el entero con signo en decimal. No realiza */ /* verificaciones. */ /* */ /* Entrada: */ /* r0: Columna (0...col - 1) */ /* r1: Fila (0...fil - 1) */ /* r2: Entero a imprimir */ /* */ /* Salida: */ /* r0: Numero de caracteres impresos */ .balign 4 printInt: push {r4-r7, lr} @ Se va a crear en la pila una cadena con el número mov r5, sp @ en decimal, por eso ponemos r5 apuntando a sub r5, r5, #4 @ SP + 4 y reservamos espacio para 12 caracteres. sub sp, #12 mov r6, r0 @ Se guardan las coordenadas en r6 y r7 mov r7, r1 mov r0, r2 @ y se copia el número en r0 mov r4, #0 @ r4 guardará 1 si es negativo and r2, r2 @ Lo verificamos mirando su msb bpl mas_3 neg r0, r2 @ si es negativo le cambiamos el signo add r4, r4, #1 @ y lo marcamos en r4 mas_3: mov r1, #0 @ Ponemos el final de cadena en r5. Al ir dividiendo entre strb r1, [r5] @ 10 la cadena se va a crear de la cifra menos significativa buc_3: @ hacia la más, es decir de arriba a abajo en memoria sub r5, r5, #1 @ Se decrementa r5 para el siguiente caracter mov r1, #10 @ y se divide el número entre 10 bl divide add r1, #48 @ Se pasa el resto a carácter strb r1, [r5] @ y se escribe en la cadena cmp r0, #0 @ Si el cociente es 0 se ha terminado bne buc_3 @ en otro caso se continúa cmp r4, #0 @ Si el número era negativo beq positivo mov r4, #'- @ Se añade el signo menos al principio sub r5, r5, #1 strb r4, [r5] positivo: mov r0, r6 @ Recuperamos las coordenadas mov r1, r7 mov r2, r5 @ y ponemos en r2 la dirección de la cadena bl printString @ Se imprime y pone en r0 su longitud add sp, #12 @ Se ajusta la pila pop {r4-r7, pc} @ y se termina. /********************************************************/ /* printWord(int col, int fil, unsigned int val) */ /********************************************************/ /* Imprime en el display a partir de las coordenadas */ /* dadas el entero en hexadecimal. Siempre imprime 8 */ /* caracteres hexadecimales. No realiza verificaciones. */ /* */ /* Entrada: */ /* r0: Columna (0...col - 1) */ /* r1: Fila (0...fil - 1) */ /* r2: Entero a imprimir */ /* */ /* Salida: */ /* --- */ .balign 4 printWord: mov r3, #8 @ r3 guarda los caracteres a imprimir b printHex @ se imprimen en printHex /********************************************************/ /* printHalf(int col, int fil, unsigned int val) */ /********************************************************/ /* Imprime en el display a partir de las coordenadas */ /* dadas el half en hexadecimal. Siempre imprime 4 */ /* caracteres hexadecimales. No realiza verificaciones. */ /* */ /* Entrada: */ /* r0: Columna (0...col - 1) */ /* r1: Fila (0...fil - 1) */ /* r2: Entero a imprimir */ /* */ /* Salida: */ /* --- */ .balign 4 printHalf: mov r3, #4 @ r3 guarda los caracteres a imprimir b printHex @ se imprimen en printHex /********************************************************/ /* printByte(int col, int fil, unsigned int val) */ /********************************************************/ /* Imprime en el display a partir de las coordenadas */ /* dadas el byte en hexadecimal.Siempre imprime 2 */ /* caracteres hexadecimales. No realiza verificaciones. */ /* */ /* Entrada: */ /* r0: Columna (0...col - 1) */ /* r1: Fila (0...fil - 1) */ /* r2: Entero a imprimir */ /* */ /* Salida: */ /* --- */ .balign 4 printByte: mov r3, #2 @ r3 guarda los caracteres a imprimir printHex: @ Comienzo del código de impresion push {r4-r5, lr} ldr r4, =col @ Se calcula la dirección del caracter mul r1, r1, r4 @ menos significativo: se multiplica la fila por add r1, r1, r0 @ el numero de columnas, se suma la columna, ldr r0, =display @ la dirección del display add r0, r0, r1 add r0, r0, r3 @ y el número de caracteres mov r5, #0x0f @ En r5 se guarda la máscara para dejar 4 bits -una cifra hex-. buc_4: mov r1, r2 @ Se copia en r1 el número actual and r1, r1, r5 @ se deja el nibble -4 bits- bajo add r1, #'0 @ se pasa a caracter cmp r1, #'9 + 1 @ Si es menor o igual que '9 ya está bcc nosuma add r1, #'A - '9 - 1 @ si no, lo pasamos a la letra correspondiente nosuma: sub r0, r0, #1 @ Decrementamos la posición del display lsr r2, r2, #4 @ Desplazamos 4 bits el número -dividimos entre 16- strb r1, [r0] @ dejamos el caracter en el display sub r3, r3, #1 @ y decrementamos la cuenta de caracteres a escribir. bne buc_4 @ Si no es 0, seguimos end_4: pop {r4-r5, pc} @ Termina la función /********************************************************/ /* fill(char val) */ /********************************************************/ /* Rellena el display con el valor val. */ /* */ /* Entrada: */ /* r0: Valor a rellenar (8 lsb) */ /* */ /* Salida: */ /* --- */ .balign 4 fill: mov r1, #0xFF @ Dejamos en r2 el carácter de r0 and r0, r1 @ dejando el resto del registro a 0 mov r2, r0 @ con el and anterior lsl r0, r0, #8 @ Dejamos espacio para otro caracter igual orr r2, r0 @ que añadimos con or lsl r0, r0, #8 @ Repetimos tres veces para dejar el orr r2, r0 @ caracter original en los 4 bytes lsl r0, r0, #8 @ de r2 orr r2, r0 b limpia @ saltamos a escribir los caracteres /********************************************************/ /* cls() */ /********************************************************/ /* Limpia el display */ /* */ /* Entrada: */ /* --- */ /* */ /* Salida: */ /* --- */ .balign 4 cls: ldr r2, =0x20202020 @ Un entero con 4 caracteres espacio -blancos- limpia: ldr r0, =display @ r0 apunta a la dirección del display ldr r1, =(fil*col)/4 @ en r1 el número de caracteres entre 4 buc_5: str r2, [r0] @ Se escribe entero a entero add r0, r0, #4 @ incrementando en 4 la dirección sub r1, r1, #1 @ decrementando en 1 el número de enteros que faltan bne buc_5 @ Terminamos al llegar a 0 mov pc, lr @ y volvemos .end