CAPÍTULO 9 CONSIDERACIONES SOBRE EL RESTABLECIMIENTO (RESET) Y LAS INTERRUPCIONES

9.0 VECTORES


Antes de ver cómo manejan las interrupciones y los arranques (start-up) los microprocesadores de la familia MCS650X, se necesita desarrollar una breve definición del concepto de Punteros Vectoriales.
En las secciones de Saltos y Bifurcaciones, siempre se asumió que el Contador de Programa es cambiado por el microprocesador bajo el control del programador mientras se accede a las direcciones que se encuentran en la secuencia del programa. Con el fin de poner en marcha el microprocesador y manejar correctamente el control externo o interrupción, se desarrolló una forma diferente de configurar el Contador de Programa para que éste apunte a una ubicación específica. Este concepto se llama Punteros Vectoriales. Un puntero vectorial consta de un byte superior y un byte inferior que, bajo el control del microprocesador y cuando ocurren ciertos eventos, son cargados en el Contador de Programa. El concepto de vector se desarrolla a partir del hecho de que el microprocesador controla directamente la posición de la memoria desde la cual la operación obtendrá el valor del Contador de Programa.
Al permitir que el programador especifique la dirección del vector y luego escriba una línea de código que apunte a la dirección, el microprocesador pone a disposición del programador todo el control necesario para desarrollar un programa de control de propósito general. El microprocesador tiene una dirección fija en la memoria desde la cual toma los vectores. Por medio de esta implementación, se obtiene un hardware mínimo en el microprocesador. Las posiciones de la FFFA a la FFFF están reservadas para los punteros vectoriales del microprocesador. En estas ubicaciones se almacenan los vectores de interrupción o punteros para interrupciones no enmascarables, solicitudes de reinicio y de interrupción.

9.1 RESTABLECER (RESET) O REINICIAR (RESTART)


En el microprocesador tenemos un contador de estado que controla cuando el microprocesador va a utilizar el Contador de Programa para acceder a la memoria y recoger una instrucción. Luego, después de cargar la instrucción, el microprocesador pasa por una secuencia fija de instrucciones de interpretación, y desarrolla una serie de operaciones que se basan en la decodificación del OP CODE.
Hasta este punto, hemos asumido que el Contador de Programa se estableció en algún lugar y que todos sus cambios eran entonces dirigidos por el programa luego de haber sido inicializado.
Tenemos instrucciones para la inicialización y carga de todos los demás registros en el microprocesador, excepto para la configuración inicial del Contador de Programa. La línea de restablecimiento (reset) del microprocesador se utiliza para hacer que la configuración inicial del Contador de Programa apunte a una ubicación fija en la posición del vector de reinicio (restart) especificada por el programador del microprocesador.
La línea de restablecimiento (RESET) se controla durante la inicialización del encendido y es una línea común que está conectada a todos los dispositivos de la microcomputadora y que tienen que ser inicializados a un estado conocido. La inicialización de la mayoría de los dispositivos de E/S es tal que se activan en un estado benigno de modo que, con una codificación mínima en la microcomputadora, el programador puede configurar y controlar las E/S de manera ordenada.
Este concepto tiene importantes implicaciones en sistemas donde se pueden producir daños si los dispositivos periféricos aparecen en estados desconocidos. Por lo tanto, en la familia MCS650X, el control de encendido o reinicio opera en dos niveles. Primero, manteniendo una línea externa a tierra y teniendo esta línea conectada a todos los dispositivos durante condiciones transitorias de encendido, todo el sistema del microcomputador se inicializa en un estado desactivado conocido. En segundo lugar, la transición de la línea de restablecimiento (reset) desde la condición tierra o TTL cero a la condición TTL uno hace que el microprocesador sea automáticamente inicializado: primero por el vector de hardware interno, que lo hace apuntar a una ubicación del programa conocida, y en segundo lugar a través de un programa software escrito por el usuario para controlar la puesta en marcha ordenada del sistema.
Todas las partes de la familia MCS650X también obedecen a una disciplina en la que mientras la línea de reinicio está baja, el sistema se encuentra en un estado de detención o restablecimiento (reset). Así se garantiza que el microprocesador estará en estado de lectura y al transicionar la línea de restablecimiento (reset) desde tierra a positivo, el microprocesador continuará manteniendo la línea en un estado de lectura hasta que se haya dirigido al lugar del contador especificado en el vector, momento en el que el control del microprocesador estará disponible para el programador.
NOTA: La familia de procesadores MC6800 también sigue esta convención.

9.2 LA FUNCIÓN DE INICIO


Mientras la línea de restablecimiento (reset) está en estado bajo, se puede suponer que los registros internos pueden inicializarse en cualquier condición aleatoria; por lo tanto, no se asumen condiciones sobre el estado interno del microprocesador aparte de que éste ejecuta la siguiente secuencia, un ciclo después de que la línea de restablecimiento (reset) cambia a estado alto:


Ejemplo 9.1: Ilustración del Ciclo de Inicio


CiclosBus de DireccionesBus de DatosFuncionamiento ExternoFuncionamiento Interno
1??No importaMantener Durante el Restablecimiento
2? + 1?No importaPrimer Estado de Inicio
30100 + SP?No importaSegundo Estado de Inicio
40100 + SP-1?No importaTercer Estado de Inicio
50100 + SP-2?No importaCuarto Estado de Inicio
6FFFCIniciar PCLObtener Primer Vector
7FFFDIniciar PCHObtener Segundo VectorRetener PCL
8PCH PCLPrimer OP CODECargar Primer OP CODE

El ciclo de Inicio en realidad toma siete ciclos de reloj desde el momento en que la línea de restablecimiento (RESET) cambia a TTL positivo. En el octavo ciclo, el vector obtenido desde las posiciones de memoria FFFC y FFFD es utilizado para acceder a la siguiente instrucción. El microprocesador se encuentra ahora en una secuencia de carga normal del programa, la ubicación donde apunta el vector debe ser el primer OP CODE que el programador desea ejecutar.
El segundo punto a tener en cuenta es que el microprocesador en realidad accede a la Pila tres veces durante la secuencia de inicio, en los ciclos 3, 4 y 5. Esto se debe a que la secuencia de inicio es en efecto un forma especializada de interrupción con la excepción de que la línea de lectura/escritura está deshabilitada, para que no se realicen escrituras en la Pila durante ninguno de estos ciclos.

9.3 CONSIDERACIONES DEL PROGRAMADOR PARA LAS SECUENCIAS DE INICIALIZACIÓN


Hay dos hechos importantes para recordar relativos a la Inicialización. Uno de ellos es que las únicas operaciones automáticas del microprocesador durante el restablecimiento (RESET) son: establecer en 1 el bit de Deshabilitación de la Interrupción, forzar al Contador de Programa a que apunte a la ubicación del vector especificada en las ubicaciones FFFC y FFFD, y cargar la primera instrucción desde esa ubicación. Por lo tanto, la primera operación en cualquier programa normal será inicializar la Pila. Esto debe hacerse teniendo previamente decidido cuál debería ser el valor de la Pila para las operaciones iniciales y luego haciendo un LDX inmediato de este valor seguido de un TXS. Con esta sencilla operación, el microprocesador estará listo para cualquier operación de interrupción, ya sea enmascarable o no, que pudiera ocurrir durante el resto de la secuencia de puesta en marcha.
Una vez cumplido lo anterior, las dos operaciones no variables de la máquina estarán bajo control: El Contador de Programa es inicializado y puesto bajo el control del programador, y la Pila es inicializada y puesta bajo el control del programa. Las siguientes operaciones durante las secuencias de inicialización consistirán en preparar y configurar las diversas funciones de control necesarias para realizar la E/S que necesite el microprocesador.
Una vez cumplido lo anterior, las dos operaciones no variables de la máquina estarán bajo control: El Contador de Programa es inicializado y puesto bajo el control del programador, y la Pila es inicializada y puesta bajo el control del programa. Las siguientes operaciones durante las secuencias de inicialización consistirán en preparar y configurar las diversas funciones de control necesarias para realizar la E/S que necesite el microprocesador.
En la Sección 11 se tratan las consideraciones específicas relativas a la puesta en marcha.
Lo más importante que debe tenerse en cuenta es el estado actual del dispositivo de E/S y las operaciones no destructivas que le permitan cambiar su estado a activo.
Los programas de inicialización consisten principalmente en cargar el Acumulador inmediatamente con un patrón de bits y almacenarlo en el registro de control de datos del dispositivo de E/S.
Nota: El microprocesador establece en 1 automáticamente la Desactivación de la Interrupción durante la secuencia de inicio. Esto se hace para minimizar la posibilidad de que ocurra una serie de interrupciones durante la secuencia de puesta en marcha debido a valores externos sin control, aunque normalmente es posible controlar las interrupciones como parte de la configuración.
El programador debe considerar dos efectos. Primero, que una interrupción no-enmascarable no puede ser bloqueada por esta técnica, ya que sería posible configurar un dispositivo que esté conectado a una interrupción no-enmascarable y tener que dar servicio a la interrupción inmediatamente. En segundo lugar, la máscara debe borrarse al final de la secuencia de inicio, a menos que el usuario tenga motivos específicos para inhibir las interrupciones después de haber realizado la secuencia de puesta en marcha. Por lo tanto, la penúltima instrucción de la secuencia de puesta en marcha debe ser CLI.
Cabe señalar que la rutina de puesta en marcha es una serie de operaciones secuenciales que deben ocurrir sólo durante la inicialización del encendido y es el primer paso que debe ejecutar una máquina lógica programada.
Debido a que la ejecución de la rutina de encendido ocurre muy rara vez en el funcionamiento normal de la máquina, la codificación de la secuencia de encendido debería tender a minimizar el uso del espacio de memoria en vez de minimizar la velocidad.
La última instrucción en la secuencia de inicio debe inicializar la bandera de modo Decimal a la configuración normal del programa.
La siguiente instrucción debe ser el comienzo del programa normal para su dispositivo, todo lo que precede a esto se le conoce como «labores domésticas» (housekeeping).

9.4 REINICIO


Cabe señalar que la filosofía básica de control del microprocesador permite una única línea de restablecimiento (reset) común que inicializa todos los dispositivos. Esta línea se puede utilizar para limpiar el microprocesador y para restablecer todos los periféricos y dejarlos en un estado conocido; por lo tanto, puede ser utilizado como el resultado de una interrupción de energía, durante la secuencia de encendido o como borrado externo por parte del usuario para reinicializar el sistema.
Como se explica en el Manual de Hardware, el reinicio se usa a menudo como una ayuda para asegurarse de que el microprocesador se ha interconectado correctamente y que los programas se han cargado en las ubicaciones correctas.

9.5 CONSIDERACIONES SOBRE LAS INTERRUPCIONES


Hasta este punto, el microprocesador procede bajo el control del programador a través de una variedad de secuencias. Para el programador, la única manera de alterar la secuencia de operaciones del microprocesador es cambiando la ubicación del Contador de Programa para que apunte a las nuevas operaciones. El microprocesador es responsable de obtener la siguiente instrucción una vez que termina de ejecutar la instrucción actual. La única forma en que los eventos externos puedan controlar al microprocesador, además de las interrupciones, es que el programador interrumpa o detenga periódicamente el procesamiento de datos y verifique si se ha producido un evento externo que podría causar el cambio de dirección. El problema de esta técnica es que los eventos de E/S suelen ser asíncronos, es decir, no están sincronizados con las instrucciones internas del microprocesador. Por lo tanto, es posible que el evento se produzca poco después de que el programador se haya detenido a observar los eventos de E/S, lo que significa que el evento no sería muestreado (sampled) hasta que el programador se tome nuevamente el tiempo para detener su codificación y volver a muestrear.
Debido a que normalmente el muestreo de dispositivos de E/S toma varios conteos de bytes y de ciclos, la inserción frecuente de rutinas de control en el código da como resultado retrasos significativos en todo el programa. Al tratar de usar esta técnica, tiene que existir una compensación entre el desperdicio de una cantidad significativa de tiempo verificando en el programa eventos que aún no han ocurrido versus retrasar la verificación de un evento que ha ocurrido y que, si no es reparado oportunamente, podría provocar la pérdida de datos.
Para resolver esta dicotomía se utiliza el concepto de Interrupción: esta sirve para indicar al microprocesador que ha ocurrido un evento externo y el que debe dedicarle atención inmediatamente. Esta técnica realiza un procesamiento en el que se interrumpe el programa del microprocesador y de inmediato se atiende el evento que provocó la interrupción.
El transferir la mayor parte de los datos y el control a los dispositivos de E/S en un entorno controlado por interrupciones generalmente resulta en una eficiencia máxima del programa y/o por parte del programador. Cada evento se atiende cuando ocurre, lo que significa que hay una cantidad mínima de retraso en el servicio de eventos y también una cantidad mínima de codificación debido a la eliminación de la necesidad de determinar la ocurrencia de varios eventos de manera simultánea; cada evento de interrupción es manejado como una combinación única. Es posible interrumpir una rutina de procesamiento de interrupción y, por lo tanto, toda la lógica de la interrupción utiliza la Pila, lo que permite el procesamiento de interrupciones sucesivas sin ninguna penalización excepto el aumento de la longitud de la Pila.
Un ejemplo del mundo real de un evento del tipo interrupción es cuando se le da al usuario un botón de pánico para indicarle al microcomputador que ha ocurrido un problema que requiere atención inmediata para ser resuelto por el microprocesador.
La acción y los eventos son los siguientes: El usuario del microprocesador presiona el botón de pánico; el sensor del interruptor de pánico provoca que el dispositivo le indique al microprocesador que se desea una interrupción; el microprocesador comprueba el estado de la señal interna de Inhibición de la Interrupción; si la señal interna de Inhibición fue establecida en 1, se ignora la interrupción. Sin embargo, si fue establecida en 0 o fue borrada por medio de algún programa, se produce el siguiente conjunto de operaciones:


Ejemplo 9.2: Secuencia de Interrupción


CiclosBus de DireccionesBus de DatosOperación ExternaOperación Interna
1PCOP CODEObtener OP CODEGuardare Contador de Programa, Terminar Operación Anterior
2PCOP CODEObtener OP CODEForzar una Instrucción BRK, guardar Contador-P
301FFPCHAlmacenar PCH en la PilaDisminuir Puntero de la Pila a 01FE
401FEPCLAlmacenar PCL en la PilaDisminuir Puntero de la Pila a 01FD
501FDPAlmacenar P en la PilaDecrementar Puntero de la Pila a 01FC
6FFFEPCL NuevoObtener Vector, BajoGuardar la Pila
7FFFFPCH NuevoObtener Vector, AltoVector, Bajo → PCL y poner I a 1
8Vector PCH PCLOP CÓDIGOObtener Programa de InterrupciónIncrementar PC a PC + 1

Como se puede ver en el Ejemplo 9.2, el microprocesador usa la Pila para guardar el código de reentrada o de recuperación y usa los vectores de interrupción FFFE y FFFF (o FFFA y FFFB), según se haya producido o no una solicitud de interrupción, o una solicitud de interrupción no enmascarable. Nótese que en este punto la desactivación de la interrupción es puesta en 1 automáticamente por el microprocesador.


Para que se cumpla una solicitud de interrupción, el bit de Desactivación de la Interrupción tiene que ser apagado (Puesto a 0). El retorno de la interrupción, que carga el estado del procesador antes de que ocurra la interrupción, tiene el efecto de borrar el bit de Desactivación de la Interrupción. Después de que la interrupción haya sido reconocida por el microprocesador mediante la transferencia a la ubicación adecuada del vector, hay una variedad de operaciones que el usuario puede realizar para atender la interrupción; sin embargo, todas estas operaciones deben terminar con una sola instrucción que reinicializa el microprocesador de vuelta al punto en el que la interrupción ocurrió. Esta instrucción se denomina RTI.


9.6 RTI-REGRESAR DESDE LA INTERRUPCIÓN


Esta instrucción transfiere, para la instrucción que fue interrumpida, el registro de Estado del Procesador y la ubicación del Contador de Programa desde la Pila al microprocesador. En virtud de que la Interrupción almacena estos datos antes de ejecutar la instrucción y que RTI reinicia el microprocesador al mismo estado que tenía cuando fue interrumpido, la combinación de interrupción más RTI permite una codificación verdaderamente reentrante.
La notación simbólica de RTI es ↑P ↑PC.
La instrucción RTI reinicializa todas las banderas al punto en que estaban cuando se ejecutó la interrupción y vuelve al Contador de Programa a su estado previo a la interrupción. No afecta a otros registros del microprocesador.
RTI es una instrucción de un sólo byte y su modo de direccionamiento es Implícito.
En el siguiente ejemplo podemos ver el funcionamiento interno del RTI el cual restaura el microprocesador:


Ejemplo 9.3: Retorno Desde la Interrupción


CiclosBus de DireccionesBus de DatosOperación ExternaOperación Interna
10300RTIObtener OP CODEFinalizar Operación Anterior, Incrementar PC a 0301
20301?Obtener Siguiente OP CODEDecodificar RTI
301FC?Obtener Pila DescartadaIncrementar Puntero de la Pila a 01FD
401FDPObtener Registro PIncrementar Puntero de la Pila a 01FE
501FEPCLObtener PCLIncrementar Puntero de la Pila a 01FF, Guardar PCL
601FFPCHObtener PCHM → PCL, Almacenar Puntero de la Pila
7PCH PCLOP CODEObtener OP CODEIncremento Nuevo PC

Note los efectos del ciclo extra (3) necesario para leer los datos de la Pila, estos hacen que la instrucción RTI tome seis ciclos. RTI restaura la Pila, el Contador de Programa y el registro de Estado hasta el punto en que se encontraban antes de que la interrupción fuera reconocida.
No hay guardado automático de ninguno de los otros registros del microprocesador. Debido a que la interrupción ocurrió para permitir la transferencia de datos utilizando el microprocesador, el programador debe guardar los diversos registros internos en el momento en que se toma la interrupción y restaurarlos antes de regresar de la interrupción. Es mejor guardar los registros en la Pila, ya que esto permite tantas interrupciones consecutivas como la programación permita. Por lo tanto, las rutinas que guardan todos los registros y los restauran son los siguientes:


Ejemplo 9.4: Ilustración de Guardar y Restaurar para Interrupciones


CicloBytesOperaciónInstrucciónComentario
31GUARDARPHAGuardar A
21 TXAGuardar X
31 PHA
21 TYAGuardar Y
31 PHA
135
41RESTAURARPLARestaurar Y
21 TAY
41 PLARestaurar X
21 TAX
41 PLARestaurar A
165

El código en GUARDAR asume que el programador desea guardar y restaurar los registros A, X e Y. Cabe señalar que, para muchas interrupciones, la escritura de código que debe realizarse es mínima.
En este tipo de operaciones suele ser más conveniente el acortar el tiempo de procesamiento de la interrupción en vez de usar todos los registros de la máquina. Por lo tanto, una rutina de procesamiento de interrupciones normal consiste simplemente en guardar los registros A y X, lo que significa que la rutina de restauración simplemente restaura los mismos registros. Esto tiene el efecto de acortar las rutinas de interrupción y de restauración en dos bytes, eliminar 5 ciclos a la rutina de interrupción, y eliminar 6 ciclos de la rutina de restauración.
Esta técnica, combinada con las características automáticas de la interrupción y de la instrucción RTI, permite que ocurran múltiples interrupciones, con interrupciones sucesivas interrumpiendo la interrupción actual. Esta es una de las ventajas del uso de la Pila: se pueden tener tantas interrupciones que puedan interrumpir a otras, siempre y cuando quepan en la Pila. Si en la Pila se almacenan seis bytes para cada interrupción (si se guardan todos los registros), entonces en una página se pueden almacenar 42 secuencias de interrupciones. Sin embargo, en situaciones más prácticas, las interrupciones consecutivas casi nunca superan las tres en nivel de profundidad.
La ventaja al permitir que una interrupción interrumpa a otra es que con esto los eventos asincrónicos pueden ser respondidos lo más rápido posible; por lo tanto, es deseable permitir que el procesamiento para dar servicio a una interrupción sea interrumpido para dar servicio a otra, siempre y cuando la primera interrupción haya sido atendida adecuadamente.
Para revisar cómo se logra esto usando la capacidad de interrupción normal de la familia de microprocesadores MCS650X, es importante que revisemos el concepto de bus, inherente a la familia MCS6500 y compatible con la familia M6800.
Como ya se ha discutido, todas las operaciones de E/S en este tipo de microprocesador se logran leyendo y escribiendo registros que en realidad representan conexiones a dispositivos o pines que se conectan a dispositivos físicos.
Hasta este punto, esta discusión se ha enfocado en la transferencia de datos desde y hacia el microprocesador. Sin embargo, hay un concepto inherente a la disciplina del bus que dice que cada vez que un dispositivo capaz de generar una interrupción desea realizarla, ejecuta dos acciones; primero, establece en 1 un bit, generalmente el bit 7, en un registro cuyo propósito principal es comunicarle al microprocesador el estado del dispositivo. El dispositivo que realiza la interrupción hace que una de quizás muchas líneas de salida se vuelva a un estado bajo. En la familia de microprocesadores MCS650X, todas estas salidas están conectadas al pin IRQ.
La solicitud de interrupción al MCS650X se indica cuando el pin IRQ está en un estado TTL cero. Con el fin de minimizar la coordinación necesaria para lograr una interrupción, todos los dispositivos de interrupción obedecen la regla que dice que una vez que se ha solicitado una interrupción activando el bit y bajando la interrupción, el dispositivo mantendrá la interrupción hasta que se cumpla la condición que la causó. Esto permite que varios dispositivos realicen interrupciones de manera simultánea y que el microprocesador ignore una interrupción hasta que esté listo para atenderla. Esto se realiza por medio del bit de Desactivación de la Interrupción, el que puede ser activado por el programador y que es inicializado tanto por la secuencia de interrupción como por la secuencia de inicio.
Una vez que la línea de interrupción esté baja y la Desactivación de la Interrupción haya sido desactivada, el microprocesador toma una interrupción, lo que vuelve a activar la desactivación de interrupciones. La inhabilitación de interrupciones evita que la línea baja de entrada cause más de una interrupción hasta que una de éstas haya sido atendida. No hay otro establecimiento de la comunicación (handshake) entre el microprocesador y el dispositivo de interrupción, excepto la línea colector-or'd*. Esto significa que el microprocesador debe utilizar los registros de direccionamiento normal para determinar cuál de todos los dispositivos hizo que la línea collector-or'd4 bajara y procesara la interrupción que se solicitó.
Una vez que el procesador ha identificado el dispositivo de interrupción por medio del análisis de bits de estado que indican que se ha solicitado una interrupción, el microprocesador borra el estado leyendo o escribiendo tal como lo indica el registro de Estado.
Cabe señalar que una diferencia significativa entre los registros de estado y los registros de datos en dispositivos de E/S es que los registros de estado nunca se borran al ser leídos, sólo al ser escritos en ellos cuando el microprocesador transfiere datos desde un registro de datos que corresponde a algún estado en el registro correspondiente. Ejemplos detallados de esta interacción se discuten en el Capítulo 11. La limpieza del registro de Estado también libera la salida collector-or'd y la solicitud del pin de interrupción.
La interacción básica entre el microprocesador y el dispositivo que generó la interrupción se da cuando este último establece el bit de estado y baja su línea de IRQ de salida. Si su línea de IRQ de salida está conectada a la línea de solicitud de interrupción del microprocesador, éste espera hasta que la Desactivación de la Interrupción sea borrada, toma el vector de interrupción y establece en 1 la Desactivación de la Interrupción, lo que inhibe las interrupciones en la línea IRQ. El microprocesador determina qué dispositivo está causando la interrupción y transfiere los datos desde este dispositivo.
La transferencia de datos borra el estado de la Interrupción y del pin IRQ. En este punto, el programador puede decidir que está listo para aceptar otra interrupción, aunque los datos pueden haber sido leídos pero aún no se han hecho operaciones con ellos. Cuando se permiten interrupciones en este punto, la mayoría de las aplicaciones hacen un uso más eficiente del microprocesador.
También hay momentos en que un programador puede estar trabajando en algún código cuya ejecución es tan importante que no puede permitir que ocurra una interrupción. Para estos casos, necesita activar la Deshabilitación de la Interrupción. Para esto, el microprocesador tiene la capacidad de habilitar e inhabilitar interrupciones.


4 «collector-or'd» se refiere a la conexión común que utilizan los dispositivos externos capaces de generar una interrupción. (N. del T.)

9.7 SONDEO (POLLING) DE SOFTWARE PARA LAS CAUSAS DE LAS INTERRUPCIONES


Como se indicó anteriormente, varios dispositivos son conectados a la línea collector-or'd para poder causar una IRQ. El efecto de sondear la línea IRQ baja en un dispositivo, o una combinación de ellos, es siempre el mismo. La interrupción almacena en la pila el estado actual del Contador de Programa y del procesador, y luego se transfiere a una dirección de vector fija. Al atender la interrupción, es importante guardar los registros que se utilizarán en el análisis de la interrupción y durante el procesamiento de la misma, por lo que los primeros pasos de la rutina de interrupción corresponden a procedimientos de SAVE (GUARDAR). La siguiente operación corresponde a determinar cuál de los varios potenciales dispositivos causaron la interrupción. Para lograr esto, el programador debe hacer uso del hecho de que todos los dispositivos señalizan la interrupción estableciendo un bit en el registro de estado. Todos los periféricos 6800 y 6500 implementados actualmente tienen indicadores de interrupción, ya sea el bit 7 o el bit 6 en su registro de estado. Por lo tanto, el circuito básico que un usuario puede usar para verificar la existencia de una interrupción en uno de cinco dispositivos es el siguiente:


Ejemplo 9.5: Sondeo (Polling) de Interrupciones


No. de BytesCiclos
34 LDAEstado 1
22 BMIPRIMERA
34 LDAEstado 2
22 BMISEGUNDA
34 LDAEstado 3
22 BMITERCERA
34 LDAEstado 4
22 BMICUARTA
34 LDAEstado 5
22 BMIQUINTA
RES1JMPto RESTORE
PRIMERALDADATO 1
CLI
Proceso 1
etc.

En este ejemplo, se ha asumido el caso más simple, donde las potenciales interrupciones se indican con el bit 7 activado. Esto permite aprovechar la comprobación gratuita de N bits siguiendo la carga del primer registro de Estado con una bifurcación (branch) en resultado negativo. Si el primer dispositivo tiene una solicitud de interrupción activa, la instrucción BMI será llevada a FIRST, donde los datos son transferidos. Esto borra automáticamente la interrupción para el primer dispositivo. Para permitir múltiples interrupciones, la carga del Acumulador es seguida por la instrucción CLI, lo que permite que el programa acepte otra interrupción. Como resultado de la instrucción CLI, puede ocurrir una de dos cosas: Si hay otra interrupción actualmente activa, el microprocesador continuará procesando la primera interrupción hasta el punto en que ésta sea completada y la primera subrutina haga un salto a RESTORE, que es la rutina que deshace el almacenamiento de los registros que se utilizaron en el proceso de servicio de la interrupción.
Si otro dispositivo tiene una interrupción activa que ocurrió antes de la primera interrupción, o posterior a ella, pero antes de que el microprocesador haya alcanzado el punto donde ocurre la instrucción CLI, entonces el microprocesador será interrumpido nuevamente luego de la instrucción CLI, regresará y guardará los registros, tal como se definió antes, y volverá al bucle de sondeo. Por lo tanto, múltiples interrupciones se atienden en el orden en que son analizadas en la secuencia de sondeo. El sondeo implica que el programa pregunta a cada dispositivo individualmente si es o no el que solicitó la interrupción.
Cabe señalar que el sondeo tiene el efecto de dar perfecta prioridad, en el sentido de que no importa que dos interrupciones ocurran antes de que el microprocesador sirva a una de ellas, la secuencia de sondeo siempre atiende al dispositivo de mayor prioridad primero, luego el segundo, luego el tercero, etc. Dado que esta secuencia de sondeo no requiere hardware adicional para ser implementado, aparte del disponible en los propios dispositivos de interrupción, esta es la forma más barata de interrupción y la que debe utilizarse siempre que sea posible debido a su independencia del hardware externo.
Aunque pareciera que el último dispositivo de interrupción en la secuencia paga una penalización de tiempo significativa, basada en la cantidad de instrucciones que se ejecutarán antes de que se le atienda, la cantidad de tiempo para realizar el sondeo es de sólo seis ciclos por dispositivo y, por lo tanto, la penalización adicional que el último dispositivo tiene que pagar es de 24 ciclos con respecto al primer dispositivo. Esto es en comparación con el tiempo mínimo para causar una interrupción (ocho ciclos), más el tiempo de almacenamiento de los registros (en el rango de otros 8 a 13 ciclos), lo que significa que el retraso hasta los últimos dispositivos es aproximadamente el doble de lo que le corresponde al primer dispositivo.
Esta sincronía que acabamos de describir representa una parte interesante del análisis de interrupciones en un microprocesador. Hay una cantidad significativa de gastos fijos que se deben pagar debido a la interrupción. Estos gastos incluyen el hecho de que las interrupciones sólo pueden ocurrir al final de una instrucción. Por lo tanto, si se produce una interrupción antes del final de la instrucción, el microprocesador espera hasta su finalización para poder atenderla. Por lo tanto, al hacer el análisis del peor de los casos, uno tiene que considerar el hecho de que la interrupción podría estar ocurriendo en medio de una instrucción de lectura/modificación/escritura de siete ciclos, lo que significa que, en el peor caso, el tiempo para procesar la primera instrucción en una secuencia de interrupciones es de 14 ciclos (7 ciclos más los 7 ciclos de la interrupción).
Dado que a menudo se requiere el almacenamiento de registros adicionales (al menos el Acumulador debe ser guardado), se necesitará al menos el doble de número de ciclos. En consecuencia, el tiempo mínimo absoluto para una interrupción en el peor de los casos es de 17 ciclos más el tiempo para transferir datos, o sea, 4 ciclos. Por lo tanto, los sistemas controlados por interrupciones deben ser capaces de manejar un retraso de al menos 20 ciclos y de manera más realista, 20 a 50 ciclos antes de que se atienda la primera interrupción. Esto significa que los dispositivos que funcionan totalmente controlados por interrupciones no deben requerir que se transfieran bytes sucesivos de datos al microprocesador en menos de 30 o 40 ciclos y, en un sistema dado, solo un dispositivo a la vez es capaz de operar a esa velocidad. Esto limita la frecuencia de transferencia de datos impulsada por interrupciones a 40 KHz en un sistema de reloj de un megahercio y 80 KHz en un sistema de reloj de dos megahercios.
Un problema aún más serio es el retraso de tiempo que se da cuando una interrupción acaba de empezar a ser atendida. La máscara de interrupción es activada y las interrupciones de prioridad superior son bloqueadas del servicio. En este caso, el retraso al servicio puede extenderse fácilmente hasta los 100 ciclos antes de que se borre la máscara de la interrupción. Esta es una de las razones por las que se debe borrar la máscara de interrupción tan pronto como se transfieren los datos. (La interrupción no enmascarable, que se discutirá más adelante, es una solución a este problema). Una segunda razón es usar interrupciones sólo para sistemas que tienen almacenamiento en búfer adecuado y/o tasas de transferencia más lentas. Esto no implica que la mayoría de las aplicaciones de los microprocesadores no deban ser controladas principalmente por interrupciones. El sistema de interrupciones de la familia MCS650X está diseñado para ser muy económico y fácil de aplicar. Debería utilizarse en casi todas las aplicaciones de control, excepto cuando el rendimiento descrito no es suficiente para manejar el problema particular. Recuerde que, a un megahercio, el rápido procesador de la familia MCS650X no es realmente capaz de manejar problemas con una transferencia de bytes de más de 50 KHz durante un período de funcionamiento sostenido. También es cierto que en la mayoría de las aplicaciones de control, muchas de las señales se producen a velocidades mucho más lentas o pueden ser almacenadas en búfer para que el tiempo de respuesta a una solicitud de servicio sean significativamente mayor a los 20 o 50 ciclos que normalmente se pueden esperar en un sistema de sondeo. Debido a esto, se espera que la mayoría de las aplicaciones sean implementadas utilizando la técnica de sondeo descrita anteriormente.

9.8 INTERRUPCIONES COMPLETAMENTE VECTORIZADAS


Sin embargo, hay ocasiones en las que varios periféricos de alta velocidad pueden ser manejados por el microprocesador si es que el usuario está dispuesto a hacer una inversión y así lograr una interrupción verdaderamente vectorizada. Al poner un dispositivo de alta prioridad en una línea de interrupción no enmascarable es posible tener un segundo nivel de vectorización de interrupciones. Sin embargo, en caso de que se deseen múltiples entradas con codificación de prioridad y vectorización verdadera, la familia MCS650X tiene la capacidad de transferir el control en la primera instrucción de sondeo al software de servicio apropiado del dispositivo de interrupción, siempre y cuando se combine con el hardware adecuado.
El MCS6520 contiene, en sus dos bytes de memoria, un puntero indirecto a la dirección de la subrutina en la que reside el procesamiento de interrupciones para los dispositivos, el cual ha sido seleccionado por el codificador de prioridad. Esto da un tiempo de servicio efectivo de aproximadamente 24 ciclos para una interrupción priorizada y es una de las principales aplicaciones del salto indirecto.



9.8.1 JMP Indirecto


Esta instrucción establece un nuevo valor en el Contador de Programa. Afecta sólo al Contador de Programa y no afecta a las banderas del registro de Estado.
JMP Indirecto es una instrucción de tres bytes.
En la instrucción JMP Indirecto, el segundo y tercer byte de la instrucción representan los bytes inferior y superior respectivamente de la posición de memoria que contiene a ADL. Una vez que se obtiene ADL, el Contador de Programa se incrementa con la siguiente posición de memoria, la que contiene a ADH.


Ejemplo 9.6: Ilustración de un JMP Indirecto


CicloBus de DireccionesBus de DatosOperación ExternaOperación Interna
10100OP CODEObtener OP CODETerminar operación Previa Incrementar el CP a 0101
20101IALObtener IALInterpretar Instrucciones Incrementar el CP a 102
30102IAHObtener IAHAlmacenar IAL
4IAH, IALADLObtener ADLSumar 1 a IAL
5IAH, IAL + 1ADHObtener ADHAlmacenar ADL
6ADH, ADLSiguiente OP CODEObtener el Siguiente OP CODE

9.9 RESUMEN DE LAS INTERRUPCIONES


Contamos con una línea de solicitud de interrupción ( IRQ ) que, cuando está baja, indica que uno de los dispositivos que están conectados a la línea de solicitud de interrupción requiere ser atendido. Al comienzo de la rutina de servicio de la interrupción, el usuario debe guardar en la Pila los registros que se utilizarán en su rutina de procesamiento de interrupciones. El programa luego pasa por una secuencia de sondeo para determinar el dispositivo de interrupción por medio del análisis del registro de estado en el orden de prioridad de servicio para los dispositivos de E/S. Al momento de encontrar un dispositivo que requiere ser atendido, los datos para ese dispositivo deben ser leídos o escritos tan pronto como sea posible y la Desactivación de la Interrupción debe ser borrada para que el microprocesador pueda realizar una interrupción de nuevo y así atender a los dispositivos de menor prioridad. Los dispositivos con más de 40 KHz de transferencia de bytes, y los dispositivos mixtos con más de 20 KHz normalmente no debe manejarse con interrupciones. Todos los otros deben ser controlados por interrupciones, ya que así se minimiza el tiempo de servicio y la programación de la interrupción de operaciones de E/S.

9.10 INTERRUPCIÓN NO ENMASCARABLE


Como se ha discutido, a menudo es necesario interrumpir una interrupción con un dispositivo de alta prioridad que no puede darse el lujo de esperar mientras las interrupciones están deshabilitadas. Por esta razón, la familia MCS650X tiene una segunda línea de interrupción, denominada Interrupción No Enmascarable. Las características de entrada de esta línea son diferentes a las de la línea de solicitud de interrupción que detecta que necesita ser atendida cuando esta permanece en estado bajo. La entrada no enmascarable es una entrada sensible al borde, lo que significa que cuando la entrada de la línea «collector-or'd» transiciona del estado alto al bajo, el microprocesador establece en 1 una bandera interna de manera que al comienzo de la siguiente instrucción, sin importar cuál sea la estado de la deshabilitación de la interrupción, el microprocesador realiza la secuencia de interrupción que se muestra en el ejemplo 9.2 (A excepción de que el puntero del vector que se muestra en el ciclo 6 y 7 sea FFFA y FFFB).
Esto produce dos efectos para una interrupción no enmascarable. Primero, no importa cuál sea el estado de la deshabilitación de la interrupción, la interrupción no enmascarable interrumpirá al comenzar la siguiente instrucción. Por lo tanto, el tiempo máximo de respuesta al punto del vector es de 14 ciclos. En segundo lugar, la lógica interna del MCS650X dice que, si una solicitud de interrupción y una interrupción no enmascarable ocurren simultáneamente, o si la interrupción no enmascarable ocurre antes del momento en que se seleccionan los vectores, el microprocesador siempre asigna la prioridad más alta a la interrupción no enmascarable. Por lo tanto, los vectores FFFA y FFFB siempre se toman si ambas interrupciones están activas en el momento en que se selecciona el vector. Por lo tanto, la interrupción no enmascarable es siempre una línea de respuesta rápida de mayor prioridad, y puede utilizarse en cualquier sistema para dar prioridad al dispositivo de alta velocidad.
Es posible conectar varios dispositivos a la línea de interrupción no enmascarable teniendo en cuenta que ésta es sensible al borde. Por lo tanto, la misma lógica que permite que la línea IRQ permanezca baja hasta que se haya verificado el estado y se hayan transferido los datos, mantendrá la línea de interrupción no enmascarable en un estado bajo hasta que se atienda la primera interrupción. Si después de una primera interrupción, que ocurre en una línea de interrupción no enmascarable, un segundo dispositivo «collector-or'd» activa su estado y su salida con colector, la eliminación de la primera solicitud de interrupción no causa que la línea se reinicialice al estado alto, y, por lo tanto el microprocesador ignora la segunda interrupción. En resumen, múltiples líneas conectadas a la línea de interrupción no enmascarable deben ser atendidas cuidadosamente.
En cualquier caso, la NMI es siempre una interrupción vectorial libre y de alta prioridad. En virtud del hecho de que va a un puntero vectorial diferente, se le puede garantizar al programador que en 17 ciclos puede transferir datos desde el dispositivo en la entrada de interrupción no enmascarable. IRQ and NMIson líneas que, externas al microprocesador, controlan su accionar a través de una secuencia de interrupción. Como se mencionó durante la discusión sobre el comando de inicio, el ciclo de reinicio (restart) es una operación de pseudo interrupción donde se selecciona un vector diferente para el restablecimiento (reset), el cual tiene prioridad sobre las interrupciones normales y las no enmascarables. La interrupción no enmascarable tiene prioridad sobre la interrupción normal.
También existe una técnica de software que le permite al usuario simular una interrupción usando el comando BRK del microprocesador. Se utiliza principalmente para hacer que el microprocesador pase a una condición de detención (halt, stop) durante la depuración de un programa.


9.11 BRK-INSTRUCCIÓN BREAK


La instrucción «break» (ruptura) hace que el microprocesador pase por una secuencia de interrupción bajo el control del programa. Esto significa que el Contador de Programa del segundo byte a continuación del comando BRK se almacene automáticamente en la pila, junto con el Estado del Procesador al comienzo de la instrucción «break». Luego el microprocesador transfiere el control al vector de interrupción. La notación simbólica para «break» es PC + 2↓ (FFFE)→PCL (FFFF)→PCH. La instrucción «break» no cambia valores ni en los registros ni en las banderas, sólo cambia el Contador de Programa. BRK es una instrucción de un sólo byte y su modo de direccionamiento es Implícito. Como se indica, el uso más común de la instrucción «break» es durante la depuración de un programa. Cuando el usuario observa que el programa en particular no está funcionando correctamente, puede usar la instrucción «break» sobre algún código que ya existe y con esto el programa se detendrá al llegar a ese punto. Con el fin de minimizar el costo de hardware de la instrucción BRK, que es útil sólo para la depuración, el microprocesador hace uso del punto del vector de interrupción para permitirle al usuario detecte que ha ocurrido una interrupción. Para saber si el vector fue obtenido en respuesta a una interrupción o en respuesta a una instrucción BRK, la bandera B se almacena en la Pila, en el Puntero de la Pila más 1, conteniendo un uno en la posición del bit de Interrupción, indicando que la interrupción fue causada por una instrucción BRK. El bit B en la Pila contiene si fue causado por una IRQ normal. Por lo tanto, el código para analizar esto se muestra en el Ejemplo 9.6.


Ejemplo 9.7: Procesamiento de la Interrupción «break»


CiclosBytesVerificación de BRKBandera
41PLACargar registro de estados
31PHARestaurarlo en la Pila
22AND #$10Aislar la bandera B
22BNE BRKPBifurcar para interrumpir al programa
__
11
__
6

Procesamiento Normal de la Interrupción

Este código se puede insertar en cualquier lugar en la rutina de procesamiento de la interrupción. Durante la depuración, si el usuario puede permitirse el tiempo de ejecución, debe colocarse inmediatamente después de la rutina de guardado. De lo contrario, se puede colocar al final de la rutina de sondeo, lo que da prioridad a los dispositivos de sondeo en lo que respecta al servicio de las interrupciones. Sin embargo, cabe señalar que, para no perder la interrupción, los retornos de todas las interrupciones durante la depuración deben pasar por una rutina equivalente.
Una vez que el usuario ha determinado que el «break» ha sido activado, se debe realizar un segundo análisis y una corrección. Esto no funciona de una manera normal, en la que se mantiene el Contador de Programa apuntando a la siguiente ubicación en la memoria durante la instrucción BRK. Debido a esto, el valor en la Pila para el Contador de Programa se encuentra en la instrucción «break» más dos. Si el «break» hubiera sido utilizado sobre una instrucción, generalmente no tiene importancia para el usuario. Sin embargo, si se desea procesar el siguiente byte después de la instrucción «break», se deben usar instrucciones para decrementar la memoria en la Pila.
Se recomienda que el usuario normalmente se encargue de parchar sus programas con la instrucción «break» procesando una instrucción completa antes de regresar y luego usar retornos de salto.
Una característica interesante de la instrucción «break» es que su OP CODE son solo ceros (0), y, por lo tanto, se puede utilizar para parchar PROMS con fusibles a través de un «break» a una rutina E-ROM que inserta el código parche. A continuación, se muestra un ejemplo del uso «break» para parchar PROMS:


Ejemplo 9.8: Parchado de una PROM usando «break»


                Código Antiguo   FC21 LDA
                                 FC22  05
                                 FC23  21
                                 FC24 Siguiente OP CODE

              Código Parchado    FC21 BRK 00
                                 FC22  05
                                 FC23  21
                                 FC24 Siguiente OP CODE	

La rutina del vector de interrupción apunta a:


                               Parche LDA
                                       06
                                       21
                                      JMP
                                       24
                                       FC	

Este código sustituye a:


                                      LDA 2106
                                      para el
                                      LDA 2105
                                      codificando en
                                      FC21	

mediante el uso de BRK y una rutina de procesamiento de ruptura.

9.12 MAPA DE MEMORIA


Hasta aquí se discutieron una serie de requisitos para la organización de la Memoria, la que se puede ilustrar mediante el siguiente mapa de Memoria:


Dirección HexadecimalDescripción
0000–00FFRAM utilizada para Página Cero y operaciones de direccionamiento Indirecto a Memoria
0100–01FFRAM utilizada para procesamiento de la Pila y direccionamiento Absoluto.
0200–3FFFNormalmente RAM.
4000–7FFFNormalmente E/S.
8000-FFF9Almacenamiento del programa, normalmente ROM-
FFFADirección baja del vector NMI
FFFBDirección alta del vector NMI.
FFFCDirección baja del vector RESET.
FFFDDirección alta del vector RESET.
FFFEDirección baja del vector IRQ + BRK.
FFFFDirección alta del vector IRQ + BRK.

Los esquemas de direccionamiento para el control de E/S entre las posiciones 4000 y 8000 Hexadecimal no se han desarrollado completamente. Esto se describe en detalle en el Capítulo 2 del Manual de Hardware. El direccionamiento de Página Cero requiere que la RAM comience en la ubicación 00. Si se necesita más de una página de RAM, las posiciones de la 0100 a la 01FF deben reservarse para la Pila (o al menos una parte de ellas) y el resto estará disponible para que el usuario la use como RAM normal. Las ubicaciones de la 0200 a la 4000 normalmente se reservan para la expansión de RAM. En configuraciones de memoria pequeña, como las inherentes a un dispositivo clase MCS6530, para minimizar las líneas de direccionamiento, la página dos (02XX) normalmente se usa para entrada/salida en vez de la página 40XX, la que se usa para dispositivos que requieren una cantidad significativa de RAM externa, ROM y E/S.
Dado que los microprocesadores de la familia MCS650X tiene tres puntos de vectores muy importantes seleccionados en la memoria de orden más alto, generalmente es más útil escribir programas con el almacenamiento de memoria ubicado en una dirección de inicio que permita al programador asegurarse de que la última dirección en la ROM contiene los vectores de inicio e interrupción. Debido a estas asignaciones, el usuario debe trabajar en tres direcciones. La RAM tiene asignada las ubicaciones a partir de la 0000. Los dispositivos de E/S a partir de la posición 4000, y la ROM a partir de la posición FFFF. Aunque parezca un concepto inusual, hay que recordar que el hardware realmente sólo da un buen rendimiento a ambos extremos de la memoria y, por lo tanto, los datos ubicados en el medio no tienen prioridad el uno sobre el otro. Entonces, comenzar en cualquier extremo es una técnica tan útil como comenzar en uno de ellos y proseguir.
Para aprovechar al máximo la capacidad del microprocesador, particularmente cuando se usa un ensamblador simbólico, los datos en los que se trabajará deben ubicarse comenzando en la posición 0, y las direcciones de la Pila deben reservarse hasta después de que se haya realizado el correspondiente análisis de los requisitos de almacenamiento de trabajo. El almacenamiento del programa debe comenzar en la Memoria de orden superior con algunas suposiciones sobre la cantidad de memoria requerida para ser reservada y que sea tomada como la dirección de inicio. Sin embargo, se debe tener cuidado de asignar los tres vectores fijos casi inmediatamente, al menos simbólicamente, ya que todos son necesarios para el correcto funcionamiento del microprocesador.