martes, 26 de marzo de 2019

Multiplicación de dos cifras en ensamblador

En esta ocasión, les muestro la explicacion del siguiente programa que hace la multiplicacion de dos numeros de dos cifras.

Sintaxis


.model small ;Modelo de memoria m?s utilizado
.stack

.data        ;definición de datos(variables), donde se almacenara información
.code
   chr1  db ? ;primer digito
   chr2  db ? ;segundo digito
   chr3  db ? ;multiplo
   chr4  db ?
   r1    db ? ;resultado 1
   r2    db ? ;resultado 2
   r3    db ?
   r4    db ?
   ac    db 0 ;acarreo
   ac1   db 0
.startup
   ;cls
   mov ah,00h     ;Function(Set video mode)
   mov al,03      ;Mode 80x25 8x8 16
   int 10h        ;Interruption Video

   mov ah,01h     ;Function(character read) Guarda en AL
   int 21h        ;Interruption DOS functions
   sub al,30h     ;ajustamos valores
   mov chr1,al    ;[chr1].chr2 * chr3 = ac.r1.r2

   mov ah,01h     ;Function(character read) Guarda en AL
   int 21h        ;Interruption DOS functions
   sub al,30h     ;Ajustamos valores
   mov chr2,al    ;chr1.[chr2] * chr3 = ac.r1.r2

   mov ah,02h     ;Function(character to send to standard output)
   mov dl,'*'     ;Character to show
   int 21h

   mov ah,01h     ;Function(Read character) Guarda en AL
   int 21h        ;Interruption DOS Functions
   sub al,30h     ;Transform(0dec = 30hex)
   mov chr3,al    ;chr1.chr2 * [chr3] = ac.r1.r2
  
   mov ah,01h     ;Function(Read character) Guarda en AL
   int 21h        ;Interruption DOS Functions
   sub al,30h     ;Transform(0dec = 30hex)
   mov chr4,al    ;chr1.chr2 * [chr3] = ac.r1.r2

   mov ah,02h     ;Character to send to standar output
   mov dl,'='     ;
   int 21h        ;Interruption DOS functions

   ;Realizamos operaci?n   
  
   mov al,chr4  ;unidad del segundo numero
   mov bl,chr2  ;unidad del primer numero
   mul bl       ;multiplicar
   mov ah,0     ;limpiamos ah0
   aam          ;separamos de hex a dec
   mov ac1,ah   ;decenas del primera multiplicacion
   mov r4,al    ;unidades del primera multiplicacion
            
   mov al,chr4  ;unidades del segundo numero
   mov bl,chr1  ;decentas del primer numero
   mul bl       ;multiplicar
   mov r3,al    ;movemos el resultado de la operacion a r3
   mov bl,ac1   ;movemos el acarreo a bl
   add r3,bl    ;sumamos resultado mas acarreo
   mov ah,00h   ;limpiamos ah por residuos
   mov al,r3    ;movemos el resultado de la suma a al
   aam          ;separamos  de hex a dec
   mov r3,al    ;guardamos unidades en r3
   mov ac1,ah   ;guardamos decenas en ac1

   mov al,chr3    ;al = chr3
   mov bl,chr2    ;bl = chr2
   mul bl         ;AL = chr3*chr2 (BL*AL)
   mov Ah,0h      ;
   AAM            ;ASCII Adjusment
   mov ac,AH      ;ac = AH (Acarreo)
   mov r2,AL      ;r2 = AL       (Unidad del resultado)

   mov al,chr3    ;AL = chr3
   mov bl,chr1    ;BL = chr1
   mul bl         ;AL = chr1*chr3 (BL*AL)
   mov r1,al      ;r1 = AL       (Decena del resultado)
   mov bl,ac      ;BL = Acarreo anterior
   add r1,bl      ;r1 = r1+ac (r1 + Acarreo)
   mov ah,00h     ;
   mov al,r1      ;AL = r1 (Asignaci?n para el ajust)
   AAM            ;ASCII Adjustment
   mov r1,al      ;r1 = AL
   mov ac,ah      ;ac = AH (Acarreo para la Centena del resultado)
  
  
   ;suma final
   ;R4 resulta ser las unidades de mul y no se toma en cuenta ya que se pasa entero
  
  
   mov ax,0000h   ;limpiamos ax
  
   mov al,r3      ;movemos el segundo resultado de la primera mult a al
   mov bl,r2      ;movemos primer resultado de la segunda mult a bl
   add al,bl      ;sumamos
   mov ah,00h     ;limpiamos ah
   aam            ;separamos hex a dec
   mov r3,al      ;r3 guarda las decenas del resultado final
   mov r2,ah      ;r2 se utiliza como nuevo acarreo
  
   mov ax,0000h   ;''''
  
   mov al,ac1     ;movemos el acarreo de la primera mult a al
   mov bl,r1      ;movemos segundo resultado de la segunda mult a bl
   add al,r2      ;sumamos el nuevo  acarreo de la suma anterior  a al
   add al,bl      ;sumamos al a bl
   mov ah,00h     ;limpiamos el registro ah
   aam            ;separamos de hex a dec
   mov r1,al      ;r1 guarda las centenas
   mov r2,ah      ;ah se sigue utilizando como acarreo
  
   mov al,r2      ;movemos el acarreo a al
   mov bl,ac      ;movemos ac a bl
   add al,bl      ;sumamos al a bl
   ;aam            ;separamos hex a dec
   mov ac,al      ;mov al a ac como nuestro acarreo final
  
 
  
   ;Mostramos resultado
   mov ah,02h 
   mov dl,ac
   add dl,30h
   int 21h        ;Mostramos ac (millar)

   mov ah,02H
   mov dl,r1
   add dl,30h
   int 21h        ;Mostramos r1 (centena)

                 
  
   mov ah,02H
   mov dl,r3
   add dl,30h
   int 21h        ;Mostramos r3 (decena)
  
   mov ah,02H
   mov dl,r4
   add dl,30h
   int 21h        ;unidad
  
.exit
end  


Bueno,vamos a comenzar con la explicacion parte por parte de esta sintaxis. Ya tenemos algunos comentarios que nos pueden ser de utilidad por parte del autor original del programa que estamos analizando.



La primera parte de la sintaxis que tenemos arriba, es la tipica para iniciar cualquier programa en ensamblador.
En el apartado de .code, comenzamos a declarar las variables que usaremos a lo largo de todo el programa. 4 variables para los caracteres que se van a multiplicar, 4 resultados y 2 acarreos.
Despues de la parte de declaracion, comenzamos con la captura de valores. Comenzamos inicializando las funciones de video para poder ingresar variables desde teclado y que es programa los reciba.
Posteriormente usamos la interrupcion 21h con el servicio 01h que sirve para la entrada de caracteres desde teclado, para ingresar nuestros primeros dos numeros a multiplicar.
Si ves, al momento de ingresar dicho numero(en este ejemplo usaremos la multiplicacion que se habia mostrado en la foto anterior) se le resta 30h. Esto para convertir el valor hexadecimal que nos guarda el ensamblador a su valor decimal.

Valor de 2 al ingresarlo al ensamblador: 32
Valor de 2 despues de la resta:2

Este procedimiento lo repite con ambos numeros y los guarda en chr1 y chr2. Posteriormente, imprime el caracter * con el servicio 02 de la interrupcion 21h que sirve para salida de caracter unico.
 Continuamos con el mismo proceso de ingresar y convertir a decimal con los otros dos numeros, solo que estos iran a las variables chr3 y chr4. Finalmente, en esta parte imprime el caracter = y en pantalla vemos algo como lo que aparece en la foto.
Si revisas tu apartado de variables, deberias tener los valores de los numeros en cada una de tus variables de caracter como esta en la foto(valores ya decimales).
Siguiendo con el ejemplo, hasta ahora tenemos algo parecido a lo que vemos en la foto. Sabemos que cada uno de los numeros esta dentro de una variable chr, pero..como se hara lo demas??


Aqui en donde comenzamos a realizar la operacion, tomamos el numero en chr4  y el primer numero a multiplicar. En si, lo que estamos haciendo es una multiplicacion paso a paso, como comunmente hacemos a mano.
Esos dos valores iran a los registros al y bl, una vez ahi se multiplicaran y el resultado quedara en el registro al.
Como se puede apreciar, el resultado de la multiplicacion es 10, en hexadecimal A. Para poder guardar por separado ambos numeros(ya que en si, no podemos guardar el 10 como resultado final) limpiamos la parte alta del registro AX, para hacer lo siguiente:
Aplicamos la funcion aam, y lo que hara es separarnos las unidades de las decenas en la parte alta y baja del registro.
En la tercera foto de los registro de la imagen de arriba podemos ver como, en al tenemos 0 y en ah tenemos 1.
Asi que, el resultado que deberia ir abajo como una multiplicacion comun se guardara en r4, mientras que nuestro acarrero(lo que conocemos como el numero que "se lleva") que es 1, se guardara en ac1.

Aqui realizamos la misma operacion, pero al momento de guardar nuestro resultado en r3, tambien le sumaremos ese numero de acarreo que antes habiamos sacado en la operacion anterior. Ya que, ese numero afecta al resultado de nuestra siguiente operacion.
Finalmente, volvemos a hacer la separacion de acarreo y resultado, para tener nuestro resultado en r3 y el nuevo acarreo guardarlo nuevamente en ac1.


Entonces, hasta ahorita nuestras variables se ven de la siguiente forma. Deberíamos tener todas las variables de caracteres ocupadas por los números que usamos al inicio, y los resultados 4 y 3,junto con el acarreo 1.
El paso siguiente en la sintaxis, es volver a hacer el mismo proceso que hicimos con chr4, pero ahora con chr3.
No dare mucha explicacion, ya que es el mismo proceso que el anterior. Solo que aqui, el acarreo que vayamos teniendo se guardara ahora en ac.


Hasta este punto, todas nuestras variables estan ocupadas por los siguientes valores(puedes confirmarlo siguiendo el diagrama de la imagen con la mulltiplicacion que normalmente hacemos)

La siguiente parte de nuestro programa comienza a realizar la suma de los resultados que ya tenemos. Iniciamos limpiando el registro AX para realizar las sumas necesarias.
Posteriormente, comenzamos moviendo a la parte alta del registro ax, nuestro r3. En la parte alta del registro bx, movemos r2.
Despues de estos movimientos, sumamos ambos registros y el resultado lo guardaremos en r3.
Si ves, antes de esto se realiza lo mismo de la funcion aam, por si acaso hay un acarreo. Lo cual se guardaria ahora en r2, el cual sera nuestro nuevo acarreo en la suma que estamos haciendo.
R4 solo baja como en la imagen sin mover su valor a ningun lado o sumarse porque al igual como realizamos la suma final de la multiplicacion, este numero baja sin ser afectado por algo.

Hasta ahora tenemos las unidades y decenas de nuestro resultado final.



Posteriormente, tomamos los valores de r1 y ac1 para la siguiente suma en los registros.
Hacemos la suma de ac1 con nuestro nuevo acarreo, r2 y posteriormente sumamos lo que hay en r1.
Volvemos a limpiar la parte alta de ax por si hay algo en ella, para posteriormente realizar la función que separa unidades de decenas para guardar nuestro nuevo acarreo.
 Finalmente, sumamos lo que tenemos en ac y en nuestro nuevo acarreo de la suma pasada r2. El resultado de esta suma lo tendremos guardado en ac.
En esta parte, el programa ira imprimiendo el resultado de dicha multiplicación que hemos realizado.
Si vez, es orden que sacamos en donde iba guardando los resultados el programa, es el mismo orden en como los ira imprimiendo en pantalla.

Al momento de ir imprimiendo o cargando los datos, le suma ese 30h que anteriormente le restamos para que pueda imprimir el carácter con ese valor en hexadecimal, y muestre correctamente el resultado.



No hay comentarios.:

Publicar un comentario