Hola. Vamos a ver ahora "flip-flops" D con clear y preset". ¿De qué se trata? A veces, en algunos circuitos, vale la pena tener un dispositivo, un módulo, que permita establecer el "flip-flop", el valor 1 o 0 de manera externa y asíncrona. Muy importante aquí, asíncrona. ¿Qué significa de manera asíncrona? Asíncrona significa sin estar sincronizada con el reloj, de manera independiente del reloj. Asíncrona significa que da lo mismo en qué viene este reloj. Si yo pongo un "preset" aquí, va a aparecer un 1. Si yo pongo un "clear" aquí, va a aparecer un 0. Eso es lo que significa. Da lo mismo que está el reloj. Entonces, ganan en precedencia el "preset" y el "clear" por sobre el reloj. ¿Por qué es útil? Imagínense que tengo un microcontrolador. Un microcontrolador es un circuito digital o tiene un circuito digital adentro, que incluye un microprocesador, incluye todos los circuitos de aritmética, todos los registros, y ese circuito digital, nosotros queremos que parta en un valor determinado para que el programa sepa dónde irse cuando uno lo reinicia. Ese reinicio es el "reset" y yo quiero que "reset" ocurra independientemente de cuándo entre el flanco de reloj. Ese tipo de cosas pueden ser útiles. A veces uno quiere un "preset" y un "clear". Si el preset es 0, Q es uno. Vean que aquí hay una burbuja, esa burbuja significa que el "preset" vale cuando viene negado. Podemos agregarle esto, aunque sería un poco redundante, pero podemos hacerlo. Aquí vemos también que el "clock" viene negado, o sea, esto es sensible a flancos negativos. En cambio, si el "clear" es 0, entonces, Q vale 0. Eso está en esta línea. Este es una posible implementación de ese circuito, digo "una posible", porque puede haber otras implementaciones. Esto utiliza compuertas NAND. Y vemos que el "preset" y el "clear" entran desde lejos, no entran a la circuitería que utiliza el reloj. El reloj viene por una parte, pero el "preset" y el "clear" se saltan el reloj y entran por otro lado. Perfecto. Otras veces queremos que haya un "clear" síncrono. En ese caso lo que hacemos es simplemente un AND con la entrada. Si queremos borrar la entrada, hacemos un AND y de esa forma nuestra nuestro "clear" únicamente es sensible cuando el reloj cambia a un flanco negativo. Entonces esto sería gatillado por flanco de bajada del "clock". ¿Cómo se hace Verilog un "flip-flop" D con "reset"? La señal de "reset" va a hacer que la salida del "flip-flop" se vaya al valor 0, se reinicie o se resetee, pudiendo ser un "reset" síncrono o asíncrono. Con el Verilog podemos hacerlo en un bloque "always", que es lo que está aquí a la derecha. Vemos que hay un módulo "flip-flop" que tiene una entrada adicional, en este caso entrada "reset", esa entrada es nuestra entrada adicional. Y lo que escribimos, al igual que en el caso anterior, solo que aquí si "reset" vale 0, entonces Q es 0. Si "reset" no vale 0, entonces Q es lo que debería ser. Q es D y esto sería un "flip-flop" con "reset" síncrono. Al describir esto, recordémoslo, al describir circuitos secuenciales, utilizamos casi siempre "nonblocking assignmengt", que son estas asignaciones que ocurren en paralelo. Eso es lo que decimos con esta línea. No se ejecutan en secuencia, sino que van en paralelo, y eso no lo olviden. Es importante no accesar fuera de un bloqueo "always los registros que fueron asignados con "blocking assignment", y no mezclar estos dos tipos de asignación en un bloque "always". Si tienen dudas, si no saben qué es lo que tienen que hacer, pongan en bloques "always" asignaciones no bloqueantes como las que están aquí. ¿Qué deberíamos agregar al bloque "ajways" para tener un "reset" asíncrono? ¿Se les ocurre o no? Piénsenlo un segundo y me cuentan. Para agregar esta opción de un "reset" asíncrono, deberíamos, tal vez, poner en esta lista de sensibilidad el "reset", ¿o no? Puede ser. El problema es que no funciona así. ¿Por qué no funciona así? En la lista de sensibilidad, esto es para Verilog en general, uno no puede combinar flancos y niveles. Nosotros no podemos poner simplemente cuando ocurra un flanco positivo de reloj o cuando ocurra un "reset". Si uno es flanco, todos son flancos. Si uno es nivel, todos son niveles. No podemos mezclar flancos y niveles en la lista de sensibilidad. ¿Cómo lo hacemos? Hay un truco. Ese truco está aquí. Ese truco está en este caso. Aquí tenemos el flanco negativo de "reset" o flanco positivo de "clock". ¿Y qué es lo que ocurre aquí? Si es que hay un flanco negativo de "reset", entonces se hace la pregunta: si el "reset" está en 0, entonces Q se asigna con un 0 y cualquier otro caso Q, se asigna con la entrada. Con este truco convertimos algo que queremos que opere con niveles en algo que en Verilog es descrito con flancos. Esta es una forma de hacerlo. Muy bien. Recuerden, además, que los argumentos de la lista de sensibilidad son evaluados en orden. Primero, ve si hay un flanco negativo en "reset", luego, mira si hay un flanco positivo en "clock". Hagamos otro. "flip-flop" con "enable". La función "enable" va a permitir que el "flip-flop" mantenga el estado a pesar de los flancos de reloj. O sea, lo que estamos haciendo es habilitar los cambios solo cuando existe un "enable" y no cuando el reloj está operando. Para que opere el reloj tendría que haber un "enable". Hay dos formas de hacerlo, una que tal vez es la más obvia, es la que está aquí, que es simplemente poner el reloj con el "enable" y hacer un AND entre ambos. Entonces, el "flip-flop" solamente va a ser sensible al "clock" cuando el "enable" esté habilitado. Otra forma de hacerlo, que resulta menos obvia, es poner un multiplexor y tomar la salida del "flip-flop" y realimentar la entrada, y dependiendo de si "enable" es 0, significa que está deshabilitado; por lo tanto, mi entrada va a ser lo mismo que la salida. En cambio, si el "enable" es 1, lo cual significa que está habilitado el "flip-flop", entonces mi entrada al "flip-flop" va a ser la entrada externa. Y con eso yo puedo crear un "flip-flop" con "enable". Estas dos implementaciones son distintas, aunque uno las ve como que hacen lo mismo, pero son distintas, y hay una clave aquí y es una clave importante al usar FPGA. A esto no nos hemos enfrentado en el pasado; por lo tanto, es importante que lo mencione. Un FPGA, como el Artix 7 que está puesto esta Basys 3, tienes circuitos especiales para transmitir el reloj a todo el FPGA. Para esto voy a crear una página nueva. Sucede lo siguiente: el reloj es una señal que viene, por ejemplo, desde afuera, puede venir desde afuera y tiene que entrar al chip. Y este es el chip. Tiene que entrar a través de un pin y el reloj va ruteado a todos los "flip-flop"s que hay en el circuito. Aquí tengo un "flip-flop", aquí tengo un flip- flop, aquí tengo otro "flip-flop". Tiene su entrada de reloj y el reloj tiene que ir ruteado a todos los "flip-flops" del circuito. ¿Cómo aseguran en el FPGA que el reloj llegue a todos los "flip-flops" sin retardo? Lo que hacen es poner "buffers", los dibujé de tamaños diferentes, porque los buffers suelen hacerse de esa forma, con inversores crecientes en tamaño. Los tamaños de los transistores crecen en "4 por", generalmente. Eso no lo vamos a ver en este curso, pero es algo que se estila. Y luego de estos "buffers", que voy a poner dentro de este bloque, lo que hacen es llevar el reloj a través de líneas que se distribuyen como haches, lo voy a dibujar de esta forma. Aquí se distribuyen como una h. ¿Cuál es la idea? Que el retardo del reloj sea el mismo para todos los circuitos, entonces yo entrar por aquí y el retardo hasta este punto es igual al retardo hasta este punto. ¿Qué pasa si queremos llegar más cerca aún con el reloj a los "flip-flops"? Ponemos más haches. Esto es como un fractal. Podemos poner haches sobre las haches y de esa forma, el retardo que hay hacia cualquier extremo de la h final es el mismo en cualquier h, en cualquiera de estas haches. Esa es la forma en que se transmiten los relojes. Y con esto quiero decir que hay circuitos dentro de la estrategia que están diseñados para transmitir relojes. Hay "buffers" especiales para transmitir relojes y esos buffers especiales son los que usa el FPGA y, al momento de sintetizarlo, los utiliza. Si nosotros queremos usar un FPGA e implementar un circuito en FPGA, no olvidemos que todos los "flip-flops" deberían ir conectados al mismo reloj directamente. Hay excepciones, sí, las vamos a aprender eventualmente. Podemos trabajar con diferentes dominios de reloj dentro de un FPGA, pero les comento, por ahora asumamos que todos los "flip-flops" de un FPGA van conectados al mismo reloj. Hacer esto, que parece ser lo más obvio en una estrategia, no funciona bien. Van a aparecer "warnings" al momento de sintetizar, porque en general, no es bueno cambiar el reloj que entra a un "flip-flop", aplicando lógica antes del "flip-flop". Hago esta acotación porque es importante. ¿Cómo hacemos "flip-flops" con "enable" en Verilog? El código es sencillo. Se basa principalmente en esta declaración "if-else", y la parametrización es bastante simple. Aquí está el caso sin parametrizar. Aquí a la derecha está el caso con parametrizar. Entonces tenemos la entrada "enable", y esa entrada "enable" es una de las entradas de nuestro "flip-flop". Entonces, cuando hay un flanco positivo de reloj o flanco negativo de "reset", nuevamente "reset" asíncrono, si el "reset" es 0, entonces la salida es 0 y cualquier otro caso, si hay un "enable", entonces la salida es D, y si no, la salida mantiene el valor anterior. Y eso es la implementación de este caso que esta aquí. Luego, ¿por qué ese caso? Si se fijan, el reloj no lo hemos tocado. Aquí no hemos tocado el reloj, el reloj entra tal cual como debiera entrar al módulo "flip-flop". Y luego viene esta otra opción, que es parametrizando. En este caso el parámetro es 8 por default, pero podemos cambiarlo externamente, y así tenemos un montón de "flip-flops" y tenemos, por ejemplo, un registro de salida de n menos 1 a 0. Eso significa que esto que está acá, Q, va a ser un registro de 8 bits en default. Un registro de 8 bits, en el fondo, son 8 posiciones de memoria de un bit y que yo puedo alterar de esta forma. Muy bien. ¿Qué aprendimos hoy? Aprendimos el "flip-flop" D con señal de entrada "clear" y "preset". Puede ser "clear" síncrono y puede ser "reset" síncrono o asíncrono. Vimos también "flip-flops" D con función de "enable" que hacen que el "flip-flop" mantenga su valor, a menos que haya un "enable" que me habilite la entrada. Y después vimos el diseño de "flip-flops" en Verilog con "clear", "preset" y con "enable". Muchas gracias por ver esta clase.