Prev Problem
Next Problem

72. 7-Segment Display Decoder

module sevenseg_hex (
    input  [3:0] hex,
    output reg [6:0] seg   // {a,b,c,d,e,f,g}, ACTIVE-HIGH
);
    always @* begin
        case (hex)
            4'h0: seg = 7'b1111110; // a b c d e f
            4'h1: seg = 7'b0110000; // b c
            4'h2: seg = 7'b1101101; // a b   d e   g
            4'h3: seg = 7'b1111001; // a b c d     g
            4'h4: seg = 7'b0110011; //   b c     f g
            4'h5: seg = 7'b1011011; // a   c d   f g
            4'h6: seg = 7'b1011111; // a   c d e f g
            4'h7: seg = 7'b1110000; // a b c
            4'h8: seg = 7'b1111111; // a b c d e f g
            4'h9: seg = 7'b1111011; // a b c d   f g
            4'hA: seg = 7'b1110111; // a b c   e f g
            4'hB: seg = 7'b0011111; //     c d e f g  (looks like 'b')
            4'hC: seg = 7'b1001110; // a       d e f
            4'hD: seg = 7'b0111101; //   b c d e   g  (looks like 'd')
            4'hE: seg = 7'b1001111; // a       d e f g
            4'hF: seg = 7'b1000111; // a         e f g
            default: seg = 7'b0000000; // blank
        endcase
    end
endmodule

Alternate solution using look-up table

// Bit order: seg[6:0] = {a,b,c,d,e,f,g}, ACTIVE-HIGH
module sevenseg_hex (
    input  [3:0] hex,
    output [6:0] seg
);
    // Pack 16 entries × 7 bits = 112-bit constant.
    // Concatenation is MSB..LSB, so put 0xF first and 0x0 last;
    // then select with seg = LUT[hex*7 +: 7] (entry 0 lives at bits [6:0]).
    localparam [7*16-1:0] SEG_LUT = {
        7'b1000111, // F
        7'b1001111, // E
        7'b0111101, // D (looks like 'd')
        7'b1001110, // C
        7'b0011111, // B (lowercase 'b' on 7-seg)
        7'b1110111, // A
        7'b1111011, // 9
        7'b1111111, // 8
        7'b1110000, // 7
        7'b1011111, // 6
        7'b1011011, // 5
        7'b0110011, // 4
        7'b1111001, // 3
        7'b1101101, // 2
        7'b0110000, // 1
        7'b1111110  // 0
    };

    // Variable indexed part-select:
    // pick 7 bits starting at offset (hex*7).
    wire [6:0] seg_lut = SEG_LUT[hex*7 +: 7];

    assign seg = seg_lut;  // active-high drive
endmodule

💡Remember

  • Bit order matters. We use {a,b,c,d,e,f,g}. Some boards wire {g,f,e,d,c,b,a}—adjust mapping if needed.
  • Indexed part-select SEG_LUT[hex*7 +: 7] selects 7 bits starting at bit hex*7. Works in Icarus with -g2005. No SystemVerilog needed.
  • Concatenation order matters In a wide localparam like localparam [7*16-1:0] SEG_LUT = {F, E, D, …, 1, 0}; the leftmost item lands at the MSBs. Put 0 last so entry 0 sits at bits [6:0], making hex*7 +: 7 map naturally (entry i → bits [7*i +: 7]).
  • Combinational, synthesizable ROM A constant localparam + variable slice synthesizes to a tiny ROM/mux network. No latches, no clocks.
  • Width-safe & readable Declare the LUT as [7*16-1:0] so the width matches exactly. Using expressions (7*16) is legal and self-documenting.
  • Unknowns propagate (good for TBs) If hex carries x/z, the index becomes x and seg turns X. That helps catch uninitialized or illegal inputs during simulation.