Adders
Addition is the first place gate-level thinking meets arithmetic. A full adder adds three bits (a, b, carry-in) into a sum and carry-out:
sum = a ^ b ^ cin
cout = (a & b) | (cin & (a ^ b))
Chain four of them, carry-out to carry-in, and you have a 4-bit
ripple-carry adder — the design below builds it with a generate
loop, worth reading as your first taste of structural repetition in
Verilog.
The design also computes the same sum a second way: assign {c5, s5} =
a + b + cin;. In the waveform the two results are always identical —
that's the point. Synthesis tools map + onto the FPGA's dedicated fast
carry chains, which are quicker than anything you can describe by hand
with gates. Write +, not adder structures. The value of knowing the
full adder isn't to type it; it's to understand what the tools build, why
a wide adder's delay grows with its width, and what a "carry chain" is
when the timing report mentions one.
One habit to take away: the sum of two N-bit numbers needs N+1 bits.
The concatenation trick {cout, sum} = a + b captures the carry cleanly
and appears everywhere real arithmetic is written.
Experiment: make an add/subtract unit — b ^ {4{sub}} plus sub as
carry-in is two's-complement subtraction for one extra XOR per bit. (This
exact trick reappears in the ALU capstone.)