Un circuito combinacional produce sus salidas únicamente a partir de las entradas presentes. Las puertas lógicas y las funciones booleanas permiten diseñar sumadores, comparadores, multiplexores, decodificadores y bloques básicos de un procesador.
Un circuito digital procesa señales binarias. En un circuito combinacional, cada salida depende exclusivamente de la combinación actual de entradas: no importa qué valores tuvieron antes.
Esta propiedad permite describirlo con funciones booleanas y tablas de verdad. El circuito es la realización física, o una simulación, de una regla lógica ya definida.
Si un circuito tiene n entradas y m salidas, puede verse como una función que recibe n bits y devuelve m bits. Cada salida es una función booleana de las entradas.
Una salida puede reutilizarse como entrada de otra puerta dentro del mismo circuito. Mientras no exista memoria ni retroalimentación que conserve estado, el conjunto sigue siendo combinacional.
Las puertas lógicas implementan operaciones booleanas elementales sobre señales binarias.
| Puerta | Expresión | Salida verdadera cuando... |
|---|---|---|
| NOT | ¬A | A es falsa |
| AND | A ∧ B | ambas entradas son verdaderas |
| OR | A ∨ B | al menos una entrada es verdadera |
| NAND | ¬(A ∧ B) | no son ambas verdaderas |
| NOR | ¬(A ∨ B) | ambas entradas son falsas |
| XOR | A ⊕ B | exactamente una entrada es verdadera |
| XNOR | ¬(A ⊕ B) | las entradas son iguales |
Una puerta se representa habitualmente con un símbolo gráfico, pero su tabla de verdad y su expresión booleana describen su comportamiento sin depender del dibujo.
NAND y NOR son puertas universales: usando solamente una de ellas se puede construir cualquier función booleana. Esto reduce la variedad de componentes necesaria para implementar un diseño.
En hardware real, la elección de puertas también depende de velocidad, consumo, tecnología de fabricación y restricciones del diseño, no solo de completitud funcional.
Para implementar una función podemos seguir un proceso sistemático: listar entradas, construir la tabla de verdad, obtener una expresión booleana, simplificarla y conectar puertas que realicen la expresión.
La simplificación puede disminuir la cantidad de puertas, el retraso de propagación y el consumo de energía. También hace el circuito más fácil de verificar.
Queremos una salida Y que valga 1 cuando A y B sean iguales. La tabla muestra que Y es verdadera en 00 y 11.
El circuito puede construirse con dos NOT, dos AND y un OR, o con una única puerta XNOR si está disponible en la tecnología utilizada.
const AND = (a, b) => a && b;
const OR = (a, b) => a || b;
const NOT = a => !a;
const XOR = (a, b) => a !== b;
const XNOR = (a, b) => !XOR(a, b);
function bitsIguales(a, b) {
return XNOR(a, b);
}
console.log(bitsIguales(true, true)); // true
console.log(bitsIguales(true, false)); // falseLa simulación trabaja con valores booleanos. Un circuito físico trabaja con niveles eléctricos que representan esos valores y requiere considerar aspectos que el modelo lógico abstracto no muestra.
Un semisumador suma dos bits A y B. Tiene dos salidas: S, el bit de suma, y C, el acarreo. No recibe un acarreo previo.
| A | B | Suma decimal | S | C |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 |
| 0 | 1 | 1 | 1 | 0 |
| 1 | 0 | 1 | 1 | 0 |
| 1 | 1 | 2 | 0 | 1 |
Las expresiones son S = A ⊕ B y C = A ∧ B. XOR detecta que hay exactamente un bit activo; AND detecta la única combinación que produce acarreo.
function semisumador(a, b) {
return {
suma: XOR(a, b),
acarreo: AND(a, b)
};
}
console.log(semisumador(true, true));
// { suma: false, acarreo: true }La suma binaria 1 + 1 produce 10: el bit de suma es 0 y el acarreo hacia la posición siguiente es 1.
Un sumador completo recibe A, B y un acarreo de entrada Cin. Produce el bit de suma S y un acarreo de salida Cout.
El acarreo sale activo cuando al menos dos de las tres entradas son activas. Por eso Cout es una función mayoría.
| A | B | Cin | S | Cout |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 1 | 1 | 0 |
| 0 | 1 | 0 | 1 | 0 |
| 0 | 1 | 1 | 0 | 1 |
| 1 | 0 | 0 | 1 | 0 |
| 1 | 0 | 1 | 0 | 1 |
| 1 | 1 | 0 | 0 | 1 |
| 1 | 1 | 1 | 1 | 1 |
La tabla equivale a sumar tres bits y expresar el resultado con dos bits: Cout es el bit más significativo y S el menos significativo.
function sumadorCompleto(a, b, acarreoEntrada) {
const sumaParcial = XOR(a, b);
return {
suma: XOR(sumaParcial, acarreoEntrada),
acarreoSalida: OR(AND(a, b), AND(acarreoEntrada, sumaParcial))
};
}
console.log(sumadorCompleto(true, true, true));
// { suma: true, acarreoSalida: true }La implementación usa dos semisumadores conceptuales y una OR para combinar los acarreos. Esta composición es una técnica general de diseño de circuitos.
Para sumar números de varios bits se encadenan sumadores completos. El acarreo de salida de una posición se conecta al acarreo de entrada de la siguiente posición más significativa.
Es simple, pero el último resultado debe esperar a que se propaguen los acarreos anteriores. Otros diseños calculan o anticipan acarreos para ganar velocidad a cambio de más complejidad.
Un multiplexor selecciona una de varias entradas de datos y la envía a una única salida según señales de control. Un multiplexor 2 a 1 tiene entradas D0, D1 y selector S.
El multiplexor actúa como un interruptor controlado por lógica. Es un bloque esencial para seleccionar datos, rutas de ejecución y fuentes dentro de un procesador.
function multiplexor2(selector, dato0, dato1) {
return OR(AND(NOT(selector), dato0), AND(selector, dato1));
}
console.log(multiplexor2(false, true, false)); // true: elige dato0
console.log(multiplexor2(true, true, false)); // false: elige dato1Un multiplexor de 2k entradas requiere k señales de selección. Cada combinación de selectores elige una entrada distinta.
Un decodificador realiza la operación inversa conceptual de un multiplexor: toma k bits de entrada y activa una de 2k salidas. En un decodificador 2 a 4, exactamente una salida está activa para cada entrada.
Los decodificadores se usan para seleccionar posiciones de memoria, activar dispositivos y convertir códigos binarios en señales individuales.
Un comparador determina la relación entre dos entradas. Para un bit A y un bit B, podemos producir señales A = B, A > B y A < B.
Los comparadores de varios bits combinan las comparaciones desde los bits más significativos. Son necesarios para ordenamiento, saltos condicionales y verificación de límites.
Una función pura de programación se parece a un circuito combinacional: con las mismas entradas devuelve la misma salida y no depende de estado interno mutable ni de efectos externos.
function compararBit(a, b) {
return {
igual: XNOR(a, b),
mayor: AND(a, NOT(b)),
menor: AND(NOT(a), b)
};
}
console.log(compararBit(true, false));
// { igual: false, mayor: true, menor: false }La analogía no elimina diferencias entre software y hardware, pero ayuda a diseñar componentes deterministas, fáciles de probar mediante casos de entrada y salida.
En el modelo booleano, las puertas responden instantáneamente. En hardware real, cada puerta tarda un tiempo pequeño en propagar un cambio. Caminos de distinta longitud pueden provocar transiciones momentáneas no deseadas llamadas peligros o glitches.
La simplificación algebraica es útil, pero una implementación física puede requerir términos adicionales o sincronización para evitar glitches. Este es un detalle de diseño electrónico, no una contradicción de la función booleana.
Los circuitos combinacionales son bloques de construcción. Al conectarlos con elementos que guardan estado se obtienen los circuitos secuenciales que veremos en el próximo tema.
Los circuitos combinacionales calculan funciones sin recordar el pasado. En el próximo tema incorporaremos memoria y tiempo mediante circuitos secuenciales, registros y elementos de almacenamiento.