domingo, 15 de mayo de 2016

Direccionamiento: ¿dónde estás operando de mi vida que no te puedo encontrar?

Al programar constantemente hacemos referencia a los operandos o variables que usamos. En alto nivel poco (o nada) nos preocupa dónde se ubican tales variables y cómo hará CPU para ubicarlas. Frecuentemente no tenemos mucha idea de cómo lo está logrando, a excepción del manejo de punteros en C y cosas por el estilo. Sin embargo, en el bajo nivel debemos especificar de qué forma CPU deberá obtener los operandos. Aun cuando utilicemos un ensamblador -por ejemplo el THRSim- el control del modo de direccionamiento empleado recae en el programador.
El microcontrolador Motorola 68HC11 dispone de estos modos de direccionamiento:
* extendido
* inmediato
* directo
* indexado
* relativo
* inherente

En el set de instrucciones podemos ver qué modos soporta cada instrucción, por ejemplo LDAA:
En este caso soporta modo inmediato (IMM), directo (DIR), extendido (EXT) e indexado tanto contra el registro IX (IND, X) como IY (IND, Y). Es de notar que el Opcode (código de operación) para modo de direccionamiento es totalmente distinto. (Columna a la derecha de la marcada en rojo) ¿Qué significa? Que para la unidad de control efectuar la misma operación -para el ejemplo cargar el acumulador A desde memoria- en distintos modos de direccionamiento representa realmente distintas instrucciones.
La columna Operand indica el formato del (o los) operandos de la instrucción. Para el modo inmediato (IMM) se trata de 8 bits, representados por dos letras "ii". Para el modo extendido (EXT) son 16 bits, por lo que se presenta con cuatro letras en dos pares "hh ll". Las letras H y L están señalando que se espera un operando de 16 bits donde primero se indica la parte alta H y luego la parte baja L.
Cuando se emplea direccionamiento indexado la misma instrucción indica si se haremos referencia al índice IX o a IY. Lo que acompaña el código de operación es el offset (por es las letras ff). Se puede apreciar que el offset será de 8 bits.
¿Por qué necesitamos comprender bien esto? Bueno, ¿sabría indicar cuál de las siguientes instrucciones son válidas?

LDAA #257
LDAA -1,X
LDAA 258,X
LDX #$2000

Para saber la respuesta busque en el set de instrucciones los últimos cuatro flags afectados por la instrucción MUL. Las cuatro instrucciones se corresponden con ellos (en el orden en que están). Los que tengan un delta indican las instrucciones correctas. (No hay nada particular con MUL, solo que no quería poner las respuestas aquí).

El modo directo es en realidad un modo paginado, solo que al no existir un registro de página, es aplicable solo a la página cero. Dividir la memoria en páginas es un mecanismo muy útil para separar lo que cada proceso puede acceder. En el caso del HC11 no manejamos multiprocesamiento, y tampoco podemos acceder via modo paginado a otra parte de la memoria que no sean los primeros 256 bytes (desde 0000 a 00FF). ¿Cuál es la ganancia entonces? El caso es que la página cero corresponde mayormente a memoria R/W, por tanto es el lugar donde alojamos las variables. Resulta de mucha utilidad acceder a esta porción de memoria con más facilidad. ¿Dónde radica la facilidad? Veámoslo en un ejemplo.
Se trata de una suma de dos numeros de 8 bits, nada extraño:

               ORG     $0000  
resultado      rmb     2      
op1            rmb     1      
op2            rmb     1      

               ORG     $C000      
               clr     resultado   ; Hresultado <= 0
               ldaa    op1         ; A <- op1
               adda    op2         ; A = A + op2
               staa    resultado+1    ; parte baja de resultado=A
               bcc     sale        ; Si no hay carry, chau
               inc     resultado   ; Else, Hresultado++
sale                     
               bra     sale        ; se fini
                        


Aunque no lo parezca estamos determinando qué modo de direccionamiento emplear (al menos hasta cierto punto). Cuando ensamblamos el resultado es este:
Dado que ubicamos los datos a partir de la página cero (observar que antes de la reservas de memoria dice ORG $0000), al acceder a op1, op2 y resultado se puede aprovechar el modo directo. Note que la instrucción
LDAA op1
se ha ensamblado como
96 02
Siendo 96 el código de operación en modo directo. 02 es la dirección del op1 (la parte baja, porque la parte alta es 00, lo que justamente implica el modo paginado a página cero A.K.A. directo).

Se repite lo mismo con las instrucciones ADDA y STAA. Sin embargo en el caso de CLR y INC no fue posible. ¿Por qué? Observe en el set de instrucciones los modos de direccionamiento que soportan estas instrucciones:


(mi set de instrucciones es mágico, por eso CLR está a continuación de INC).
¿Cuál es el que no tenemos? ¡Modo directo! Por eso a falta de directo el ensamblador utiliza modo extendido.
¿Qué pasaría si movemos las reservas de memoria de la página cero a cualquier otra página de R/W? Veamos...

Edité la directiva de origen inicial ORG, ahora es ORG $0100. ¿Resultado? Observer que todas las referencias a memoria, incluidas las de LDAA, ADDA y STAA ahora están en modo extendido. ¿Razón? No disponemos de modo directo para la página 01.


Nos quedan los modos inherente y relativo para un siguiente post. Los dejo con un mensaje de interés general. Fumar es malo, muy malo... sino pregúntenle a humosvaldo ... (gracias @JuanM96 por el aporte)

3 comentarios:

  1. Muy buena y detallada explicación profe, lastima que no se dedique a hacer explicaciones así de los conceptos completamente teóricos.

    ResponderBorrar
    Respuestas
    1. Gracias por la observación. Este blog recién comienza! quién te dice que aparezcan temas teóricos puros también...

      Borrar
    2. En el peor de los cosas los leeré en una "recursada"
      (Espero que no...recursar)
      Alex.

      Borrar

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