La serie “El computador mágico” está disponible también en forma de libro. |
En el último artículo de esta serie vimos el biestable de tipo D activado por flanco, cuya idea central era que introducía en su interior el bit que tuviera en la entrada cuando la entrada C pasaba de 0 a 1, y luego lo almacenaba ahí tanto tiempo como fuera necesario.
Hoy vamos a ver cómo utilizar eso, unido a la lógica combinacional que ya conocemos, para crear un ordenador muy, muy rudimentario.
Lo que vamos a construir es un pequeño sistema temporizador, con una entrada y una salida. Cuando la entrada es 0, el temporizador debe “ponerse a 0″: la salida es 0. Cuando la entrada es 1, el temporizador debe esperar 3 segundos y luego poner la salida a 1 y mantenerla así… ¿hasta cuándo? Hasta que la entrada se ponga de vuelta a 0. Entrecomillo lo de “ponerse a 0″ porque no es solamente poner un 0 en la salida, sino también reiniciar la espera del temporizador.
Lo vamos a hacer, de forma un tanto simplificada, con el siguiente esquema:
Hay algunas cosas nuevas en este esquema. Pero lo mejor es despachar rápidamente las cosas sencillas: la entrada puede ser un simple interruptor que esté conectado a 0V o a 5V, de forma que el usuario humano pueda meter ahí un 0 ó un 1 según necesite. La salida puede conectarse por ejemplo a una bombilla, para que se encienda cuando haya un 1 (5V) y se quede apagada cuando haya un 0 (0V).
Las cosas novedosas son dos: la señal de reloj y la realimentación del contenido de los biestables de vuelta a sí mismos.
La señal de reloj (en inglés Clock, y por eso la entrada de sincronismo de los biestables se suele llamar C) es una señal cuadrada, con periodo de 1 segundo. Es decir, que cada segundo tiene un flanco de subida. Date cuenta de lo que eso implica en los biestables: cada segundo, toman lo que hay en su entrada D y lo guardan con mucho cuidado en su interior.
Y aquí es donde entra esa realimentación digital: la realimentación lo que hace es calcular, en función de la entrada y del contenido actual de los biestables, cuál debe ser el contenido de los biestables en el siguiente paso.
Cuando tenemos esas dos cosas a la vez, lo que conseguimos es un circuito que cambia de estado cada vez que le llega un flanco de subida de la señal de reloj (a eso se le llama onomatopéyicamente “un tick de reloj” o simplemente “un tick”).
Por si acaso no te ha quedado claro del todo, vamos a leer lo mismo de otro modo (y con más detalle): el circuito combinacional calcula, en función de la entrada y del estado anterior, cuál debe ser el estado siguiente, y lo pone en las entradas D de los biestables. Pero los biestables no se la guardan todavía, claro.[1] Cuando llega un tick de reloj (recuerda: un flanco de subida de la onda cuadrada que es el reloj), entonces sí, se introduce lo que hay en las Ds de los biestables. Y, en ese momento, la parte combinacional va calculando lo que hará falta en el siguiente tick. Y vuelta a empezar.
Para especificar cómo funciona este circuito, podemos hacer una tabla que represente el estado “siguiente” de B1 y B0 (los he llamado nB1 y nB0) en función del estado anterior de B1 y B0 y de la entrada E.
E |
B1 |
B0 |
nB1 |
nB0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
1 |
1 |
0 |
0 |
1 |
0 |
0 |
0 |
1 |
1 |
0 |
1 |
1 |
0 |
1 |
1 |
0 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
¿Cómo interpretamos esa tabla? E es la entrada que introduce el usuario. B1 y B0 son el estado actual de los biestables. Fíjate en que lo que almacenan B1 y B0 es un número codificado en binario: 0, 1, 2 o 3. nB1 y nB2 son los estados que queremos poner cuando llegue el siguiente tick de reloj.
Cuando E es 0 (el usuario está reseteando el temporizador), queremos que el estado siguiente sea un 0 (es decir, ponemos la cuenta a 0 y la dejamos ahí). En cambio, cuando E sea 1, queremos que el estado siguiente se vaya incrementando en 1 cada vez, hasta que llegue al 3, en cuyo caso lógicamente ya no se incrementa más.
Finalmente la etapa de salida simplemente comprueba los biestables B1 y B0 y, si ambos son un 1 (es decir, hemos llegado a contar hasta 3), ponen un 1 en la salida S (y un 0 en caso contrario).
Repasa el diseño del circuito y verás que efectivamente cumple todo esto. No obstante, si no lo ves o ni siquiera quieres intentarlo, recuerda lo siguiente: este subcircuito tiene dos salidas (nB1 y nB0) cuyo valor depende exclusivamente de las tres entradas (E, B1 y B0), por lo que existe un circuito combinacional que es capaz de hacer eso. Si no recuerdas eso, vuelve al artículo de la lógica combinacional, donde dijimos que interiorizar eso era importante.
¿Vemos un ejemplo de cómo funciona el temporizador? Imagina que cuando empieza el mundo el interruptor está en 0. Van llegando ticks de reloj, y en todos ellos nB1 y nB0 son 0, así que se almacena un 0 en los biestables. Lo dejamos así durante un buen rato, no importa. Fíjate en que en todo este rato, debido a la puerta AND de la etapa de salida, la salida S siempre vale 0. En un momento determinado el usuario llevará el interruptor hasta el 1, de modo que tendremos E=1, B1=0 y B0=0; eso causa que obtengamos nB1=0, nB0=1. Cuando llegue el tick de reloj, nB1 se introducirá en B1 y nB0 se introducirá en B0. Date cuenta de que S sigue valiendo 0.
Si nada cambia (es decir, E sigue siendo 1), nB1 y nB0 han pasado a ser 1 y 0 respectivamente. Cuando llegue el próximo tick de reloj (recuerda que los ticks llegan uno cada segundo), pasará a almacenarse 1,0 (es decir, un 2 en binario) en los biestables. En ese momento, el circuito combinacional volverá a cambiar y obtendremos nB1=1 y nB0=1. En cuanto llegue el siguiente tick de reloj (y siempre suponiendo que el usuario deja el interruptor en 1) el contenido de los biestables pasará a 1,1. ¡Ya hemos llegado al final de la cuenta! El AND de la etapa de salida ahora ya sí devuelve un 1, que es el que va a la salida. ¡Conseguido!
Si el usuario no cambia el interruptor, cada vez que llegue un tick de reloj se irá metiendo de nuevo 1,1 en los biestables, una y otra vez… Cuando el usuario baje finalmente el interruptor al 0, nB1 y nB0 valdrán ambos 0 y se reseteará todo en cuanto llegue un tick.
¡Qué bonito!
Podrías tener una legítima pega: fíjate en que parte del cálculo que requiere el circuito es debido a la entrada, al interruptor que maneja el usuario. El usuario no es nada preciso, poco más o menos cambiará el interruptor cuando le apetezca. El circuito combinacional irá calculando las salidas en cada tick de reloj, de modo que dependiendo de cuándo suba el usuario el interruptor al 1 estaremos contando algo menos de 3 segundos. Como decimos, la pega es legítima. Ten en cuenta que éste es un ejemplo muy sencillito, en el que no pretendemos cumplir el requisito estricto, sino solamente mostrar el concepto. En un ejemplo real probablemente el reloj no iría a un tick por segundo, sino a miles o millones de ticks por segundo,[2] y entonces no habría que contar de 0 a 3, sino de 0 a 3000000, por ejemplo… pero a la vez nos causaría que esa falta de precisión fuera despreciable.
Lo importante aquí es que hemos conseguido un circuito que mantiene un estado un poquito más complejo que un simple biestable. En nuesto caso tenemos un estado compuesto por 2 bits, pero podría estar compuesto de 8 bits, o 100 bits o diez millones de bits. Ese estado va evolucionando con el tiempo (con los ticks de reloj) en función tanto del estado anterior como de las entradas (en nuestro caso, una sola entrada, pero podrían ser más). Y finalmente, en función de ese estado se genera una salida (en nuestro caso, un único bit, pero de nuevo podrían ser muchos más) que enciende una bombillita.
A esto es a lo que llamamos “circuito secuencial” o “lógica secuencial”, y que podemos representar genéricamente en el siguiente dibujo:
Es decir, podríamos generalizar el sistema a uno con un estado muy complejo; con muchas entradas, que dependan por ejemplo de los sensores de una cadena de montaje; y con muchas salidas, que por ejemplo actúen sobre los motores y servos de esa misma cadena de montaje.
Podríamos, sería posible. Es más, se han construido así ordenadores muy complejos: cadenas de montaje, robots, electrodomésticos, juguetes… ¿Cuál es el problema? El problema es que si hacemos nuestro sistema de esta manera, cuando queramos cambiar cambiar algo tendremos que rediseñar el hardware. Imagina que queremos hacer que no espere tres segundos, sino solamente dos. Tendríamos que modificar un poco el circuito (tanto la realimentación combinacional como la etapa de salida). O peor aún, imagina que quisiéramos contar no hasta tres, sino hasta treinta, y que necesitáramos dos entradas para activar el temporizador: tendríamos que modificar los biestables, la etapa de salida, la realimentación, la etapa de entrada… en fin, habría que modificarlo todo.
Es por eso por lo que se quiso dar un paso más allá: separar el hardware que compone la máquina del algoritmo que se ejecuta (llamado software). John von Neumann lo propuso y lo desarrolló, dando lugar a lo que hoy llamamos “arquitecturas de von Neumann”, a las que dedicaremos el tiempo en adelante. No obstante, antes de llegar a ellas tenemos que presentar algunos componentes que nos ayudarán a entenderlas más fácilmente.
Cuidado, porque esto no quiere decir que los circuitos secuenciales sean inútiles. Son utilísimos. Lo que quiere decir es que es difícil hacer sistemas muy complejos con circuitos secuenciales como este… pero eso no impide que sean la base de todo lo demás. Por lo tanto, es necesario que para continuas recuerdes lo siguiente:
- Si somos capaces de definir un estado del sistema (típicamente en forma binaria);
- y somos capaces de identificar el estado siguiente en base al estado actual y las entradas (mediante un circuito combinacional);
- y podemos definir la salida en función del estado y las entradas;
- entonces existe un circuito secuencial que es capaz de hacerlo.
Ese circuito será complejo o sencillo, grande o pequeño, caro o barato: pero existir, existe. En muchas ocasiones no será eficiente seguir el esquema genérico que hemos visto arriba, sino que será más sencillo enlazar dos o más subcircuitos secuenciales (de hecho, es lo que haremos nosotros en breve). Pero no importa: conceptualmente, ese circuito secuencial existe y podríamos diseñarlo si quisiéramos.
En los próximos capítulos veremos algunos bloques más complejos para poder presentar más tarde la arquitectura de von Neumann.
- Afortunadamente, porque si así fuera, aparecería automáticamente en las salidas Q y el circuito combinacional empezaría a utilizarlas, rompiéndose el sistema. [↩]
- O más. El reloj del ordenador donde escribo esto va a varios GHz, es decir, varios miles de millones de ticks por segundo. [↩]
The Computador mágico XVII – Lógica secuencial by , unless otherwise expressly stated, is licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 2.5 Spain License.
{ 2 } Comentarios
Muy interesante!, muy bien explicado!
Oh, vaya. Esto está muy bien explicado. Muchas gracias J
Escribe un comentario