SoloCodigo
Programación General => ASM (Ensamblador) => Mensaje iniciado por: colitroni en Jueves 9 de Octubre de 2003, 00:21
-
Bueno, esta es mi primera incursion en este lenguaje despues de leer y ver ejemplos. Lo que hago en el programa es leer un nº por teclado 2 bytes y lo que quiero es imprimirlo por pantalla y aqui es donde tengo el problema:
La tecnica que sigo es hallar el divisor (1,10,100,1000,10000) dependiendo de las cifras que tiene el nº introducido por el usuario; luego voy dividiendo el nº por el divisor, despues divido el divisor (para quitarle ceros) y ahi se produce un error de DIVIDE ERROR, el proc es el siguiente:
las definiciones que realizo son:
a dw ? ;contiene el nº introducido
diez dw 10 ;cte de valor 10
PRINTNUM PROC NEAR
mov dl,10 ; introduzco 1 retorno de carro
mov ah,02
int 21h
mov dl,13 ; introduzco 1 retorno de carro
mov ah,02
int 21h
mov ax,1 ; contador para saber el nº de cifras q tiene a
mov bx,a ; cargo en bx la variable a
bucle:
mul diez
cmp ax,bx
jbe bucle ; multiplico ax por 10 hasta que ax>bx ojo el resultado es dx:ax
div diez ; asi tiene ax las mismas cifras q bx en este punto
push ax ; guardo el divisor
SacaCifra:
pop cx ; meto el divisor en cx
mov ax,bx ; cargo en ax la variable cuyos digitos quiero mostrar
div cx ; y la divido por cx q será 1,10,100,1000 o 10000
mov bx,dx ; guardo el resto q es lo q queda por sacar
mov dx,ax ; ya que en ax está el cociente
add dl,30h ; así tengo el caracter ascii q coresponde al digito
mov ah,02 ; lo saco en pantalla
int 21h
mov ax,cx ; cargo el divisor en ax
div diez ; y le quito 1 cero ------------ ERROR QUE ME DA: DIVIDE ERROR ------------
push ax ; lo guardo en la pila
cmp ax,1
jae SacaCifra
ret
PRINTNUM ENDP
Por cierto, al que quiera aprender como yo estoy haciendo, le recomiendo el emu8086 que es emulador, ensamblador y desensamblador todo en 1, funciona en Win9x,ME y XP y lo bueno es q si haces burradas, no se cuelga ya q es un emulador;) Si quisierais el nº de serie os podria pasar el mio para registrarlo;)
Salu2 y Espero vuestras respuestas
-
Bueno, pues he encontrado el pequeño fallo. Era que como divido por word, no tenia en cuenta que dx no es cero llegado a esa linea, ya que en dl pongo el valor ascii del caracter para sacarlo por pantalla, asi pues me salia un nº enorme y claro al dividir por 10 me daba error de desbordamiento por división, la solucion la he encontrado leyendo en esta peich, por si os sirve de ayuda a los q como yo estamos empezando:
http://www.sinergia-web.com.mx/clases/a ... lase12.htm (http://www.sinergia-web.com.mx/clases/asm9708/Temas/clase12.htm)
Asi pues, funciona correctamente poniendo la ultima parte como queda:
mov ax,cx ; cargo el divisor en ax
xor dx,dx ; pongo a cero el word alto ya que el cociente es dx:ax
div diez ; y le quito 1 cero
push ax ; lo guardo en la pila
cmp ax,1
jae SacaCifra
Como veis he insertado un xor dx,dx para ponerlo a cero. Tambien hay que poner un pop ax justo antes del ret, o poner ret 2 para que desapile el ultimo push ax cuando ya no hay cifras que sacar.
Salu2.
-
El programa me parece interesante, pero tengo una duda: ¿el numero a mostrar de cuantos digitos es, ya que si es introducido(por teclado) estaria en ascii, y en que momento se introduce el numero?
eso seria todo Gracias
-
para mostrar un numero de 16bit que esta en AX:
;;*****************
cmp ax,0 ;verifiacmos si AX es cero
jz fin ;si lo es el programa termi
mov si,offset cadena + 5;
mov bx,10 ;dividor para obtener
c1: xor dx,dx ;los digitos
div bx ;el digito va a DL
;en AX el #restante
add dl,48 ;lo convertimos en ascii
mov [si],dl;movemos a la cadena
dec si
jmp c1 ;continuamos con el resto
fin: mov ah,9
mov dx,offset cadena
int 21h
int 20h
cadena db '00000$' ;cadena a ser mostradamostrada
;;****************
no compile el programa pero espero que la idea se entienda
-
El usuario puede teclear un nº entre 0 y 65535 que es lo que corresponde a 2 bytes unsigned, ya que en el print_num no tengo encuenta el signo. La entrada termina cuando el usuario termina con enter. El nº queda almacenado en num y el procedimiento quedaria como sigue:
intronum proc near
push ax
push bx
push dx
lea bx,num ; bx apunta a num
xor dx,dx ; pongo a cero dx
mov [bx],dx
introcar:
mov ah,01h
int 21h ; espero caracter de usuario -> viene en al
cmp al,13 ; si es enter....
jz fin ; terminamos
sub al,48 ; convierto el caracter a digito
mov dl,al ; guardo el digito en dx
mov ax,[bx] ; cargo en ax el valor momentaneo de la variable
push dx ; al multiplicar por word afecto a dx por eso lo guardo
mul diez ; lo multiplico por 10 ojo el resultado es dx:ax
pop dx ; recupero el valor de dx
add ax,dx ; le sumo el digito introducido para obtener el valor momentaneo
mov [bx],ax ; guardo el numero en la variable num
jmp introcar: ; voy a por el siguiente digito
fin:
pop dx
pop bx
pop ax
ret
intronum endp
Ahora quiero tratar con nº mayores de 2 bytes (ya q estos caben en 1 reg y es facil la transferecia mem-reg-mem) Mi siguiente reto es intentar nº de 4 bytes con lo que ya podria almacenar nº bastante grandes. Mira a ver que te parecen las siguientes ideas:
1) Creo variable tipo dd (DoubleWord)
p.e.: numero dd ?
2) Con LES ax,numero creo q tendria el word bajo en AX y el alto en ES, con lo que pasando ES a DX ya tendria mi nº en DX:AX dispuesto para realizar cualquier operacion aritmetica, esto correcto???
3) Tengo 1 duda q quiero preguntarte, una vez modificado ese nº DX:AX como lo paso otra vez a la variable numero, hay alguna instruccion de carga directa que me pudiera servir??? o podria hacerlo son SI apuntando a num y meter AX y luego incrementar SI en 2 y meter DX ???
Por cierto, en tu codigo al dividir, el resto no estaria en DX y el digito en al????
Espero tus respuestas, Salu2.
-
me gusta ese reto, pero en este instante no se me ocurre una solucion, pero veamos la dudas:
1) LES AX,numero
Esto carga el desplazamiento de numero en AX y su segmento en ES, No carga la parte baja en AX y la alta en ES, por lo tanto no seria corresta la suposicion.
2)movimiento directo de DX:AX a memoria
Creo que existe alguna instruccion que produce esa o una operacion similar pero no la recuerdo;
Despues una alternativa seria usar registros de 32bits como EAX,EBX,...pero cuando quieras trabajar con numeros mas grandes ya no funcionaria y seria la misma historia.
Hace algun tiempo tenia la tarea de multiplicar 3 numeros de 32Bits en el 68000MC, y hacerlo de forma iterativa consumia un tiempo enorme(practicamnete se colgaba), lo que hice fue dividir los numeros grandes resultantes en words, y aunque no era tan facil pues no lo termine, creo que podria ser una alternativa.
-
Hola Colitroni tengo una version de puerba del emu8086 y me gustaria tener el serial
si me lo puedes pasar este es mi correo seth_los@yahoo.com
saludos gracias
-
En lugar de fomentar la pirateria, porque no usas compiladores com NASM (http://www.proc.org.tohoku.ac.jp/befis/download/nasm/) que son gratuitos :P