Práctica 2 : Lógica Booleana

Recursos

Introducción

El objetivo principal de este proyecto es construir todas las compuertas descritas en la lógica booleana, obteniendo así un conjunto básico de chips. Para llevar a cabo esto, solamente se hizo uso de la compuerta Nand primitiva, la cual sirvió para construir todas las demás compuertas lógicas a partir de ella. De esta manera, el resultado suministrado es un conjunto de compuertas estándar para construir los chips de almacenamiento y procesamiento de información. Por ejemplo, todo dispositivo digital, ya sea un ordenador personal, un teléfono móvil o un router de red, se fundamenta en los chips mencionados anteriormente. Finalmente, se utilizó el software The Nand2tetris Software Suite, el cual contiene todas las herramientas y archivos necesarios para completar la práctica.


NOT

Utilizando la compuerta primitiva NAND, comparamos dos entradas del mismo valor y así obtenemos la salida que es equivalente a la compuerta NOT.

Not.hdl

/**

* Not gate:

* out = not in

*/


CHIP Not {

IN in;

OUT out;


PARTS:

Nand(a=in, b=in, out=out);

}

Resultados obtenidos

AND

Para esta compuerta también utilizamos la compuerta NAND con dos entradas, luego negamos la salida con una compuerta NOT.

And.hdl

/**

* And gate:

* out = 1 if (a == 1 and b == 1)

* 0 otherwise

*/


CHIP And {

IN a, b;

OUT out;


PARTS:

Nand(a=a, b=b, out=nandab);

Nand(a=nandab, b=nandab, out=out);

}

Resultados obtenidos

OR

Para esta utilizamos 2 compuertas NAND, negando ambas entradas, después utilizamos otra compuerta NAND donde sus entradas son la salida de las compuertas NAND mencionadas anteriormente, y nos da el resultado esperado.



Or.hdl

/**

* Or gate:

* out = 1 if (a == 1 or b == 1)

* 0 otherwise

*/


CHIP Or {

IN a, b;

OUT out;


PARTS:

Nand(a=b, b=b, out=notb);

Nand(a=a, b=a, out=nota);

Nand(a=nota, b=notb, out=out);

}

Resultados obtenidos

XOR

Para la compuerta XOR se hace uso de una compuerta NAND con las entradas iniciales, a y b, seguido se utilizaron dos compuertas NAND, una tiene como entrada la salida de la primera NAND junto con la entrada a, la otra también tiene la salida de la primera NAND pero junto con la entrada b, luego las salidas de éstas van a una compuerta NAND y el resultado es lógica de la compuerta XOR.

Xor.hdl

/**

* Exclusive-or gate:

* out = not (a == b)

*/


CHIP Xor {

IN a, b;

OUT out;


PARTS:

Nand(a=a, b=nandab, out=top);

Nand(a=a, b=b, out=nandab);

Nand(a=b, b=nandab, out=bottom);

Nand(a=top, b=bottom, out=out);

}

Resultados obtenidos

MUX

Para éste chip utilizamos una entrada sel, que se niega a través de una compuerta NAND y esta negación se evalúa junto con la entrada a en otra NAND, también se evalúa la entrada sel con la entrada b en otra compuerta NAND. Finalmente, la salida de estas compuertas se evalúan en una compuerta NAND y se obtiene la salida de la MUX.

Mux.hdl

/**

* Multiplexor:

* out = a if sel == 0

* b otherwise

*/


CHIP Mux {

IN a, b, sel;

OUT out;


PARTS:

Nand(a=a, b=notsel, out=apart);

Nand(a=sel, b=sel, out=notsel);

Nand(a=b, b=sel, out=bpart);

Nand(a=apart, b=bpart, out=out);

}

Resultados obtenidos

DMUX

Con una entrada in vamos a dos compuertas NAND donde evaluamos in con una entrada sel que previamente pasa por una compuerta NAND para ser negada de ahí pasa a una compuerta NAND para negar la salida y obtenemos a, por otro lado en la compuerta restante evaluamos in y sel, pasa por una NAND para ser negada y obtenemos b.

Dmux.hdl

/**

* Demultiplexor:

* {a, b} = {in, 0} if sel == 0

* {0, in} if sel == 1

*/


CHIP DMux {

IN in, sel;

OUT a, b;


PARTS:

Nand(a=sel, b=sel, out=notsel);

Nand(a=apart, b=apart, out=a);

Nand(a=in, b=notsel, out=apart);

Nand(a=bpart, b=bpart, out=b);

Nand(a=in, b=sel, out=bpart);

}

Resultados obtenidos

NOT16

En la Not16 evaluamos 16 valores de un array y con una compuerta NAND para cada valor de ese array obtenemos cada valor negado de ese array.


Not16.hdl

/**

* 16-bit Not:

* for i=0..15: out[i] = not in[i]

*/


CHIP Not16 {

IN in[16];

OUT out[16];


PARTS:

Nand(a=in[0], b=in[0], out=out[0]);

Nand(a=in[1], b=in[1], out=out[1]);

Nand(a=in[2], b=in[2], out=out[2]);

Nand(a=in[3], b=in[3], out=out[3]);

Nand(a=in[4], b=in[4], out=out[4]);

Nand(a=in[5], b=in[5], out=out[5]);

Nand(a=in[6], b=in[6], out=out[6]);

Nand(a=in[7], b=in[7], out=out[7]);

Nand(a=in[8], b=in[8], out=out[8]);

Nand(a=in[9], b=in[9], out=out[9]);

Nand(a=in[10], b=in[10], out=out[10]);

Nand(a=in[11], b=in[11], out=out[11]);

Nand(a=in[12], b=in[12], out=out[12]);

Nand(a=in[13], b=in[13], out=out[13]);

Nand(a=in[14], b=in[14], out=out[14]);

Nand(a=in[15], b=in[15], out=out[15]);

}

Resultados obtenidos

AND16

La And16 se contemplan dos arrays de valores que se comparan en una compuerta NAND, al final obtenemos un valor para cada comparación del par de valores y éste resultado pasa a otra NAND siendo negado y dando como resultado la lógica de la AND16.

And16.hdl

/**

* 16-bit bitwise And:

* for i = 0..15: out[i] = (a[i] and b[i])

*/


CHIP And16 {

IN a[16], b[16];

OUT out[16];


PARTS:

Nand(a=a[0], b=b[0], out=nandab0);

Nand(a=nandab0, b=nandab0, out=out[0]);

Nand(a=a[1], b=b[1], out=nandab1);

Nand(a=nandab1, b=nandab1, out=out[1]);

Nand(a=a[2], b=b[2], out=nandab2);

Nand(a=nandab2, b=nandab2, out=out[2]);

Nand(a=a[3], b=b[3], out=nandab3);

Nand(a=nandab3, b=nandab3, out=out[3]);

Nand(a=a[4], b=b[4], out=nandab4);

Nand(a=nandab4, b=nandab4, out=out[4]);

Nand(a=a[5], b=b[5], out=nandab5);

Nand(a=nandab5, b=nandab5, out=out[5]);

Nand(a=a[6], b=b[6], out=nandab6);

Nand(a=nandab6, b=nandab6, out=out[6]);

Nand(a=a[7], b=b[7], out=nandab7);

Nand(a=nandab7, b=nandab7, out=out[7]);

Nand(a=a[8], b=b[8], out=nandab8);

Nand(a=nandab8, b=nandab8, out=out[8]);

Nand(a=a[9], b=b[9], out=nandab9);

Nand(a=nandab9, b=nandab9, out=out[9]);

Nand(a=a[10], b=b[10], out=nandab10);

Nand(a=nandab10, b=nandab10, out=out[10]);

Nand(a=a[11], b=b[11], out=nandab11);

Nand(a=nandab11, b=nandab11, out=out[11]);

Nand(a=a[12], b=b[12], out=nandab12);

Nand(a=nandab12, b=nandab12, out=out[12]);

Nand(a=a[13], b=b[13], out=nandab13);

Nand(a=nandab13, b=nandab13, out=out[13]);

Nand(a=a[14], b=b[14], out=nandab14);

Nand(a=nandab14, b=nandab14, out=out[14]);

Nand(a=a[15], b=b[15], out=nandab15);

Nand(a=nandab15, b=nandab15, out=out[15]);

}

Resultados obtenidos

OR16

En ésta compuerta se utilizan dos arrays, a y b, cada uno de 16 valores, cada array entra a una compuerta NAND dando el mismo valor a las entradas, lo que hace papel de una compuerta NOT, posteriormente la salida de ambas NAND, son entradas a una compuerta NAND, lo que nos da como salida, la lógica de la OR16.

Or16.hdl

/**

* 16-bit bitwise Or:

* for i = 0..15 out[i] = (a[i] or b[i])

*/


CHIP Or16 {

IN a[16], b[16];

OUT out[16];


PARTS:

Nand(a=a[0], b=a[0], out=nota0);

Nand(a=b[0], b=b[0], out=notb0);

Nand(a=nota0, b=notb0, out=out[0]);

Nand(a=a[1], b=a[1], out=nota1);

Nand(a=b[1], b=b[1], out=notb1);

Nand(a=nota1, b=notb1, out=out[1]);

Nand(a=a[2], b=a[2], out=nota2);

Nand(a=b[2], b=b[2], out=notb2);

Nand(a=nota2, b=notb2, out=out[2]);

Nand(a=a[3], b=a[3], out=nota3);

Nand(a=b[3], b=b[3], out=notb3);

Nand(a=nota3, b=notb3, out=out[3]);

Nand(a=a[4], b=a[4], out=nota4);

Nand(a=b[4], b=b[4], out=notb4);

Nand(a=nota4, b=notb4, out=out[4]);

Nand(a=a[5], b=a[5], out=nota5);

Nand(a=b[5], b=b[5], out=notb5);

Nand(a=nota5, b=notb5, out=out[5]);

Nand(a=a[6], b=a[6], out=nota6);

Nand(a=b[6], b=b[6], out=notb6);

Nand(a=nota6, b=notb6, out=out[6]);

Nand(a=a[7], b=a[7], out=nota7);

Nand(a=b[7], b=b[7], out=notb7);

Nand(a=nota7, b=notb7, out=out[7]);

Nand(a=a[8], b=a[8], out=nota8);

Nand(a=b[8], b=b[8], out=notb8);

Nand(a=nota8, b=notb8, out=out[8]);

Nand(a=a[9], b=a[9], out=nota9);

Nand(a=b[9], b=b[9], out=notb9);

Nand(a=nota9, b=notb9, out=out[9]);

Nand(a=a[10], b=a[10], out=nota10);

Nand(a=b[10], b=b[10], out=notb10);

Nand(a=nota10, b=notb10, out=out[10]);

Nand(a=a[11], b=a[11], out=nota11);

Nand(a=b[11], b=b[11], out=notb11);

Nand(a=nota11, b=notb11, out=out[11]);

Nand(a=a[12], b=a[12], out=nota12);

Nand(a=b[12], b=b[12], out=notb12);

Nand(a=nota12, b=notb12, out=out[12]);

Nand(a=a[13], b=a[13], out=nota13);

Nand(a=b[13], b=b[13], out=notb13);

Nand(a=nota13, b=notb13, out=out[13]);

Nand(a=a[14], b=a[14], out=nota14);

Nand(a=b[14], b=b[14], out=notb14);

Nand(a=nota14, b=notb14, out=out[14]);

Nand(a=a[15], b=a[15], out=nota15);

Nand(a=b[15], b=b[15], out=notb15);

Nand(a=nota15, b=notb15, out=out[15]);

}

Resultados obtenidos

MUX16

Para esta se hace uso de 2 arrays de 16 valores para dos entradas, a y b, éstas se comparan de manera independiente con el valor sel en las compuertas MUX, y al final se obtiene el array de los valores de salida.

Mux16.hdl

/**

* 16-bit multiplexor:

* for i = 0..15 out[i] = a[i] if sel == 0

* b[i] if sel == 1

*/


CHIP Mux16 {

IN a[16], b[16], sel;

OUT out[16];


PARTS:

Mux(a=a[0], b=b[0], sel=sel, out=out[0]);

Mux(a=a[1], b=b[1], sel=sel, out=out[1]);

Mux(a=a[2], b=b[2], sel=sel, out=out[2]);

Mux(a=a[3], b=b[3], sel=sel, out=out[3]);

Mux(a=a[4], b=b[4], sel=sel, out=out[4]);

Mux(a=a[5], b=b[5], sel=sel, out=out[5]);

Mux(a=a[6], b=b[6], sel=sel, out=out[6]);

Mux(a=a[7], b=b[7], sel=sel, out=out[7]);

Mux(a=a[8], b=b[8], sel=sel, out=out[8]);

Mux(a=a[9], b=b[9], sel=sel, out=out[9]);

Mux(a=a[10], b=b[10], sel=sel, out=out[10]);

Mux(a=a[11], b=b[11], sel=sel, out=out[11]);

Mux(a=a[12], b=b[12], sel=sel, out=out[12]);

Mux(a=a[13], b=b[13], sel=sel, out=out[13]);

Mux(a=a[14], b=b[14], sel=sel, out=out[14]);

Mux(a=a[15], b=b[15], sel=sel, out=out[15]);

}

Resultados obtenidos

OR8WAY

Para esta compuerta tenemos una serie de compuertas OR que evalúan en forma descendiente la salida de la primera compuerta hacia otra compuerta con una nueva entrada así con 7 compuertas OR hasta llegar al resultado esperado.

Or8Way.hdl

/**

* 8-way Or:

* out = (in[0] or in[1] or ... or in[7])

*/


CHIP Or8Way {

IN in[8];

OUT out;


PARTS:

Or(a=in[0], b=in[1], out=or01);

Or(a=in[2], b=in[3], out=or23);

Or(a=in[4], b=in[5], out=or45);

Or(a=in[6], b=in[7], out=or67);

Or(a=or01, b=or23, out=or0123);

Or(a=or45, b=or67, out=or4567);

Or(a=or0123, b=or4567, out=out);

}

Resultados obtenidos

MUX4WAY16

Para realizar esta compuerta utilizamos dos compuertas Mux16 los cuales presentan 2 entradas que constituyen arrays de 16 valores cada una, luego sus salidas pasan a ser entradas de una nueva compuerta Mux16 para obtener el resultado esperado.

Mux4Way16.hdl

/**

* 4-way 16-bit multiplexor:

* out = a if sel == 00

* b if sel == 01

* c if sel == 10

* d if sel == 11

*/


CHIP Mux4Way16 {

IN a[16], b[16], c[16], d[16], sel[2];

OUT out[16];


PARTS:

Mux16(a=c, b=d, sel=sel[0], out=muxcd);

Mux16(a=a, b=b, sel=sel[0], out=muxab);

Mux16(a=muxab, b=muxcd, sel=sel[1], out=out);

}

Resultados obtenidos

MUX8WAY16

Para esta compuerta se utilizan 2 compuertas Mux4Way16 cada una con 4 entradas distintas y obtenemos una salida para cada una luego usamos una compuerta Mux16 cuyas entradas serán las 2 salidas de las compuertas anteriores y así tener la salida.

Mux8Way16.hdl

/**

* 8-way 16-bit multiplexor:

* out = a if sel == 000

* b if sel == 001

* etc.

* h if sel == 111

*/


CHIP Mux8Way16 {

IN a[16], b[16], c[16], d[16],

e[16], f[16], g[16], h[16],

sel[3];

OUT out[16];


PARTS:

Mux4Way16(a=e, b=f, c=g, d=h, sel=sel[0..1], out=muxefgh);

Mux4Way16(a=a, b=b, c=c, d=d, sel=sel[0..1], out=muxabcd);

Mux16(a=muxabcd, b=muxefgh, sel=sel[2], out=out);

}

Resultados obtenidos

DMUX4WAY

Para hacer esta compuerta nos basamos en las compuertas DMux, como vimos anteriormente para esta compuerta presentamos una entrada y un sel y obtenemos 2 salidas y cada una queda como entrada de otras compuertas DMux, al final obtendremos 4 salidas

DMux4Way.hdl

/**

* 4-way demultiplexor:

* {a, b, c, d} = {in, 0, 0, 0} if sel == 00

* {0, in, 0, 0} if sel == 01

* {0, 0, in, 0} if sel == 10

* {0, 0, 0, in} if sel == 11

*/


CHIP DMux4Way {

IN in, sel[2];

OUT a, b, c, d;


PARTS:

DMux(in=upper, sel=sel[0], a=a, b=b);

DMux(in=lower, sel=sel[0], a=c, b=d);

DMux(in=in, sel=sel[1], a=upper, b=lower);


}

Resultados obtenidos

DMUX8WAY

La realización de esta compuerta es de las más complejas, para realizarla se necesita una compuerta DMux y sus dos salidas, cada salida pasa a ser la entrada de una compuerta DMux4Way por lo cual al final presentamos 8 salidas.

DMux8Way.hdl

/**

* 8-way demultiplexor:

* {a, b, c, d, e, f, g, h} = {in, 0, 0, 0, 0, 0, 0, 0} if sel == 000

* {0, in, 0, 0, 0, 0, 0, 0} if sel == 001

* etc.

* {0, 0, 0, 0, 0, 0, 0, in} if sel == 111

*/


CHIP DMux8Way {

IN in, sel[3];

OUT a, b, c, d, e, f, g, h;


PARTS:

DMux4Way(in=mayor, sel=sel[0..1], a=a, b=b, c=c, d=d);

DMux4Way(in=menor, sel=sel[0..1], a=e, b=f, c=g, d=h);

DMux(in=in, sel=sel[2], a=mayor, b=menor);


}

Resultados obtenidos