Sequential Logic
D flip-flops, registers, counters — the memory elements of digital logic.
From Combinational to Sequential
Combinational logic has no memory. To store state, we use memory elements synchronized on a clock.
Synchronous circuit: Inputs → Combinational Logic → Registers → Outputs (with current state feedback)
Image à ajouter
This model is the foundation of every synchronous digital circuit.
The D Flip-Flop
The D flip-flop is the fundamental memory element.
Behavior
| Event | Action |
|---|---|
| Rising edge of CLK | Q ← D |
| Between edges | Q retains its value |
| RST active (synchronous) | Q ← 0 on next edge |
-- Simple D flip-flop
process(i_clk)
begin
if rising_edge(i_clk) then
r_q <= i_d;
end if;
end process;D Flip-Flop with Synchronous Reset and Enable
process(i_clk)
begin
if rising_edge(i_clk) then
if i_rst = '1' then
r_q <= '0';
elsif i_en = '1' then
r_q <= i_d;
end if;
end if;
end process;Registers
A register is a group of N D flip-flops sharing the same clock — stores N bits simultaneously.
Simple N-bit Register
entity register_8bit is
port (
i_clk : in std_logic;
i_rst : in std_logic;
i_en : in std_logic;
i_data : in std_logic_vector(7 downto 0);
o_data : out std_logic_vector(7 downto 0)
);
end entity register_8bit;
architecture rtl of register_8bit is
signal r_data : std_logic_vector(7 downto 0);
begin
process(i_clk)
begin
if rising_edge(i_clk) then
if i_rst = '1' then
r_data <= (others => '0');
elsif i_en = '1' then
r_data <= i_data;
end if;
end if;
end process;
o_data <= r_data;
end architecture register_8bit;Shift Register
architecture rtl of shift_reg is
signal r_shift : std_logic_vector(7 downto 0);
begin
process(i_clk)
begin
if rising_edge(i_clk) then
if i_rst = '1' then
r_shift <= (others => '0');
else
-- Right shift, serial input on MSB
r_shift <= i_serial & r_shift(7 downto 1);
end if;
end if;
end process;
o_parallel <= r_shift; -- parallel output
o_serial <= r_shift(0); -- serial output
end architecture rtl;Usage: serial-to-parallel conversion (UART, SPI), N-cycle delay.
Counters
Simple Binary Counter
architecture rtl of counter is
signal r_count : unsigned(7 downto 0);
begin
process(i_clk)
begin
if rising_edge(i_clk) then
if i_rst = '1' then
r_count <= (others => '0');
else
r_count <= r_count + 1; -- naturally overflows: 255 → 0
end if;
end if;
end process;
o_count <= std_logic_vector(r_count);
end architecture rtl;Counter with Limit (Modulo N)
architecture rtl of counter_mod is
constant c_MAX : integer := 99; -- counts 0 to 99
signal r_count : integer range 0 to c_MAX;
begin
process(i_clk)
begin
if rising_edge(i_clk) then
if i_rst = '1' then
r_count <= 0;
elsif r_count = c_MAX then
r_count <= 0;
o_tick <= '1'; -- overflow pulse
else
r_count <= r_count + 1;
o_tick <= '0';
end if;
end if;
end process;
end architecture rtl;Up/Down Counter
process(i_clk)
begin
if rising_edge(i_clk) then
if i_rst = '1' then
r_count <= (others => '0');
elsif i_up = '1' then
r_count <= r_count + 1;
elsif i_down = '1' then
r_count <= r_count - 1;
end if;
end if;
end process;Clock Domains and Synchronization
When data crosses different clock domains (CDC — Clock Domain Crossing), metastability issues can occur.
The standard solution: the double-flop synchronizer
-- 2-stage synchronizer for a 1-bit signal
signal r_sync1, r_sync2 : std_logic;
process(i_clk_dst)
begin
if rising_edge(i_clk_dst) then
r_sync1 <= i_signal_src; -- first register: may be metastable
r_sync2 <= r_sync1; -- second register: stable with high probability
end if;
end process;
o_signal_dst <= r_sync2;The first register may enter a metastable state, but the second cycle gives it time to resolve.
Rule: never directly use a signal from another clock domain without a synchronizer.