domingo, 1 de abril de 2012

Ensamblador 8086 itoa

Una vez entendiendo la función atoi del post anterior, decidí implementar la función que realiza la operación inversa. Ahora la entrada es un valor entero y lo debemos transformar en cadena. El pseudo-código se muestra a continuación:

1 temp = 0
2 indice = 0
3 while entero > 0
4   residuo = entero modulo 10
5   entero = entero div 10
6   cadena[indice] = residuo + 30h
7   indice = indice + 1
8 end while

La idea es ir extrayendo los dígitos (empezando por el menos significativo) e ir guardándolos en la cadena, noten que sumamos 30h para guardar el valor ascii que representa el dígito. Sin embargo, esta implementación genera una cadena al revés, es decir, si entero inicia con valor de 1234, la cadena final contendrá “4321”. Por lo que es necesario invertir esta cadena.

Pero es posible evitar invertir la cadena al final, para ello usaremos el stack (una estructura lifo – last in first out).

01 temp = 0
02 indice = 0
03 ndigitos = 0
04 while entero > 0
05   temp = entero modulo 10
06   entero = entero div 10
07   push temp
08   ndigitos = ndigitos + 1
09 end while
10 while ndigitos > 0
11   pop temp
12   cadena[indice] = temp + 30h
13   ndigitos = ndigitos – 1
14   indice = indice + 1
15 end while

El primer ciclo (línea 04-09) extrae los dígitos y los guarda en el stack, al final del ciclo el dígito más significativo se encuentran arriba del stack. El segundo ciclo (línea 10-15) extrae los dígitos del stack y los guarda en la cadena final.

El siguiente programa convierte dos cadenas a enteros usando atoi, los suma y convierte el resultado a cadena usando itoa para poder desplegarlo.

.model SMALL
.STACK 128
.DATA
  cadena1 db '411$'
  cadena2 db '144$'
  cadena3 db 6 DUP(?)
  op1 dw ?
  op2 dw ?

.CODE
  .STARTUP
  mov ax,@data
  mov ds,ax

main proc
  ; SI parametro
  mov si, offset cadena1
  call atoi
  mov op1,bx
   
  ; SI parametro
  mov si, offset cadena2
  call atoi
  mov op2,bx
   
  ; sumar
  mov ax, op1
  add ax, op2
  mov bx, offset cadena3
  call itoa
   
  mov dx, offset cadena3
  call desplegar
   
  ; INT 21h / AH=4Ch retorna el control al sistema operativo
  ;                  termina el programa
  salir:
  mov ax,4c00h
  int 21h
  ret
main endp

; ============ Proc: Desplegar mensaje ====================
; Parametros
; dx: offset de cadena terminada por $ con respecto a DS
desplegar proc
   ; INT 21h / AH=9 - despliega cadena apuntada por DS:DX. 
   ; la cadena debe estar terminada por '$'.
   mov ah,09h
   ;mov dx, offset cad
   int 21h
   ret
desplegar endp

; ========= Convertir cadena a numero =====================
; Parametros
; si: offset inicial de la cadena con respecto a DS
; Retorna
; bx: valor
atoi proc
  xor bx,bx   ;BX = 0

  atoi_1:
  lodsb       ;carga byte apuntado por SI en AL
              ;e incrementa si
  cmp al,'0'  ;es numero ascii? [0-9]
  jb noascii  ;no, salir
  cmp al,'9'
  ja noascii  ;no, salir

  sub al,30h  ;ascii '0'=30h, ascii '1'=31h...etc.
  cbw         ;byte a word
  push ax
  mov ax,bx   ;BX tendra el valor final
  mov cx,10
  mul cx      ;AX=AX*10
  mov bx,ax
  pop ax
  add bx,ax
  jmp atoi_1  ;seguir mientras SI apunte a un numero ascii
  noascii:
  ret         ;BX tiene el valor final
atoi endp

; =============== Convertir numero a cadena ===============
; Parametros
; ax: valor
; bx: donde guardar la cadena final
; Retorna
; cadena
itoa proc
  xor cx,cx  ;CX = 0

  itoa_1:
  cmp ax,0   ; El ciclo itoa_1 extrae los digitos del
  je itoa_2  ; menos al mas significativo de AX y los
             ; guarda en el stack. Al finalizar el 
  xor dx,dx  ; ciclo el digito mas significativo esta
  push bx    ; arriba del stack.
  mov bx,10  ; CX contiene el numero de digitos
  div bx
  pop bx
  push dx
  inc cx
  jmp itoa_1

  itoa_2:
  cmp cx,0    ; Esta seccion maneja el caso cuando
  ja itoa_3   ; el numero a convertir (AX) es 0.
  mov ax,'0'  ; En este caso, el ciclo anterior
  mov [bx],ax ; no guarda valores en el stack y
  inc bx      ; CX tiene el valor 0
  jmp itoa_4

  itoa_3:
  pop ax      ; Extraemos los numero del stack
  add ax,30h  ; lo pasamos a su valor ascii
  mov [bx],ax ; lo guardamos en la cadena final
  inc bx
  loop itoa_3

  itoa_4:
  mov ax,'$'  ; terminar cadena con '$' para 
  mov [bx],ax ; imprimirla con la INT21h/AH=9
  ret
itoa endp

end

2 comentarios:

  1. Excelente..!!! Gracias por compartirlo me fue de mucha ayuda.

    ResponderEliminar