HW 02 - CMOS Full Adder - Learnings
Class: CSCE-312
Notes:
Build a Full Adder
For this assignment, you should build a full adder circuit using CMOS P and N transistors in a little C program I came up with. Currently the C program implements an OR gate with two inputs and one output. You should modify or replace the code to implement a full adder with three inputs and two outputs. The program will call your code to build the circuit, then print the circuit in a somewhat human-readable format, then exhaustively test the circuit with all possible combinations of three inputs. You're done when the output of the program shows the correct truth table for a full adder, i.e. something like this:
...
found 3 input nodes, 2 output nodes
2 1 0 | 4 3
----------------
0 0 0 0 0
0 0 1 0 1
0 1 0 0 1
0 1 1 1 0
1 0 0 0 1
1 0 1 1 0
1 1 0 1 0
1 1 1 1 1
The Full Adder Logic Diagram
One implementation of the full adder circuit looks as follow:
/CSCE-312/Visual%20Aids/Pasted%20image%2020250913203629.png)
Strategy for Minimal node number design (Static-CMOS)
Basically use the diagram above as a blueprint of your circuit
- Compute P = A ⊕ B
- Compute Sum = P ⊕ Cin
- Compute G = A · B
- Compute Cout = G + (P · Cin)
Transmission Gates
1. What is a transmission gate (TG)?
A transmission gate is basically a “bidirectional switch” built from one NMOS and one PMOS in parallel, controlled by complementary signals.
A ----|| NMOS (gate=C) ||---- B
|| PMOS (gate=¬C) ||
- Control signal:
C - NMOS gate:
C - PMOS gate:
¬C(complement)
When C=1:
- NMOS conducts strongly (good at passing 0, weak at passing 1).
- PMOS conducts strongly (good at passing 1, weak at passing 0).
Together → both 0s and 1s are passed strongly.
When C=0:
- NMOS OFF, PMOS OFF → path is open, no conduction.
So a transmission gate is just a controllable wire (closed switch when enabled, open when disabled).
Diagram Example:
/CSCE-312/Visual%20Aids/Pasted%20image%2020250913220520.png)
2. Why use TGs?
- Pass both logic levels strongly (unlike NMOS-only pass transistor, which distorts logic high).
- Save transistors compared to building full PDN/PUN networks for some functions.
- Ideal for XORs and MUXes, where the output is “one of two inputs” depending on a select line.
3. Example: XOR with TGs
We can build X = A ⊕ B with just 8 transistors using TGs:
Circuit intuition:
- Use B as the control.
- If B=0 → output should equal A.
- If B=1 → output should equal ¬A.
That’s a 2:1 multiplexer:
A multiplexer is the perfect job for a transmission gate:
- One TG passes
Awhen B=0. - One TG passes
¬Awhen B=1. - Their outputs join at node X.
Total transistors:
- 2 TGs × 2 devices = 4T
- Inverter for ¬A = 2T
- Inverter for ¬B (control complement) = 2T
- Total = 8T
Compare with static CMOS XOR (~12T). Much leaner.
1. Building a Transmission Gate (TG)
We want to achieve the following behavior
| SEL | NMOS gate | PMOS gate | NMOS | PMOS | TG |
|---|---|---|---|---|---|
| 0 | 0 | 1 | OFF | OFF | Open |
| 1 | 1 | 0 | ON | ON | Closed |
- You “invert the PMOS control” (or equivalently “invert the NMOS control”) so the two gates are always opposite, guaranteeing both ON when enabled and both OFF when disabled.
- Which one you invert sets whether your TG is active-high or active-low. Conventionally we keep NMOS=SEL, PMOS=¬SEL (active-high).
Wired up in C framework:
void make_TGate (circuit *c, int input_wire, int select_wire, int output_wire) {
// Define building blocks (PMOS, NMOS)
int p, n;
// get P and N transistors
p = new_node (c, P);
n = new_node (c, N);
// Invert the selecter (to be used by PMOS)
int not_sel_wire = new_wire(c);
make_inverter (c, select_wire, not_sel_wire);
// Now the not_sel_wire will give the opposite of what select_wire gives
// Wire up PMOS (triggered when select = 0)
attach_node_to_wire(c, p, not_sel_wire, CONTROL); // not_select_wire to SELECT
attach_node_to_wire(c, p, input_wire, INPUT); // input_wire to INPUT
attach_node_to_wire(c, p, output_wire, OUTPUT); // output_wire to DRAIN
// We want both ON at the same time when the switch/select is “ON”
// and both OFF together when it's “OFF”
// Note: I could have inverted NMOS instead, will give the same.
// Wire up NMOS (triggered when select = 1)
attach_node_to_wire(c, n, select_wire, CONTROL); // select_wire to SELECT
attach_node_to_wire(c, n, input_wire, INPUT); // input_wire to INPUT
attach_node_to_wire(c, n, output_wire, OUTPUT); // output_wire to DRAIN
}
2. Building a 2:1 MUX
A 2:1 multiplexer is a gate that chooses between two inputs D0,D1 and forwards one of them to the output, depending on a select input (SEL):
| SEL | Y |
|---|---|
| 0 | D0 |
| 1 | D1 |
| So, the MUX is basically a controlled switch that says: “If SEL=0, connect D0 → Y; if SEL=1, connect D1 → Y.” |
A MUX is just two TGs in parallel onto the same output, one passing D0 when SEL=0, the other passing D1 when SEL=1.
/CSCE-312/Visual%20Aids/Pasted%20image%2020250913225517.png)
Why do we need it?
Because many complex functions can be rewritten as a MUX. For example:
-
XOR:
If B=0 → output A; if B=1 → output ¬A.
-
Full-adder carry-out:
If P=0 → output G; if P=1 → output Cin.
Much simpler than building a big AOI structure.
So, using a MUX often reduces transistor count and node clutter.