sequential component
Four-Digit Display Scanner
A four-digit seven-segment display needs 28 segment wires if every digit is driven directly. The scanner drives one shared seven-segment bus and four digit enables instead: eleven wires. Only one digit is lit at any instant, and the scan walks fast enough that the eye reads all four as steady.
A two-bit counter picks the active digit. Its value selects one nibble of value through a mux. A sixteen-entry constant table decodes that nibble to active-high segments, seg(0) for segment a through seg(6) for segment g. The same counter drives the one-hot digit_sel enable. This reference advances one digit per clock cycle so a whole rotation fits in a short waveform. A real board divides the clock first, so each digit holds for about a millisecond.
In the waveform: with value at 0x1A2F, seg steps through the codes for F, 2, A, and 1 while digit_sel walks 0001 to 1000.
In the netlist: there is exactly one decode table, shared by all four digits. Four direct-driven digits would synthesize four copies; the scanner trades them for one mux and one counter.
The course builds the decoder and the mux from first principles in Combinational Building Blocks.
-- Four-digit display scanner: one shared seven-segment bus, one hex decode
-- table, a scan counter walking one-hot digit enables across the value
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity four_digit_scanner is
port (
clk : in std_logic;
rst : in std_logic;
value : in std_logic_vector(15 downto 0);
seg : out std_logic_vector(6 downto 0);
digit_sel : out std_logic_vector(3 downto 0)
);
end entity four_digit_scanner;
architecture rtl of four_digit_scanner is
type seg_table_t is array (0 to 15) of std_logic_vector(6 downto 0);
-- Active-high segments, seg(0) = a .. seg(6) = g
constant SEG_TABLE : seg_table_t := (
"0111111", "0000110", "1011011", "1001111",
"1100110", "1101101", "1111101", "0000111",
"1111111", "1101111", "1110111", "1111100",
"0111001", "1011110", "1111001", "1110001"
);
signal scan_r : unsigned(1 downto 0) := (others => '0');
signal nibble : std_logic_vector(3 downto 0) := (others => '0');
begin
-- Scan counter: one digit per clock cycle (a real board divides this down)
scan_p : process(clk)
begin
if rising_edge(clk) then
if rst = '1' then
scan_r <= (others => '0');
else
scan_r <= scan_r + 1; -- 3 wraps back to digit 0
end if;
end if;
end process scan_p;
-- Digit mux: the scan position picks one nibble of the value
with scan_r select
nibble <= value(3 downto 0) when "00",
value(7 downto 4) when "01",
value(11 downto 8) when "10",
value(15 downto 12) when others;
seg <= SEG_TABLE(to_integer(unsigned(nibble)));
-- One-hot enable for the digit currently being driven
with scan_r select
digit_sel <= "0001" when "00",
"0010" when "01",
"0100" when "10",
"1000" when others;
end architecture rtl;