CS ATLAS A map of computing

Project 2 · Arithmetic

Adders: from half adder to ALU

The gates from the previous page are enough; from here they are combined into things that compute: half adder → full adder → 16-bit adder → incrementer → ALU. The carry travels through all sixteen full adders, bit by bit.

HalfAdder half adder

sum = a ⊕ b, carry = a ∧ b

Truth table

absumcarry
0000
0110
1010
1101

Structure

a 1b 1sum 0carry 1

What it does

CHIP HalfAdder {
  IN a, b;
  OUT sum, carry;
  PARTS:
  Xor(a=a, b=b, out=sum);
  And(a=a, b=b, out=carry);
}

Two gates are enough: sum is XOR, carry is AND.

FullAdder full adder

sum = a ⊕ b ⊕ c, carry = (a∧b) ∨ (c∧(a⊕b))

Truth table

abcsumcarry
00000
00110
01010
01101
10010
10101
11001
11111

Structure

HalfAdderlow bitHalfAdderplus carrya 1b 1c 1ab 0c1 1c2 0sum 1carry 1

What it does

CHIP FullAdder {
  IN a, b, c;
  OUT sum, carry;
  PARTS:
  HalfAdder(a=a, b=b, sum=ab, carry=c1);
  HalfAdder(a=ab, b=c, sum=sum, carry=c2);
  Or(a=c1, b=c2, out=carry);
}

Two half adders and an Or: the first adds a and b, the second adds c in.

Add16 16-bit adder

out = a + b (16 bits, overflow dropped)

Demo

a00000000111111110x00FF
b00000000000000010x0001
out00000001000000000x0100

Structure

a[0]=1 b[0]=1HAout[0]=0c1=1a[1]=1 b[1]=0 c1=1FAout[1]=0c2=1a[2]=1 b[2]=0 c2=1FAout[2]=0c3=1a[3]=1 b[3]=0 c3=1FAout[3]=0c4=1a[4]=1 b[4]=0 c4=1FAout[4]=0c5=1a[5]=1 b[5]=0 c5=1FAout[5]=0c6=1a[6]=1 b[6]=0 c6=1FAout[6]=0c7=1a[7]=1 b[7]=0 c7=1FAout[7]=0c8=1a[8]=0 b[8]=0 c8=1FAout[8]=1c9=0a[9]=0 b[9]=0 c9=0FAout[9]=0c10=0a[10]=0 b[10]=0 c10=0FAout[10]=0c11=0a[11]=0 b[11]=0 c11=0FAout[11]=0c12=0a[12]=0 b[12]=0 c12=0FAout[12]=0c13=0a[13]=0 b[13]=0 c13=0FAout[13]=0c14=0a[14]=0 b[14]=0 c14=0FAout[14]=0c15=0a[15]=0 b[15]=0 c15=0FAout[15]=0c16=0

What it does

CHIP Add16 {
  IN a[16], b[16];
  OUT out[16];
  PARTS:
  HalfAdder(a=a[0], b=b[0], sum=out[0], carry=carry1);
  FullAdder(a=a[1], b=b[1], c=carry1, sum=out[1], carry=carry2);
  FullAdder(a=a[2], b=b[2], c=carry2, sum=out[2], carry=carry3);
  FullAdder(a=a[3], b=b[3], c=carry3, sum=out[3], carry=carry4);
  FullAdder(a=a[4], b=b[4], c=carry4, sum=out[4], carry=carry5);
  FullAdder(a=a[5], b=b[5], c=carry5, sum=out[5], carry=carry6);
  FullAdder(a=a[6], b=b[6], c=carry6, sum=out[6], carry=carry7);
  FullAdder(a=a[7], b=b[7], c=carry7, sum=out[7], carry=carry8);
  FullAdder(a=a[8], b=b[8], c=carry8, sum=out[8], carry=carry9);
  FullAdder(a=a[9], b=b[9], c=carry9, sum=out[9], carry=carry10);
  FullAdder(a=a[10], b=b[10], c=carry10, sum=out[10], carry=carry11);
  FullAdder(a=a[11], b=b[11], c=carry11, sum=out[11], carry=carry12);
  FullAdder(a=a[12], b=b[12], c=carry12, sum=out[12], carry=carry13);
  FullAdder(a=a[13], b=b[13], c=carry13, sum=out[13], carry=carry14);
  FullAdder(a=a[14], b=b[14], c=carry14, sum=out[14], carry=carry15);
  FullAdder(a=a[15], b=b[15], c=carry15, sum=out[15], carry=carry16);
}

Sixteen FullAdder chips chained, each passing its carry out into the carry in of the next.

Inc16 incrementer

out = in + 1

Demo

in00000000111111110x00FF
out00000001000000000x0100

Structure

Add16b = 1in[16]out[16]

What it does

CHIP Inc16 {
  IN in[16];
  OUT out[16];
  PARTS:
  // or as one line: Add16(a=in, b[0]=true, b[1..15]=false, out=out);
  Add16(a=in,
        b[0]=true,
        b[1]=false,
        b[2]=false,
        b[3]=false,
        b[4]=false,
        b[5]=false,
        b[6]=false,
        b[7]=false,
        b[8]=false,
        b[9]=false,
        b[10]=false,
        b[11]=false,
        b[12]=false,
        b[13]=false,
        b[14]=false,
        b[15]=false,
        out=out);
}

Just Add16 with b = 1.

Coda: why an adder can subtract

The clock-face idea: imagine a 12-hour dial reading 3 o’clock, and you want to go back two hours to 1. There are two ways:
① turn back two hours (borrow subtraction: 3 − 2 = 1);
② turn forward ten hours (modular addition: 3 + 10 = 13 ≡ 1 mod 12).
Hardware hates borrowing and loves overflow. Set the dial to 65536 (the top-bit carry is dropped automatically) and subtracting X becomes adding 65536 − X.

In binary, 65536 − X = (65535 − X) + 1. Since 65535 is all ones (0xFFFF), subtracting X from it is exactly inverting every bit (~X).

Negation = invert every bit, then add 1. That is two’s complement — it removes the need for a whole subtractor and lets the same Add16 handle both addition and subtraction.

In the ALU, subtraction needs only three control bits: nx=1 (invert x), f=1 (add), no=1 (invert the output) — the ALU page has the full derivation.