Binary to Excess-3 Code Converter in Verilog with Code

A binary (BCD) to Excess-3 converter adds 3 to every decimal digit, so the valid digits 0 through 9 map to the codes 0011 through 1100. Excess-3 (also written XS-3) is a self-complementing code that was widely used in early decimal arithmetic hardware because taking the 9’s complement of a digit is as simple as inverting its bits. This page gives clean, simulator-verified binary to excess 3 verilog code for both the forward converter and the reverse decoder.

Both modules below are purely combinational and are driven by self-checking testbenches that compare every output against a golden reference computed in the bench, so a real bug would print a FAIL line instead of the PASS lines you see in the logs.

The clearest implementation: Excess-3 is simply the 4-bit BCD value plus 3, so a single assign expresses the whole converter. The testbench sweeps all ten valid digits (0-9), checks each output equals digit + 3, then prints the don’t-care outputs for the invalid inputs 10-15.

module bcd_to_excess3 (
    input  [3:0] bcd,
    output [3:0] xs3
);
    assign xs3 = bcd + 4'd3;
endmodule

module tb;
    reg  [3:0] bcd;
    wire [3:0] xs3;
    integer d;
    integer errors;

    bcd_to_excess3 dut (.bcd(bcd), .xs3(xs3));

    initial begin
        errors = 0;
        for (d = 0; d <= 9; d = d + 1) begin
            bcd = d[3:0];
            #1;
            if (xs3 !== (d[3:0] + 4'd3)) begin
                $display("FAIL: digit=%0d xs3=%b expected=%b", d, xs3, d[3:0]+4'd3);
                errors = errors + 1;
            end else begin
                $display("PASS: BCD %0d (%b) -> Excess-3 %b (decimal %0d)", d, bcd, xs3, xs3);
            end
        end
        // Show don't-care region 10-15 (still just +3, wraps past 4 bits)
        for (d = 10; d <= 15; d = d + 1) begin
            bcd = d[3:0];
            #1;
            $display("NOTE: invalid BCD input %0d (%b) -> output %b (unused / don't-care)", d, bcd, xs3);
        end
        if (errors == 0)
            $display("ALL TESTS PASSED");
        else
            $display("TESTS FAILED: %0d", errors);
        $finish;
    end
endmodule
PASS: BCD 0 (0000) -> Excess-3 0011 (decimal 3)
PASS: BCD 1 (0001) -> Excess-3 0100 (decimal 4)
PASS: BCD 2 (0010) -> Excess-3 0101 (decimal 5)
PASS: BCD 3 (0011) -> Excess-3 0110 (decimal 6)
PASS: BCD 4 (0100) -> Excess-3 0111 (decimal 7)
PASS: BCD 5 (0101) -> Excess-3 1000 (decimal 8)
PASS: BCD 6 (0110) -> Excess-3 1001 (decimal 9)
PASS: BCD 7 (0111) -> Excess-3 1010 (decimal 10)
PASS: BCD 8 (1000) -> Excess-3 1011 (decimal 11)
PASS: BCD 9 (1001) -> Excess-3 1100 (decimal 12)
NOTE: invalid BCD input 10 (1010) -> output 1101 (unused / don't-care)
NOTE: invalid BCD input 11 (1011) -> output 1110 (unused / don't-care)
NOTE: invalid BCD input 12 (1100) -> output 1111 (unused / don't-care)
NOTE: invalid BCD input 13 (1101) -> output 0000 (unused / don't-care)
NOTE: invalid BCD input 14 (1110) -> output 0001 (unused / don't-care)
NOTE: invalid BCD input 15 (1111) -> output 0010 (unused / don't-care)
ALL TESTS PASSED

The log shows all ten valid digits converting correctly (0→0011 up to 9→1100), each line a PASS because the output matched the golden digit + 3 computed in the bench. The six NOTE lines expose the don't-care behaviour for inputs 10-15, which a real decimal system never presents. The closing ALL TESTS PASSED confirms zero mismatches.

The reverse converter subtracts 3 to recover the BCD digit. This variant also demonstrates the defining property of Excess-3: it is self-complementing, meaning the bitwise complement of Excess-3(d) equals Excess-3(9−d). The bench checks both facts over all ten digits.

module excess3_to_bcd (
    input  [3:0] xs3,
    output [3:0] bcd
);
    assign bcd = xs3 - 4'd3;
endmodule

module tb;
    reg  [3:0] xs3;
    wire [3:0] bcd;
    integer d;
    integer errors;
    reg [3:0] xs3_d;      // Excess-3 of d
    reg [3:0] xs3_9md;    // Excess-3 of (9-d)

    excess3_to_bcd dut (.xs3(xs3), .bcd(bcd));

    initial begin
        errors = 0;
        // Reverse: valid Excess-3 codes are d+3 for d=0..9, i.e. 3..12
        for (d = 0; d <= 9; d = d + 1) begin
            xs3 = d[3:0] + 4'd3;
            #1;
            if (bcd !== d[3:0]) begin
                $display("FAIL: xs3=%b decoded=%b expected=%b", xs3, bcd, d[3:0]);
                errors = errors + 1;
            end else begin
                $display("PASS: Excess-3 %b -> BCD %0d (%b)", xs3, bcd, bcd);
            end
        end
        // Self-complementing property: ~Excess3(d) == Excess3(9-d)
        for (d = 0; d <= 9; d = d + 1) begin
            xs3_d   = d[3:0] + 4'd3;
            xs3_9md = (9 - d) + 4'd3;
            if ((~xs3_d) !== xs3_9md) begin
                $display("FAIL self-comp: d=%0d ~%b=%b but Excess3(9-d)=%b",
                         d, xs3_d, ~xs3_d, xs3_9md);
                errors = errors + 1;
            end else begin
                $display("PASS self-comp: d=%0d  ~Excess3(%0d)=%b = Excess3(%0d)=%b",
                         d, d, ~xs3_d, 9-d, xs3_9md);
            end
        end
        if (errors == 0)
            $display("ALL TESTS PASSED");
        else
            $display("TESTS FAILED: %0d", errors);
        $finish;
    end
endmodule
PASS: Excess-3 0011 -> BCD 0 (0000)
PASS: Excess-3 0100 -> BCD 1 (0001)
PASS: Excess-3 0101 -> BCD 2 (0010)
PASS: Excess-3 0110 -> BCD 3 (0011)
PASS: Excess-3 0111 -> BCD 4 (0100)
PASS: Excess-3 1000 -> BCD 5 (0101)
PASS: Excess-3 1001 -> BCD 6 (0110)
PASS: Excess-3 1010 -> BCD 7 (0111)
PASS: Excess-3 1011 -> BCD 8 (1000)
PASS: Excess-3 1100 -> BCD 9 (1001)
PASS self-comp: d=0  ~Excess3(0)=1100 = Excess3(9)=1100
PASS self-comp: d=1  ~Excess3(1)=1011 = Excess3(8)=1011
PASS self-comp: d=2  ~Excess3(2)=1010 = Excess3(7)=1010
PASS self-comp: d=3  ~Excess3(3)=1001 = Excess3(6)=1001
PASS self-comp: d=4  ~Excess3(4)=1000 = Excess3(5)=1000
PASS self-comp: d=5  ~Excess3(5)=0111 = Excess3(4)=0111
PASS self-comp: d=6  ~Excess3(6)=0110 = Excess3(3)=0110
PASS self-comp: d=7  ~Excess3(7)=0101 = Excess3(2)=0101
PASS self-comp: d=8  ~Excess3(8)=0100 = Excess3(1)=0100
PASS self-comp: d=9  ~Excess3(9)=0011 = Excess3(0)=0011
ALL TESTS PASSED

The first ten PASS lines prove the decoder recovers the original digit for every valid Excess-3 code (0011 through 1100). The next ten lines verify the self-complementing identity: inverting the four bits of Excess-3(d) yields exactly Excess-3(9−d) — for example ~Excess3(0)=1100=Excess3(9). Both checks compare against values recomputed in the bench, and ALL TESTS PASSED means neither check ever failed.

What Excess-3 is and why it is self-complementing

Excess-3 represents a decimal digit by its 4-bit binary value biased, or "excessed", by 3. Digit 0 becomes 0011, digit 5 becomes 1000, and digit 9 becomes 1100. Because the bias is 3, the ten valid code words occupy the middle of the 4-bit range (3 to 12) rather than the bottom (0 to 9) as in straight BCD.

The key property is that Excess-3 is self-complementing: the 1's complement (bitwise NOT) of the code for digit d is the code for digit 9−d, which is the 9's complement of d. This is extremely useful for decimal subtraction, because 9's-complement arithmetic lets you subtract by adding a complement, and here the complement is free — it is just an inverter on each bit. Codes like plain BCD and 8421 do not have this property.

The +3 derivation

Why exactly 3? For a 4-bit code to be self-complementing, the code words of d and 9−d must be bitwise complements, so each pair must sum to 1111 (decimal 15). If the code for d is d + k for some fixed offset k, then:

code(d) + code(9-d) = (d + k) + ((9 - d) + k) = 9 + 2k

Setting this equal to 15 gives 2k = 6, so k = 3. That is the unique offset that makes a 4-bit weighted-plus-bias code self-complementing, which is precisely why the code is called Excess-3.

Truth table and K-map note

The converter maps each valid BCD input to its Excess-3 output:

  • 0000 → 0011
  • 0001 → 0100
  • 0010 → 0101
  • 0011 → 0110
  • 0100 → 0111
  • 0101 → 1000
  • 0110 → 1001
  • 0111 → 1010
  • 1000 → 1011
  • 1001 → 1100

In a classic digital-logic course you would derive four output equations, one per Excess-3 bit, and simplify each with a Karnaugh map, treating inputs 1010 through 1111 as don't-cares to get minimal gates. The RTL above lets the synthesis tool do that minimization for you: writing bcd + 3 yields the same optimized logic a hand K-map would produce, which is why a behavioural +3 is the idiomatic way to express this in Verilog.

Difference from straight BCD

Straight BCD (8421) encodes digit d as its plain binary value, so 0 is 0000 and 9 is 1001. Excess-3 shifts every code up by 3. The practical differences:

  • No all-zero code: digit 0 is 0011, not 0000. This historically helped distinguish a genuine zero digit from an inactive or blank line.
  • Self-complementing: Excess-3 supports easy 9's-complement decimal subtraction; 8421 BCD does not.
  • Carry behaviour: adding two Excess-3 digits introduces a bias of 6 in the sum, so correction (adding or subtracting 3) is needed, which is a different fix-up rule than the add-6 correction used for BCD addition.

Synthesis notes and common mistakes

Both modules synthesize to a small block of combinational logic — a handful of XOR/AND gates per output bit — with no clock or storage. A few things to watch:

  • Widths: keep operands 4 bits wide. The + 4'd3 literal is sized deliberately so the result stays in 4 bits and naturally wraps for the don't-care inputs.
  • Don't-cares, not errors: inputs 1010-1111 are not valid BCD. The hardware still produces some output for them (shown in the Example 1 log), but a correct system must never drive those values. If your design can, add an explicit validity check.
  • Reverse-converter range: the decoder assumes a valid Excess-3 word (0011-1100). Feeding it 0000-0010 or 1101-1111 produces out-of-range results, so gate the input upstream if needed.
  • Blocking vs non-blocking: because this is combinational, a continuous assign (or always @(*) with blocking assignments) is correct; do not use always @(posedge clk) unless you intend to register the result.

FAQ

Is Excess-3 the same as Gray code? No. Gray code changes only one bit between adjacent values; Excess-3 is a biased weighted code and is self-complementing, which Gray code is not.

Can I build this structurally with gates? Yes — derive the four per-bit Boolean equations from the truth table and instantiate xor/and/or primitives. The behavioural +3 here is equivalent after synthesis and far easier to read.

Have questions about this topic?
Share your question in comments or talk to our mentor team for batch guidance.
▶ Try it in the ChipXpert Lab

Open this design in the free in-browser simulator — edit, compile and see the waveform/log instantly.

Run it in the Lab

Learn Verilog with mentors, labs and placement support

This free series is maintained by the ChipXpert training team in Hyderabad & Bengaluru. Go deeper with instructor-led courses on real EDA tools.

Explore VLSI Courses
Next batch starts 18th November 2026
Start your VLSI career with ChipXpert

Live online and classroom batches in Hyderabad & Bengaluru. Fill in your details and a counsellor will call you back.

  • Real EDA tools in your browser: industry-standard EDAReal EDA tools in your browser
  • Recorded sessions on the elearn portalRecorded sessions
  • Placement assistance: resume, mock interviewsPlacement assistance
  • Merit scholarship up to 60% · EMI optionsScholarship up to 60%
Hi! Ask me about courses, fees, batches or discounts. ×
BENGALURU
HYDERABAD