CAPÍTULO 8 EL PROCESAMIENTO DE LA PILA

8.0 INTRODUCCIÓN A LA PILA Y AL CONCEPTO DE EMPUJE (PUSH) HACIA ABAJO


En todas las discusiones sobre direccionamiento, se ha asumido que se conoce la ubicación exacta o al menos una relación con la ubicación exacta de una dirección de memoria.
Aunque esto es correcto en la mayor parte de la programación para aplicaciones de control, hay ciertos tipos de programación y aplicaciones que requieren que el programa básico no trabaje con posiciones conocidas, sino sólo con un orden conocido para acceder a ella. Este tipo de programación se llama codificación de reentrada (re-entrant coding) y se usa a menudo en el servicio de interrupciones.
Para implementar este tipo de direccionamiento, el microprocesador mantiene un generador de direcciones separado que el programa utiliza para acceder a la memoria. Este generador de direcciones utiliza el concepto de empuje hacia abajo de la Pila («push down stack»).
Las discusiones sobre el este concepto generalmente se expresan mejor considerando que si a uno le dan 3 cartas, un as, un rey y un diez y le dicen que el orden de las cartas es importante y le piden que las dejen sobre la mesa en el orden en que fueron dadas, el as primero, el rey encima y finalmente el diez, y luego, si se retira una carta a la vez, el diez se recupera primero a pesar de que se puso en último lugar, el rey se recupera en segundo lugar, el as se recuperó en último lugar, a pesar de que se puso primero.
Los únicos comandos necesarios para implementar esta operación son «poner la siguiente carta en la Pila» y «sacar la siguiente carta de la Pila». La Pila podría procesar tréboles y luego ir a diamantes y volver a los tréboles. Sin embargo, sabemos que mientras procesamos tréboles, siempre encontraremos el diez primero, luego el rey, etc. La implementación hardware de la Pila de cartas ordenada que se acaba de describir corresponde a un contador de 16 bits, en el que está almacenada la dirección de una posición de memoria. Este contador se denomina «Puntero de la Pila». Cada vez que los datos van a ser empujados a la Pila, se coloca el Puntero de la Pila en el bus de Direcciones, los datos se escriben en la memoria direccionada por el puntero de Pila, y este puntero se decrementa en 1, tal como se puede ver en el ejemplo 8.1. Cada vez que se extraen datos de la Pila, su puntero se incrementa en 1. El Puntero de la Pila se coloca en el bus de Direcciones y los datos se leen desde la posición de memoria direccionada por el puntero de la Pila. Esta implementación del uso del puntero de la Pila da el efecto de una Pila de empuje hacia abajo, lo que corresponde a un direccionamiento independiente del programa.


Ejemplo 8.1: Mapa Básico de la Pila para Secuencia de Salto a Subrutina de Profundidad 3


Dirección de la PilaDatos
01FFPCH 1
01FEPCL 1
01FDPCH 2
01FCPCL 2
01FBPCH 3
01FAPCL 3
01F9

En el ejemplo anterior, el Puntero de la Pila comienza en 0lFF. El Puntero de la Pila se utiliza para almacenar el primer estado del Contador de Programa, almacenando el contenido de su byte superior en 0lFF y el del byte inferior en 0lFE. El Puntero de la Pila ahora apunta a 0lFD. La segunda vez que se realiza el almacenamiento del Contador de Programa, su byte superior se almacena en la Pila en la dirección 01FD y su byte inferior en la dirección 01FC. El Puntero de la Pila ahora apunta a 01FB. El mismo procedimiento se utiliza para almacenar por tercera vez el Contador de Programa.
Cuando se toman datos de la Pila, PCL 3 vendrá primero y PCH 3 a continuación, siempre y cuando sumemos 1 al puntero de Pila antes de cada lectura de memoria. El ejemplo anterior guarda el Contador de Programa por 3 operaciones sucesivas de salto y almacenamiento, donde el salto transfiere el control a una subrutina y almacena el valor del Contador de Programa en la Pila para recordar a qué dirección debe regresar el programa después de completar la subrutina.


El siguiente es un programa que recrea la operación de Pila del Ejemplo 8.1.



Esto se conoce como anidamiento de subrutinas y se encuentra a menudo al resolver ecuaciones de control complejas.
Para usar correctamente la Pila en este tipo de operaciones, se requiere una instrucción de salto a la subrutina y otra de retorno desde la subrutina.


8.1 JSR-SALTAR A LA SUBRUTINA


Esta instrucción transfiere el control del Contador de Programa a la ubicación de una subrutina, pero deja un puntero de retorno en la Pila para permitir que el usuario retorne y ejecute la siguiente instrucción en el programa principal después de que la subrutina se haya completado. Para lograr esto, la instrucción JSR almacena en la Pila la dirección del Contador de Programa, la cual apunta al último byte de la instrucción de salto, usando el Puntero de la Pila. El byte de la Pila contiene primero el byte superior del Contador de Programa, seguido por el byte inferior del mismo.


JSR entonces transfiere las direcciones que vienen a continuación, de la instrucción de salto al byte inferior y superior del Contador de Programa, instruyéndole así al programa para que comience en esa nueva dirección.


La notación simbólica para esto es PC + 2↓, (PC + 1) → PCL, (PC + 2) → PCH.


La instrucción JSR no afecta a las banderas, sólo hace que el Puntero de la Pila se decremente en 2 y sustituye los nuevos valores del byte inferior y superior del Contador de Programa. El modo de direccionamiento para JSR siempre es Absoluto.


El ejemplo 8.3 da los detalles de una instrucción JSR.


Ejemplo 8.3: Ilustración de la Instrucción JSR


Memoria del Programa

CPDatos
0100JSR
0101ADL
0102ADH Subrutina

Memoria de la Pila

Puntero de la PilaPila
01FD
01FE02
01FF01

CicloBus de DirecciónBus de DatosOperación ExternaOperación Interna
10100OP CODEObtener InstrucciónFinalizar Operación Anterior; Incrementar PC a 0101
20101Nuevo ADLObtener Nuevo ADLDecodificar JSR; Incrementar PC a 0102
301FF Guardar ADL
401FFPCHAlmacenar PCHGuardar ADL, Decrementar S a 01FE
501FEPCLAlmacenar PCLGuardar ADL, Decrementar S a 01FD
60102ADHObtener ADHGuardar Puntero de la Pila
7ADH, ADLNuevo OP CODEBuscar nuevo OP CODEADL → PCL, ADH → PCH

  • S denota «Puntero de Pila».

En este ejemplo, se puede ver que el microprocesador obtiene la instrucción JSR durante el primer ciclo. El byte inferior de la dirección del Contador de Programa nuevo se obtiene durante el segundo ciclo. Al final del ciclo 2, el microprocesador ha decodificado la instrucción JSR y mantiene el byte inferior de la dirección en el microprocesador hasta que se completen las operaciones de la Pila.
NOTA: La Pila siempre se almacena en la página 1 (dirección hexadecimal 0100–01FF).
El funcionamiento de la Pila en la familia de microprocesador MCS650X es tal que el Puntero de la Pila siempre se deja apuntando a la siguiente posición de memoria donde se pueda almacenar datos. En el ejemplo 8.3, se supone que al comienzo el Puntero de la Pila está en 01FF y el PC (Program Counter – Contador de Programa) en la dirección 0100. Durante el tercer ciclo, el microprocesador coloca el Puntero de la Pila en las líneas de dirección y en el cuarto escribe el contenido del valor actual del byte superior del Contador de Programa, 01, en la posición de memoria indicada por la dirección del Puntero de la Pila. Durante el tiempo que se lleva a cabo la escritura, el Puntero de la Pila se decrementa automáticamente en 1, por lo que queda apuntando a 01FE. Durante el quinto ciclo, el byte inferior del Contador de Programa (PCL) se almacena en la siguiente posición de memoria con el puntero de Pila decrementado de manera automática.
Cabe señalar que el byte inferior del Contador de Programa, que ahora se almacena en la Pila, apunta a la última dirección en la secuencia de JSR. Esto no es lo que se espera como resultado de una instrucción JSR. La Pila debe apuntar a la siguiente instrucción. Esta aparente anomalía en la máquina se corrige durante la instrucción RTS («Return from Subroutine» – Regresar desde de subrutina).


Nota: Al final de la instrucción JSR, los valores en la Pila contienen el byte inferior y el byte superior del Contador de Programa, que hace referencia a la última dirección de la instrucción JSR. Cualquier llamada a subrutina que desee utilizar el Contador de Programa como puntero intermedio debe tener en cuenta esto. Cabe señalar también que la instrucción RTS («Return from Subroutine») realiza un incremento automático al finalizar, lo que significa que cualquier Contador de Programa que se sustituya en la Pila deben ser de 1 byte o 1 contador de puntero menos que el Contador de Programa que RTS le devuelve al programador.
La ventaja de retrasar el acceso al byte superior de la dirección hasta después de que el Contador de Programa actual se pueda escribir en la Pila es que sólo el byte inferior de la dirección tiene que ser almacenado en el microprocesador. Esto acorta la instrucción JSR en 1 byte y también minimiza los requisitos de almacenamiento.
Después de que tanto el byte inferior como superior del Contador de Programa han sido transferidos a la Pila, éste se usa para acceder al siguiente byte, que corresponde al byte superior de la dirección para la instrucción JSR. Durante esta operación, en el sexto ciclo, el microprocesador internamente almacena el puntero de la Pila, que ahora apunta a 01FD, o a la siguiente posición en la que se puede cargar la memoria.
Durante el séptimo ciclo, el byte superior de la dirección del bus de Datos y el byte inferior de la dirección almacenada en el microprocesador se transfieren al nuevo Contador de Programa, y se utilizan para acceder al siguiente OP CODE, lo que convierte a JSR en una instrucción de 6 ciclos.
Al finalizar la subrutina, el programador quiere volver a la instrucción que va a continuación, de la instrucción JSR («Jump-to-Subroutine» – Saltar a la subrutina). Esto es se logra transfiriendo los últimos 2 bytes de la Pila al Contador de Programa, permitiendo que el microprocesador reanude las operaciones en la instrucción que viene a continuación, de JSR, lo que se hace mediante la instrucción RTS.


8.2 RTS-REGRESAR DESDE LA SUBRUTINA


Esta instrucción carga el Contador de Programa con el byte inferior y superior del Contador de Programa almacenado en la Pila, y luego lo incrementa de manera que apunte a la instrucción que viene a continuación, de JSR. El Puntero de la Pila se ajusta incrementándolo dos veces.
La notación simbólica para RTS es PC↑, INC PC.
La instrucción RTS no afecta a ninguna bandera y sólo afecta a PCL y a PCH. RTS es una instrucción de un sólo byte y su modo de direccionamiento es Implícito.
El ejemplo 8.4 proporciona los detalles de la instrucción RTS. Es el reverso completo del JSR que se muestra en el Ejemplo 8.3.


Ejemplo 8.4: Ilustración de la Instrucción RTS


Memoria del Programa

PCDatos
0300RTS
0301?

Memoria de la Pila

Puntero de la PilaPila
01FD?
01FE02
01FF01

Regresar desde Subrutina (Ejemplo)

CicloBus de DirecciónBus de DatosOperación ExternaOperación Interna
10300OP CODEObtener OP CODEFinalizar Operación Anterior, 0301 → PC
20301Dato DescartadoObtener Dato DescartadoDecodificar RTS
301FDDato DescartadoObtener Dato DescartadoIncrementar el Puntero de la Pila a 01FE
401FE02Obtener PCLIncrementar el Puntero de la Pila a 01FF
501FF01Obtener PCH
60102Dato DescartadoApagar PCIncrementar PC en 1 a 0103
70103Siguiente OP CODEObtener Siguiente OP CODE

Como se puede ver, la instrucción RTS efectivamente deshace lo que la instrucción JSR le hizo a la Pila. Debido a que RTS es una instrucción de un sólo byte, desperdicia el segundo acceso a la memoria al hacer una operación anticipada. Durante el segundo ciclo, se lee el valor ubicado en la dirección del programa inmediatamente después de la instrucción RTS, pero no se utiliza en esta operación. Se debe tomar en consideración que la Pila siempre se deja apuntando a la siguiente posición vacía, lo que significa que, para sacar datos de la Pila, el microprocesador tiene que esperar un ciclo mientras suma 1 a la dirección de la Pila. Esto se hace para acortar la secuencia de interrupción que se discutirá a continuación; por lo tanto, el ciclo 3 es un ciclo muerto en el que el microprocesador obtiene, pero no utiliza el valor actual de la Pila y, tal como la recuperación del byte inferior de la dirección en operaciones Indexadas y de Página Cero Indexada, no hace más que poner el microprocesador en el estado adecuado. Se puede ver que el Puntero de la Pila decrece a medida que los datos se envían a la Pila y se incrementa a medida que los datos son sacados de ella. En el cuarto ciclo de la instrucción RTS, el microprocesador saca la dirección 01FE, lee los datos almacenados allí, que corresponde al byte inferior del Contador de Programa que se escribió en el segundo ciclo de escritura de JSR. Durante el quinto ciclo, el microprocesador saca la Pila incrementada recogiendo el byte superior del Contador de Programa que se escribió en el primer ciclo de escritura de la JSR.
Como se indicó durante la discusión de la instrucción JSR, el Contador de Programa almacenado en la Pila realmente apunta a la última dirección de la instrucción JSR; por lo tanto, durante el sexto ciclo, RTS hace que el Contador de Programa de la Pila sea incrementado. Ese es el único propósito del sexto ciclo. Finalmente, en el séptimo ciclo, el Contador de Programa incrementado se utiliza para buscar la siguiente instrucción; por lo tanto, la instrucción RTS toma en total 6 ciclos.
Debido a que cada subrutina requiere una instrucción JSR seguido de una instrucción RTS, el tiempo para saltar y regresar de una subrutina es de 12 ciclos. En los 2 ejemplos anteriores, hemos mostrado las instrucciones JSR, ubicada en la posición 100, y RTS, ubicada en la posición 300. El siguiente diagrama pictórico, ejemplo 8.5, ilustra cómo podría verse el mapa de memoria para esta operación:



Con esta capacidad de creación de subrutinas, el microprocesador permite que el programador pueda ir desde el programa principal a la primera subrutina, luego a la segunda subrutina, y luego a la tercera, para finalmente regresar al programa principal. El ejemplo 8.6 es una expansión del ejemplo 8.2 con los retornos incluidos.



Este concepto se conoce como anidamiento de subrutinas, y el número de subrutinas que pueden ser llamadas y devueltas de tal manera es
limitado únicamente por la longitud de la Pila.

8.3 IMPLEMENTACIÓN DE LA PILA EN LOS MICROPROCESADORES DEL MCS6501 AL MCS6505


Como hemos visto, el requisito principal para la Pila es que, independientemente de dónde o cuándo se llama a una operación de Pila, el microprocesador debe tener un contador o registro independiente que contenga la dirección de la Pila. Este registro se denomina Puntero de la Pila (S). La Pila se convierte en un campo auxiliar de la Memoria, que es básicamente independiente del control del programador. Más adelante hablaremos de cómo el Puntero de la Pila se inicializa, pero una vez que esto sucede, el principal requisito es que sea autoajustable; en otras palabras, las operaciones que colocan datos en la Pila hacen que su puntero disminuya automáticamente; las operaciones que quitan datos de la Pila hacen que el puntero se incremente automáticamente. Sólo en raras circunstancias el programador debería considerar necesario mover su Pila de un lugar a otro si es que está usando la Pila tal como se diseñó.
En base a esto, no es necesario que la Pila tenga más de 256 bytes. Para realizar una sola llamada a una subrutina se necesitan tan sólo 2 bytes de memoria de la Pila. Para realizar una interrupción sólo se necesitan 3 bytes de Memoria de la Pila. Por lo tanto, con 256 bytes, uno puede tener acceso a una profundidad de hasta 128 subrutinas o realizar 85 interrupciones. Por lo tanto, es muy poco probable que la longitud de la Pila sea una limitante. Los modelos MCS6501 al MCS6505 tienen una longitud de Pila de 256 bytes.
La figura 8.1, que ahora es el diagrama de bloques completo, muestra todos los registros del microprocesador. El registro de 8 bits puntero de la Pila, S, ha sido agregado. Este es inicializado por el programador y luego automáticamente incrementado o decrementado, dependiendo de si los datos son puestos o sacados de la Pila por el microprocesador ya sea bajo el control del programa o de las líneas de interrupción.



El propósito principal de la Pila es proporcionar un bloque de posiciones de memoria en el que el microprocesador pueda escribir datos, como el Contador de Programa, para su uso en el procesamiento posterior. En muchos sistemas de control, las peticiones de memoria de lectura/escritura son mínimos y la Pila representa sólo una más de estas solicitudes. Por lo tanto, a estas aplicaciones les gustaría que la Pila se ubicara en la Página Cero para que se puedan ejecutar tanto la asignación de memoria para la Pila, como las operaciones de Página Cero y el direccionamiento Indirecto. Por lo tanto, uno de los requisitos de una Pila es que sea fácilmente localizable en la Página Cero.
Por otro lado, si se necesita más de una página de RAM debido a la cantidad de datos que deben manejar los programas del usuario, el tener la Pila en la Página Cero es un desperdicio innecesario de esta memoria en el sentido de que la Pila no puede sacar ninguna ventaja real al estar ubicada en la Página Cero, mientras que otras operaciones sí pueden hacerlo.
En cada uno de los ejemplos, la Pila se ubica en una dirección de memoria con orden superior 01 seguida del orden inferior. De la misma manera en que el microprocesador asigna un 00 a los 8 bits de orden superior de las posiciones de memoria de las operaciones de Página Cero, el microprocesador automáticamente asigna 01 hexadecimal a los bits de orden superior de la dirección durante cada operación de la Pila. Esto tiene la ventaja para el usuario de ubicar la Pila en la Página Uno de la memoria, que sería la siguiente ubicación de memoria a sumar si los requisitos de funcionamiento de la Página Cero superan la capacidad de su memoria. Esto tiene la ventaja de que la Pila no requiere que se le agregue memoria específicamente, sólo requiere la asignación de ubicaciones de memoria existentes. Cabe señalar que los conceptos de direccionamiento seleccionados por los dispositivos que soportan el microprocesador MCS650X implican conectar las memorias de tal manera que el bit 8, que es el bit de selección de Página Uno versus Página Cero, sea un valor que «no importa» para las operaciones en las que el usuario no necesita más de una página de memoria de lectura/escritura. Esto es lo que le da al usuario el efecto de ubicar la Pila en la Página Cero para esas aplicaciones.
La segunda característica que debe notar de los ejemplos es que la Pila estaba ubicada al final de la Página Uno y disminuyó a partir de ahí hasta llegar el principio de la página. Esta es la manera natural en que opera la Pila. La Memoria RAM viene en incrementos discretos de 64, 128 y 256 bytes, por lo que el método normal de asignación del direccionamiento de la Pila es que el usuario calcule el número de bytes probablemente necesarios para el acceso a la Pila. Esto se puede hacer analizando ya sea el número de subrutinas que son llamadas y la cantidad de datos que se colocan en la Pila para comunicarse entre ellas, o el número de interrupciones y de subrutinas que podrían ocurrir con sus datos respectivos almacenados en la Pila para cada uno de ellas. Contando 3 bytes por cada interrupción, 2 bytes por cada salto a una subrutina, más 1 byte por cada operación de Pila controlada por el programador, el diseñador del microprocesador puede estimar la cantidad de memoria que debe ser asignada para la Pila. Esto es parte de su proceso de toma de decisiones para decidir cuánta memoria es necesaria para su programa.
Una vez realizada la asignación, se recomienda al usuario distribuir su almacenamiento de trabajo partiendo desde el principio de la memoria y siempre cargando su Pila al final de la Página Cero, o de la Página Uno, o al final de la memoria física que se encuentra ubicada en uno de esos lugares. Esto dará el efecto de tener los bytes de memoria más altos asignados a la Pila y los bytes de memoria más bajos asignados al almacenamiento de trabajo del usuario, los que con suerte nunca se superpondrán.
Cabe señalar que el funcionamiento natural de la Pila, que a menudo es llamado por hardware que no está totalmente bajo el control del programa, es tal que continuará disminuyendo a lo largo de la página a la que se asigna, independientemente del deseo del usuario de que así lo haga. Un error normal en la asignación en la memoria puede resultar en que el usuario escriba datos en una ubicación de memoria y luego la acceda con otra subrutina u otra parte de su programa, sólo para descubrir que la Pila ha escrito sobre esa área como resultado de la realización de operaciones de control de hardware. Este es uno de los problemas más difíciles de diagnosticar. Si el programador sospecha este problema, debe analizar las posiciones mayores a las que contienen los datos alterados.
Hay un patrón distintivo para las operaciones de Pila que son únicas al programa del usuario pero que son bastante predecibles. Un análisis del valor que ha sido destruido a menudo indicará que éste forma parte de una dirección que normalmente se esperaría durante la ejecución del programa entre el momento en que se almacenaron los datos y en que se recuperaron. Esto es una indicación de que la Pila de alguna manera alcanzó el área del programa del usuario. Esto casi siempre es causado por un control inadecuado de las líneas de interrupción u operaciones inesperadas de interrupción o llamadas a subrutinas y tiene sólo 2 soluciones: (1) Si la operación es normal y predecible, el usuario debe asignar más memoria a su programa y particularmente reasignarla de manera que la Pila tenga más espacio para operar; o (2) si el funcionamiento de las líneas de interrupción no es predecible, se debe resolver el problema de hardware que causa este tipo de operación impredecible.


8.3.1 Resumen de la Implementación de la Pila


Los microprocesadores del MCS6501 al MCS6505 tienen un único registro Pila de 8 bits. Este registro se incrementa y decrementa automáticamente bajo el control del microprocesador para realizar operaciones de manipulación de la Pila, bajo la dirección del programa del usuario o de las líneas de Interrupción. Una vez que se ha inicializado el Puntero de la Pila al final de cualquier memoria en la que quiera que opere, el programador puede ignorar el direccionamiento de la Pila excepto en aquellos casos en los que hay una interferencia entre las operaciones de la Pila y el espacio de trabajo normal de su programa.
En los microprocesadores del MCS6501 a MCS6505, la Pila se ubica automáticamente en la Página Uno. Para cada operación de Pila, el microprocesador siempre suma la dirección 0100 al registro de la Pila. Por medio de ciertas técnicas de memoria, el usuario puede ubicar la Pila en la Página Cero o en la Página Uno, dependiendo de si la Página Cero está disponible o no para su hardware.

8.4 USO DE LA PILA POR PARTE DEL PROGRAMADOR


En la Sección 8.1 se discutió el uso de la instrucción JSR para llamar a una subrutina. Sin embargo, no se indicó la técnica por la cual la subrutina sabe sobre qué datos operar. Hay 3 técnicas clásicas para comunicar datos entre subrutinas. La primera técnica, que es la más sencilla, es que cada subrutina tenga un conjunto definido de registros de trabajo ubicados en la Página Cero en las que el usuario ha dejado valores para ser utilizados por la subrutina. Los registros pueden contener los valores directamente o pueden contener punteros indirectos a las direcciones de los valores que se utilizarán. El siguiente ejemplo muestra una combinación de estos:


Ejemplo 8.7: Subrutina «Call-a-move» Usando Posiciones de Memoria Preasignadas


  • Ubicación 10 = Conteo
  • Ubicación 11, 12 = Dirección base «FROM» (Origen)
  • Ubicación 13, 14 = Dirección base «TO» (Destino)

Rutina Principal

Nº de BytesInstrucciónComentario
2LDA #Conteo -1Cargar valor fijo para el movimiento
2STA 10
2LDA #FRADH
2STA 12Configurar el puntero de origen
2LDA #FRADL
2STA 11
2LDA #TOADL
2STA 13
2LDA #TOADH
2STA 14Configuración del puntero de destino
3JSR SUB1
23 bytes

Codificación de la Subrutina

Nº de BytesEtiquetaInstrucción
2SUB1LDY 10
2BUCLELDA (11), Y
2 STA (13), Y
1 DEY
2 BNE BUCLE
1 RTS
33 bytes en tota

Como se ha desarrollado previamente, el tiempo del bucle es la consideración primordial en lugar del tiempo de preparación para un gran número de ejecuciones. Puede verse que hemos utilizado las técnicas desarrolladas en secciones anteriores relativas a la referenciación indirecta, al salto a la subrutina y el retorno de la subrutina para realizar este tipo de comunicación de valores. En este caso, no hubo uso de la Pila excepto para almacenar el valor del Contador de Programa.
Una segunda forma de comunicación es el uso de la propia Pila como almacenamiento intermedio de los datos que se van a comunicar a la subrutina. Para que el programador use la Pila como almacenamiento intermedio, necesita instrucciones que le permitan poner y leer datos de la Pila. Estas instrucciones se conocen como instrucciones de introducir (push) y extraer (pull).


8.5 PHA-INTRODUCIR (PUSH) EL CONTENIDO DEL ACUMULADOR EN LA PILA


Esta instrucción transfiere el valor actual del Acumulador a la siguiente ubicación en la Pila, decrementándola automáticamente para que apunte a la siguiente posición vacía.
La notación simbólica para esta operación es A↓. Cabe señalar que la notación ↓ significa introducir a la Pila, mientras que ↑ significa extraer de la Pila.
La instrucción Push A sólo afecta al registro del puntero de Pila, el que se decrementa en 1 como resultado de la operación. No afecta a las banderas.
PHA es una instrucción de un sólo byte y su modo de direccionamiento es Implícito.
El siguiente ejemplo muestra las operaciones que ocurren durante la instrucción Push A.


Ejemplo 8.8: Operación de PHA, Asumiendo que la Pila Se Encuentra en 01FF


CiclosBus de DireccionesBus de DatosOperaciones ExternasOperaciones Internas
10100OP CODEObtener InstrucciónFinalizar Operación Anterior, Incrementar PC a 0101
20101Siguiente OP CODEObtener Siguiente OP CODE y descartarInterpretar Instrucción PHA, retener contador P
301FF(A)Escribir A en la PilaDecrementar el Puntero de la Pila a 01FE
40101Siguiente OP CODEObtener Siguiente OP CODE

Como se puede observar, cuando PHA lleva 3 ciclos, aprovecha el hecho de que el Puntero de la Pila apunta a la ubicación correcta para escribir el valor de A. Como resultado de esta operación, el Puntero de la Pila se ajusta a 01FF. La notación (A) hace referencia al contenido del Acumulador. Ahora que los datos están en la Pila, más adelante el programador solicitará los datos que se recuperarán de la Pila usando la instrucción PLA en su programa.


8.6 PLA-EXTRAER (PULL) EL CONTENIDO DEL ACUMULADOR DESDE LA PILA


Esta instrucción suma 1 al valor actual del Puntero de la Pila, y lo usa para dirigirse a la Pila y cargar su contenido en un registro.
Su notación simbólica es A↑.
La instrucción PLA no afecta las banderas de Acarreo o Desbordamiento. Esta instrucción establece en 1 la bandera Negativo si, como resultado de las instrucciones, el bit 7 del Acumulador fue activado. De lo contrario, se borra. Si el Acumulador es cero como resultado de la instrucción PLA, entonces la bandera Z se establece en 1. De lo contrario, se borra.
La instrucción PLA cambia el contenido del Acumulador al contenido de la posición de memoria ubicada en el registro de Pila más 1, y también incrementa este registro.
La instrucción PLA es una instrucción de un sólo byte y su modo de direccionamiento es Implícito.
En el siguiente ejemplo, los datos almacenados en la Pila del Ejemplo 8.8 se transfieren al Acumulador.


Ejemplo 8.9: Operación PLA de la Pila del Ejemplo 8.8


CiclosBus de DireccionesBus de DatosOperaciones ExternasOperaciones Internas
10200PLAObtener InstrucciónFinalizar Operación Anterior, Incrementar PC a 0101
20201Siguiente OP CODEObtener Siguiente OP CODE y descartarInterpretar Instrucción, retener contador P
301FE Leer la PilaIncrementar el Puntero de la Pila a 01FF
401FF(A)Obtener AGuardar la Pila
50201Siguiente OP CODEObtener Siguiente OP CODEM → A

Al sacar datos de la Pila, hay un ciclo adicional durante el cual se accede, pero no se usa el contenido actual del registro de la Pila y el Puntero de la Pila se incrementa en 1 para permitir el acceso al valor que se almacenó previamente en ella. El Puntero de la Pila se deja apuntando a esta posición porque ahora se le considera una ubicación vacía que puede ser utilizada por la Pila durante una operación posterior.

8.7 USO DE LAS INSTRUCCIONES PUSH (INTRODUCIR) Y PULL (EXTRAER) PARA COMUNICAR VARIABLES ENTRE OPERACIONES DE SUBRUTINA


En el Ejemplo 8.10, realizamos la misma operación que hicimos en el Ejemplo 8.7; solo que aquí, en lugar de usar ubicaciones fijas para recoger los punteros, vamos a utilizar la Pila como vehículo de comunicaciones:


Ejemplo 8.10: Subrutina «Call-a-move» Usando la Pila Para Comunicarse


  • Ubicación 11, 12 = Dirección base de «FROM» (Desde)
  • Ubicación 13, 14 = Dirección base de «TO» (Hasta)

Rutina Principal

BytesInstrucción
2LDA #Count -1
1PHA
2LDA #FRADL
1PHA
2LDA #FRADH
1PHA
2LDA #TOADL
1PHA
2LDA #TOADH
1PHA
3JSR SUB1
18

Subrutina

BytesEtiquetaInstrucciónComentarios
2SUB1LDX 6
1BUCLE1PLA
2 STA 10,X
1 DEXMover Pila a la Memoria
2 BNE BUCLE1
1 PLAPreparar contador
1 TAY
2BUCLE2LDA (11), Y
2 STA (13),YMover ubicación de Memoria
2 DEY
2 BNE BUCLE2
2 LDA 15
2 PHA
2 LDA 16Restaurar CP a la Pila
2 PHA
1 RTS
42 bytes en tota

En este ejemplo podemos ver que usar la Pila como medio de comunicación en realidad aumenta el número de bytes en la subrutina y el total de bytes en general. Sin embargo, la única vez que uno debería usar subrutinas de este tipo es cuando ésta es bastante larga y es utilizada de manera bastante frecuente. Esta técnica reduce el número de bytes en la secuencia de llamada. La secuencia de llamada se repite normalmente una vez por cada llamada a la instrucción; por lo tanto, el uso de la Pila para comunicarse debería resultar en una reducción neta en el número de bytes utilizados por el programa.
Hasta este momento, hemos considerando que la Pila está en una ubicación fija y que todas las referencias a la Pila usan el Puntero de la Pila. No se ha explicado cómo el puntero de Pila en el microprocesador es cargado o accedido. Esto se hace a través de la comunicación entre el Puntero de la Pila y el registro Índice X.


8.8 TXS-TRANSFERIR EL REGISTRO ÍNDICE X AL PUNTERO DE LA PILA


Esta instrucción transfiere el valor en el registro Índice X al puntero de la Pila.
La notación simbólica es X → S.
TXS cambia sólo el Puntero de la Pila, haciéndolo igual al contenido del registro Índice X. No afecta a ninguna de las banderas.
TXS es ​​una instrucción de un sólo byte y su modo de direccionamiento es Implícito.
Otra aplicación para TXS es el concepto de pasar parámetros a la subrutina almacenándolos inmediatamente después de la instrucción de salto a la subrutina.
En el ejemplo 8.11, la dirección «desde» y «hasta», más el contador con el número de valores, se escriben a continuación, de la instrucción JSR y su dirección.
Al ubicar la Pila en la Página Cero, la dirección del último byte de la instrucción JSR se puede incrementar para que apunte a los bytes del parámetro y luego se puede usar como un puntero indirecto para mover el parámetro a su ubicación en la memoria. La clave de este enfoque es transferir el Puntero de la Pila a X, que permite que el programa opere directamente en la dirección mientras está en el Pila. Cabe señalar que este enfoque deja automáticamente la dirección en la Pila, posicionado de manera tal que RTS recoja la dirección del siguiente OP CODE.


Ejemplo 8.11: Salto a Subrutina (JSR) Seguido de Parámetros


Bus de DireccionesDatos
0100JSR
0101ADL
0102ADH
0103Byte superior de «desde»
0104Byte inferior de «desde»
0105Byte superior de «hasta»
0106Byte inferior de «hasta»
0107Contador
0108Siguiente OP CODE

Antes de concluir esta discusión sobre subrutinas y el paso de parámetros, uno debe notar nuevamente que el uso de subrutinas debe limitarse a aquellos casos en los que el usuario espera duplicar código de longitud significativa varias veces dentro del programa. En estos casos, y sólo en estos casos, se garantiza el uso de la llamada de subrutina en lugar del modo normal en el que se conocen las direcciones y se especifican en una instrucción. En todos los casos en que el tiempo es de gran interés, también deben evitarse las subrutinas. Las subrutinas aumentan significativamente el tiempo de configuración y ejecución de la solución del problema. Sin embargo, definitivamente tienen su lugar en el código de microcomputadoras y se han presentado 3 alternativas para su uso en programas de aplicación. El usuario encontrará útil la combinación de las técnicas anteriores para resolver su problema particular.


8.9 TSX-TRANSFERIR EL PUNTERO DE LA PILA AL REGISTRO ÍNDICE X


Esta instrucción transfiere el valor del puntero de Pila al registro Índice X.
La notación simbólica es S → X.
TSX no afecta las banderas de acarreo o desbordamiento. Establece en 1 la bandera N si el bit 7 está activado en el índice X como resultado de la instrucción; de lo contrario, se borra. Si el índice X es cero como resultado de la instrucción TSX, se establece en 1 la bandera Z; de lo contrario, se borra. TSX cambia el valor del índice X, haciéndolo igual al contenido del Puntero de la Pila.
TSX es una instrucción de un sólo byte y su modo de direccionamiento es Implícito.

8.10 ALMACENAMIENTO DEL REGISTRO DE ESTADO DEL PROCESADOR


Durante las secuencias de interrupción, el contenido actual del registro de Estado del Procesador (P) se guarda en la Pila automáticamente. Sin embargo, hay ocasiones en que el contenido actual del registro P debe guardarse para realizar algún tipo de operación. Un ejemplo particular de esto sería el caso de una subrutina que se llama de forma independiente y que implica aritmética decimal. Es importante que el programador realice un seguimiento del modo aritmético en el que se encuentra el programa en todo momento. Una manera de hacer esto es convenir que la máquina siempre estará en modo binario o decimal, con cada subrutina cambiando su modo y siendo responsable de restaurarlo al estado conocido. Esta es una convención superior a la que se describe a continuación.
Una convención más general sería aquella en la que la subrutina que quiere cambiar los modos de operación empuja P a la Pila, luego establece el modo Decimal para realizar la subrutina y luego extrae P de la Pila antes de regresar de la subrutina.
Las instrucciones que le permiten al usuario lograr esto son las siguientes:


8.11 PHP-INTRODUCIR EL REGISTRO DE ESTADO DEL PROCESADOR EN LA PILA


Esta instrucción transfiere el contenido del registro de Estado del Procesador a la Pila sin cambios, tal como lo dicta el Puntero de la Pila.
La notación simbólica es P↓.
La instrucción PHP no afecta a registros ni banderas en el microprocesador.
PHP es una instrucción de un sólo byte y su modo de direccionamiento es Implícito


8.12 PLP-EXTRAER EL REGISTRO DE ESTADO DEL PROCESADOR DESDE LA PILA


Esta instrucción transfiere el siguiente valor en la Pila al registro de estado del procesador, cambiando así todas las banderas y configurando el modo en base a los valores que se han obtenido de la Pila.
La notación simbólica es P↑.
La instrucción PLP no afecta a ningún registro en el procesador, excepto al registro de Estado.
Esta instrucción podría afectar todas las banderas en el registro de Estado.
PLP es una instrucción de un sólo byte y su modo de direccionamiento es Implícito.

8.13 RESUMEN DE LA PILA


La Pila de la familia MCS650X es una Pila de empuje hacia abajo («push-down») implementada por un registro del procesador llamado Puntero de la Pila, el cual el programador inicializa por medio de una instrucción LDX seguida inmediatamente de una instrucción TXS. A partir de ese momento es controlado por el microprocesador, el que carga los datos en la memoria basado en una dirección construida en base a la suma del contenido del Puntero de la Pila y una dirección fija, la dirección hexadecimal 0100. Cada vez que el microprocesador carga datos en la memoria usando el puntero de Pila, automáticamente disminuye el puntero, dejándolo así apuntando al siguiente byte de memoria disponible. Cada vez que el microprocesador accede a los datos de la Pila, suma 1 al valor actual del Puntero de la Pila y lee la posición de memoria obteniendo la dirección 0100 más el Puntero de la Pila. El registro de estado apunta automáticamente a la siguiente ubicación de Memoria en la que ahora se pueden escribir datos. La Pila es un lugar interesante para almacenar datos temporales sin que el programador tenga que preocuparse por la ubicación real donde serán almacenados.
Hay 8 instrucciones que afectan a la Pila. Estas son: BRK, JSR, PHA, PHP, PLA, PLP, RTI y RTS.
BRK y RTI involucran el manejo de las Interrupciones.