Vamos a por el segundo ejemplo. Supongamos un objeto móvil que puede ser, por ejemplo, una parte de una máquina herramienta que tiene dos sensores ópticos y que se mueve hacia la derecha o hacia la izquierda junto a una cinta fija o a una especie de regla que tiene, zonas blancas y zonas grises e intervalos iguales. Cada uno de los sensores del, del, del dispositivo móvil genera una señal de salida igual a cero si detecta frente a él una zona blanca y un uno si detecta junto a él una zona gris. Si el móvil se mueve hacia la derecha comenzando, por ejemplo, en esta posición, los dos sensores irán generando el valor cero cero, el valor cero uno, el valor uno uno, el valor uno cero y vuelta al estado o al, o a los valores cero cero. Por el contrario, si se mueve hacia la izquierda empezando en esta posición generará los valores cero cero, uno cero, uno uno, cero uno y cero cero. Bien, pues lo que queremos es construir un circuito que detecte en qué sentido se está moviendo el objeto. Queremos construir el circuito que reciba las entradas de los dos sensores, x1 y x0 y que genere una señal z que tome el valor cero cuando se detecta esta secuencia de entrada correspondiente al movimiento del móvil hacia la derecha y que la salida tome el valor uno cuando se detecta esta segunda secuencia que corresponde con el movimiento del móvil hacia la izquierda. Y lo vamos a hacer con una máquina de Mealy. Bien, para ello vamos a crear un grafo con cuatro estados A, B, C, D, que nos irán informando en cada momento de cuantas parejas, x1, x0 han ido llegando en el orden correcto y dependiendo de si el móvil se mueve en un sentido o en otro. Para simplificar la nomenclatura, yo voy a seguir el convenio de que en cada arco, en cada transición voy a escribir el valor x1, x0 barra y el valor de la salida, es decir que si sobre un arco veis un cero uno barra uno, quiere decir se da esta transición cuando x1 y x0 valen cero y uno, respectivamente, y la salida asociada a esta transición es z es igual a uno, ¿de acuerdo? Vale, vamos a suponer que en el estado A nos ha llegado un cero cero y nos mantenemos en este estado. Bien, a partir de aquí todavía no voy a escribir las salidas, you lo escribiré más tarde, si me llega un cero uno, pues si me llega un cero uno me moveré al estado B y me quedaré en este estado hasta que detecte otra entrada distinta de cero uno. Fijaros que, dependiendo de la velocidad, el móvil puede estar suministrándome los valores cero uno durante varios ciclos del reloj. Bien, a continuación si detectamos un uno uno, pasaré al estado C y me quedaré aquí, si nos llega un uno cero pasaremos al estado D y si nos llega el cero cero pasaremos al estado A y nos mantendremos en este estado. Fijaros que todo este ciclo responde a la secuencia esta de aquí arriba que corresponde al movimiento hacia la derecha y decíamos que si el móvil se mueve a la derecha queremos que z sea igual a cero, es decir que voy a asociar salida cero a cada una de estas transiciones. Podemos ver que de cada nodo no salen todas las combinaciones posibles x1 y x2, por ejemplo. Si estamos en el estado B y nos llega un cero cero el grafo todavía no nos dice qué transición hemos de, hemos de hacer. Bueno, esto lo hemos hecho a propósito para poder detectar también la segunda secuencia, la secuencia de movimiento hacia la izquierda. Y para detectar esta segunda secuencia y que el grafo no se nos complique demasiado, que podamos hacerlo con un grafo de cuatro estados vamos a utilizar, digamos, dos trucos. El primero es que vamos a reconocer la secuencia cero cero, uno cero, uno uno, cero uno moviéndonos en el grafo en el sentido opuesto a como lo hemos hecho ahora, es decir nos moveremos del estado A al D, del D al C, del C al B y del B al A. Y el segundo truco consistirá en que en vez de detectar la secuencia cero cero, uno cero, uno uno, cero uno, vamos a detectar la secuencia uno cero, uno uno, cero uno, cero cero y vuelta de nuevo al uno cero. Esto solo nos puede causar un pequeño mal funcionamiento si en el momento que inicializáramos el circuito el objeto se estuviese moviendo hacia la izquierda. Pero podemos imponer la condición lógica de que cuando inicializamos por primera vez el circuito el objeto está parado. Bueno, pues vamos a proceder de la misma manera que hemos hecho antes. Vamos a suponer que si estamos en el estado A es porque hemos detectado you una secuencia completa de movimiento hacia la izquierda y nos está llegando por las entradas un uno cero. Si a continuación nos llega un uno uno nos iremos al estado D y permaneceremos en este estado hasta que cambien los valores de entrada, si nos llega un cero uno pasaremos al estado C, si a continuación nos llega un cero cero pasaremos al estado B y si nos llega un uno cero pasaremos al estado A y estaremos en las condiciones iniciales. Y si detectamos esta secuencia, quiere decir que el móvil se está moviendo hacia la izquierda y que por lo tanto la salida debe ser uno, es decir que vamos a asociar aquí los valores de salida z igual a uno. Podríamos comprobar que de cada estado ahora salen todas las combinaciones de x1 y x2 y que además no sale ninguna de ellas repetida. Tal vez alguno de vosotros se esté preguntando, ¿pero no quedamos que los registros de desplazamientos se utilizan precisamente para detectar secuencias? ¿No podríamos utilizar un registro de desplazamiento o dos registros de desplazamientos y ahorrarnos toda, todo este trabajo de definición del grafo? Y la respuesta es que no, que no es posible, porque fijaros que a priori no sabemos cuantos ciclos del reloj tarda el móvil en pasar de una zona a la siguiente, es decir el problema son estas transiciones, que nos obligan a quedarnos en un cierto estado y que no sabemos a priori durante cuantos ciclos del reloj nos vamos a quedar en cada uno de estos estados. Precisamente es este hecho, el no saber a priori cuantos patrones de cada tipo me voy a encontrar lo que hace imposible el uso de los registros de desplazamiento en este caso. Siguiendo con el ejemplo, aquí tenéis una versión compactada de lo que sería la tabla de transiciones y la tabla de salidas. Tablas que, de hecho, de una manera más convencional habríamos expresado así. Habríamos expresado para cada estado en función de las entradas, el estado siguiente es el que aparece en esta columna y la salida es la que aparece en esta columna. Pues bien, toda esta información la hemos compactado en una tabla más sencilla. Es muy habitual utilizar esta nomenclatura también en circuitos secuenciales. Aquí estamos poniendo por un lado los estados y por otro lado las combinaciones de las entradas, cero cero, cero uno, uno cero y uno uno. Y estamos diciendo: si estamos en el estado A y me llega un cero cero, el estado siguiente es A y la salida asociada es cero. Es decir estamos en el estado A y me llega un cero cero, el estado siguiente es A y la salida es cero. Otro ejemplo, si estamos en el estado D y me llega un uno cero el circuito se queda en el mismo estado y la salida asociada es cero. Si estamos en el estado D y me llega un uno cero, el estado siguiente es D y la salida asociada es cero. Podéis comprobar que esta tabla describe fielmente el grafo que hemos definido. Como siempre vamos a describir la máquina de estados finitos en VHDL utilizando dos procesos, un proceso que que nos definirá las transiciones de estado, next state, y un proceso para las salidas. El proceso next state, sensible, como siempre, a reset y a clk, lo que hace es, primero inicializa el circuito al estado A cuando reset es uno, aquí el current state lo hemos llamado cs y a partir de aquí para cada pulso de la señal del reloj entramos en este case que nos va diciendo si estamos en el estado A y las entradas son cero y uno, esto you lo habríamos definido previamente, entonces pasamos al estado B, cs es igual a B. O en caso contrario, si las entradas son uno uno, pasamos al estado D. Estamos en el estado A si nos llega un cero uno, pasamos al estado B si nos llega un uno uno, pasamos al estado D. Y esta transición y esta transición no la escribimos simplemente porque se mantiene en el mismo estado. Y en esos casos dijimos que en VHDL no hace falta que lo escribamos explícitamente. Otro ejemplo si estamos en el estado C y las entradas son cero cero, pasamos al estado B current state igual a B y en caso contrario si las entradas son uno cero pasamos al estado D. Y las otras dos transiciones no son necesarias porque se mantiene la máquina de estados finitos en el mismo estado. Aquí tenemos el segundo proceso, el proceso output state que en este caso va a ser sensible al estado actual y a las entradas puesto que estamos trabajando con una máquina de Mili. Aquí tenemos la sentencia case que nos va a decir qué salidas asociamos a cada combinación de estados y entradas. Cuando estamos en el estado A realmente lo que tendríamos que escribir es, si estamos en el estado A, when A entonces si las entradas X1 X0 toman el valor cero cero entonces la salida debe tomar el valor cero, este de aquí. En caso contrario si X1 X0 las entradas toman el valor cero uno, la salida debe tomar el valor cero, este cero de aquí. Lo mismo en caso contrario, si X1 X0 toma los valores uno cero entonces Z debería tomar el valor uno, este uno y finalmente end if si toma los valores X1 X0 los valores uno uno, entonces a Z le tendríamos que dar el valor uno y aquí tendríamos todos los end ifs correspondientes, ¿vale? Todo esto iría aquí. Lo que ocurre es que hemos procesado todo este resultado y nos hemos dado cuenta de que si estoy en el estado A el valor de Z coincide siempre con el valor de la entrada X1, aquí X1 es cero y Z es cero, X1 es cero y Z es cero, X1 es uno y Z es uno, X1 es uno y Z es uno. Por lo tanto hemos sustituido todo este código simplemente por la sentencia carga en Z el valor de X sub uno. Lo mismo hemos hecho cuando estamos en el estado B donde en la tabla podemos comprobar que la salida coincide con el valor de X0 negado, aquí X0 vale cero y la salida vale uno, X0 vale uno y la salida vale cero, X0 vale cero y la salida vale uno, X0 vale uno y la salida vale cero, lo mismo hemos hecho en el resto de casos. Os dejo con una pregunta. Con esto concluye la lección 7.2 A modo de resumen hemos visto dos ejemplos de descripción de máquinas de estado finito utilizando VHDL. El primer ejemplo era una máquina que controlaba la ejecución de una secuencia de operaciones, un temporizador programable que modelamos como una máquina de Moore y el segundo ejemplo era un detector de movimiento que hemos modelado como una máquina de Miri. El primer ejemplo además nos ha servido para introducir el concepto de unidad de proceso o data path y de unidad de control. Y para ver que esta es una arquitectura muy importante cuando se trabaja con las llamadas máquinas algorítmicas. Y finalmente también vimos que esta división en unidad de control y unidad de proceso no significa necesariamente que la descripción VHDL deba contener procesos diferentes para cada una de ellas, sino que se puede integrar todo en un único proceso.