ELEC 4706 -- Digital SERDES with Clock and Data Recovery

Author: Colin Byrne (101224212)

Institution: Carleton University

Date: December 4, 2025

1. Introduction

This laboratory focused on the design, implementation, and hardware verification of a complete SERDES system incorporating a pseudo-random bit sequence (PRBS) generator, frame-recovery logic, a clock-and-data-recovery (CDR) loop, and a real-time error-counting subsystem. The objective was to build a functional digital CDR capable of extracting timing information from an incoming data stream and reproducing a correctly aligned recovered clock and recovered data signal.

The system was first validated through functional simulation to confirm correctness of PRBS alignment, phase detection, and loop-filter behavior. The design was then synthesized and deployed on the DE1-SoC board, where oscilloscope measurements were used to assess timing, lock behavior, and the integrity of the recovered bitstream.

2. Process

System Integration and Top-Level Design

The first step involved creating the SERDES_TOP module, which interfaced the internal CDR logic with the DE1-SoC I/O. GPIO pins were configured as bidirectional signals to allow an external signal generator to drive the transmit clock while routing the input data, recovered data, and recovered clock to an oscilloscope. Reset signals were mapped to on-board pushbuttons, and the seven-segment displays were used to present the 16-bit error counter output.

The SERDES module integrated the PRBS transmitter and CDR, frame recovery logic, receive-side PRBS generator, and the error counter. Retiming flip-flops were used to ensure alignment between recovered data and reference PRBS bits before comparison.

PRBS Generation and Frame Recovery

The PRBS generator implemented the polynomial x^10 + x^7 + 1 and reset to an initial state of all ones. Since this PRBS sequence produces ten consecutive logic ones once every 1023 bits, the frame recovery block used a 10-bit shift register followed by an and_reduce() operation to detect alignment.

Upon detection, the receive-side PRBS generator was reset, ensuring alignment between transmitted and recovered bitstreams. Additional retiming stages were included to correct minor timing offsets.

CDR Implementation

The CDR architecture consisted of an 8-phase phase generator, a phase rotator controlled by increment and decrement signals, a bang-bang phase detector, a digital loop filter, and a clock divider. Together, these blocks generated a recovered sampling clock and synchronized recovered data.

Error Counter and Display

Recovered data and the receive-side PRBS reference were XORed and passed through a retiming flip-flop before being counted. A 16-bit error counter accumulated bit mismatches, and the count was displayed in hexadecimal on the seven-segment displays.

Functional Simulation

Functional simulation was performed using a PRBS clock of 12.5 MHz and a reference clock of 100 MHz. These values preserved timing relationships while reducing simulation time. The simulation confirmed successful frame detection, PRBS alignment, and zero error accumulation after lock.

On-Board Hardware Verification

After simulation, the design was synthesized and programmed onto the DE1-SoC board. A 6.25 MHz clock was applied to the transmitter, while the on-board 50 MHz clock drove the CDR. Oscilloscope measurements were used to observe input data, recovered data, recovered clock, and eye diagrams.

3. Results

Simulation Results

Simulated waveform of the complete CDR system
Figure 1: Simulated waveform of the complete CDR system

Hardware Results

Oscilloscope capture of the implemented CDR
Figure 2: Oscilloscope capture of the implemented CDR
Recovered eye diagram on hardware
Figure 3: Recovered eye diagram on hardware

4. Conclusion

The implemented SERDES and CDR system successfully met all design objectives. Functional simulation confirmed correct PRBS alignment, stable CDR operation, and error-free data recovery. Hardware verification further demonstrated reliable clock recovery, stable phase alignment, and accurate data sampling. Overall, the design represents a complete and functional digital CDR implemented on the DE1-SoC platform.

5. Appendix: VHDL Source Code

SERDES TOP


-- SERDES_TOP.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity SERDES_TOP is
	port(
	KEY : in std_logic_vector(1 downto 0);
	CLOCK_50 : in std_logic;
	GPIO_O : inout std_logic_vector(3 downto 0);
   -- 7-segment displays
   HEX3 : out std_logic_vector(6 downto 0);
   HEX2 : out std_logic_vector(6 downto 0);
   HEX1 : out std_logic_vector(6 downto 0); 
   HEX0 : out std_logic_vector(6 downto 0)
	);
end SERDES_TOP;

architecture Structural of SERDES_TOP is
	--SERDES
	component SERDES is
		Port(
			tx_clk : in STD_LOGIC;
			ref_clk : in STD_LOGIC;
			prbs_rst : in STD_LOGIC;
			cdr_rst : in STD_LOGIC;
			Din : out STD_LOGIC;
			Dout : out STD_LOGIC;
			rec_clk : out STD_LOGIC;
			HEX3 : out std_logic_vector(6 downto 0);
			HEX2 : out std_logic_vector(6 downto 0);
			HEX1 : out std_logic_vector(6 downto 0);
			HEX0 : out std_logic_vector(6 downto 0)
		);
	end component;

	begin
	
	U_SERDES : SERDES
		Port map(
			tx_clk => GPIO_O(0),
			ref_clk => CLOCK_50,
			prbs_rst => KEY(1),
			cdr_rst => KEY(0),
			Din => GPIO_O(1),
			Dout => GPIO_O(2),
			rec_clk => GPIO_O(3),
			HEX3 => HEX3,
			HEX2 => HEX2,
			HEX1 => HEX1,
			HEX0 => HEX0
		);
		
	end Structural;

  

SERDES


-- SERDES.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity SERDES is
	Port(
	tx_clk : in STD_LOGIC;
	ref_clk : in STD_LOGIC;
	prbs_rst : in STD_LOGIC;
	cdr_rst : in STD_LOGIC;
	rx_prbs : out std_LOGIC;
	fr_out : out std_LOGIC;
	rx_rst: out std_LOGIC;
	Din : out STD_LOGIC;
	Dout : out STD_LOGIC;
	rec_clk : out STD_LOGIC;
	error_cnt : out STD_LOGIC_VECTOR(15 downto 0);
	HEX3 : out std_logic_vector(6 downto 0);
	HEX2 : out std_logic_vector(6 downto 0);
	HEX1 : out std_logic_vector(6 downto 0);
	HEX0 : out std_logic_vector(6 downto 0)
	);
end SERDES;

architecture Structural of SERDES is
	-- Internal Singals
	signal Dout_signal, rec_clk_sig : std_LOGIC;
	signal Rx_rst_sig : std_LOGIC;
	signal FR_xor_in, RX_xor_in, xor_out, xor_out_good : std_logic;
	signal FR_Q, RX_out : std_LOGIC;
	--Components
	component Top_Test is
		port(
		tx_clk : in STD_LOGIC;
		ref_clk : in STD_LOGIC;
		prbs_rst : in STD_LOGIC;
		cdr_rst : in STD_LOGIC;
		Dout : out STD_LOGIC;
		rec_clk : out STD_LOGIC;
		Din : out STD_LOGIC
	);
	end component;

	component PRBS_Generator is
		port (
        clk     : in  std_logic;
        reset   : in  std_logic;
        bit_out : out std_logic;
        q_out   : out std_logic_vector(9 downto 0)
		);
	end component;
	
	component colin_frame_recovery is
		Port(
			Dout : in STD_LOGIC;
			clk : in STD_LOGIC;
			rst : in STD_LOGIC;
			Q : out STD_LOGIC;
			Rx_rst : out STD_LOGIC
		);
	end component;
	
	component colin_error_counter is
		Port(
			xor_in : in std_logic;
			clk : in std_logic;
			rst : in std_logic;
			count : out std_logic_vector(15 downto 0);
			HEX3 : out std_logic_vector(6 downto 0);
			HEX2 : out std_logic_vector(6 downto 0);
			HEX1 : out std_logic_vector(6 downto 0);
			HEX0 : out std_logic_vector(6 downto 0)
		);
	end component;
	
	component DFF_Custom is
		Port (
			clk   : in  STD_LOGIC;
			reset : in  STD_LOGIC;
			D     : in  STD_LOGIC;
			reset_value : in STD_LOGIC;
			Q     : out STD_LOGIC
		);
	end component;
	
	begin
	
	U_TopTest : Top_Test
		port map(
			tx_clk => tx_clk,
			ref_clk => ref_clk,
			prbs_rst => prbs_rst,
			cdr_rst => cdr_rst,
			Dout => Dout_signal,
			rec_clk => rec_clk_sig,
			Din => Din
		);
		
	U_FR : colin_frame_recovery
		port map(
			Dout => Dout_signal,
			clk => rec_clk_sig,
			rst => cdr_rst,
			Q =>	FR_Q,
			Rx_rst => Rx_rst_sig
		);
		
	U_RXPRBS : PRBS_Generator
		port map(
			clk => rec_clk_sig,
			reset => Rx_rst_sig,
			bit_out => RX_out
		);

	FR_Latch : DFF_Custom
		port map(
			D => RX_out,
			clk => rec_clk_sig,
			reset => not(cdr_rst),
			reset_value => '0',
			Q => RX_xor_in
		);
		
			
	FRQ_FF : DFF_Custom
		port map(
			D => FR_Q,
			clk => rec_clk_sig,
			reset => not(cdr_rst),
			reset_value => '0',
			Q => FR_xor_in
		);
		
	xor_out <= FR_xor_in xor RX_xor_in;
	
	RX_FF : DFF_Custom
		port map(
			D => xor_out,
			clk => rec_clk_sig,
			reset => not(cdr_rst),
			reset_value => '0',
			Q => xor_out_good
		);
		
		
	U_EC : colin_error_counter
		port map(
			xor_in => xor_out_good,
			clk => rec_clk_sig,
			rst => cdr_rst,
			count => error_cnt,
			HEX3 => HEX3,
			HEX2 => HEX2,
			HEX1 => HEX1,
			HEX0 => HEX0
		);
		
	Dout <= Dout_signal;
	rec_clk <= rec_clk_sig;
	rx_prbs <= RX_xor_in;
	FR_out <= FR_xor_in;
	rx_rst <= rx_rst_sig;
	
	
end Structural;


  

Frame Recover


-- colin_frame_recovery.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_MISC.ALL;

entity colin_frame_recovery is
	Port(
		Dout : in STD_LOGIC;
		clk : in STD_LOGIC;
		rst : in STD_LOGIC;
		Q : out STD_LOGIC;
		parallel_out : out STD_LOGIC_VECTOR(9 downto 0);
		Rx_rst : out STD_LOGIC;
		d_latch : out std_LOGIC
	);
end colin_frame_recovery;

architecture Structural of colin_frame_recovery is
	--Internal signals
	signal serial_out, d_latch_sig : STD_LOGIC;
	signal parallel_out_sig : STD_LOGIC_VECTOR(9 downto 0);
	
	component colin_shift_reg is
		port(
			clk    : in  std_logic;
			rst    : in  std_logic;  -- synchronous reset
			sin    : in  std_logic;  -- serial input
			sout   : out std_logic;  -- serial output
			q      : out std_logic_vector(9 downto 0)  -- internal contents
		);
	end component;
	 
	 component colin_latch is
		port(
			D : in STD_LOGIC;
			en : in STD_LOGIC;
			rst : in STD_LOGIC;
			Q : out STD_LOGIC	
		);
	end component;
		
	component DFF_Custom is
		Port (
			clk   : in  STD_LOGIC;
			reset : in  STD_LOGIC;
			D     : in  STD_LOGIC;
			reset_value : in STD_LOGIC;
			Q     : out STD_LOGIC
		);
	end component;
	
	begin
	
	FR_Shift_Reg : colin_shift_reg
		port map(
			clk => clk,
			rst => not(rst),
			sin => Dout,
			sout => serial_out,
			Q => parallel_out_sig
		);
		
	d_latch_sig <= and_reduce(parallel_out_sig);
		
	FR_Latch : DFF_Custom
		port map(
			D => d_latch_sig,
			clk => clk,
			reset => not(rst),
			reset_value => '0',
			Q => RX_rst
		);
		
	FR_DFF : DFF_Custom
		port map(
			clk => clk,
			reset => not(rst),
			D => serial_out,
			reset_value => '0',
			Q => Q
		);
		
		d_latch <= d_latch_sig;
		parallel_out <= parallel_out_sig;
	
end Structural;
	
  

Shift Register


-- colin_shift_reg.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity colin_shift_reg is
    port (
        clk    : in  std_logic;
        rst    : in  std_logic;  -- synchronous reset
        sin    : in  std_logic;  -- serial input
        sout   : out std_logic;  -- serial output
        Q      : out std_logic_vector(9 downto 0)  -- internal contents
    );
end colin_shift_reg;

architecture Structural of colin_shift_reg is
		signal qo : std_logic_vector(9 downto 0);
		signal d : std_logic_vector(9 downto 0);
		signal reset_bits : std_logic_vector(9 downto 0);
begin

    --------------------------------------------------------------------
    -- Next-state logic
    --------------------------------------------------------------------
    d(9) <= qo(8);
    d(8) <= qo(7);
    d(7) <= qo(6);
    d(6) <= qo(5);
    d(5) <= qo(4);
    d(4) <= qo(3);
    d(3) <= qo(2);
    d(2) <= qo(1);
    d(1) <= qo(0);
    d(0) <= sin;

    reset_bits(9) <= '0';
    reset_bits(8) <= '0';
    reset_bits(7) <= '0';
    reset_bits(6) <= '0';
    reset_bits(5) <= '0';
    reset_bits(4) <= '0';
    reset_bits(3) <= '0';
    reset_bits(2) <= '0';
    reset_bits(1) <= '0';
    reset_bits(0) <= '0';

    gen_dffs : for i in 0 to 9 generate
    begin
        DFF_inst : entity work.DFF_Custom
            port map (
                clk         => not(clk),
                reset       => rst,
                D           => d(i),
                reset_value => reset_bits(i),  -- per-bit reset value
                Q           => qo(i)
            );
    end generate;


    Q   <= qo;
    sout <= qo(9);


end Structural;


  

Error Counter


-- colin_error_counter.vhd
library IEEE;
use IEEE.std_logic_1164.all;
--Colin Byrne 101224212
entity colin_error_counter is
	Port(
		xor_in : in std_logic;
		clk : in std_logic;
		rst : in std_logic;
		count : out std_logic_vector(15 downto 0);
		HEX3 : out std_logic_vector(6 downto 0);
		HEX2 : out std_logic_vector(6 downto 0);
		HEX1 : out std_logic_vector(6 downto 0);
		HEX0 : out std_logic_vector(6 downto 0)
	);
end colin_error_counter;

architecture Structural of colin_error_counter is

	--Internal Signals
	signal count_signal : STD_LOGIC_VECTOR(15 downto 0);
	
	component colin_counter is
		Port(
			xor_in : in STD_LOGIC;
			clk : in STD_LOGIC;
			rst : in STD_LOGIC;
			count : out STD_LOGIC_VECTOR(15 downto 0)
		);
	end component;	
	
	component seven_segment_decoder is
		Port(
			SW : in STD_LOGIC_VECTOR(3 downto 0);   -- 4-bit input from switches
			HEX0 : out STD_LOGIC_VECTOR(6 downto 0) -- 7-segment display output
		);
	end component;
	
begin

	counter16 : colin_counter
		port map(
			xor_in => xor_in,
			clk => clk,
			rst => rst,
			count => count_signal
		);
		
	sevenseg0 : seven_segment_decoder
		port map(
			SW => count_signal(3 downto 0),
			HEX0 => HEX0
		);
	
	sevenseg1 : seven_segment_decoder
		port map(
			SW => count_signal(7 downto 4),
			HEX0 => HEX1
		);
		
	sevenseg2 : seven_segment_decoder
		port map(
			SW => count_signal(11 downto 8),
			HEX0 => HEX2
		);
		
	sevenseg3 : seven_segment_decoder
		port map(
			SW => count_signal(15 downto 12),
			HEX0 => HEX3
		);
		
		count <= count_signal;

end Structural;


  

Seven Segment Decoder


-- seven_segment_decoder.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity seven_segment_decoder is
    Port (
        SW : in STD_LOGIC_VECTOR(3 downto 0);   -- 4-bit input from switches
        HEX0 : out STD_LOGIC_VECTOR(6 downto 0) -- 7-segment display output
    );
end seven_segment_decoder;


architecture Behavioral of seven_segment_decoder is
begin
    process(SW)
    begin
        case SW is
            when "0000" => HEX0 <= "1000000"; -- 0
            when "0001" => HEX0 <= "1111001"; -- 1
            when "0010" => HEX0 <= "0100100"; -- 2
            when "0011" => HEX0 <= "0110000"; -- 3
            when "0100" => HEX0 <= "0011001"; -- 4
            when "0101" => HEX0 <= "0010010"; -- 5
            when "0110" => HEX0 <= "0000010"; -- 6
            when "0111" => HEX0 <= "1111000"; -- 7
            when "1000" => HEX0 <= "0000000"; -- 8
            when "1001" => HEX0 <= "0010000"; -- 9
            when "1010" => HEX0 <= "0001000"; -- A
            when "1011" => HEX0 <= "0000011"; -- b
            when "1100" => HEX0 <= "1000110"; -- C
            when "1101" => HEX0 <= "0100001"; -- d
            when "1110" => HEX0 <= "0000110"; -- E
            when "1111" => HEX0 <= "0001110"; -- F
            when others => HEX0 <= "1111111"; -- All segments off (default)
        end case;
    end process;
end Behavioral;
  

DFF


-- DFF_Custom.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity DFF_Custom is
    Port (
        clk   : in  STD_LOGIC;
        reset : in  STD_LOGIC;
        D     : in  STD_LOGIC;
		  reset_value : in STD_LOGIC;
        Q     : out STD_LOGIC
    );
end DFF_Custom;

architecture Behavioral of DFF_Custom is
begin
    process (clk, reset)
    begin
			if reset = '1' then
				Q <= reset_value;
        elsif rising_edge(clk) then
            Q <= D; -- Latch D to Q on rising clock edge
        end if;
    end process;
end Behavioral;
  

PRBS Generator


-- PRBS_Generator.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_misc.all;

entity PRBS_Generator is
    port (
        clk     : in  std_logic;
        reset   : in  std_logic;
        bit_out : out std_logic;
        q_out   : out std_logic_vector(9 downto 0);
		  all_one : out std_logic
    );
end entity PRBS_Generator;

architecture Structural of PRBS_Generator is
    signal q : std_logic_vector(9 downto 0);
    signal d : std_logic_vector(9 downto 0);
    signal feedback_bit : std_logic;
    signal reset_bits : std_logic_vector(9 downto 0);
begin

    feedback_bit <= q(9) xor q(6);

    d(9) <= q(8);
    d(8) <= q(7);
    d(7) <= q(6);
    d(6) <= q(5);
    d(5) <= q(4);
    d(4) <= q(3);
    d(3) <= q(2);
    d(2) <= q(1);
    d(1) <= q(0);
    d(0) <= feedback_bit;

    reset_bits(9) <= '1';
    reset_bits(8) <= '1';
    reset_bits(7) <= '1';
    reset_bits(6) <= '1';
    reset_bits(5) <= '1';
    reset_bits(4) <= '1';
    reset_bits(3) <= '1';
    reset_bits(2) <= '1';
    reset_bits(1) <= '1';
    reset_bits(0) <= '1';

    gen_dffs : for i in 0 to 9 generate
    begin
        DFF_inst : entity work.DFF_Custom
            port map (
                clk         => not(clk),
                reset       => reset,
                D           => d(i),
                reset_value => reset_bits(i),  -- per-bit reset value
                Q           => q(i)
            );
    end generate;

    q_out   <= q;
    bit_out <= q(9);
	 all_one <= and_reduce(q);

end architecture Structural;
  

CDR


-- CDR.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity CDR is
    Port (
        Din           : in  STD_LOGIC;
        ref_clk       : in  STD_LOGIC;
        cdr_rst       : in  STD_LOGIC;
        Dout          : out STD_LOGIC;
        rec_clk       : out STD_LOGIC;
        Clk_early_out : out STD_LOGIC;
        Clk_edge_out  : out STD_LOGIC;
        Clk_late_out  : out STD_LOGIC;
        Up            : out STD_LOGIC;
        Down          : out STD_LOGIC;
        div_clk       : out STD_LOGIC;
        P0            : out STD_LOGIC;
        P1            : out STD_LOGIC;
        P2            : out STD_LOGIC;
        P3            : out STD_LOGIC;
        P4            : out STD_LOGIC;
        P5            : out STD_LOGIC;
        P6            : out STD_LOGIC;
        P7            : out STD_LOGIC;
        Out_P         : out STD_LOGIC;
        Out_N         : out STD_LOGIC;
        counter_out   : out STD_LOGIC_VECTOR(2 downto 0)
    );
end CDR;

architecture Structural of CDR is

    -- Internal Signals
    signal Clk_early_sig, Clk_edge_sig, Clk_late_sig : STD_LOGIC;
    signal DFF_Clk_late_sig, PR_clk_sig : STD_LOGIC;
    signal div_clk_sig : STD_LOGIC;
    signal P0_sig, P1_sig, P2_sig, P3_sig : STD_LOGIC;
    signal P4_sig, P5_sig, P6_sig, P7_sig : STD_LOGIC;
    signal up_sig, down_sig : STD_LOGIC;
    signal out_p_sig, out_n_sig : STD_LOGIC;
    signal rec_clk_sig : STD_LOGIC;

    -- Component Declarations
    component Phase_Generator is
        Port (
            clk : in STD_LOGIC;
            rst : in STD_LOGIC;
            P0  : out STD_LOGIC;
            P1  : out STD_LOGIC;
            P2  : out STD_LOGIC;
            P3  : out STD_LOGIC;
            P4  : out STD_LOGIC;
            P5  : out STD_LOGIC;
            P6  : out STD_LOGIC;
            P7  : out STD_LOGIC
        );
    end component;

    component Clock_Divider is
        Port (
            clk     : in STD_LOGIC;
            rst     : in STD_LOGIC;
            clk_div : out STD_LOGIC
        );
    end component;

    component Phase_Rotator is
        Port (
            clk_div     : in  STD_LOGIC;
            rst         : in  STD_LOGIC;
            INC         : in  STD_LOGIC;
            DEC         : in  STD_LOGIC;
            P0          : in  STD_LOGIC;
            P1          : in  STD_LOGIC;
            P2          : in  STD_LOGIC;
            P3          : in  STD_LOGIC;
            P4          : in  STD_LOGIC;
            P5          : in  STD_LOGIC;
            P6          : in  STD_LOGIC;
            P7          : in  STD_LOGIC;
            CLK_early   : out STD_LOGIC;
            CLK_edge    : out STD_LOGIC;
            CLK_late    : out STD_LOGIC;
            counter_out : out STD_LOGIC_VECTOR(2 downto 0)
        );
    end component;

    component DFF_Custom is
        Port (
            clk          : in  STD_LOGIC;
            reset        : in  STD_LOGIC;
            D            : in  STD_LOGIC;
            reset_value  : in  STD_LOGIC;
            Q            : out STD_LOGIC
        );
    end component;

    component BBPD is
        Port (
            Clk_early : in STD_LOGIC;
            Clk_edge  : in STD_LOGIC;
            Clk_late  : in STD_LOGIC;
            rst       : in STD_LOGIC;
            Data_in   : in STD_LOGIC;
            Up        : out STD_LOGIC;
            Down      : out STD_LOGIC
        );
    end component;

    component Digital_Filter is
        Port (
            clk    : in STD_LOGIC;
            rst    : in STD_LOGIC;
            In_P   : in STD_LOGIC;  -- Up signal from BBPD
            In_N   : in STD_LOGIC;  -- Down signal from BBPD
            Out_P  : out STD_LOGIC; -- INC to Phase Rotator
            Out_N  : out STD_LOGIC  -- DEC to Phase Rotator
        );
    end component;

begin

    -- Phase Generator (creates 8-phase clocks)
    U_Phase_Gen : Phase_Generator
        port map (
            clk => ref_clk,
            rst => cdr_rst,
            P0  => P0_sig,
            P1  => P1_sig,
            P2  => P2_sig,
            P3  => P3_sig,
            P4  => P4_sig,
            P5  => P5_sig,
            P6  => P6_sig,
            P7  => P7_sig
        );

    -- Phase Rotator (selects phases based on INC/DEC)
    U_Phase_Rot : Phase_Rotator
        port map (
            clk_div     => PR_clk_sig,
            rst         => cdr_rst,
            INC         => out_p_sig,
            DEC         => out_n_sig,
            P0          => P0_sig,
            P1          => P1_sig,
            P2          => P2_sig,
            P3          => P3_sig,
            P4          => P4_sig,
            P5          => P5_sig,
            P6          => P6_sig,
            P7          => P7_sig,
            CLK_early   => Clk_early_sig,
            CLK_edge    => Clk_edge_sig,
            CLK_late    => Clk_late_sig,
            counter_out => counter_out
        );

    -- DFF for Late Clock
    DFF_DIV : DFF_Custom
        port map (
            clk          => ref_clk,
            reset        => not(cdr_rst),
            D            => Clk_late_sig,
            reset_value  => '0',
            Q            => DFF_Clk_late_sig
        );

    -- Recovered Clock DFF
    DFF_REC : DFF_Custom
        port map (
            clk          => ref_clk,
            reset        => not(cdr_rst),
            D            => DFF_Clk_late_sig,
            reset_value  => '0',
            Q            => rec_clk_sig
        );

    -- Clock Divider (generates CLK/4)
    U_Clock_Div : Clock_Divider
        port map (
            clk     => DFF_Clk_late_sig,
            rst     => not(cdr_rst),
            clk_div => div_clk_sig
        );

    -- Phase Rotator Clock DFF
    DFF_POST_DIV : DFF_Custom
        port map (
            clk          => ref_clk,
            reset        => not(cdr_rst),
            D            => div_clk_sig,
            reset_value  => '0',
            Q            => PR_clk_sig
        );

    -- Phase Detector
    U_Phase_Det : BBPD
        port map (
            Clk_early => Clk_early_sig,
            Clk_edge  => Clk_edge_sig,
            Clk_late  => Clk_late_sig,
            rst       => cdr_rst,
            Data_in   => Din,
            Up        => up_sig,
            Down      => down_sig
        );

    -- Digital Filter
    U_Digital_Fil : Digital_Filter
        port map (
            clk    => DFF_Clk_late_sig,
            rst    => cdr_rst,
            In_P   => up_sig,
            In_N   => down_sig,
            Out_P  => out_p_sig,
            Out_N  => out_n_sig
        );

    -- DFF for Recovered Data
    DFF_REC_DATA : DFF_Custom
        port map (
            clk          => rec_clk_sig,
            reset        => not(cdr_rst),
            D            => Din,
            reset_value  => '0',
            Q            => Dout
        );

    -- Output assignments
    Clk_early_out <= Clk_early_sig;
    Clk_edge_out  <= Clk_edge_sig;
    Clk_late_out  <= Clk_late_sig;
    rec_clk       <= rec_clk_sig;
    Up            <= up_sig;
    Down          <= down_sig;
    div_clk       <= div_clk_sig;
    P0            <= P0_sig;
    P1            <= P1_sig;
    P2            <= P2_sig;
    P3            <= P3_sig;
    P4            <= P4_sig;
    P5            <= P5_sig;
    P6            <= P6_sig;
    P7            <= P7_sig;
    Out_P         <= out_p_sig;
    Out_N         <= out_n_sig;

end Structural;
  

Clock Divider


-- Clock_Divider.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity Clock_Divider is
    Port (
        clk : in STD_LOGIC;
        rst : in STD_LOGIC;
        clk_div : out STD_LOGIC
    );
end Clock_Divider;

architecture Behavioral of Clock_Divider is
    signal clk_temp : STD_LOGIC := '0';
begin
    process(clk, rst)
	 variable div_counter : unsigned(1 downto 0) := "00";
    begin
        if rst = '1' then
            div_counter := "00";
            clk_temp <= '0';
        elsif falling_edge(clk) then
            if div_counter = "10" then
                div_counter := "00";
                clk_temp <= not clk_temp;
				end if;
            div_counter := div_counter + 1;
			end if;
    end process;
    
    clk_div <= clk_temp;
end Behavioral;
  

Digital Filter


-- Digital_Filter.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity Digital_Filter is
    Port (
        clk : in STD_LOGIC;
        rst : in STD_LOGIC;
        In_P : in STD_LOGIC;  -- Up signal from BBPD
        In_N : in STD_LOGIC;  -- Down signal from BBPD
        Out_P : out STD_LOGIC; -- INC to Phase Rotator
        Out_N : out STD_LOGIC  -- DEC to Phase Rotator
    );
end Digital_Filter;

architecture Behavioral of Digital_Filter is
    type shift_reg_type is array (0 to 3) of STD_LOGIC;
    signal up_shift_reg, down_shift_reg : shift_reg_type;
    signal up_or_out, down_or_out : STD_LOGIC;
begin

    -- Generate 4 DFFs for Up signal path
    UP_DFF_GEN: for i in 0 to 3 generate
        FIRST_UP: if i = 0 generate
            UP_DFF0: entity work.DFF_Custom
                port map (
                    clk => clk,
                    reset => not(rst),
                    D => In_P,
                    reset_value => '0',
                    Q => up_shift_reg(i)
                );
        end generate FIRST_UP;
        
        REST_UP: if i > 0 generate
            UP_DFF: entity work.DFF_Custom
                port map (
                    clk => clk,
                    reset => not(rst),
                    D => up_shift_reg(i-1),
                    reset_value => '0',
                    Q => up_shift_reg(i)
                );
        end generate REST_UP;
    end generate UP_DFF_GEN;

    -- Generate 4 DFFs for Down signal path
    DOWN_DFF_GEN: for i in 0 to 3 generate
        FIRST_DOWN: if i = 0 generate
            DOWN_DFF0: entity work.DFF_Custom
                port map (
                    clk => clk,
                    reset => not(rst),
                    D => In_N,
                    reset_value => '0',
                    Q => down_shift_reg(i)
                );
        end generate FIRST_DOWN;
        
        REST_DOWN: if i > 0 generate
            DOWN_DFF: entity work.DFF_Custom
                port map (
                    clk => clk,
                    reset => not(rst),
                    D => down_shift_reg(i-1),
                    reset_value => '0',
                    Q => down_shift_reg(i)
                );
        end generate REST_DOWN;
    end generate DOWN_DFF_GEN;

    -- OR gates (any of the four flip-flop outputs)
    up_or_out <= up_shift_reg(0) or up_shift_reg(1) or up_shift_reg(2) or up_shift_reg(3);
    down_or_out <= down_shift_reg(0) or down_shift_reg(1) or down_shift_reg(2) or down_shift_reg(3);

    -- AND gates with inverted inputs for mutual exclusion
    Out_P <= up_or_out and not down_or_out;
    Out_N <= down_or_out and not up_or_out;

end Behavioral;
  

BBPD


-- BBPD.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity BBPD is
    Port (
        Clk_early : in STD_LOGIC;
        Clk_edge  : in STD_LOGIC;
        Clk_late  : in STD_LOGIC;
        rst       : in STD_LOGIC;
        Data_in   : in STD_LOGIC;
        Up        : out STD_LOGIC;
        Down      : out STD_LOGIC
    );
end BBPD;

architecture Structural of BBPD is
    component DFF_Custom
        Port (
            clk : in STD_LOGIC;
            reset : in STD_LOGIC;
            D : in STD_LOGIC;
            reset_value : in STD_LOGIC;
            Q : out STD_LOGIC
        );
    end component;
	 
	 component Falling_DFF_Custom
        Port (
            clk : in STD_LOGIC;
            reset : in STD_LOGIC;
            D : in STD_LOGIC;
            reset_value : in STD_LOGIC;
            Q : out STD_LOGIC
        );
    end component;
    
    -- Signals for data sampling
    signal data_early, data_edge, data_late : STD_LOGIC;
    
    -- Signals for XOR outputs
    signal xor_early_edge, xor_late_edge : STD_LOGIC;
    
begin

    -- Sample Data at Early Phase (Clk_early)
    DFF_EARLY: DFF_Custom
        port map (
            clk => Clk_early,
            reset => not(rst),
            D => Data_in,
            reset_value => '0',
            Q => data_early
        );
    
    -- Sample Data at Edge Phase (Clk_edge)  
    DFF_EDGE: DFF_Custom
        port map (
            clk => Clk_edge,
            reset => not(rst),
            D => Data_in,
            reset_value => '0',
            Q => data_edge
        );
    
    -- Sample Data at Late Phase (Clk_late)
    DFF_LATE: DFF_Custom
        port map (
            clk => Clk_late,
            reset => not(rst),
            D => Data_in,
            reset_value => '0',
            Q => data_late
        );  
    
    -- XOR between early sample and edge sample
    xor_early_edge <= data_early xor data_edge;
    
    -- XOR between late sample and edge sample  
    xor_late_edge <= data_late xor data_edge;
    
    -- Up output: Early sample differs from Edge sample (synchronized to Clk_late)
    DFF_EARLY_DELAY: DFF_Custom
        port map (
            clk => not(Clk_late),
            reset => not(rst),
            D => xor_early_edge,  -- XOR of data_early and data_edge
            reset_value => '0',
            Q => Up               -- Direct output
        );
    
    -- Down output: Late sample differs from Edge sample (synchronized to Clk_late)  
    DFF_LATE_DELAY: DFF_Custom
        port map (
            clk => not(Clk_late),
            reset => not(rst),
            D => xor_late_edge,   -- XOR of data_late and data_edge
            reset_value => '0',
            Q => Down             -- Direct output
        );
    
end Structural;

  

Phase Generator


-- Phase_Generator.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity Phase_Generator is
    Port (
        clk : in STD_LOGIC;
        rst : in STD_LOGIC;
        P0 : out STD_LOGIC;
        P1 : out STD_LOGIC;
        P2 : out STD_LOGIC;
        P3 : out STD_LOGIC;
        P4 : out STD_LOGIC;
        P5 : out STD_LOGIC;
        P6 : out STD_LOGIC;
        P7 : out STD_LOGIC
    );
end Phase_Generator;

architecture Structural of Phase_Generator is
    component DFF_Custom
        Port (
            clk : in STD_LOGIC;
            reset : in STD_LOGIC;
            D : in STD_LOGIC;
            reset_value : in STD_LOGIC;
            Q : out STD_LOGIC
        );
    end component;
    
    signal q_outputs : STD_LOGIC_VECTOR(7 downto 0);
    signal d_inputs : STD_LOGIC_VECTOR(7 downto 0);
    constant RESET_VALUES : STD_LOGIC_VECTOR(7 downto 0) := "00000001";
    
begin
    -- Explicit ring counter connections
    d_inputs(0) <= q_outputs(7);
    d_inputs(1) <= q_outputs(0);
    d_inputs(2) <= q_outputs(1);
    d_inputs(3) <= q_outputs(2);
    d_inputs(4) <= q_outputs(3);
    d_inputs(5) <= q_outputs(4);
    d_inputs(6) <= q_outputs(5);
    d_inputs(7) <= q_outputs(6);

    -- Generate only the DFF instances
    GEN_DFFS: for i in 0 to 7 generate
        DFF_INST: DFF_Custom 
            port map (
                clk => clk,
                reset => not(rst),
                D => d_inputs(i),
                reset_value => RESET_VALUES(i),
                Q => q_outputs(i)
            );
    end generate GEN_DFFS;
    
    -- Output connections
    P0 <= q_outputs(0);
    P1 <= q_outputs(1);
    P2 <= q_outputs(2);
    P3 <= q_outputs(3);
    P4 <= q_outputs(4);
    P5 <= q_outputs(5);
    P6 <= q_outputs(6);
    P7 <= q_outputs(7);
    
end Structural;
  

Phase Rotator


-- Phase_Rotator.vhd
library IEEE;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity Phase_Rotator is
    Port (
        clk_div : in STD_LOGIC;
        rst : in STD_LOGIC;
        INC : in STD_LOGIC;
        DEC : in STD_LOGIC;
        P0 : in STD_LOGIC;
        P1 : in STD_LOGIC;
        P2 : in STD_LOGIC;
        P3 : in STD_LOGIC;
        P4 : in STD_LOGIC;
        P5 : in STD_LOGIC;
        P6 : in STD_LOGIC;
        P7 : in STD_LOGIC;
        CLK_early : out STD_LOGIC;
        CLK_edge : out STD_LOGIC;
        CLK_late : out STD_LOGIC;
        counter_out : out STD_LOGIC_VECTOR(2 downto 0)
    );
end Phase_Rotator;

architecture Behavioral of Phase_Rotator is
    signal counter : unsigned(2 downto 0) := "000";
begin
    -- 3-bit Phase Rotator Counter (operates at CLK/4)
    process(clk_div, rst)
    begin
        if rst = '0' then
            counter <= "000";
        elsif rising_edge(clk_div) then
            if INC = '1' then
                counter <= counter + 1;  -- Rotate right (advance phase)
				end if;
            if DEC = '1' then
                counter <= counter - 1;  -- Rotate left (delay phase)
            end if;
        end if;
    end process;
    
    -- Phase Selection with 90-degree spacing (2 unit difference)
    process(counter, P0, P1, P2, P3, P4, P5, P6, P7)
    begin
        case counter is
            when "000" => 
                CLK_early <= P0; CLK_edge <= P2; CLK_late <= P4;
            when "001" => 
                CLK_early <= P1; CLK_edge <= P3; CLK_late <= P5;
            when "010" => 
                CLK_early <= P2; CLK_edge <= P4; CLK_late <= P6;
            when "011" => 
                CLK_early <= P3; CLK_edge <= P5; CLK_late <= P7;
            when "100" => 
                CLK_early <= P4; CLK_edge <= P6; CLK_late <= P0;
            when "101" => 
                CLK_early <= P5; CLK_edge <= P7; CLK_late <= P1;
            when "110" => 
                CLK_early <= P6; CLK_edge <= P0; CLK_late <= P2;
            when "111" => 
                CLK_early <= P7; CLK_edge <= P1; CLK_late <= P3;
            when others => 
                CLK_early <= P0; CLK_edge <= P2; CLK_late <= P4;
        end case;
    end process;
    
    counter_out <= STD_LOGIC_VECTOR(counter);
end Behavioral;