Foro de elhacker.net

Programación => ASM => Mensaje iniciado por: Juan Martinez en 15 Mayo 2017, 18:01 pm



Título: Ayuda en ensamblador, no sale del ciclo
Publicado por: Juan Martinez en 15 Mayo 2017, 18:01 pm
Tengo este programa, es para calcular el promedio de n números ingresados por el usuario,
Corre todo bien hasta el momento de ingresar los datos, nunca sale del ciclo en el que se encuentra.
Este es el código:


Código
  1. .model small
  2. .stack 64
  3. .data
  4. ;.........................................
  5. VAL1 DB ?
  6. msj1 DB 0AH,0DH, Cuantos numeros deseas introducir? : , $
  7. msj2 DB 0AH,0DH, Numero: , $
  8. msj3 DB 0AH,0DH, Promedio: , $
  9. buffer DB 3,4 DUP(?)
  10. ;.........................................
  11. .code
  12. empezar proc far
  13. mov ax,@data
  14. mov ds,ax
  15. mov es,ax
  16.  
  17. LEA DX,msj1
  18. MOV AH,09H
  19. INT 21H
  20.  
  21. MOV AH,0AH
  22. INT 21H
  23. SUB AL,30H
  24.  
  25. MOV CL,AL
  26. MOV BL,AL
  27. MOV AL,00
  28. MOV VAL1,AL
  29. proc1:
  30. LEA DX,msj2
  31. MOV AH,09H
  32. INT 21H
  33.  
  34. MOV AH,0AH
  35. LEA DX,buffer
  36. INT 21H
  37. SUB AL,30H
  38.  
  39. ADD AL,VAL1
  40. MOV VAL1,AL
  41. LOOP proc1
  42.  
  43. proc2:
  44. LEA DX,msj3
  45. MOV AH,09H
  46. INT 21H
  47.  
  48. MOV AX,00
  49. MOV AL,VAL1
  50. DIV BL
  51. ADD AX,3030H
  52. MOV DX,AX
  53. MOV AH,09H
  54. INT 21H
  55.  
  56.  
  57. mov ax,4c00h ;fin del programa con interrupcion
  58. int 21h
  59. empezar endp
  60.  
  61. end empezar
  62.  
  63.  

Ojala y me puedan ayudar, gracias

MOD: Etiqueta GeSHi


Título: Re: Ayuda en ensamblador, no sale del ciclo
Publicado por: Serapis en 15 Mayo 2017, 21:42 pm
Loop Proc1, te devuelve a Proc1, pero antes decrementa el registro CX en una unidad, cuando CX llega a 0, deja de hacer el salto a Proc1... Entonces se trata de saber que valor ingresas en el registro CX.

Si miramos el código, al registro CX, no se le ha asignado explícitamente ningún valor, luego contendrá la basurilla que reste de otro programa, si más adelante colocas un valor en CL, pero no sabemos cual hay en CH, luego...  :silbar: :silbar: :silbar:

Típicamente un bucle lleva la estructura:

Código
  1. MOV CX, Contador
  2. Inicio:
  3. ... codigo a repetir
  4. LOOP Inicio
  5.  
  6. cuando CX valga 0
  7. ...codigo despues del bucle

Prueba a asignar a contador un valor arbitrario cada vez, por ejemplo 13, ejecuta paso a paso y verás como el bucle retorna una y otra vez al 'Inicio', y cólo cuando CX valga 0, ejecuta el código tras el bucle.

Dado que dices "n números ingresados", Contador debería valer ese 'n'. Si 'n' no es conocido, porque se debe ejecutar una y otra vez hasta que el usuario tome una decisión al respecto, entonces el bucle que debe usarse no va por Loop, mejor LOOPNE, o LOOPNZ por ejemplo haciendo que cuando el usuario quiera terminar pulse una determinada tecla, tu haces un TEST entre el valor de la letra esperada (Q) y el valor de la letra introducida por el usuario, y acto seguido saltas en función del resultado del test... a diferencia de otros lenguajes, el ensambalador permite una infinidad de opciones para hacer lo mismo. compruebas si la tecla pulsada es la deseada, en cuyo caso puedes hacer un XOR CX CX (que cambia su contenido a 0, y entonces usas LOOPNZ), cuando CX sea 0, saldrá del bucle... en este caso el salto está condicionado, por la pulsación de una tecla concreta (la 'Q' por ejemplo de "Quit")...
Y tu código quedaría controlado tal que así:

Código
  1. MOV CX, 1 <-- poner un valor en el contador
  2. Inicio:
  3. .... tu codigo (entrada de datos por parte del usuario)
  4. TEST teclaesperada "Q", contra valor entrado
  5. JNE FinOpera <--- SALTAR si igual (o si no cero JNZ)
  6. INC CX
  7. .... tu código para sumar el nuevo valor entrado (distinto de Q)
  8. FinOpera:  <--- punto de salto si usuario pulsa tecla Q (salir)
  9. LOOPNZ Inicio
Al llegar a Loop, si la tecla introducida es distinta de la esperada, se incrementa CX, entonces CX=2, luego Loop decrementa CX, y CX vuelve a valer 1.
En cambio, si el númnero recibido es igual al valor ASCII de Q (81) el test devuelve 'True', y por tanto saltamos el incremento de CX, como vale 1, cuando llegue a LOOP decrementa 1, vale 0 y por tanto sale ya del bucle.

En resumen:
- Fíjate que tu no tienes claro (yo por lo menos leyendo tu código), el valor de CX, así que no hay forma de saber cuando llega a cero...
- LOOP decrementa CX en 1 cada vez que se ejecuta y si CX vale 0, sale fuera del bucle.
- Si el condicional de salida depende de algún factor más, puedes o bien controlar directamente CX (como te muestro en el ejemplo), o bien usar otras variantes de LOOP, LOOPE, LOOPZ, LOOPNE, LOOPNZ, o incluso alguna instrucción condicional de salto... (por ejemplo JNE, podría saltar fuera del bucle directamente, es buena práctica al inicio, tener una única salida de un procedimiento, cuando tengas buen control del código, no te importará que se salga desde más de una parte)...


Título: Re: Ayuda en ensamblador, no sale del ciclo
Publicado por: Juan Martinez en 15 Mayo 2017, 23:51 pm
Muchas gracias por tu ayuda

entonces quedaria asi:
Código
  1. MOV CX,1
  2. proc1:
  3.        LEA DX,msj2
  4.        MOV AH,09H
  5.        INT 21H
  6.  
  7.        MOV AH,0AH  
  8.    LEA DX,buffer
  9.    INT 21H
  10.    SUB AL,30H
  11.  
  12. TEST
  13. JNE FinOpera
  14. INC CX
  15.  
  16.        ADD AL,VAL1
  17.  MOV VAL1,AL
  18. FinOpera:
  19.        LOOPNZ proc1

o que mas es lo que tengo que modificar?


· Los códigos deben ir en etiquetas GeSHi (segunda advertencia)
>aquí las reglas del foro (http://foro.elhacker.net/reglas.htm)
-Engel Lex


Título: Re: Ayuda en ensamblador, no sale del ciclo
Publicado por: Serapis en 16 Mayo 2017, 02:18 am
Antes de nada: Date cuenta que te han corregido el código para encerrarlo entre (USA) etiquetas CODE, hazlo tú en lo sucesivo... para delimitar el código y que resulte más legible.
En los botoncitos del editor (de mensajes), a la derecha pone: "Código Geshi", despliega el combo y elige el lenguaje pertinente, al caso ASM. Es la 2ª advertencia que te dan, no se que pasará a la 3ª  :silbar:

Bueno, lo que veo es que o no conoces la instrucción Test, o se te ha pasado (piensa que yo te he puesto algo intermedio entre ensamblador y pseudocódigo, me gusta que la gente soluciones su tema, pero pensando un poco no solo copiando y pegando)...
La instrucción TEST, es muy similar a la instrucción CMP  y como ella, lleva dos operandos (en el mensaje previo, he expresado ambos operandos en forma de pseudocódigo), Destino y fuente, técnicamente es un AND (y por tanto igual de rápida) y a diferencia de AND y CMP, no almacena el resultado en destino, solo altera (si así sucede), los banderines de estados (los mismos que AND, ya que el hardware implementa esta instrucción partiendo de AND, técnicamente es un AND (si no es un procesador RISC), sin la microoperación copiar el resultado en destino).

Así en TEST, uno de sus operandos puede contener la mascara con la que se compara. Si al caso como yo decía la letra Q (ASCII=81), si es un valor inmediato entonces debe ser el operando origen, en el otro operando puedes poner un registro, o una dirección de memoria, donde yace el valor de la letra con la que se evalúa.

Ejemplo:
TEST Al, 51H - 30H
<--- Igual que a los números 0-9 (ASCII 48-57, les restamos 48
Para que sean  en el rango 0-9, al valor inmediato también le tenemos que restar, para que coincida que el valor leído (y al que se le descontó, 48 (30H))... obviamente, la resta puedes ponerla ya como un resultado, pero si nu ncomentario, más adelabnte puede que te preguntes de dónde viene compararlo con ese valor... hasta que tengas costumbre, los comentarios 'tontos', te serán necesarios, ponlos...

p.d.: Una última cosa... no es preciso, que me envíes un mensaje privado para que responda en tu tema, ya cuando entro procuro mirar temas que entienda 'tener a medias'... siempre que mi tiempo libre me lo permita.