domingo, 22 de mayo de 2016

Ensamblado manual (continuación): ¡ya sáquenme de la matrix!

Retomemos el programa que estábamos ensamblando. Lo copio de nuevo:


VEC     EQU    $0040

        ORG    0000
MENOR   RMB    1      Aqui quedara el menor
DIRINI  FDB    VEC    Direccion inicial del vector
CANT    FCB    07     Cantidad de elementos del vector

* El vector lo estoy ubicando en otro lugar de memoria R/W
        ORG    VEC
VECTOR  FCB    $14,$33,$FF,$E0,$09,$11,$10

* Notar que la dir inicial del programa es la que cargo en el vector de reset al final, para que inicialice el PC.


        ORG    $C000
main    LDX    DIRINI   * Cargo IX con la direccion inicial
        LDAA   0,X      * Cargo el primer elemento del vector en A
        DEC    CANT     * Decremento la cant directamente en memoria
SIGO    INX       
        LDAB   0,X      * Cargo el segundo elemento del vector
        CBA             * y los comparo
        BLS    Amenor   * Si el primero ya era menor, no lo cambio
        TBA             * Copio B en A
Amenor  DEC    CANT     * Decremento la cant directamente en memoria
        BNE    SIGO     * Si aun quedan elementos, sigue
        STAA   MENOR    * Sino guarda el menor en donde se pidió
FIN     BRA    FIN

        ORG    $FFFE
RESET   FDB    main


Esta es la tabla de símbolos como la dejamos:

identificador valor (hexadecimal)
VEC           0040
MENOR         0000
DIRINI        0001
CANT          0003 
VECTOR        0040 
main          C000
Amenor
SIGO
FIN
RESET         FFFE

y hasta aquí habíamos llegado ensamblando:

                         ORG    $C000
$C000  DE 01     main    LDX    DIRINI

$C002  A6 00             LDAA   0,X     
$C004                    DEC    CANT

Para continuar tenemos que ensamblar la instrucción DEC. Observemos los modos de direccionamiento que soporta:
En este caso DEC no admite modo directo, sino solo indexado y extendido. No estamos usando indexado porque la referencia CANT es una dirección de memoria, así que el código de operación es 7A. Observe que el operando se debe expresar en 16 bits, por eso en el set de instrucciones aparece como "hh ll", o sea parte alta (High) y parte baja (Low) de la dirección. En la tabla de símbolos vemos que CANT es 0003, por tanto al ensamblarlo queda así:

                         ORG    $C000
$C000  DE 01     main    LDX    DIRINI

$C002  A6 00             LDAA   0,X     
$C004  7A 00 03          DEC    CANT 
$C007            SIGO    INX       

Dado que la instrucción DEC CANT ensamblada ocupa tres bytes, la dirección de la siguiente instrucción es $C007 ($C0004 + 3). Seguramente ya habrá comprendido la dinámica del cálculo de la dirección de la siguiente instrucción. También habrá concluido que no es posible "predecir" la dirección de una instrucción cualquiera sin antes ensamblar todas las anteriores. Hay que tener especial cuidado de no asumir que podemos usar modo directo con todas las instrucciones, ya que existen algunas que no lo admiten (DEC, INC, CLR por ejemplo).

La siguiente instrucción tiene una etiqueta (SIGO) por tanto podemos completar esa entrada de la tabla de símbolos: SIGO equivale a $C007. El código de operación de INX es fácil de determinar porque opera solo en modo inherente. Las dos instrucciones que siguen (LDAB en modo indexado y CBA, que solo admite inherente) no representan mayor dificultad, así que también las ensamblamos sin mayor inconveniente. Llegamos a este punto, donde BLS también admite un solo modo de direccionamiento: relativo.

                         ORG    $C000
$C000  DE 01     main    LDX    DIRINI

$C002  A6 00             LDAA   0,X     
$C004  7A 00 03          DEC    CANT 
$C007            SIGO    INX       
$C00E6 00             LDAB   0,X     
$C00A  11                CBA             

$C00B  23 ??             BLS    Amenor  
                         TBA            
                 Amenor  DEC    CANT     

                         BNE    SIGO    
                         STAA   MENOR    

                 FIN     BRA    FIN
La cuestión es: ¿cómo completamos lo marcado con signos de interrogación? El modo relativo de BLS (o de cualquier branch) utiliza un operando de 8 bits, por eso en el set de instrucciones vemos que dice rr:

Por tanto aunque aun no calculamos el operando, sabemos que es de 8 bits. En un post anterior sobre Direccionamiento relativo hemos visto cómo operan las instrucciones de salto (tal vez merezca un repaso). Como tenemos que calcular el salto a la etiqueta Amenor pero aun no la completamos en la tabla de símbolos, continuemos el ensamblado dejando el lugar para el operando que nos falta. Luego volveremos a ella. Dejaremos también pendientes los otros saltos relativos.


                         ORG    $C000
$C000  DE 01     main    LDX    DIRINI

$C002  A6 00             LDAA   0,X     
$C004  7A 00 03          DEC    CANT 
$C0008        SIGO    INX       
$C00E6 00             LDAB   0,X     
$C00A  11                CBA             

$C00B  23 ??             BLS    Amenor  
$C00D  17                TBA            
$C00E  7A 00 03  Amenor  DEC    CANT     

$C011  26 ??             BNE    SIGO    
$C013  97 00             STAA   MENOR    

$C015  20 ??     FIN     BRA    FIN
$C017
Aunque todavía nos faltan determinar tres operandos de los branch del ejercicio, ya podemos completar la tabla de símbolos:

identificador valor (hexadecimal)
VEC           0040
MENOR         0000
DIRINI        0001
CANT          0003 
VECTOR        0040 
main          C000
Amenor        C00E
SIGO          C007
FIN           C015
RESET         FFFE

¿Cómo calculamos el direccionamiento relativo de los saltos? Tal como vimos en el post sobre ese tema, lo que acompaña la instrucción de salto es el offset que se aplica al PC (claro está, cuando se cumple la condición del branch). Este offset puede ser positivo, lo que provocaría un salto hacia adelante, o negativo, que se traduce en un salto hacia atrás.
En el ejemplo tenemos los dos tipos de saltos. La línea BLS Amenor es un salto hacia adelante. Cuando CPU haya leído la instrucción completa (pero aun antes de ejecutarla) el PC tendrá el valor de la siguiente instruccion $C00D. La etiqueta Amenor corresponde a la dirección C00E -tal como apuntamos en la tabla de símbolos-. Haciendo la resta, C00E - C00D (donde queremos estar menos donde estamos) obtenemos el offset, en este caso 01.
Consideremos otro de los saltos: BNE SIGO. Este salto -de ejecutarse- es hacia atrás. Luego de leer la instrucción completa "BNE SIGO", el valor del PC es C013. La etiqueta SIGO segun la tabla de símbolos corresponde a la dirección C007. El offset lo obtenemos entonces restando donde queremos estar de donde estamos: C007-C013. Esta cuenta en hexadecimal nos da un valor negativo (podemos restar al revés y recordar aplicarle el signo negativo): -12 (en decimal). Nos queda expresar -12 en negativo como complemento a la base, lo cual equivale a 11110100 en binario, o F4 en hexadecimal.
Finalmente hay un salto en la última instrucción: FIN BRA FIN. En este caso el PC queda con el valor C017 y queremos que salte a C015, por tanto el offset es -2 (en decimal). Expresado en hexadecimal sería FE (negativo en complemento a la base).

Completemos el programa:


                         ORG    $C000
$C000  DE 01     main    LDX    DIRINI

$C002  A6 00             LDAA   0,X     
$C004  7A 00 03          DEC    CANT 
$C0008        SIGO    INX       
$C00E6 00             LDAB   0,X     
$C00A  11                CBA             

$C00B  23 01             BLS    Amenor  
$C00D  17                TBA            
$C00E  7A 00 03  Amenor  DEC    CANT     

$C011  26 F4             BNE    SIGO    
$C013  97 00             STAA   MENOR    

$C015  20 FE     FIN     BRA    FIN 
$C017
Note que la última dirección la anotamos para guiarnos en el cálculo del último offset, pero realmente no es parte de la respuesta a la consigna.
¿Qué les pareció el procedimiento? ¿Alguna duda?
En otro post les cuento el método más práctico -a mi criterio- para obtener rápidamente la representación en complemento a la base de un número.

7 comentarios:

  1. Profeee en el caso que tenga que ensamblar la instruccion SUBD en modo directo, qué quieren decir las jj kk que hay en la parte de operando?

    Micaela Ramos

    ResponderBorrar
    Respuestas
    1. Me corrijo, en modo directo noN Inmediato*

      Borrar
    2. Hola Micaela! SUBD resta en 16 bits (D menos memoria). Lo que le vas a restar lo podés indicar en modo inmediato, con el numeral. Ahora bien, si vas a restar en 16 bits, tenés que poner un operando de 16 bits. Por ejemplo:
      SUBD #10FA
      o tan siquiera
      SUBD #0078
      si es que el operando "cabe" en 8 bits. El asunto es que debés expresarlo en 16. Habría que ver qué hace el THRSim si en el fuente podés:
      SUBD #78
      probablemente le agregue los dos ceros delante del 78.

      Borrar
  2. hola profe! estoy haciendo un ejercicio parecido a este pero además de guardar el numero mas grande me pide que guarde su dirección en DIR. No se como guardar su dirección del numero.

    ResponderBorrar
    Respuestas
    1. Hola Griselda! Si estás recorriendo un vector usando el índice IX, por ejemplo habiendo leido el valor con algo asi como un "LDAA 0,x" entonces en el registro IX tenes la direccion. Bastará con hacer un "STX dir" para guardar la dirección. Obviamente dir es una palabra de 2 bytes.

      Borrar
  3. Gracias profe! le hago otra preg, si me pide el complemento de 16 bits, y me da la dirección del valor a complementar y la direccionen donde guardarlo. Lo que hice fue:
    ldd #0
    subd dato
    stad resul
    mi duda esta en que según el ejercicio me da la "Dirección" del valor a complementar, por que no se si esta bien restarle Dato.

    ResponderBorrar

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