La serie “El computador mágico” está disponible también en forma de libro. |
En los últimos capítulos de esta serie nos hemos dedicado a estudiar cómo funciona un ordenador sencillo, sencillísimo, minimalista: el C16A. Luego lo ampliamos, inventando el ordenador C16B, para poder hacer llamadas a subrutinas. En la última entrada hablamos del compilador. Ahora vamos a presentar la última de las modificaciones: el C16C.
La arquitectura de este sistema es la siguiente:
¡Pero si casi no cambia nada!
Pues sí, cambia un montón. Es solamente un concepto nuevo el que vamos a introducir, pero todo el diseño de los sistemas modernos se basa en él. Vamos a introducir el concepto de interrupción.
Probablemente no recuerdes ya el programa que hicimos hace un par de capítulos para leer del teclado y actuar en consecuencia… vamos a pegarlo de nuevo, para que puedas recordarlo.
/TECLA 0×000 | LD /TECLADO | |
BRZ /TECLA | # Espero a que se pulse una tecla | |
ST /PULSADA | # Me guardo la tecla pulsada | |
ST /CONTADOR | ||
/MULTIPLICACION | LD /CONTADOR | # Bucle multiplicador PULSADA*SEGUNDO |
BRZ /FINMULTIPLICACION | ||
DEC | ||
ST /CONTADOR | ||
LD /SUMATORIO | ||
ADD /SEGUNDO | ||
ST /SUMATORIO | ||
BR /MULTIPLICACION | ||
/FINMULTIPLICACION | LD /SUMATORIO | # Al llegar aquí, SUMATORIO=PULSADA*SEGUNDO |
/ESPERA | DEC | # Espera durante SUMATORIO ciclos |
BRZ /FINESPERA | ||
BR /ESPERA | ||
/FINESPERA 0×010 | LD /PULSADA | # Al llegar aquí, han pasado PULSADA segundos |
ST /PANTALLA1 | ||
/HALT | NOP | # Fin |
BR /HALT | ||
/SEGUNDO | 200 | # Un segundo |
/PULSADA | 0×0000 | # Donde guardare la tecla pulsada |
/SUMATORIO | 0×0000 | # Donde ire calculando la multiplicacion |
/CONTADOR | 0×0000 | # Donde ire almacenando el contador de la multiplicacion |
… | ||
/PANTALLA1 0×800 | 0×0000 | # Pantalla |
… | ||
/TECLADO 0×820 | 0×0000 | # Teclado |
… |
No hace falta que lo recuerdes en detalle. Solo es importante que te fijes en las dos primeras líneas: ¿cómo se lee una tecla pulsada por el usuario?
Lo que hace es mirar a ver si el usuario ha pulsado una tecla, y volver a mirar, y otra vez… y otra y otra… así hasta que el usuario efectivamente pulsa una tecla. Esto es lo que se llama espera activa: en lugar de estar simplemente esperando, está preguntando continuamente si ya está. La espera activa tiene sus aplicaciones, sobre todo el si el sistema no permite hacer otra cosa, pero como norma general es una chapuza. Date cuenta de que hemos dicho, por ejemplo, que en los sistemas modernos si ejecutamos NOP le estamos diciendo al sistema que no tenemos nada que hacer (por ejemplo para que aplique políticas de ahorro)… pero aquí no estamos “haciendo nada”, sino que estamos haciendo algo: preguntar si ya hay una tecla pulsada.
Es como cuando tu jefe te encarga que hagas algo, y cada cinco minutos pasa por tu sitio y te pregunta “¿ya has terminado?”. Y cinco minutos después, otra vez. Y otra, y otra. A la cuarta vez le dices, conteniendo la ira, “déjame en paz, ya te avisaré yo cuando termine”. Bueno, al menos en este ejemplo el jefe te ha encargado algo. La espera activa es peor aún: es como si cada cinco minutos te pregunta tu jefe “¿ha llamado algún cliente?”. “Déjame en paz, ya te avisaré si llama algún cliente”…
Bien, pues eso es una interrupción: la CPU no le pregunta al teclado continuamente si tiene algo nuevo, sino que la CPU sigue a su rollo, y el teclado le avisará cuando tenga algo nuevo.
¿Cómo lo hará? Lo hará a través de la línea de IRQ que tiene la CU (IRQ viene de Interruption ReQuest, petición de interrupción). La línea de IRQ funciona por flanco de subida (como los biestables que veíamos hace mucho): si pasa de 0 a 1, es que hay una petición de interrupción del teclado. Esa es la forma en la que el teclado le dice a la CPU que el usuario ha pulsado una tecla.
El esquema del teclado es muy sencillo: simplemente se pasan todas las teclas por un AND, de modo que casi siempre valdrá 0. Cuando el usuario pulse una tecla pasará a valer 1 por un breve instante, pero será suficiente, dado que la línea de interrupción funciona por flanco de subida.
Y una vez que ya tenemos la línea de IRQ, ¿cómo funciona? ¿Qué hace la CU con ella? Lo que hace la CU es lo siguiente:
- Termina de ejecutar la instrucción que estuviera ejecutando. Recuerda que una instrucción puede tardar más de un ciclo de reloj. Las instrucciones que nosotros hemos hecho en este ordenador son sencillitas, pero hay instrucciones más complejas (en el próximo capítulo veremos más sobre esto).
- Guarda en la pila el “estado del sistema”. En nuestro caso el estado del sistema son los dos registros: PC y AC. Vale, pues los guarda en la pila.
- Salta a la posición 0×100 y ejecuta lo que haya allí. Es decir, pone en PC el número 0×100 y continúa.
¿Te das cuenta de que es algo parecido a las subrutinas? Es una forma un poco especial de subrutina, pero vaya… se parece, en cierto modo. Así que habrá algún tipo de forma de retorno, ¿no? Sí, efectivamente: se define una nueva instrucción llamada RTI (ReTurn from Interruption, retorno de interrupción) que hace básicamente lo contrario: saca de la pila el valor de AC que habíamos guardado y lo restaura; saca de la pila el valor de PC que habíamos guardado y lo restaura. Como antes, no vamos a ver en detalle cómo se hacen estas dos operaciones, pero a estas alturas espero que no te resulte completamente mágico el cómo lo hace la CU.
Entonces, ¿cómo quedaría nuestro programa?
/HALT | NOP | # Fin |
BR /HALT | ||
… | ||
/TECLA 0×100 | LD /TECLADO | # Leo la tecla que me han pulsado |
ST /PULSADA | # Me guardo la tecla pulsada | |
ST /CONTADOR | ||
CLR | ||
ST /SUMATORIO | ||
/MULTIPLICACION | LD /CONTADOR | # Bucle multiplicador PULSADA*SEGUNDO |
BRZ /FINMULTIPLICACION | ||
DEC | ||
ST /CONTADOR | ||
LD /SUMATORIO | ||
ADD /SEGUNDO | ||
ST /SUMATORIO | ||
BR /MULTIPLICACION | ||
/FINMULTIPLICACION | LD /SUMATORIO | # Al llegar aquí, SUMATORIO=PULSADA*SEGUNDO |
/ESPERA | DEC | # Espera durante SUMATORIO ciclos |
BRZ /FINESPERA | ||
0×110 | BR /ESPERA | |
/FINESPERA | LD /PULSADA | # Al llegar aquí, han pasado PULSADA segundos |
ST /PANTALLA1 | ||
RTI | ||
/SEGUNDO | 200 | # Un segundo |
/PULSADA | 0×0000 | # Donde guardare la tecla pulsada |
/SUMATORIO | 0×0000 | # Donde ire calculando la multiplicacion |
/CONTADOR | 0×0000 | # Donde ire almacenando el contador de la multiplicacion |
… | ||
/PANTALLA1 0×800 | 0×0000 | # Pantalla |
… | ||
/TECLADO 0×820 | 0×0000 | # Teclado |
La mayor parte del programa es el mismo, pero las diferencias son brutales. Date cuenta de que, nada más empezar, en las líneas 0×000 y 0×001, simplemente ¡entra en el bucle de fin! ¡Es decir, ya se queda sin hace nada! La diferencia ahora es que a partir de la línea 0×100 hay cosas. La posición 0×100 es a donde saltará la ejecución cuando el usuario pulse una tecla… y a partir de ahí, es exactamente igual que en el programa anterior: multiplica, espera durante unos segundos y escribe la tecla pulsada en pantalla… y después retorna de la interrupción, el RTI de la línea 0×111. Es decir, vuelve al bucle a no hacer nada (es decir, hasta que el usuario pulse otra tecla, en cuyo momento volverá a saltar la interrupción y vuelta a empezar).
Puede parecer que es una tontería, y que no ha cambiado mucho… ahora intentaré convencerte de lo contrario. Pero primero, asegúrate de entenderlo, incluso aunque creas que el concepto no es importante. La CPU puede estar ejecutando cualquier cosa: cuando se levante una interrupción a través de la línea IRQ, ejecutará esa especie de subrutina y luego seguirá por donde iba.
La potencia de este método viene del hecho de que en los ordenadores reales no existe una entrada de interrupción, sino muchas. Vamos a poner unos cuantos ejemplos, pero no te fijes en el orden para ver su importancia: las del final son muy muy importantes también.
- Cuando el usuario pulsa una tecla.
- Cuando la pantalla ha terminado de escribir lo que le han pedido.
- Cuando entra sonido a través del micrófono de la tarjeta de sonido.
- Cuando ha terminado de reproducir (a través de la tarjeta de sonido) lo que le hemos pedido que reproduzca.
- Cuando entran datos a través de la tarjeta de red.
- Cuando la tarjeta de red ha terminado de enviar los datos que le habíamos pedido que enviara.
- Cuando existe una división por cero. Sabes que dividir cualquiercosa/0 es un error… pues bien, eso levanta una interrupción que viene de la ALU.
- Cuando se intenta acceder a una zona de memoria que no existe o sobre la que no tenemos permiso (veremos más sobre esto más adelante).
- Cuando lo pide el programa. Suele haber una (o varias) instrucciones que generan una interrupción. También veremos esto más adelante. Esto es lo que se llama una “interrupción por software”.
- Periódicamente, según un reloj. Por ejemplo, cada 1ms.
- Cuando se prevé un fallo de alimentación.
- Cuando ha terminado de escribir en disco lo que le hemos pedido.
Prácticamente cualquier cosa importante que pueda ocurrir en un ordenador hoy en día genera una interrupción.
La gracia de esas interrupciones es que pueden ocurrir en cualquier momento… ¡incluso mientras estoy ejecutando otra interrupción![1]
Volveremos sobre esto más adelante, cuando veamos los sistemas multiproceso, pero los sistemas operativos modernos hacen absolutamente todo su trabajo en base a interrupciones. Un sistema operativo moderno, una vez que se ha inicializado, simplemente se queda en un bucle sin hacer nada hasta que salta una interrupción. Lo veremos más adelante con más detalle, de momento céntrate solo en conocer el concepto de interrupción y cómo opera.
En el próximo capítulo terminaremos este nivel de la máquina nombrando alguna de las diferencias más importantes entre los sistemas reales y estos ejemplos de máquinas académicas.
- No obstante, suele haber algún mecanismo de priorización, porque algunas de las interrupciones son muy importantes y no se deben interrumpir. Por ejemplo, se pueden numerar y una interrupción solo puede ser interrumpida por otra interrupción de número menor. [↩]
The Computador mágico XXVII – Ordenador C16C: interrupciones by , unless otherwise expressly stated, is licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 2.5 Spain License.
{ 4 } Comentarios
Felicitaciones! Soy atento lector de esta serie y he aprendido mucho. !!! El computador se va haciendo menos mágico, pero más interesante.
Si, yo también sigo la serie y me parece muy interesante por el enfoque que le estás dando don de cada parte va cobrando sentido poco a poco según se añada. Animo y felicitaciones!
Perdon mi ignorancia, el texto dice “Se pasan todas las teclas por un AND”… para que la salida (la IRQ) sea un 1… ¿Deberían pulsarse todas las teclas a la vez? o es una compuerta OR?
Mauro,
tienes razón: es un OR. Ahora mismo no puedo corregirlo porque necesito cambiar el dibujo también. Gracias por el aviso.
Escribe un comentario