CAPÍTULO 6 LOS REGISTROS ÍNDICE Y EL DIRECCIONAMIENTO INDEXADO

6. CONCEPTO GENERAL DE INDEXADO


En las secciones anteriores se han discutido técnicas de uso del Contador de Programa para direccionar ubicaciones de memoria a continuación, del código de operación, con el objeto de determinar la dirección de una operación en particular. Aparte de los casos en que el programador cambia directamente la memoria del programa, se puede considerar que los modos de direccionamiento discutidos hasta ahora son para direcciones fijas o directas, y cada una tiene los méritos que han sido discutidos en su respectiva sección. Sin embargo, un concepto más poderoso es el direccionamiento Calculado. Hay básicamente dos tipos de direccionamiento Calculado: el direccionamiento Indexado y el direccionamiento Indirecto.
El direccionamiento Indexado utiliza una dirección que se calcula modificando los datos de la dirección del Contador de Programa por medio de un registro interno llamado registro Índice.
El direccionamiento Indirecto utiliza una dirección calculada y almacenada que es accedida por un puntero indirecto en la secuencia del programa.
En la familia de productos MCS650X, se utilizan ambos modos y sus combinaciones.
Antes de abordar los conceptos más difíciles del direccionamiento Indirecto, se desarrollará el concepto de instrucciones indexadas.
Se puede escribir el siguiente programa para mover cinco bytes de memoria desde una dirección contenida en el CAMPO 1 a otro conjunto de direcciones, comenzando con el CAMPO 2:


Ejemplo 6.1: Mover Cinco Bytes de Datos Usando Código en Línea Recta


ETIQUETAINSTRUCCIÓNOPERANDOCOMENTARIOS
INICIOLDA
STA
CAMPO 1
CAMPO 2
Mover Primer Valor
LDA
STA
CAMPO 1 + 1
CAMPO 2 + 1
Mover Segundo Valor
LDA
STA
CAMPO 1 + 2
CAMPO 2 + 2
Mover Tercer Valor
LDA
STA
CAMPO 1 + 3
CAMPO 2 + 3
Mover Cuarto Valor
LDA
STA
CAMPO 1 + 4
CAMPO 2 + 4
Mover Quinto Valor

En este ejemplo, los datos se obtienen desde la primera posición de memoria de CAMPO 1; esta posición de memoria es direccionada por uno o dos bytes que vienen a continuación, del OP CODE en la memoria del programa; luego, este dato es almacenado temporalmente en el Acumulador y escrito en la primera posición de memoria de CAMPO 2, y también es direccionado por uno o dos bytes que vienen a continuación, en la memoria del programa. Esta secuencia se repite, cambiando sólo las direcciones de memoria, hasta que todos los datos han sido transferidos. Este tipo de programación se llama «programación en línea recta» porque cada operación repetitiva corresponde a un grupo separado de instrucciones listadas en secuencia o en forma de línea recta en la memoria de programa.
Cuando se implementa de esta manera, se necesita un total de 10 instrucciones para realizar el movimiento de datos. Cabe señalar que no se indica si CAMPO 1 o CAMPO 2 son direcciones de Página Cero o si son direcciones absolutas.
Si fueran direcciones de Página Cero, el número total de bytes consumidos en la solución del problema serían dos bytes por cada instrucción: por lo tanto, se requieren 20 bytes de memoria; si tanto CAMPO 1 como CAMPO 2 fueran ubicaciones de memoria absolutas, cada instrucción tomaría 3 bytes y este programa requeriría 30 bytes.
El programa de Página Cero se ejecutaría en tres ciclos por instrucción, o sea 30 ciclos, y la versión de ubicación absoluta se ejecutaría en cuatro ciclos por instrucción, o sea, 40 ciclos.
En este ejemplo se ha introducido un nuevo concepto, el de la notación simbólica en lugar de las ubicaciones reales para las instrucciones.
Este breve programa está escrito utilizando el direccionamiento simbólico, en el que la dirección de inicio del programa tiene el nombre START («INICIO»). Las representaciones simbólicas de direcciones como «START» se conocen como etiquetas. También se les han dado nombres a las direcciones de los dos campos de direcciones utilizados en este ejemplo: la primera dirección del primer campo se llama CAMPO 1; y la primera dirección del segundo campo se llama CAMPO 2. A cada dirección adicional de los campos se le ha dado un número que hace referencia al primer número; por ejemplo, el tercer byte en el CAMPO 1 es el CAMPO 1+2. Todos estos conceptos se implementan para simplificar el escribir un programa, porque el usuario no tiene que preocuparse por las ubicaciones de CAMPO 1 y CAMPO 2 hasta después de haber analizado las necesidades de memoria de todo el programa. La notación simbólica da como resultado un programa más legible.
La traducción de las instrucciones y direcciones de la forma simbólica a direcciones y OP CODES numéricos reales se realiza mediante un programa llamado «ensamblador simbólico». Para la familia de productos MCS650X existen diferentes ensambladores simbólicos y cross assemblers. En el resto de este texto se utilizará la notación simbólica debido a su facilidad de comprensión y porque las direcciones de byte individuales son innecesarias, aunque para la explicación de un modo en particular, se puede utilizar la representación en bytes.
En este ejemplo, sólo se usaron direcciones directas. A continuación, se presenta un programa para reducir el número de bytes necesarios para mover los cinco valores:



El ejemplo 6.2 corresponde a un listado de programa basado en el diagrama de flujo:


Ejemplo 6.2: Mover Cinco Bytes de Datos Usando un Bucle


ETIQUETAINSTRUCCIÓNOPERANDOCOMENTARIOS
INICIALIZARCLC
INICIO
OTRO
LDA
STA
CAMPO 1
CAMPO 2
Bucle de movimiento
LDA
ADC
STA
LDA
ADC
STA
INICIO + 1
#1
INICIO + 1
OTRO + 1
#1
OTRO + 1
Modificar valores de movimiento
CMP
BNE
#CAMPO 2 + 5
INICIO
Comprobar si es el final

NOTA: Para facilitar la lectura, las etiquetas se han escrito en la forma «CAMPO 1». Este es un formato incorrecto para ser usado en los diversos ensambladores simbólicos. Al codificar para formatos de ensamblador, «FIELD 1» debe escribirse «FIELD1».


El ejemplo 6.3 a continuación, fue escrito suponiendo direccionamiento directo en Página Cero usando un byte por línea, tal como aparecería en la memoria del programa. Esto proporciona una descripción más detallada del Ejemplo 6.2.


Ejemplo 6.3: Detalle de la Programación del Movimiento de Campos Usando un Bucle
ETIQUETANOMBRES DE LOS CÓDIGOSCOMENTARIOS
CLCBorrar bandera de Acarreo
INICIOLDA CAMPO 1(CAMPO 1) → A
OTROSTA CAMPO 2A → (CAMPO 2)
LDA INICIO + 1Dirección de origen → A
ADC 1A + 1 → A
STA INICIO + 1A → Dirección de origen
LDA OTRO + 1Dirección de destino → A
ADC 1A + 1 → A
STA OTRO + 1A + Dirección de destino
CMP CAMPO ORIGINAL 2 + 5A – CAMPO 2 ORIGINAL + 5
BNE INICIODe lo contrario, salte a INICIO

En este ejemplo, el programa modifica las direcciones de una instrucción de carga y una de almacenamiento, en lugar de escribir diez instrucciones para mover cinco bytes de datos, y cincuenta instrucciones para mover veinticinco bytes de datos.
La dirección de la instrucción Load A está ubicada en la memoria en START + 1, y la instrucción Store en OTHER + 1. Para realizar esta operación, la dirección debe ser modificada en cada operación de movimiento, hasta que se muevan todos los datos.
La verificación del final de los movimientos se logra comprobando el resultado de la modificación de la dirección para determinar si esta excede el final del segundo campo. Cuando esto sucede, la rutina sido completada. Si se movieran cien valores, este programa tendría 20 bytes de largo, mientras que la solución al primer problema requeriría un programa de 200 instrucciones.


El tipo de codificación utilizado en este ejemplo se denomina «bucle» o «ciclo». Aunque el bucle del programa en este caso requiere tantos bytes como el programa original, se podrán mover más valores sin aumentar el largo del programa. Cuanto mayor sea el número de operaciones repetitivas que se van a realizar, mayor será la ventaja la programación con bucles por sobre la programación en línea recta.


Nota importante: El tiempo de ejecución requerido para mover los cinco valores es significativamente más largo usando programación con bucles que usando la programación en línea recta. Si suponemos una operación de Página Cero, el tiempo total para realizar el movimiento usando programación en línea recta será de 30 ciclos. Usando la programación con bucles, el tiempo de ejecución para mover cinco valores es de cinco veces a lo largo de todo el bucle, lo que da un total de 25 ciclos. Por lo tanto, el tiempo total para mover cinco valores es de 125 ciclos.


Si bien los bucles tienen una ventaja en la eficiencia del espacio de codificación, todos los bucles cuestan Todavía tarda 13 ó 15 ciclos por byte movido tiempo. Si el programador tiene un problema que es extremadamente dependiente del tiempo, a menudo lo resolverá sacando el bucle y utilizando la programación en línea recta, a pesar de que es extremadamente ineficiente en términos de utilización de memoria.


La técnica de programación en línea recta se vuelve muy útil en algunas aplicaciones de control. Sin embargo, no se recomienda su uso como técnica estándar. Sólo debe usarse cuando se tienen problemas extremos de sincronización. El uso de bucles normalmente ahorrará una cantidad significativa de bytes, pero siempre tomará más tiempo.


La técnica utilizada en el ejemplo del programa usando un bucle tiene dos principales problemas:


1. La necesidad de modificar la memoria del programa. Esto se debería evitar para aprovechar la posibilidad de poner programas en memoria de sólo lectura con los correspondientes ahorros en costos de hardware.


2. Aunque esta es la forma más simple de direccionamiento calculado, se necesitan menos bytes de programa que la forma de programación sofisticada que se muestra en el siguiente diagrama de flujo:



En la familia de microprocesadores MCS650X, al contador se le llama «registro Índice». Es un registro de 8 bits que se carga desde la memoria y tiene la posibilidad de que se le sume 1 mediante una instrucción de incremento (INX, INY). Se pueden comparar directamente con la memoria utilizando la instrucción de comparación de índice (CPX, CPY). El ejemplo 6.4 muestra el listado del programa para el diagrama de flujo de Figura 6.2.


Ejemplo 6.4: Mover Cinco Bytes de Datos Usando un Registro Índice


BYTESETIQUETAINSTRUCCIÓNOPERANDOCOMENTARIOS
2 LDX0Cargar Cero en el Índice
3BUCLELDACAMPO 1,X
3 STACAMPO 2,X
1 INX Incrementar el Contador
2 CPX5Compararlo con el final
2 BNEBUCLE
13
para Absoluto

En este ejemplo, el registro Índice X se utiliza como índice y como contador. Se inicializa en cero. Los datos se obtienen de la memoria en la dirección «CAMPO 1 más el valor del registro X», y se coloca en el registro A (Acumulador). Luego, los datos se escriben desde A a la memoria en la dirección «FIELD 2 más el valor del registro X». El registro X se incrementa en uno y se compara con 5 para determinar si los cinco valores de datos han sido transferidos. Si este no es el caso, el programa regresa a LOOP. En esto ejemplo, «CAMPO 1» se denomina «Dirección Base», que es la dirección a la que hace referencia la indexación.


Esto sólo toma 11 ó 13 bytes, dependiendo de si el campo está en la Página Cero o en la memoria Absoluta. Todavía tarda 13 ó 15 ciclos por byte movido, confirmando nuevamente que los bucles son excelentes para ahorrar espacio de codificación, pero no tiempo de ejecución.


En el ejemplo se puede ver que básicamente se tienen dos requisitos para un registro Índice; uno, debe ser un registro fácil de incrementar, comparar, cargar y almacenar; y dos, que en una sola instrucción se puede especificar tanto la Dirección Base como el valor de X.


En la familia de microprocesadores MCS650X, la forma en que se representan simbólicamente las instrucciones indexadas es «OP CODE, Dirección, X». Esto le indica al ensamblador simbólico que debe seleccionar una instrucción de un OP CODE que deba especificar la dirección Absoluta modificada por el contenido del registro Índice X, o que deba especificar la dirección de Página Cero modificada por el contenido del registro Índice X.


Al realizar estas operaciones, el microprocesador busca la instrucción OP CODE tal como se describió previamente, obtiene la dirección, modifica la dirección sumándole el registro Índice antes de cargar o almacenar el valor de la memoria.


El registro Índice es un contador. Como se discutió anteriormente, una de las ventajas de las banderas en el microprocesador es que un valor puede ser modificado y sus resultados comprobados. Supongamos que el último ejemplo es modificado para que en lugar de mover el primer valor en el CAMPO 1 al primer valor en el CAMPO 2, el último valor en el CAMPO 1 se mueve primero al último valor en el CAMPO 2, luego al penúltimo valor, y así sucesivamente, hasta finalmente mover el primer valor. Con el registro Índice precargado con 5 y usando la instrucción decremento, el contenido del registro Índice terminará siendo cero después de que se transfirieron los 5 campos de datos. El cero indica que el número de veces a través del ciclo es correcto y se sale del bucle por el uso de la comprobación de cero. El listado del programa para esta modificación se muestra en el Ejemplo 6.5:


Ejemplo 6.5: Mover Cinco Bytes de Datos Usando la Disminución de un registro Índice
ETIQUETAINSTRUCCIÓNOPERANDO
LDX5
BUCLELDACAMPO 1–1,X
STACAMPO 2–1,X
DEX
BNEBUCLE

En este ejemplo, el registro Índice X se usa nuevamente como un Contador de Dirección, pero para contar hacia atrás. En este ejemplo se inicializa en 5. Los datos se obtienen desde la memoria a partir de la dirección «CAMPO 1 más el valor del Registro X» y se colocan en el registro A (Acumulador). Luego, los datos se escriben desde el registro A hacia la memoria en la dirección «CAMPO 2 más el valor del registro X». El registro X se decrementa en uno. Si el valor decrementado es distinto de cero, según lo determinado por la instrucción Branch on Zero (Bifurcar si es cero), el programa regresa a BUCLE.


El bucle se ha reducido a 9 u 11 bytes y el tiempo de ejecución por byte se ha reducido de 15 ciclos a 13 ciclos por valor, lo que muestra la ventaja de comprobar el estado de la bandera como resultado de la instrucción Decrementar Índice.


Ahora los dos registros índice X e Y se pueden agregar al diagrama de bloques del sistema, tal como se ve en la Figura 6.3



Cada uno de los registros Índice tiene una longitud de 8 bits y se cargan y almacenan en memoria usando técnicas similares a las del Acumulador. Debido a esta capacidad, pueden ser considerados canales auxiliares para el flujo de datos a través del microprocesador. Sin embargo, su uso principal es ser sumados a las direcciones obtenidas de la memoria para formar una dirección efectiva modificada, tal como se describió anteriormente. Ambos registros Índice tienen la capacidad de ser comparados con la memoria (CPX, CPY) y ser incrementados (INX, INY) o decrementados (DEX, DEY).


Debido a las limitaciones del OP CODE, X e Y tienen usos ligeramente distintos. X es un poco más flexible porque tiene operaciones de Página Cero que Y no tiene, a excepción de LDX y STX. Dejando de lado los modos que modifican, los registros son autónomos, independientes y de valor similar.

6.1 DIRECCIONAMIENTO INDEXADO ABSOLUTO


El direccionamiento Indexado Absoluto corresponde a un direccionamiento Absoluto con un registro Índice sumado a la dirección absoluta. Los pasos que se ejecutan en el direccionamiento Indexado Absoluto sin cruce del límite de página son los siguientes:


Ejemplo 6.6: Direccionamiento Indexado Absoluto; Sin Cruce de Límite de Página


CicloBus de DirecciónDatosOperación ExternaOperación Interna
10100OP CODEObtener OP CODEIncrementar PC a 101, Terminar Instrucción Anterior
20101BALObtener BALIncrementar PC a 102, Interpretar Instrucción
30102BAHObtener BAHIncrementar PC a 103, Calcular BAL + X
4BAH, BAL+XOPERANDOApagar Dirección Efectiva
5103Siguiente OP CODEObtener Siguiente OP CODETerminar Operaciones

BAL y BAH se refieren respectivamente a los bytes de orden inferior y superior de la dirección base. Mientras que el índice X se usó en el ejemplo 6.7, el índice Y es igualmente aplicable.


Si no se cruza el límite de una página, la suma del byte inferior con X no produce un acarreo. El procesador es capaz de segmentar (pipeline) la suma del registro Índice de 8 bits al byte inferior de la dirección base (BAL) y no sufrir ningún tipo de degradación de tiempo en el direccionamiento indexado absoluto, comparado con el direccionamiento Absoluto directo. En otras palabras, mientras se obtiene BAH, se produce la suma de X más BAL. Ambos modos de direccionamiento requieren cuatro ciclos con la única diferencia de que X o Y deben establecerse en un valor conocido, y el OP CODE debe especificar un índice X o Y.


La segunda posibilidad es que al sumar el registro Índice y el byte inferior de la dirección base, la dirección resultante se encuentre en la página siguiente. Esto se ilustra en el Ejemplo 6.7.


Ejemplo 6.7: Direccionamiento Indexado Absoluto; Con Cruce de Límite de Página


CicloBus de DirecciónBus de DatosOperación ExternaOperación Interna
10100OP CODEObtener OP CODEFinalizar Operación Anterior Incrementar PC a 101
20101BALObtener BALInterpretar Instrucción Incrementar PC a 102
30102BAHObtener BAHSumar BAL + Índice Incrementar PC a 103
4BAH, BAL + XDato (Ignorar)Obtener Dato (El dato es ignorado)Sumar BAH + Acarreo
5BAH + 1, BAL + X DatoObtener dato
6103Siguiente OP CODEObtener Siguiente OP CODEFinalizar Operación

La diferencia más sustancial entre una operación que cruza el límite de una página y otra que no lo hace, es que durante el cuarto ciclo se obtienen la dirección superior y la dirección inferior, direccionando incorrectamente la misma página como si fuera la dirección base. Esta operación se lleva a cabo en paralelo con la suma del acarreo al byte superior de la dirección. Durante el cuarto ciclo, el byte superior de la dirección se suma al acarreo del sumador y se pone en el bus de Direcciones, moviendo la operación a la siguiente página. De este modo tenemos dos efectos del cruce del límite de una página. 1. El direccionamiento de una dirección falsa. Esto es similar a lo que sucede en un salto relativo durante el cruce del límite de una página. 2. La operación toma un ciclo adicional mientras calcula el byte superior de la nueva dirección. Al igual que con el salto relativo, este cruce del límite de página ocurre independientemente de la acción del programador y no hay penalización en la memoria por haber cruzado el límite de la página. Es posible que el programador pueda predecir un cruce de página al conocer el valor de la dirección base y el valor máximo de desplazamiento en el registro Índice. Si el tiempo es motivo de preocupación, la dirección base se puede ajustar para que el campo dirección siempre esté dentro de la página.


Al igual que con el direccionamiento Absoluto, el direccionamiento Indexado Absoluto es la forma más general de indexación. Es posible hacer tanto direccionamiento Indexado Absoluto modificado por X como direccionamiento Indexado Absoluto modificado por Y. Las instrucciones que permiten el direccionamiento indexado absoluto por X son ADC, AND, ASL, CMP, DEC, EOR, INC, LDA, LDY, LSR, ORA, ROL, SBC y STA. Las instrucciones que permiten el indexado absoluto por Y son ADC, AND, CMP, EOR, LDA, LDX, ORA, SBC y STA.

6.2 DIRECCIONAMIENTO INDEXADO DE PÁGINA CERO


Al igual que con el direccionamiento no calculado, hay una ventaja en el uso de la memoria por sobre el direccionamiento de Página Cero. Excepto en las instrucciones LDX y STX que pueden ser modificadas por Y, la Página Cero sólo puede ser modificada por X. Si el valor de la dirección base más X excede el valor que se puede almacenar en un sólo byte, entonces no se genera acarreo; por lo tanto, no se produce el cruce del límite de la página. Se producirá un rodeo («wrap-around») dentro de la Página Cero. El siguiente ejemplo ilustra las operaciones internas de indexación de Página Cero.


Ejemplo 6.8: Ilustración del Indexado de Página Cero


CicloBus de DirecciónBus de DatosOperación ExternaOperación Interna
10100OP CODEObtener OP CODEFinalizar Operación Anterior,
0101 → PC
20101BALObtener Byte Inferior de la Dirección Base (BAL)Interpretar Instrucción,
0102 → PC
300, BALDato (Descartado)Obtener Dato DescartadoSumar: BAL + X
400,BAL + XDatoObtener dato
50102Siguiente OP CODEObtener Siguiente OP CODEFinalizar operación

Como se puede ver en el ejemplo, no hay ahorro de tiempo en la Indexación de Página Cero comparada con la indexación Absoluta sin cruce de límite de página. En el caso del direccionamiento Absoluto indexado, durante el ciclo 3 el byte superior de la dirección está siendo obtenido al mismo tiempo que la suma del índice con el byte inferior de la dirección. En el caso del direccionamiento de Página Cero, no hay oportunidad para este tipo de superposición; por lo tanto, las instrucciones indexadas de Página Cero tardan un ciclo más que las instrucciones no indexadas.


Tanto en la indexación de Página Cero como en la indexación Absoluta con cruce de límite de página, tenemos direcciones calculadas de manera incorrecta. Se han tomado medidas para asegurarnos de que sólo ocurra una operación de lectura (READ) durante este tiempo. Operaciones de modificación de memoria como STORE, SHIFT, ROTATE, etc. se retrasan todas hasta que la dirección correcta esté disponible, prohibiendo así cualquier posibilidad de escribir datos en una ubicación incorrecta y destruir los datos anteriores que se encontraban en esa ubicación.


Como se ha dicho anteriormente, no hay acarreo de la operación Página Cero. En el ciclo 4 se obliga a que el byte superior de la dirección tenga el valor 00 bajo toda circunstancia. Por ejemplo, si el registro Índice que contiene el valor 10 se suma a la dirección base que contiene el valor F7, ocurriría la siguiente operación:


Ejemplo 6.9: Demostración del Rodeo (Wrap-Around)


CicloBus de DireccionesOperación Interna
300F7F7 + 10
40007

Esto indica el efecto de rodeo que ocurre con la indexación de Página Cero con cruce del límite de página. Este rodeo no aumenta el tiempo de ciclo por sobre el mostrado en el ejemplo anterior.
Sólo se permite el índice X como modificador en la Página Cero. Las instrucciones que tienen esta característica son: ADC, AND, ASL, CMP, DEC, EOR, INC, LDA, LDY, LSR, OKA, ROL, SBC, STA y STY. Tenga en cuenta que el uso del índice Y está permitido en las instrucciones LDX y STX.

6.3 DIRECCIONAMIENTO INDIRECTO


Para resolver cierta clase de problemas, a veces es necesario tener una dirección que sea un valor verdaderamente calculado, no sólo una dirección base con algún tipo de desplazamiento, sino un valor que se calcula o a veces se obtiene como un grupo de direcciones. Se presenta el uso del direccionamiento Indirecto para poder implementar este tipo de indexación o direccionamiento.


En la familia MCS650X, las operaciones indirectas tienen una estructura especial. La estructura básica del direccionamiento Indirecto es el de una instrucción que consta de un OP CODE seguido de una dirección de la Página Cero. El microprocesador obtiene la dirección efectiva de la operación tomándola desde la dirección en la Página Cero. La operación del direccionamiento Indirecto es muy similar al direccionamiento Absoluto, excepto que el direccionamiento Indirecto utiliza una operación de direccionamiento de Página Cero para acceder a la dirección efectiva. En el caso del direccionamiento Absoluto, el valor del Contador de Programa se utiliza como la dirección de donde se debe obtener el byte inferior de la dirección efectiva; luego se suma uno al Contador de Programa, el que se utiliza para obtener el byte superior de la dirección efectiva. En el caso de direccionamiento Indirecto, el valor que viene a continuación, del OP CODE, que es direccionado por el Contador de Programa, es utilizado como un puntero para direccionar el byte inferior de la dirección efectiva en la Página Cero. A continuación, el puntero se incrementa en uno con el byte superior de la dirección efectiva obtenido desde la siguiente posición de memoria. El siguiente ciclo coloca el byte superior (ADH) y el byte inferior (ADL) de la dirección efectiva en el bus de Direcciones, para finalmente obtener los datos. Una ilustración de esto se muestra en la Figura 6.4.



La dirección que sigue a la instrucción es realmente la dirección de una dirección; es decir, se trata de una dirección «indirecta». La dirección indirecta es representada por IAL en la figura.


Una definición más detallada de direccionamiento Indirecto se incluye en el Apéndice.


Aunque la familia de microprocesadores MCS650X tiene operaciones indirectas, no tiene un direccionamiento Indirecto simple como el descrito anteriormente. Hay dos modos de direccionamiento Indirecto en la familia de microprocesadores MCS650X: El Indexado Indirecto y el Indirecto Indexado.

6.4 DIRECCIONAMIENTO INDIRECTO INDEXADO


El principal uso que se le da al direccionamiento Indirecto Indexado es para obtener datos de un tabla o lista de direcciones para poder realizar una operación. Ejemplos donde se aplica el direccionamiento Indirecto Indexado es en el sondeo (polling) de dispositivos de E/S o en la realización de operaciones con una o más cadenas de caracteres (strings). El direccionamiento Indirecto indexado utiliza el registro Índice X. En lugar de realizar el direccionamiento Indirecto tal como como se muestra en la Figura 6.4, el registro Índice X se suma a la dirección de la Página Cero, lo que permite variar la dirección del puntero indirecto. El funcionamiento y la temporización del direccionamiento Indirecto Indexado se muestra en la Figura 6.5.



Ejemplo 6.10: Ilustración del Direccionamiento Indirecto Indexado


CicloBus de DirecciónBus de DatosOperación ExternaOperación Interna
10100OP CODEObtener OP CODEFinalizar Operación Anterior, 0101 → PC
20101BALObtener BALInterpretar Instrucción, 0102 → PC
300, BALDato (Descartado)Obtener Dato DescartadoSumar BAL + X
400, BAL + XADLObtener ADLSumar 1 a BAL + X
500, BAL + X + 1ADHObtener ADHGuardar ADL
6ADH, ADLDatoObtener Dato
70102Siguiente OPRecuperar Siguiente OP CODEFinalizar operación 0103 → PC

Una de las ventajas de este tipo de indexación es que una dirección de 16 bits se puede obtener con sólo dos bytes de memoria: el byte que contiene el OP CODE y el byte que contiene el puntero indirecto. Sin embargo, requiere que haya una tabla de direcciones mantenida en la memoria de lectura/escritura, que es más costosa que tenerla en la memoria de sólo lectura. Por lo tanto, este enfoque normalmente se reserva para aplicaciones donde el uso del direccionamiento Indirecto Indexado resulta en una mejora significativa de código o de rendimiento, o cuando la dirección que se obtiene es una dirección calculada variable.


Observando el ejemplo, es obvio que al usar esta forma de direccionamiento el usuario paga una penalización menor en tiempo, ya que para obtener un sólo operando, al direccionamiento Indirecto indexado siempre le toma 6 ciclos, lo que es un 25% más que una referencia a un operando usando direccionamiento Absoluto, y un 50% más usando direccionamiento de Página Cero. Tal como en el direccionamiento de Página Cero Indexado, las operaciones en los ciclos 3 y 4 están ubicadas en la Página Cero y no hay posibilidad de pasar a la siguiente página. Es posible desarrollar un valor del índice que sumado a la dirección base exceda de 255; en este caso, la dirección obtenida dará un rodeo y quedará en la parte baja de la Página Cero.


Las instrucciones que permiten el uso del direccionamiento Indirecto indexado son ADC, AND, CMP, EOR, LDA, ORA, SBC, STA.

6.5 DIRECCIONAMIENTO INDEXADO INDIRECTO


La instrucción indexada indirecta combina las características del direccionamiento Indirecto y la capacidad de indexación. Esta instrucción la utilizan principalmente aquellas operaciones en las que se puede utilizar uno de varios valores como parte de una subrutina. Al tener un puntero indirecto a la operación base y al usar el registro Índice Y como un contador normal, se puede tener la ventaja de una dirección que apunta a cualquier parte de la memoria, combinada con la capacidad de desplazamiento del contador del registro Índice.


La Figura 6.6 ilustra el concepto de indexado indirecto en forma de flujo, mientras que el Ejemplo 6.11 indica la operación interna de una vuelta (rollover) sin página de un índice indirecto.



Ejemplo 6.11: Direccionamiento Indexado Indirecto; Sin Cruce de Límite de Página


CicloBus de DirecciónBus de DatosOperación ExternaOperación Interna
10100OP CODEObtener OP CODEFinalizar Operación Anterior, 0101 → PC
20101IALObtener IALInterpretar Instrucción, 0102 → PC
300, BALBALObtener BALSumar 1 a IAL
400, IAL + 1BAHObtener BAHSumar BAL + Y
5BAH, BAL + YDATOObtener Operando
60102Siguiente OP CODEObtener Siguiente OP CODEFinalizar operación 0103 → PC

El índice indirecto aún requiere dos bytes de almacenamiento: uno para el OP CODE, y otro para el puntero indirecto. Después del puntero indirecto, la indexación de la posición de memoria indirecta es igual que si se tratara de una operación indexada absoluta en el sentido de que si no se cruza el límite de página, la segmentación (pipelining) se produce mientras se obtiene el byte superior al sumar el registro Índice Y al byte inferior de la dirección, y, por lo tanto, la solución sin cruce de límite de página es un ciclo más corta que en el caso de la indirecta indexada. En Ejemplo 6.12 se ve que el problema de cruce de límite de página que ocurre en el direccionamiento Indexado Absoluto también sucede en el caso de direccionamiento Indexado Indirecto.


Ejemplo 6.12: Direccionamiento Indexado Indirecto; Con Cruce de Límite de Página


CicloBus de DirecciónBus de DatosOperación ExternaOperación Interna
10100OP CODECargar OP CODEFinalizar Operación Anterior, 0101 → PC
20101IALObtener IALInterpretar Instrucción, 0102 → PC
300, BALIALObtener BALSumar 1 a IAL
400, IAL + 1BAHObtener BAHSumar BAL a Y
5BAH, BAL + Y DATO (Descartado)Obtener DATOSumar 1 to BAH
6BAH + 1, BAL + YDATOObtener datos
70102Siguiente OP CODEBuscar siguiente OP CODEOP Terminar esto CÓDIGO OP CODEeración,
0103 → PC

Cuando hay un cruce del límite de página, el byte superior de la dirección base y el byte inferior sumado a Y apuntan a una ubicación incorrecta dentro de la página referenciada. Sin embargo, cabe señalar que el programador tiene el control de esta referencia incorrecta en el sentido de que siempre está apuntando a la página de la dirección base. En un ciclo más se hará referencia a la dirección correcta. Como ocurría en el caso del direccionamiento Indexado Absoluto, los datos en la dirección incorrecta sólo se leen. STA y los diversos comandos para leer, modificar y escribir la memoria, todos funcionan asumiendo que ocurrirá un cruce del límite de página; toman el tiempo de ciclo adicional para realizar la suma y el acarreo y sólo realizan una escritura en el sexto ciclo en lugar de aprovechar el atajo de cinco ciclos que está disponible para las operaciones de lectura. Este ciclo adicional garantiza que una posición de memoria nunca será escrita con datos incorrectos.


Las instrucciones que permiten el uso del direccionamiento Indirecto Indexada son ADC, AND, CMP, EOR, LDA, ORA, SBC y STA.


En los siguientes dos ejemplos se puede ver una comparación entre el uso de direccionamiento Absoluto modificado por Y, y el Indexado Indirecto.


En estos ejemplos se realiza la misma función. Los valores de dos ubicaciones de memoria se suman y el resultado se almacena en una tercera ubicación, asumiendo que se tienen varios valores por sumar. El primer ejemplo considera ubicaciones de campo conocidas. El segundo ejemplo, como podría ser tradicionalmente utilizado en subrutinas, considera ubicaciones de campo que varían entre las rutinas. En la Página Cero se almacena un puntero de dos bytes para cada rutina que utiliza la subrutina. También se almacena el número de valores que se sumarán en cada rutina.


Ejemplo 6.13: Suma Indexada Absoluta – Programa de Ejemplo


#Bytes    Ciclos     Etiqueta           Instrucción           Comentarios

   2        2        INICIO             LDY #CONTEO -1        Establecer Y = Fin de CAMPO
   3        4        BUCLE              LDA CAMPO 1,Y         Cargar Ubicación 1
   3        4                           ADC FIELD 2,Y         Sumar Ubicación 2
   3        4                           STA CAMPO 3,Y         Almacenar en Ubicación 3
   1        2                           DEY
   2        3                           BPL BUCLE             Comprobar si es Menor a Cero
  __       __                           _____________________________________________
  14       19                           Tiempo para 10 Bytes = 171 Ciclos	

Ejemplo 6.14: Suma Indexada Indirecta – Programa de Ejemplo


#Bytes    Ciclos     Etiqueta           Instrucción           Comentarios

   2        2        INICIO             LDY #CONTEO -1        Establecer Y = Fin de CAMPO
   2        5        BUCLE              LDA (PNT1),Y          Cargar Valor DE CAMPO 1 
   2        5                           ADC (PNT2),Y          Sumar Valor de CAMPO 2
   2        5                           STA (PNT3),Y          Almacenar Valor de CAMPO 3
   1        2                           DEY
   2        3                           BPL BUCLE
  __       __                           _____________________________________________
  11       22                           Tiempo para 10 Bytes = 201 Ciclos

      +6 bytes para los punteros	

El término «CONTEO» en estos ejemplos representa el número de conjuntos de valores a sumar y almacenar. Al cargar el registro Índice con CONTEO-1 se provoca que no se cumpla la condición de la instrucción BPL justo cuando se completa el cálculo de todo el conjunto de valores.


Al usar direccionamiento Indirecto, se tiene un ahorro en el almacenamiento del programa, porque sólo requiere dos bytes para cada puntero indirecto: el OP CODE y el puntero de la ubicación en la Página Cero; mientras que, en el caso del direccionamiento Absoluto, se necesitan tres bytes: el OP CODE, el byte inferior y el byte superior de la dirección.


Se puede observar que utilizamos seis bytes de memoria en la Página Cero para punteros, es decir, dos bytes para cada puntero. El número de posiciones de memoria asignados al problema son 17 para el indirecto, y 14 para el problema donde se conocen los valores. El tiempo de ejecución es mayor en el ciclo del direccionamiento Indirecto. A pesar de que el aumento en el tiempo que toma un solo paso a través del bucle es de sólo tres ciclos, si se van a transferir muchos valores, estos tiempos se van sumando. Es importante tener en cuenta que los bucles requieren tiempo para su configuración, pero sólo se usa una vez. Pero en el bucle mismo, el tiempo adicional se multiplica por el número de veces que el programa pasa por el ciclo; por lo tanto, en problemas donde el tiempo de ejecución es importante, el esfuerzo para reducir el tiempo debe ponerse en el bucle.


Aunque el tiempo del ciclo es más largo y la memoria real que se gasta es mayor para la suma indirecta indexada, esta tiene la ventaja de que, a diferencia del direccionamiento Absoluto, no requiere saber con anticipación las ubicaciones de CAMPO 1, CAMPO 2 y CAMPO 3 al momento de escribir el programa


Se debe investigar bien antes de intentar definir problemas que aprovechen el uso menor de memoria y de tiempo de ejecución que provee la definición de campos. Sin embargo, en casi todos los programas, se debe realizar la misma operación varias veces. En estos casos, a veces es más útil definir una subrutina y definir los valores que la subrutina utilizará en campos en la memoria. Los punteros a estos campos se colocan en la Página Cero de la memoria y luego se utiliza la operación indirecta indexada para realizar la función. Este es el principal uso de la operación indirecta indexada.

6.6 DIRECCIONAMIENTO ABSOLUTO INDIRECTO


En el caso de todas las operaciones indirectas antes descritas, la referencia siempre fue hacia una ubicación dentro de la Página Cero, desde la cual se recogen el byte inferior y superior de la dirección efectiva. En la familia de microprocesadores MCS650X tenemos una excepción a la instrucción de salto, la que permite saltos indirectos absolutos. El uso del salto indirecto absoluto se explica mejor en la discusión sobre interrupciones donde se detalla este modo de direccionamiento y sus capacidades.

6.7 APLICACIÓN DE LOS ÍNDICES


Tal como se ha desarrollado en muchos de los ejemplos anteriores, un registro Índice tiene valores primarios tanto como modificador y como contador. Al actuar como modificador de una operación sobre una dirección base, el registro Índice permite el acceso a grupos contiguos de datos por medio de su modificación simple. Esta es la principal aplicación de los índices y es para este propósito que fueron creados. En virtud del hecho de que todas las instrucciones de la familia MCS650X tienen la dirección base en la instrucción, o en el caso del direccionamiento Indirecto, en el puntero, generalmente se puede usar un sólo índice para dar servicio a un ciclo completo, porque cada una de las muchas instrucciones en el ciclo normalmente se refieren al mismo valor relativo en cada una de las listas. Un ejemplo de esto puede ser el sumar el tercer byte de un número con el correspondiente tercer byte de otro número, y luego almacenar el resultado en la posición de memoria que representa al tercer byte del resultado; Por lo tanto, el registro Índice sólo necesita tener el valor 3 para lograr la ejecución de las tres funciones.


Otros microprocesadores usan registros internos como punteros indirectos. El requisito de tener un sólo registro es una ventaja significativa del tipo de indexación realizada en el la familia MCS650X. Aunque estos procesadores tienen dos índices, la mayoría de las veces el usar un sólo índice resolverá muchos problemas, debido al hecho de que los datos normalmente están organizados en campos contiguos.


La segunda característica del tipo de indexación de los procesadores MCS650X es que, si se usa correctamente, el registro Índice también puede almacenar el conteo de las operaciones a realizar.


Los ejemplos han tratado de mostrar cómo aprovechar esa característica. Hay dos enfoques para contar: conteo hacia adelante y conteo hacia atrás. En el conteo hacia adelante, los datos en la memoria pueden ser organizados de tal manera que el registro Índice comienza en cero y se incrementa en cada operación sucesiva. La desventaja de este tipo de enfoque es que la instrucción de comparación del índice, como la que se usa en el ejemplo 6.13, debe insertarse en el bucle para determinar que se completó el número correcto de operaciones.


En los últimos ejemplos se ha utilizado el enfoque de conteo hacia atrás. Los datos deben estar organizados apropiadamente para la operación de conteo hacia atrás. El primer valor sobre el que se debe operar está al final del CAMPO, el siguiente valor se encuentra ubicado una posición de memoria más adelante, y así. La ventaja de este tipo de operación es que se aprovecha la capacidad combinada de disminución y comprobación del procesador. Hay dos maneras de usar la comprobación. En primer lugar, está el caso en que el número de operaciones a realizar se carga en el registro Índice, tal como se hizo en el ejemplo 6.13. En este caso, el índice contiene el conteo correcto, pero si es sumado directamente a la base, estaría apuntando a un valor más adelante de CAMPO porque la dirección base contiene el primer byte. Por lo tanto, cuando se utiliza el recuento real en el registro Índice, siempre se hace referencia a la dirección base menos uno. Esto se puede lograr fácilmente, tal como se muestra en los ejemplos. El cross-assembler acepta referencias simbólicas en forma de dirección base menos uno, y el microprocesador realiza con mucho cuidado la operación que se muestra.


La ventaja de poner el conteo real en el registro es que se puede usar la instrucción BNE («Branch on result not zero» – «Bifurcar si el resultado es distinto de Cero») porque el valor del registro llega a cero en la última operación.


La segunda alternativa es cargar el contador con el conteo menos uno, tal como se hizo en el ejemplo 6.14. En este caso, el valor real de la dirección base se utiliza en el desplazamiento (offset). Sin embargo, la bifurcación hacia atrás ahora es una bifurcación hacia adelante si el resultado es positivo, recordando que el valor en el registro Índice no será negativo (todos son unos) hasta que decrementemos más allá de cero. Cuando el valor del contador sea -1 ó 0, se tomará la bifurcación. El bucle se completará sólo cuando se intente hacer referencia a un valor inferior al de la dirección base.


Cualquiera de estos enfoques proporciona una codificación mínima y sólo requieren que el usuario organice siempre sus datos con el primer valor al final. En muchos casos, las operaciones tales como MOVE (mover) se pueden realizar incluso si los datos están organizados de otra manera. Los programadores experimentados descubren que esta forma de conteo inverso es en realidad más conveniente de usar y siempre da como resultado un bucle mínimo tanto en tiempo como en espacio.


Aunque para la mayoría de las aplicaciones el registro Índice de 8 bits permite conteos simples en operaciones de desplazamiento (offset), hay algunas operaciones donde el conteo hasta 256 no es suficiente. Una primera solución puede ser el codificar el programa con dos conjuntos de bases, es decir, duplicando la codificación para el ciclo con dos bytes superiores de direcciones diferentes, cada uno con una página de diferencia. La segunda solución, más útil, es utilizar operaciones indirectas, porque el puntero indirecto puede ser modificado para permitir una operación indexada infinita. Un ejemplo del movimiento por debajo y por encima de 256 se muestra en el siguiente ejemplo:


Ejemplo 6.16: Mover N Bytes (N <= 256)


Número de CiclosEtiqueta del ProgramaMnemónico de la InstrucciónCAMPO OPERANDOComentarios
2 LDX#BLOCKConfigurar 2 Ciclos
4BUCLELDADESDE-1,X
4 STAHASTA-1,XTiempo del BUCLE: 13 ciclos
2 DEX
3 BNEBUCLE

  • Memoria requerida: 11 bytes

Ejemplo 6.17: Mover N Bytes (N > 256)


Número de CiclosEtiqueta del ProgramaMnemónico de la InstrucciónCAMPO OPERANDOComentarios
2MOVERLDA#FROML
3 STAFRPOINT
2 LDA#FROMHMover de dirección a
3 STAFRPOINT + 1un puntero indirecto
2 LDA#TOL
3 STATOPOINTMover A para que direccione a un puntero de índice
2 LDA#TOH
3 STATOPOINT + 1
2 LDX#BLOCKSConfigurar # de 256 bloques
2 LDY#0a mover
5BUCLELDA(FRPOINT), YTiempo del Bucle: 16 ciclos/
6 STA(TOPOINT), Ybyte. Mover 256 bytes
2 DEY
3 BNEBUCLE
5ESPECIALINCFRPOINT + 1Incrementar puntero
5 INCTOPOINT + 1alto
2 DEX
2 BMIAFUERAVerificar si es el último movimiento
3 BNEBUCLE
2 LDA#CUENTA
3 BNEBUCLEConfigurar último movimiento
AFUERA----

  • Memoria requerida: 40 bytes