Como decíamos anteriormente, existen herramientas software capaces no solo de realizar automáticamente la simplificación de expresiones booleanas, sino incluso de sintetizar directamente el circuito que las implementa. La automatización de la minimización de expresiones booleanas se basa en dos conceptos que vamos a ver a continuación: la llamada "notación cúbica" y la idea de "adyacencia". Dada una función, una expresión booleana f de n variables, un cubo es cualquier secuencia de n caracteres 0, 1 o x. Cada cubo representa un producto de la función siguiendo estas reglas. Es decir, si tenemos estamos en n igual a 4 y tenemos una función de las variables a b c d, el cubo 0 1 1 x representa el producto a-barra, b, c. El como sabemos exactamente qué producto representa nos lo dicen, insisto, estas reglas. Pero vamos a verlo de una manera práctica y sencilla. Básicamente lo que hacemos es colocar en cada posición las variables a b c d y decir: si en la posición correspondiente a la variable "a" el cubo tiene un 1 quiere decir que, en este producto, la variable "a" aparece tal cual, sin negar. Si en la posición correspondiente a la variable, en este caso "b", en el cubo aparece un 0 quiere decir que la variable "b" aparece negada, y si aparece en x quiere decir que estas variables no están en el producto. Es decir, el cubo 1 0 x x representa el producto a por b-barra. Oro jemplo más para que quede claro, 1 1 x 1, por ejemplo, ¿que sería?... Esta es la posición correspondiente a "a b c d". La "a" aparece sin negar, la "b" aparece sin negar, la "c" no aparece y la "d" aparece sin negar es decir, este cubo es el cubo "a b d". Toda función booleana puede representarse como suma de productos y, por tanto, toda función booleana puede representarse como suma de cubos. Dos cubos que se diferencien en una única posición se dice que son adyacentes, por ejemplo: los cubos 0 1 x 1 y 0 0 x 1 son adyacentes porque sólo se diferencian en esta posición. Dos cubos adyacentes pueden sustituirse por un único cubo en el cual en esta posición en la cual tienen un 0 o un 1 respectivamente colocamos una x. ¿Por qué podemos hacer esto? Vamos a ver qué término producto representa este cubo: el a el "a-barra b d"; y este cubo representa el "a-barra b-barra d" Si la función contiene estos dos cubos, y como hemos dicho, seguramente muchos más, contiene la suma de estos dos productos y de estos dos productos podemos sacar factor común el "a-barra d", y el "b" más "b-barra" sabemos que es 1; por lo tanto esto se puede sustituir por "a-barra d". Estos dos términos productos se pueden simplificar con "a-barra d", que corresponde al cubo 0 x x 1, que es el que hemos visto aquí. Bien pues esta técnica de buscar cubos adyacentes e ir sustituyéndolos es lo que se utiliza para automatizar la simplificación de funciones booleanas. Veamos un ejemplo: supongamos esta función en la que los minterms de esta función son los que aparecen aquí. Aquí tenemos dos minterms que en el fondo son cubos, ¿no? son cubos donde aparecen todas las variables. Estos dos cubos son adyacentes porque se diferencian sólo en esta última posición y, por lo tanto, se pueden sustituir por un único cubo que será el 0 0 1 x. Por la misma razón por ejemplo, estos dos cubos también son adyacentes y se pueden sustituir por el 0 1 1 x. Pero es más, fijaros que ahora los dos cubos que nos han salido también son adyacentes entre sí y por lo tanto podemos sustituirlos por el 0 x 1 x. Sigamos analizando. Por ejemplo, también tenemos aquí estos dos cubos que son adyacentes y que podemos sustituirlos por el 0 1 x 1. Y este cubo de aquí que no es adyacente con ninguno y que por lo tanto no podemos hacer nada con él. Bien pues, la función será la suma de este cubo más este cubo más este cubo. Fijaros que cogiendo estos tres cubos tengo incluidos todos los minterms de la función, quiere decir que esta función la puedo escribir como "a-barra c" más este de aquí, que será el "a-barra b d", más este último cubo que es el producto "a b-barra c-barra d-barra". Estas técnicas son las que se utilizan reiteradamente en los sistemas automáticos de minimización de funciones. Supongamos ahora un caso ligeramente distinto en el cual estos tres minterms que aparecen en rojo, son términos redundantes. Haríamos exactamente lo mismo. Estos dos cubos se pueden minimizar. Estos dos cubos se pueden también minimizar, y los voy a escribir en rojo precisamente porque, es la minimización de dos cubos que son términos redundantes. Éste será el 0 1 1 x. Continuamos, estos dos términos igual que vimos anteriormente, también pueden reducirse y se convierten en el 0 1 x 1. Estos dos términos también son adyacentes, estos dos cubos se pueden, sustituir por el 0 x 1 x. Fijaros que no lo pongo en rojo porque este cubo viene de un cubo redundante que viene de términos redundantes, pero de otro cubo que no tiene términos redundantes. Sólo lo escribiremos en rojo si el cubo correspondiente procede de de cubos que son redundantes. Bien, y este pues, como en el caso anterior, no podríamos hacer nada con él. Ahora, a la hora de seleccionar la función diríamos que esta función se puede minimizar por: este cubo de aquí, este cubo de aquí ... y este cubo, como que es totalmente redundante pues, optamos por no ponerlo. La función será el producto de "a-barra c" más el producto de "a-barra b d". Esto es un ejemplo muy sencillo, simplemente para que veáis que, jugando con el concepto de adyacencia y jugando con el concepto de cubo, y jugando aquí, lo que hemos hecho es apuntar en rojo los cubos redundantes, pero fijaros que esto desde el punto de vista de un algoritmo automático simplemente es tener un flag que me indique este término este cubo viene de términos redundantes, podemos no sólo minimizar las funciones booleanas sino además seleccionar automáticamente qué términos redundantes cogemos y cuáles no, para que la función resultante sea lo más sencilla posible. Vamos a ver un ejemplo de una de estas herramientas de minimización automática de funciones booleanas. Y vamos a ver una herramienta que tenéis en el paquete VerilUOC-Desktop. Para acceder a ella basta con clicar en "proyecto", "analizar circuito" y nos sale, una ventana como ésta donde vamos a especificar las entradas las salidas y, o bien la tabla de verdad, o bien la expresión booleana que queremos minimizar. Vamos a utilizar como ejemplo la tabla de verdad del visualizador de 7-segmentos que hemos visto hace un momento. Lo primero que haríamos es especificar las entradas. A continuación, las salidas. En vez de tratar de minimizar todas las funciones de salida vamos a jugar solo con la "b" y la "c" para hacerlo simplemente más corto. Y, como primer ejemplo, vamos a minimizar a través de la tabla de verdad. Clicando en tabla nos sale esta tabla de verdad donde véis que las salidas están todas indeterminadas. Aquí, clicando una o dos veces, podemos especificar 0s, 1s o términos redundantes como queramos. En este caso la salida "b" era 1 ... y la salida "c" ... El resto de términos los dejamos con las x porque se trata de términos redundantes. Si vamos a la pestaña "Minimizado" ya nos sale directamente la función minimizada. Esta es la función minimizada para la salida "b", y si queremos ver la de la salida "c" la tenemos aquí. Podéis comprobar que coincide con las funciones booleanas que nos han salido cuando hemos estudiado el ejemplo. Este mapa de colores que véis aquí es un mapa de Karnaugh. Los mapas de Karnaugh son útiles a la hora de minimizar las funciones booleanas, pero lo que ocurre es que son muy limitados. porque sólo se pueden utilizar en funciones booleanas de hasta cuatro variables de entrada y esto, en la práctica, es muy poco. Esta herramienta nos permite incluso, ya véis que hemos podido minimizar las funciones, pero es capaz de dibujarnos directamente el circuito. Clicando en "Crear circuito" y aquí le damos un nombre por ejemplo "test1", aceptar. Pues veis que directamente nos sale dibujado el circuito correspondiente. Esta parte de la herramienta tiene un pequeño inconveniente, y es que no minimiza los inversores. Fijaros aquí tenemos x1 que entra negado a esta puerta y entra también negado a esta otra puerta. Realmente no hacen falta dos inversores, con uno sería suficiente. Pero la potencia de esta herramienta es que este circuito lo podemos editar, es decir, podemos quitar este inversor, esta conexión, esta conexión, vamos a retirar un poco a la izquierda el inversor y conectar directamente, y ya tenemos el circuito que deseamos. ¿De acuerdo? Bueno pues ahora vamos a ver un segundo ejemplo donde minimizaremos a través de la función booleana. De nuevo iríamos a "Proyecto", "Analizar circuito" y, en este caso, vamos a jugar con la función booleana que veis a la izquierda. Procederíamos como antes, entramos las entradas, especificamos las salidas, que en este caso es una única salida y ahora en vez de clicar en "Tabla" vamos a clicar en "Expresión", y aquí vamos a introducir la expresión booleana. Otra vez a la izquierda tenéis un resumen que nos dice que para entrar una variable negada, para indicar la negación, para la inversión, se utiliza el signo de admiración; para la suma booleana se utiliza el + y para el producto booleano se utiliza el &. La función que queremos introducir será algo como esta, !a + !b por (&) !c, + a por (&) b por (&) c, + !a por (&) d por (&) e. Entramos la expresión. Aquí nos aparece la misma expresión que hemos entrado nosotros pero escrito de una manera más entendible, en el sentido de tal como estamos acostumbrados a hacerlo. Vale la pena siempre comprobar que la expresión que hemos escrito es la correcta y, simplemente, clicando otra vez en "Minimizado" nos sale la expresión minimizada. Fijaros que aquí ya no ha aparecido el dibujo de colores, la tabla de colores, porque esta función booleana tiene 5 variables y por lo tanto en el mapa de Karnaugh ya no puede representarla bien. Si queremos dibujar el circuito, primero le decimos que fije esta expresión minimizada como la expresión con la que vamos a trabajar y, otra vez, "Crear circuito". Le damos el nombre por ejemplo de test2, y directamente nos sale el circuito. Como veis la herramienta es potente. La verdad es que es una herramienta del tipo educacional, es decir, las profesionales tienen más prestaciones pero que refleja bastante bien el cómo se puede minimizar automáticamente funciones booleanas y tablas de verdad. Lo que acabamos de ver es realmente potente. Hemos dicho que existen herramientas, paquetes de software, que el paquete de software que os he enseñado es de tipo educativo, educacional, pero que existen paquetes profesionales más potentes que básicamente hacen lo mismo, que a partir de una tabla de verdad o a partir de una función lógica es capaz de darnos el circuito combinacional que implementa esta función. Por otro lado, nosotros tenemos la descripción funcional del circuito que normalmente expresamos con una porción de pseudocódigo, pseudocódigo que después, cuando lo formalicemos un poco más, acabará siendo un lenguaje de descripción hardware de alto nivel como puede ser el VHDL, Verilog o algún otro. Bien lo que pondríamos aquí es añadir un módulo que desde esta descripción funcional nos genere la tabla de verdad, cosa que es relativamente fácil porque lo hemos estado haciendo a mano una y otra vez. Cuando el sistema digital es grande, normalmente el circuito se implementa no utilizando puertas individuales o circuitos integrados de bajo nivel de integración sino que se utilizan módulos programables como las FPGAs o circuitos integrados de aplicación específica. Bien, lo que los programas profesionales hacen es añadir un nuevo módulo por aquí, en el cual lo que hacen es un volcado del circuito combinacional a la FPGA o el ASIC, FPGA perdón, vamos a escribirlo bien. Las FPGAs las veremos más adelante, pero la idea es que son chips que contienen un montón de puertas y una serie de interconexiones que podemos programarlas a voluntad. Pues este módulo lo que haría es programar estas conexiones para que el circuito que acabe configurado dentro de la FPGA sea el que nosotros queremos. A este módulo habitualmente se le da el nombre de "technology mapping", por cuanto lo que hace es "mapear" nuestro circuito en la tecnología correspondiente. Si ahora lo vemos como un todo, estamos diciendo que existen sistemas en los cuales yo le doy mi descripción del circuito a alto nivel y simplemente me devuelven la FPGA programada totalmente. O la programación, que después paso por el módulo programador. Pues, ... esto es muy potente; y esto son las llamadas "herramientas de síntesis automática" de sistemas lógicos, que existen pues a un nivel profesional y se utilizan muchísimo. Normalmente estos paquetes de síntesis automática incluyen herramientas como estas que acabamos de ver y además incluyen simuladores para que podamos, antes de implementar el circuito en la FPGA o en el ASIC, simular el funcionamiento y ver si es correcto o no. Bueno pues con esto acabamos esta primera lección. Hemos visto el concepto de término redundante y cómo estos términos redundantes nos pueden ayudar a simplificar el circuito, a reducir el tamaño del circuito. Y hemos visto también unas herramientas de ayuda capaces de automatizar la simplificación de funciones booleanas y capaces además de darnos directamente el circuito combinacional que implementa la función que nosotros hemos introducido. Estas herramientas insisto, las que hemos visto, son muy sencillas y son de tipo educacional, pero reflejan los puntos primordiales de las grandes herramientas profesionales de diseño de sistemas digitales.