sábado, 14 de mayo de 2016

Simulando programas assembler con THRSim

Aprender programación mirando el pizarrón es como aprender cocina mirando la tele... todo muy lindo, pero la verdad está ahí afuera... cuando llega el momento de sentarse frente a la compu y ver si el profesor nos mintió como a niños, ¡ahí se pone complicado! Veamos entonces cómo simular un programa con THRSim.
Partiré de la premisa de que tenemos un programa para probar, en este caso uno bien sencillito: determinar el tipo de triángulo e informarlo con una letra. La validación de si realmente es un triángulo (verificable por las longitudes de los lados) la dejamos fuera.

El programa podría ser así:

       org     $0000
l1     rmb     1   
l2     rmb     1
l3     rmb     1
tipot  rmb     1    Guardo el ASCII del tipo de triangulo:
* I para isosceles; Q para equilatero; E para escaleno

       org     $c000
       ldaa    l1
       ldab    l2
       cba
       beq     igual    si l1==l2, es equilatero?
       cmpa     l3    caso contrario, todavia puede ser isosceles
       beq     isos
       cmpb    l3    si l2 y l3 son iguales, tambien es isosceles
       beq     isos
       ldab     #'E    son todos distintos, es escaleno   
       bra    listo
igual  cmpa     l3    si l1==l2 y l1==l3 son iguales...
       bne     isos    (sino es isosceles)
       ldab     #'Q    ... entonces es equilatero
       bra     listo
isos   ldab     #'I
listo  stab     tipot  todos confluyen aqui
fin    bra     fin



En este momento nos centraremos en simular el programa, así que la explicación del algoritmo la dejamos para otro momento. Tampoco es tan complicado... y además puse comentarios para que se pueda seguir.

La primera sección del programa, a partir de la directiva de ORG (origen) en 0000, indica que tenemos cuatro reservas de un byte: los lados del triángulo (l1, l2, l3) y el resultado de la determinación de su tipo (tipoT). Para simular el programa necesitamos primero cargar los valores de los lados. ¿Cómo se hace? Veamos distintas formas.

1. Cargando posiciones de memoria individuales.
Menu View -> Memory -> Memory List...
Al acceder a esa opción nos preguntará desde qué dirección de memoria deseamos listar:
Como sugiere la dirección $0000, que es justamente donde definimos la directiva de origen en cuestión, el valor por default es el que buscamos, le damos OK y presenta la memoria:
¿Cómo se completa ahora? Hacemos doble click en el valor actual ($ff indica en este caso un valor no inicializado) y se habilita el cursor para tipear los valores:

Pero... ¿no sería mucho más fácil que la ventana de Memory List nos muestre a qué reserva de memoria (RMB) corresponde cada dirección? Efectivamente, y puede hacerlo. Pero para ello debemos ensamblar el programa. Si solo queremos ensamblarlo, pero no ejecutarlo, vamos al menu "File -> Assemble".
Attenti! Primero hacer foco en la ventana del código fuente. Entonces menú File->Assemble:
Cuando hagamos esto se presentará la ventana LST con el ensamblado... si es que no tenemos errores! Ahora si abrimos nuevamente la ventana Memory List, veremos que se asignaron las etiquetas a las posiciones de memoria:
Esto hace más fácil la carga del juego de prueba.

2. Cargando posiciones de memoria estilo vector
Otra forma de cargar juegos de prueba es editar la memoria en una vista más cercana al concepto de vector, esto es, un valor al lado del otro. Menu View -> Memory -> Memory Dump...
Nuevamente preguntará a partir de qué dirección hacer el volcado (dump), y tal como antes, para este caso nos sirve el valor default ($0000). Se presenta una ventana donde la memoria aparece como renglones de 16 bytes:

Aquí no tenemos las etiquetas de las reservas. Podemos editar la memoria haciendo doble click (tal como antes). La parte derecha de la ventana (que en la captura muestra puntos) es la representación ASCII del valor de memoria. ¿Por qué muestra tantísimos puntos? Porque no todos los códigos ASCII son caracteres imprimibles. Muchos de ellos, particularmente los valores bajos, corresponden a caracteres de control (cosas tales como inicio de archivo, fin de archivo, retorno de línea, etc) que no tienen una representación visual.

3. Inicializando directo en el código
Aunque visualizar la memoria se hace necesario para verificar el resultado de la ejecución del programa, disponemos de una herramienta para cargar los juegos de prueba directamente en el fuente. Lo que haremos es usar la directiva db (define byte) en lugar de RMB (reserve memory byte). Modificamos el fuente:

       org     $0000
l1     db     5   
l2     db     6
l3     db     2
tipot  rmb     1    Guardo el ASCII del tipo de triangulo:
* I para isosceles; Q para equilatero; E para escaleno


De esta forma estamos incluyendo el juego de prueba directamente en el código. En este caso no representa cambio alguno en la forma de simularlo.

¿Qué diferencia tiene esta forma de simularlo con la carga directa en la memoria? Al usar DB/DW el juego de prueba se carga al momento de ensamblar el fuente. Si deseamos cambiar los valores de prueba, debemos volver a ensamblar. ¡No alcanza con reinicializar el PC y ejecutarlo de nuevo!

Se puede verificar que los valores están en memoria usando las opciones antes descritas (Memory view y memory dump) y en la ventana LST (habiendo ensamblado nuevamente) donde aparece como contenido de la memoria:


Llegado a este punto hemos cargado el juego de prueba. Lo que sigue es ejecutar el programa y verificar si determina correctamente el tipo de triángulo. Para ello desde la ventana de ensamblado (LST) o desde la ventana del fuente ejecutamos el programa :
* menu Execute -> Run
* tecla F9
* icono "play" en azul

El programa quedará en el bucle final, hay que detenerlo (el botón STOP, tecla F2 o Menu Execute->Stop).
Luego hacemos un Memory Dump... (tal como se explica anteriormente) y podemos verificar que el cuarto byte de la memoria (dirección 0003) tiene el ASCII E, correspondiente a Escaleno:


Repasemos lo visto aquí:
* uso de la ventana Memory list
* uso de la ventana Memory dump
* carga de variables directa en el codigo con define byte (db)
* ejecución del programa

¿Preguntas, comentarios?


Mientras practican con el simulador, escuchen El Gran Simulador...



 

2 comentarios:

  1. Profe, una consulta aunque no tenga que ver con lo explicado en este post. Si tengo una variable FLAG seria lo mismo hacer "LDAA#1 STAA FLAG" que hacer "INC FLAG"? (si previamente hice un CLR FLAG).

    ResponderBorrar
    Respuestas
    1. Hola! Va un espacio entre LDAA y #1. Fuera de ese detallecito, la respuesta a tu pregunta es si. Lo que podrías comparar es si al ensamblar las dos variantes hay alguna que consuma menos bytes. También podrías sumar los ciclos de las dos formas y ver si una es más rápida que la otra.

      Borrar

Aunque no es obligatorio, es de buena educación firmar los comentarios.