FPGA_ROADMAP · CNN → Virtex-7
← all phases
PHASE 01 / 12 · ~2–3 days

Number systems & binary

Every CNN weight and pixel value eventually becomes a pattern of on/off signals.

Here's the core idea to internalize before anything else: hardware physically only understands two states — voltage present (1) or voltage absent (0). There's no native concept of "10" or "-5" or "3.14" inside a wire. Every number your CNN uses — every weight, every pixel value, every intermediate sum — eventually has to be squeezed down into a pattern of on/off signals. Binary, hex, and two's complement aren't separate "topics" so much as different human-readable lenses for looking at the exact same on/off pattern.

Binary and hex are just notation, not new math. Binary is base-2 (only digits 0 and 1); each position is a power of 2, the same way each position in decimal is a power of 10. So 1011 in binary = (1×8)+(0×4)+(1×2)+(1×1) = 11 in decimal. Hex (base-16) exists purely as a shorthand for binary, because writing out 32 or 64 bits of 1s and 0s by hand is miserable. Each hex digit represents exactly 4 binary bits (since 2⁴ = 16) — you'll see hex constantly in Verilog code and in Vivado's memory dumps.

Two's complement is the part that actually bites people — let's slow down here. Hardware doesn't have a "minus sign" wire. So how do you represent -5 using only 1s and 0s? The trick: instead of a separate sign symbol, you reserve the pattern space itself to represent negative numbers. In an 8-bit two's complement system, 00000000 through 01111111 represent 0 through 127 (positive), and 10000000 through 11111111 represent -128 through -1.

To get the two's complement representation of a negative number, you flip every bit of the positive version and add 1. So +5 is 00000101; flip all bits → 11111010; add 1 → 11111011, which is -5.

Why does anyone bother with this weird scheme? Because it makes subtraction trivially just addition. To compute A − B in hardware, you don't need a separate subtractor circuit — you just compute A + (two's complement of B) using the same adder circuit you already built for addition. One circuit does both jobs; that's a real hardware simplification, not a mathematical curiosity.

Why this directly matters for your CNN deployment: your CNN weights are signed numbers — some positive, some negative. When you quantize a trained float weight down to INT8 for FPGA storage (Phase 6), that INT8 value is stored in two's complement. If anywhere in your Verilog code, or your understanding, you assume "the sign bit is separate" or treat it like sign-magnitude notation, negative weights will silently corrupt your math — not crash, not error out, just quietly produce incorrect convolution outputs that look plausible. This exact bug class is one of the most common "why is my FPGA output different from my Python reference" issues in CNN-on-FPGA work.

A good self-test: take -12, convert it to 8-bit two's complement by hand (flip bits of +12, add 1), then convert it back to decimal to confirm you get -12 again. Do this a few times with different numbers until it's automatic — this fluency pays for itself the first time you're staring at a hex dump of your CNN weights inside Vivado, trying to figure out why layer 2's output is off.

+5 → 00000101 00000101 flip every bit flipped → 11111010 11111010 then add 1 -5 → 11111011 11111011
FIG 01 — NUMBER SYSTEMS & BINARY
Self-test: convert -12 to 8-bit two's complement
+12  =  00001100
flip  →  11110011
+1    →  11110100   = -12 ✓
Why this matters for your CNN deployment

Your CNN weights are signed. When you quantize a trained float weight down to INT8, that value is stored in two's complement. If your Verilog treats it like a separate sign bit instead of true two's complement, negative weights will silently compute wrong values — no crash, no error, just quietly incorrect convolution outputs that still look plausible.

← PreviousPhase 00 — What even is an FPGA?