Fascinated by a lecture as part of my CS degree pursuits (there is light at the end of the tunnel!), I decided to build some digital circuitry beginning with logic gates and ending with a full 32-bit adder. LIVE DEMO

*So here’s my question: I’ve got a 32-bit adder… What now?*

Beginning with basic AND, and OR functions, (&& and || operators are native to JavaScript), I built a simple XOR function — which is the first building block not built in to JavaScript:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/* AND =========*/ function and(a,b){ return (a && b) + 0; } /* OR =========*/ function or(a,b){ return (a || b) + 0; } /* XOR =========*/ function xor(a,b){ if (and(a,b)) {return false + 0;} if (or(a,b)) {return true + 0;} return false + 0; } |

I wanted each gate/function to work with simple Boolean values, as in JavaScript 1==True, 0==False can get a bit messy. For formatting reasons, I return each value + 0, so they results of higher order circuits are displayed numerically in binary, rather than a series of True, False’s

After implementing, these foundational gates, I coded up a full adder:

1 2 3 4 5 6 7 8 9 |
/* Full-Adder ===============*/ function fullAdder(a,b,c){ return { c:or(and(xor(a,b),c), and(a,b)), // C is the carry s:xor(xor(a,b),c) // S is the sum }; } |

Within the returned object, “c” represents the carry, and “s” represents the sum. Information about how adders function can be found at this great Wikipedia article.

While there are more complex versions, a simple 4-bit adder is just 4 full-adders daisy chained together which each carry leading into the next adder. The final carry is returned from the 4-bit adder:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* 4-bit Adder Composed of 4 full-adders ==============================*/ function adder4(a, b, c){ var adder_1 = fullAdder(a[3], b[3], c), adder_2 = fullAdder(a[2], b[2], adder_1.c), adder_3 = fullAdder(a[1], b[1], adder_2.c), adder_4 = fullAdder(a[0], b[0], adder_3.c); return { s: [adder_4.s, adder_3.s,adder_2.s, adder_1.s].join(''), c: adder_4.c }; } |

16, and 32 bit adders function in the same way: several smaller units daisy chained together, returning the final carry along with the sum:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
/* 16-bit Adder Composed of 4 4-bit adders ==============================*/ function adder16(a,b,c){ var adder_1 = adder4([a[12], a[13], a[14], a[15]], [b[12], b[13], b[14], b[15]], c), adder_2 = adder4([a[8], a[9], a[10], a[11]], [b[8], b[9], b[10], b[11]], adder_1.c), adder_3 = adder4([a[4], a[5], a[6], a[7]], [b[5], b[5], b[6], b[7]], adder_2.c), adder_4 = adder4([a[0], a[1], a[2], a[3]], [b[0], b[1], b[2], b[3]], adder_3.c); return{ s: [adder_4.s, adder_3.s, adder_2.s, adder_1.s].join(' '), c: adder_4.c }; } /* 32-bit Adder Composed of 2 16-bit adders ================================*/ function adder32(a,b,c){ var adder_1 = adder16([a[16], a[17], a[18], a[19], a[20], a[21], a[22], a[23], a[24], a[25], a[26], a[27], a[28], a[29], a[30], a[31]], [b[16], b[17], b[18], b[19], b[20], b[21], b[22], b[23], b[24], b[25], b[26], b[27], b[28], b[29], b[30], b[31]], c), adder_2 = adder16([a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]], [b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]], adder_1.c); return{ s: [adder_2.s, adder_1.s].join(' '), c: adder_2.c }; } |

The functions can be used like so:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
/* Some Tests ===============*/ out(adder4([0,0,0,1], [0,0,0,1], 0).s); out(adder16([0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], 0).s); out(adder32([0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1], [0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0],0).s); /* Out writes to screen =====================*/ function out(value){document.write(value + "</br>");} |

*So here’s where you come in: What do I do with a 32-bit adder, other than build a 64-bit adder?*