Перейти к содержанию
    

Мажоритарный элемент на 10 входов. VHDL

посмотрите, может подойдет:

 


dvi_in.vhd
----------------------------------------------------------------------------------
-- 
-- Module Name: dvi_in.vhd - Behavioral 
--
-- Description: Design to capture raw DVI-D input
--
-- REALLY IMPORTANT NOTE - on my PCB some of the + and - differential
-- pairs are transposed to allow better routing and avioding vias. 
-- You most likely want to change the value of "invert" on the gearbox 
-- instances.
--
-- I've also got do do some work to automatically adjust the phase of the
-- bit clocks, at the moment it needs to be manually tuned to match your source
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

library UNISIM;
use UNISIM.VComponents.all;

entity dvi_in is
   Port ( clk32      : in  STD_LOGIC;
          hdmi_clk_p : in  STD_LOGIC;
          hdmi_clk_n : in  STD_LOGIC;
          hdmi_c0_p  : in  STD_LOGIC;
          hdmi_c0_n  : in  STD_LOGIC;
          hdmi_c1_p  : in  STD_LOGIC;
          hdmi_c1_n  : in  STD_LOGIC;
          hdmi_c2_p  : in  STD_LOGIC;
          hdmi_c2_n  : in  STD_LOGIC;
          hdmi_sclk  : inout  STD_LOGIC;
          hdmi_sdat  : inout  STD_LOGIC;

          red        : out std_logic_vector(2 downto 0);
          green      : out std_logic_vector(2 downto 0);
          blue       : out std_logic_vector(1 downto 0);
          hsync      : out std_logic;
          vsync      : out std_logic;

          btns       : in  std_logic_vector(3 downto 0);
          leds       : out std_logic_vector(3 downto 0));
end dvi_in;

architecture Behavioral of dvi_in is
  signal hdmi_clk             : std_logic;
  signal hdmi_clk_buffered    : std_logic;
  signal ioclock              : std_logic;
  signal serdes_strobe        : std_logic;


  signal clock_x1             : std_logic;
  signal clock_x2             : std_logic;
  signal clock_x10            : std_logic;
  signal clock_x10_unbuffered : std_logic;
  signal clock_x2_unbuffered  : std_logic;
  signal clock_x1_unbuffered  : std_logic;

  signal clk_feedback         : std_logic;
  signal pll_locked           : std_logic;
  signal sync_seen            : std_logic;

  signal c0_d       : std_logic_vector(7 downto 0);
  signal c0_c       : std_logic_vector(1 downto 0);
  signal c0_active  : std_logic;

  signal c1_d       : std_logic_vector(7 downto 0);
  signal c1_c       : std_logic_vector(1 downto 0);
  signal c1_active  : std_logic;

  signal c2_d       : std_logic_vector(7 downto 0);
  signal c2_c       : std_logic_vector(1 downto 0);
  signal c2_active  : std_logic;

  signal led_count   : unsigned( 2 downto 0)        := (others => '0');
  signal framing     : std_logic_vector(3 downto 0) := (others => '0');
  signal since_sync  : unsigned(14 downto 0)        := (others => '0');

  signal start_calibrate : std_logic;
  signal reset_delay     : std_logic;
  signal cal_start_count : unsigned(7 downto 0) := (others => '0');          

  COMPONENT input_channel
  GENERIC(
        fixed_delay     : in natural
     );
  PORT(
     clk_fabric    : IN  std_logic;
     clk_fabric_x2 : IN  std_logic;
     clk_input     : IN  std_logic;
     strobe        : IN  std_logic;
     tmds_p        : in  STD_LOGIC;
     tmds_n        : in  STD_LOGIC;
     invert        : IN  std_logic;
     framing       : IN  std_logic_vector(3 downto 0);          
     data_out      : OUT std_logic_vector(7 downto 0);
     control       : OUT std_logic_vector(1 downto 0);
     active_data   : OUT std_logic;
     sync_seen     : OUT std_logic;

     adjust_delay    : IN  std_logic;
     increase_delay  : IN  std_logic;
     reset_delay     : IN  std_logic;
     start_calibrate : IN  std_logic;          
     calibrate_busy  : OUT std_logic
     );
  END COMPONENT;

begin   
  ----------------------------------
  -- Output the decoded VGA signals
  ----------------------------------
  red   <= c0_d(7 downto 5);
  blue  <= c1_d(7 downto 6);
  green <= c2_d(7 downto 5);
  hsync <= c2_c(0);
  vsync <= c2_c(1);

  ----------------------------------
  -- Debug
  ----------------------------------
  leds <= framing;

  ----------------------------------
  -- EDID I2C signals (not implemented)
  ----------------------------------
  hdmi_sclk <= '1';
  hdmi_sdat <= '1';

------------------------------------------
-- Receive the differential clock
------------------------------------------
clk_diff_input : IBUFDS
  generic map (
     DIFF_TERM    => FALSE,
     IBUF_LOW_PWR => TRUE,
     IOSTANDARD   => "TMDS_33")
  port map (
     O  => hdmi_clk,
     I  => hdmi_clk_p,
     IB => hdmi_clk_n
  );

------------------------------------------
-- Buffer it before the PLL
------------------------------------------
BUFG_clk : BUFG port map ( I => hdmi_clk, O => hdmi_clk_buffered);

------------------------------------------
-- Generate the bit clocks for the serdes
-- 
-- Adjust the phase in a 10:2:1 ratio (e.g. 50:10:5)
------------------------------------------
PLL_BASE_inst : PLL_BASE
  generic map (
     CLKFBOUT_MULT => 10,                  
     -- Almost works with Western Digital Live @ 720p/60 -Noise on blue channel.
     --CLKOUT0_DIVIDE => 1,       CLKOUT0_PHASE => 200.0,   -- Output 10x original frequency
     --CLKOUT1_DIVIDE => 5,       CLKOUT1_PHASE => 40.0,   -- Output 2x original frequency
     --CLKOUT2_DIVIDE => 10,      CLKOUT2_PHASE => 20.0,    -- Output 1x original frequency
     -- Works with Western Digital Live @ 640x480/60Hz
     CLKOUT0_DIVIDE => 1,       CLKOUT0_PHASE => 0.0,   -- Output 10x original frequency
     CLKOUT1_DIVIDE => 5,       CLKOUT1_PHASE => 0.0,   -- Output 2x original frequency
     CLKOUT2_DIVIDE => 10,      CLKOUT2_PHASE => 0.0,    -- Output 1x original frequency
     CLK_FEEDBACK => "CLKFBOUT",                         -- Clock source to drive CLKFBIN ("CLKFBOUT" or "CLKOUT0")
     CLKIN_PERIOD => 10.0,                               -- IMPORTANT! Approx 77 MHz
     DIVCLK_DIVIDE => 1                                  -- Division value for all output clocks (1-52)
  )
     port map (
     CLKFBOUT => clk_feedback, 
     CLKOUT0  => clock_x10_unbuffered,
     CLKOUT1  => clock_x2_unbuffered,
     CLKOUT2  => clock_x1_unbuffered,
     CLKOUT3  => open,
     CLKOUT4  => open,
     CLKOUT5  => open,
     LOCKED   => pll_locked,      
     CLKFBIN  => clk_feedback,    
     CLKIN    => hdmi_clk_buffered, 
     RST      => '0'              -- 1-bit input: Reset input
  );

  BUFG_pclockx2  : BUFG port map ( I => clock_x2_unbuffered,  O => clock_x2);
  BUFG_pclock    : BUFG port map ( I => clock_x1_unbuffered,  O => clock_x1);
  BUFG_pclockx10 : BUFG port map ( I => clock_x10_unbuffered, O => clock_x10 );


------------------------------------------------
-- Buffer the clocks ready to go the serialisers
------------------------------------------------
BUFPLL_inst : BUFPLL
  generic map (
     DIVIDE => 5,         -- DIVCLK divider (1-8) !!!! IMPORTANT TO CHANGE THIS AS NEEDED !!!!
     ENABLE_SYNC => TRUE  -- Enable synchrnonization between PLL and GCLK (TRUE/FALSE) -- should be true
  )
  port map (
     IOCLK        => ioclock,               -- Clock used to receive bits
     LOCK         => open,                 
     SERDESSTROBE => serdes_strobe,         -- Clock use to load data into SERDES 
     GCLK         => clock_x2,              -- Global clock use as a reference for serdes_strobe
     LOCKED       => pll_locked,            -- When the upstream PLL is locked 
     PLLIN        => clock_x10_unbuffered   -- Clock to use for bit capture - this must be unbuffered
  );

----------------------------------------
-- c0 channel input - Carries the RED channel
----------------------------------------
input_channel_c0: input_channel GENERIC MAP(
     fixed_delay     => 30
   ) PORT MAP(
     clk_fabric      => clock_x1,
     clk_fabric_x2   => clock_x2,
     clk_input       => ioclock,
     strobe          => serdes_strobe,
     tmds_p          => hdmi_c0_p,
     tmds_n          => hdmi_c0_n,
     invert          => '0',
     framing         => framing,
     data_out        => c0_d,
     control         => c0_c,
     active_data     => c0_active,
     sync_seen       => open,
     adjust_delay    => '0',
     increase_delay  => '0',
     reset_delay     => reset_delay,
     start_calibrate => start_calibrate,
     calibrate_busy  => open
  );   

----------------------------------------
-- c1 channel input - Carries the BLUE channel
----------------------------------------

input_channel_c1: input_channel GENERIC MAP(
     fixed_delay     => 40
   ) PORT MAP(
     clk_fabric      => clock_x1,
     clk_fabric_x2   => clock_x2,
     clk_input       => ioclock,
     strobe          => serdes_strobe,
     tmds_p          => hdmi_c1_n,
     tmds_n          => hdmi_c1_p,
     invert          => '1',
     framing         => framing,
     data_out        => c1_d,
     control         => c1_c,
     active_data     => c1_active,
     sync_seen       => open,
     adjust_delay    => '0',
     increase_delay  => '0',
     reset_delay     => reset_delay,
     start_calibrate => start_calibrate,
     calibrate_busy  => open
  );   

----------------------------------------
-- c2 channel input - Carries the GREEN channel and syncs
----------------------------------------
input_channel_c2: input_channel GENERIC MAP(
     fixed_delay     => 30
   )  PORT MAP(
     clk_fabric      => clock_x1,
     clk_fabric_x2   => clock_x2,
     clk_input       => ioclock,
     strobe          => serdes_strobe,
     tmds_p          => hdmi_c2_n,
     tmds_n          => hdmi_c2_p,
     invert          => '1',
     framing         => framing,
     data_out        => c2_d,
     control         => c2_c,
     active_data     => c2_active,
     sync_seen       => sync_seen,
     adjust_delay    => '0',
     increase_delay  => '0',
     reset_delay     => reset_delay,
     start_calibrate => start_calibrate,
     calibrate_busy  => open
  );   

calibrate_preocess: process (clock_x2)
  begin
     if rising_edge(clock_x2) then
        if cal_start_count = "10000000" then
           start_calibrate <= '0';
        else
           start_calibrate <= '0';
        end if;
        if cal_start_count = "11111100" then
           reset_delay <= '0';
        else
           reset_delay <= '0';
        end if;

        if cal_start_count /= "11111111" then
           cal_start_count <= cal_start_count + 1;
        end if;
     end if;
  end process;

process(clock_x1) 
  begin
     if rising_edge(clock_x1) then
        -- Work out what we need to do to frame the TMDS data correctly
        if sync_seen = '1' then
           ------------------------------------------------------------
           -- We've just seen a sync codeword, so restart the counter
           -- This means that we are in sync
           ------------------------------------------------------------
           since_sync  <= (others => '0');
        elsif since_sync = "111111111111111" then
           ------------------------------------------------------------
           -- We haven't seen a sync in 16383 pixel cycles, so it can't 
           -- be in sync. By incrementing 'framing' we bitslip one bit.
           --            
           -- The 16k number is special, as they two sync codewords
           -- being looked for will not be seen during the VSYNC period
           -- (assuming that you are looking in the channel that 
           -- includes the encoded HSYNC/VSYNC signals 
           ------------------------------------------------------------
           if framing = "1001" then
              framing <= (others =>'0');
           else
              framing <= std_logic_vector(unsigned(framing) + 1);
           end if;
           since_sync  <= since_sync + 1;
        else
           ------------------------------------------------------------
           -- Keep counting and hoping for a sync codeword
           ------------------------------------------------------------
           since_sync  <= since_sync + 1;
        end if;

     end if;
  end process;
end Behavioral;

input_channel.vhd
----------------------------------------------------------------------------------
-- 
-- Module Name:    input_channel - Behavioral 
-- Description:    The end-to-end processing of a TMDS input channel
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
library UNISIM;
use UNISIM.VComponents.all;


entity input_channel is
  GENERIC(
        fixed_delay     : in natural
     );
   Port ( clk_fabric      : in  STD_LOGIC;
          clk_fabric_x2   : in  STD_LOGIC;
          clk_input       : in  STD_LOGIC;
          strobe          : in  STD_LOGIC;
          tmds_p          : in  STD_LOGIC;
          tmds_n          : in  STD_LOGIC;
          invert          : in  STD_LOGIC;
          framing         : in  std_logic_vector(3 downto 0);
          data_out        : out STD_LOGIC_VECTOR (7 downto 0);
          control         : out STD_LOGIC_VECTOR (1 downto 0);
          active_data     : out std_logic;
          sync_seen       : out std_logic;

          adjust_delay    : IN  std_logic;
          increase_delay  : IN  std_logic;
          reset_delay     : IN  std_logic;
          start_calibrate : IN  std_logic;          
          calibrate_busy  : OUT std_logic
);
end input_channel;

architecture Behavioral of input_channel is

  COMPONENT input_serialiser
  PORT(
     clk_fabric_x2 : IN  std_logic;
     clk_input     : IN  std_logic;
     strobe        : IN  std_logic;
     ser_input     : IN  std_logic;          
     ser_data      : OUT std_logic_vector(4 downto 0)
     );
  END COMPONENT;

  COMPONENT gearbox
  PORT(
     clk_fabric_x2 : IN  std_logic;
     framing       : IN  std_logic_vector(3 downto 0);
     invert        : IN  std_logic;
     data_in       : IN  std_logic_vector(4 downto 0);
     data_out      : OUT std_logic_vector(9 downto 0)
     );
  END COMPONENT;

  COMPONENT tmds_decode
  PORT(
     clk         : IN  std_logic;
     data_in     : IN  std_logic_vector(9 downto 0);          
     data_out    : OUT std_logic_vector(7 downto 0);
     c           : OUT std_logic_vector(1 downto 0);
     active_data : OUT std_logic
     );
  END COMPONENT;

  signal serial_data         : std_logic;
  signal raw_tmds_word       : std_logic_vector(9 downto 0);          
  signal half_words          : std_logic_vector(4 downto 0);          
begin

diff_input : IBUFDS
  generic map (
     DIFF_TERM    => FALSE,
     IBUF_LOW_PWR => TRUE,
     IOSTANDARD   => "TMDS_33")
  port map (
     O  => serial_data,
     I  => tmds_p,
     IB => tmds_n
  );

i_input_serialiser: input_serialiser PORT MAP(
     clk_fabric_x2 => clk_fabric_x2,
     clk_input     => clk_input,
     strobe        => strobe,
     ser_input     => serial_data,
     ser_data      => half_words
  );

i_gearbox: gearbox PORT MAP(
     clk_fabric_x2 => clk_fabric_x2,
     invert        => invert,
     framing       => framing,
     data_in       => half_words,
     data_out      => raw_tmds_word
  );

i_tmds_decode: tmds_decode PORT MAP(
     clk         => clk_fabric,
     data_in     => raw_tmds_word,
     data_out    => data_out,
     c           => control,
     active_data => active_data 
  );

look_for_sync: process (clk_fabric)
  begin
     if rising_edge(clk_fabric) then
        ------------------------------------------------------------
        -- Is the TMDS data one of two special sync codewords?
        ------------------------------------------------------------
        if raw_tmds_word = "1101010100" or raw_tmds_word = "0010101011" then
           sync_seen <= '1';
        else
           sync_seen <= '0';
        end if;
     end if;
  end process;
end Behavioral;

gearbox.vhd
This 'gearbox' takes 5-bit data at 2x the pixel clock, and converts it to 10-bit data at the pixel clock.
----------------------------------------------------------------------------------
--
-- Module Name:    Gearbox - Behavioral 
-- Project Name:   DVI-I Input
-- Description:  Receives the 5-bits-per-cycle data from the serialisers at twice
--               the pixel clock, then 'downshifts' the data to 10-bit words.
--
--               The 'framing' signal allows to bit-slip to different word
--               framing, allowing the design to hunt for the sync codewords.
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity gearbox is
   Port ( clk_fabric_x2 : in  STD_LOGIC;
          invert        : in  STD_LOGIC;
          framing       : in  std_logic_vector(3 downto 0);
          data_in       : in  std_logic_vector(4 downto 0);
          data_out      : out std_logic_vector(9 downto 0));
end gearbox;

architecture Behavioral of gearbox is
  signal every_other : std_logic := '0';
  signal joined      : std_logic_vector(14 downto 0);
begin

process(clk_fabric_x2) 
  begin
     if rising_edge(clk_fabric_x2) then
        if every_other = '1' then
           case framing is
              when "0000" => data_out <= joined( 9 downto 0);
              when "0001" => data_out <= joined(10 downto 1);
              when "0010" => data_out <= joined(11 downto 2);
              when "0011" => data_out <= joined(12 downto 3);
              when "0100" => data_out <= joined(13 downto 4);
              when others => NULL;
           end case;
        else
           case framing is
              when "0101" => data_out <= joined( 9 downto 0);
              when "0110" => data_out <= joined(10 downto 1);
              when "0111" => data_out <= joined(11 downto 2);
              when "1000" => data_out <= joined(12 downto 3);
              when "1001" => data_out <= joined(13 downto 4);
              when others => NULL;
           end case;
        end if;
        if invert = '1' then 
           joined <= data_in & joined(joined'high downto 5) ;
        else
           joined <= (data_in xor "11111") & joined(joined'high downto 5) ;
        end if;
        every_other <= not every_other;
     end if;
  end process;

end Behavioral;

tmds_decode.vhd
----------------------------------------------------------------------------------
-- 
-- Module Name:    tmds_decode - Behavioral 
--
-- Description: TMDS decode as per Digital Display Working Groups Digital Visual 
--              Interface Revision 1.0 section 3.3.3
--
-- This doesn't seem 100% correct - "elsif sometimes_inverted(8) = '0' then" should
-- be "elsif sometimes_inverted(8) = '1' then" according to the standard.
-- 
-- However it does actually work!
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity tmds_decode is
   Port ( clk         : in  STD_LOGIC;
          data_in     : in  STD_LOGIC_VECTOR (9 downto 0);
          data_out    : out  STD_LOGIC_VECTOR (7 downto 0);
          c           : out  STD_LOGIC_VECTOR (1 downto 0);
          active_data : out std_logic);
end tmds_decode;

architecture Behavioral of tmds_decode is
  signal data_delayed       : STD_LOGIC_VECTOR(9 downto 0);
  signal sometimes_inverted : STD_LOGIC_VECTOR(8 downto 0);
  signal next_c             : STD_LOGIC_VECTOR(1 downto 0);
  signal next_active_data   : STD_LOGIC;
begin

process(clk)
  begin
     if rising_edge(clk) then

        c           <= next_c;
        active_data <= next_active_data;

        if next_active_data = '0' then
           data_out <= (others => '0');
        elsif sometimes_inverted(8) = '0' then
           data_out(0) <= sometimes_inverted(0);
           data_out(1) <= sometimes_inverted(1) XOR sometimes_inverted(0);
           data_out(2) <= sometimes_inverted(2) XOR sometimes_inverted(1);
           data_out(3) <= sometimes_inverted(3) XOR sometimes_inverted(2);
           data_out(4) <= sometimes_inverted(4) XOR sometimes_inverted(3);
           data_out(5) <= sometimes_inverted(5) XOR sometimes_inverted(4);
           data_out(6) <= sometimes_inverted(6) XOR sometimes_inverted(5);
           data_out(7) <= sometimes_inverted(7) XOR sometimes_inverted(6);
        else
           data_out(0) <= sometimes_inverted(0);
           data_out(1) <= sometimes_inverted(1) XNOR sometimes_inverted(0);
           data_out(2) <= sometimes_inverted(2) XNOR sometimes_inverted(1);
           data_out(3) <= sometimes_inverted(3) XNOR sometimes_inverted(2);
           data_out(4) <= sometimes_inverted(4) XNOR sometimes_inverted(3);
           data_out(5) <= sometimes_inverted(5) XNOR sometimes_inverted(4);
           data_out(6) <= sometimes_inverted(6) XNOR sometimes_inverted(5);
           data_out(7) <= sometimes_inverted(7) XNOR sometimes_inverted(6);
        end if;

        if data_delayed(9) = '1' then
           sometimes_inverted <= data_delayed(8 downto 0) xor "011111111";
        else
           sometimes_inverted <= data_delayed(8 downto 0);
        end if;

        case data_in is
           when "0010101011" => next_c <= "01"; next_active_data <= '0';
           when "1101010100" => next_c <= "00"; next_active_data <= '0';
           when "0101010100" => next_c <= "10"; next_active_data <= '0';
           when "1010101011" => next_c <= "11"; next_active_data <= '0';
           when others       => next_c <= "00"; next_active_data <= '1';
        end case;

        data_delayed <= data_in;
     end if;
  end process;
end Behavioral;

input_serialiser.vhd
----------------------------------------------------------------------------------
-- 
-- Module Name: input_serialiser 
--
-- Description: A 5-bits per cycle SDR input serialiser
--
--              Maybe in the future the 'bitslip' funciton can be implemented.
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
library UNISIM;
use UNISIM.VComponents.all;

entity input_serialiser is
   Port ( clk_fabric_x2 : in  STD_LOGIC;
          clk_input     : in  STD_LOGIC;
          strobe        : in  STD_LOGIC;
          ser_data      : out  STD_LOGIC_VECTOR (4 downto 0);
          ser_input     : in STD_LOGIC);
end input_serialiser;

architecture Behavioral of input_serialiser is
  signal clk0,     clk1,     clkdiv : std_logic;
  signal cascade : std_logic;
  signal bitslip : std_logic := '0';
begin
  clkdiv <= clk_fabric_x2;
  clk0   <= clk_input;
  clk1   <= '0';

ISERDES2_master : ISERDES2
  generic map (
     BITSLIP_ENABLE => TRUE,         -- Enable Bitslip Functionality (TRUE/FALSE)
     DATA_RATE      => "SDR",        -- Data-rate ("SDR" or "DDR")
     DATA_WIDTH     => 5,            -- Parallel data width selection (2-8)
     INTERFACE_TYPE => "RETIMED",    -- "NETWORKING", "NETWORKING_PIPELINED" or "RETIMED" 
     SERDES_MODE    => "MASTER"      -- "NONE", "MASTER" or "SLAVE" 
  )
  port map (
     CFB0      => open,      -- 1-bit output: Clock feed-through route output
     CFB1      => open,      -- 1-bit output: Clock feed-through route output
     DFB       => open,       -- 1-bit output: Feed-through clock output
     FABRICOUT => open,      -- 1-bit output: Unsynchrnonized data output
     INCDEC    => open,      -- 1-bit output: Phase detector output
     -- Q1 - Q4: 1-bit (each) output: Registered outputs to FPGA logic
     Q1        => ser_data(1),
     Q2        => ser_data(2),
     Q3        => ser_data(3),
     Q4        => ser_data(4),
     SHIFTOUT  => cascade,   -- 1-bit output: Cascade output signal for master/slave I/O
     VALID     => open,      -- 1-bit output: Output status of the phase detector
     BITSLIP   => bitslip ,   -- 1-bit input: Bitslip enable input
     CE0       => '1',        -- 1-bit input: Clock enable input
     CLK0      => clk0,       -- 1-bit input: I/O clock network input
     CLK1      => clk1,       -- 1-bit input: Secondary I/O clock network input
     CLKDIV    => clkdiv,     -- 1-bit input: FPGA logic domain clock input
     D         => ser_input,  -- 1-bit input: Input data
     IOCE      => strobe,     -- 1-bit input: Data strobe input
     RST       => '0',        -- 1-bit input: Asynchronous reset input
     SHIFTIN   => '0'         -- 1-bit input: Cascade input signal for master/slave I/O
  );

ISERDES2_slave : ISERDES2
  generic map (
     BITSLIP_ENABLE => TRUE,         -- Enable Bitslip Functionality (TRUE/FALSE)
     DATA_RATE      => "SDR",        -- Data-rate ("SDR" or "DDR")
     DATA_WIDTH     => 5,            -- Parallel data width selection (2-8)
     INTERFACE_TYPE => "RETIMED",    -- "NETWORKING", "NETWORKING_PIPELINED" or "RETIMED" 
     SERDES_MODE    => "SLAVE"       -- "NONE", "MASTER" or "SLAVE" 
  )
  port map (
     CFB0      => open,      -- 1-bit output: Clock feed-through route output
     CFB1      => open,      -- 1-bit output: Clock feed-through route output
     DFB       => open,      -- 1-bit output: Feed-through clock output
     FABRICOUT => open,    -- 1-bit output: Unsynchrnonized data output
     INCDEC    => open,    -- 1-bit output: Phase detector output
     -- Q1 - Q4: 1-bit (each) output: Registered outputs to FPGA logic
     Q1        => open,
     Q2        => open,
     Q3        => open,
     Q4        => ser_data(0),
     SHIFTOUT  => open,      -- 1-bit output: Cascade output signal for master/slave I/O
     VALID     => open,      -- 1-bit output: Output status of the phase detector
     BITSLIP   => bitslip,   -- 1-bit input: Bitslip enable input
     CE0       => '1',       -- 1-bit input: Clock enable input
     CLK0      => clk0,      -- 1-bit input: I/O clock network input
     CLK1      => clk1,      -- 1-bit input: Secondary I/O clock network input
     CLKDIV    => clkdiv,    -- 1-bit input: FPGA logic domain clock input
     D         => '0',       -- 1-bit input: Input data
     IOCE      => '1',       -- 1-bit input: Data strobe input
     RST       => '0',       -- 1-bit input: Asynchronous reset input
     SHIFTIN   => cascade    -- 1-bit input: Cascade input signal for master/slave I/O
  );

end Behavioral;

 

At the moment it can receive 720p in DVI-D format and display it on an Analogue VGA output.

With the Spartan 6 FPGA you need external termination resistors if you want to receive TMDS signals - a 50 ohm resistor is needed from 3.3 V to each of the signal lines.

Also the Extended Display Identification Data (EDID) interface runs at 5V logic, so a level converter is needed.

The revision 0.1 PCB has an error on it, so I've got a v0.2 on its way. It is missing the 3.3V supply to the I2C level translator (D'oh!).

It needs eight 50 Ohm (or slightly bigger) resistors, and an HDMI socket. If you want to use EDID support you will need to add a wire bodge to power the level translator.

I'm actually surprised that it actually worked - the three channels are running at 750 Mb/s each, and the termination resistors are quite far from the FPGA - in fact it is the other side of a 0.1" header!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

посмотрите, может подойдет:

 


dvi_in.vhd
----------------------------------------------------------------------------------
-- 
-- Module Name: dvi_in.vhd - Behavioral 
--
-- Description: Design to capture raw DVI-D input
--
-- REALLY IMPORTANT NOTE - on my PCB some of the + and - differential
-- pairs are transposed to allow better routing and avioding vias. 
-- You most likely want to change the value of "invert" on the gearbox 
-- instances.
--
-- I've also got do do some work to automatically adjust the phase of the
-- bit clocks, at the moment it needs to be manually tuned to match your source
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

library UNISIM;
use UNISIM.VComponents.all;

entity dvi_in is
   Port ( clk32      : in  STD_LOGIC;
          hdmi_clk_p : in  STD_LOGIC;
          hdmi_clk_n : in  STD_LOGIC;
          hdmi_c0_p  : in  STD_LOGIC;
          hdmi_c0_n  : in  STD_LOGIC;
          hdmi_c1_p  : in  STD_LOGIC;
          hdmi_c1_n  : in  STD_LOGIC;
          hdmi_c2_p  : in  STD_LOGIC;
          hdmi_c2_n  : in  STD_LOGIC;
          hdmi_sclk  : inout  STD_LOGIC;
          hdmi_sdat  : inout  STD_LOGIC;

          red        : out std_logic_vector(2 downto 0);
          green      : out std_logic_vector(2 downto 0);
          blue       : out std_logic_vector(1 downto 0);
          hsync      : out std_logic;
          vsync      : out std_logic;

          btns       : in  std_logic_vector(3 downto 0);
          leds       : out std_logic_vector(3 downto 0));
end dvi_in;

architecture Behavioral of dvi_in is
  signal hdmi_clk             : std_logic;
  signal hdmi_clk_buffered    : std_logic;
  signal ioclock              : std_logic;
  signal serdes_strobe        : std_logic;


  signal clock_x1             : std_logic;
  signal clock_x2             : std_logic;
  signal clock_x10            : std_logic;
  signal clock_x10_unbuffered : std_logic;
  signal clock_x2_unbuffered  : std_logic;
  signal clock_x1_unbuffered  : std_logic;

  signal clk_feedback         : std_logic;
  signal pll_locked           : std_logic;
  signal sync_seen            : std_logic;

  signal c0_d       : std_logic_vector(7 downto 0);
  signal c0_c       : std_logic_vector(1 downto 0);
  signal c0_active  : std_logic;

  signal c1_d       : std_logic_vector(7 downto 0);
  signal c1_c       : std_logic_vector(1 downto 0);
  signal c1_active  : std_logic;

  signal c2_d       : std_logic_vector(7 downto 0);
  signal c2_c       : std_logic_vector(1 downto 0);
  signal c2_active  : std_logic;

  signal led_count   : unsigned( 2 downto 0)        := (others => '0');
  signal framing     : std_logic_vector(3 downto 0) := (others => '0');
  signal since_sync  : unsigned(14 downto 0)        := (others => '0');

  signal start_calibrate : std_logic;
  signal reset_delay     : std_logic;
  signal cal_start_count : unsigned(7 downto 0) := (others => '0');          

  COMPONENT input_channel
  GENERIC(
        fixed_delay     : in natural
     );
  PORT(
     clk_fabric    : IN  std_logic;
     clk_fabric_x2 : IN  std_logic;
     clk_input     : IN  std_logic;
     strobe        : IN  std_logic;
     tmds_p        : in  STD_LOGIC;
     tmds_n        : in  STD_LOGIC;
     invert        : IN  std_logic;
     framing       : IN  std_logic_vector(3 downto 0);          
     data_out      : OUT std_logic_vector(7 downto 0);
     control       : OUT std_logic_vector(1 downto 0);
     active_data   : OUT std_logic;
     sync_seen     : OUT std_logic;

     adjust_delay    : IN  std_logic;
     increase_delay  : IN  std_logic;
     reset_delay     : IN  std_logic;
     start_calibrate : IN  std_logic;          
     calibrate_busy  : OUT std_logic
     );
  END COMPONENT;

begin   
  ----------------------------------
  -- Output the decoded VGA signals
  ----------------------------------
  red   <= c0_d(7 downto 5);
  blue  <= c1_d(7 downto 6);
  green <= c2_d(7 downto 5);
  hsync <= c2_c(0);
  vsync <= c2_c(1);

  ----------------------------------
  -- Debug
  ----------------------------------
  leds <= framing;

  ----------------------------------
  -- EDID I2C signals (not implemented)
  ----------------------------------
  hdmi_sclk <= '1';
  hdmi_sdat <= '1';

------------------------------------------
-- Receive the differential clock
------------------------------------------
clk_diff_input : IBUFDS
  generic map (
     DIFF_TERM    => FALSE,
     IBUF_LOW_PWR => TRUE,
     IOSTANDARD   => "TMDS_33")
  port map (
     O  => hdmi_clk,
     I  => hdmi_clk_p,
     IB => hdmi_clk_n
  );

------------------------------------------
-- Buffer it before the PLL
------------------------------------------
BUFG_clk : BUFG port map ( I => hdmi_clk, O => hdmi_clk_buffered);

------------------------------------------
-- Generate the bit clocks for the serdes
-- 
-- Adjust the phase in a 10:2:1 ratio (e.g. 50:10:5)
------------------------------------------
PLL_BASE_inst : PLL_BASE
  generic map (
     CLKFBOUT_MULT => 10,                  
     -- Almost works with Western Digital Live @ 720p/60 -Noise on blue channel.
     --CLKOUT0_DIVIDE => 1,       CLKOUT0_PHASE => 200.0,   -- Output 10x original frequency
     --CLKOUT1_DIVIDE => 5,       CLKOUT1_PHASE => 40.0,   -- Output 2x original frequency
     --CLKOUT2_DIVIDE => 10,      CLKOUT2_PHASE => 20.0,    -- Output 1x original frequency
     -- Works with Western Digital Live @ 640x480/60Hz
     CLKOUT0_DIVIDE => 1,       CLKOUT0_PHASE => 0.0,   -- Output 10x original frequency
     CLKOUT1_DIVIDE => 5,       CLKOUT1_PHASE => 0.0,   -- Output 2x original frequency
     CLKOUT2_DIVIDE => 10,      CLKOUT2_PHASE => 0.0,    -- Output 1x original frequency
     CLK_FEEDBACK => "CLKFBOUT",                         -- Clock source to drive CLKFBIN ("CLKFBOUT" or "CLKOUT0")
     CLKIN_PERIOD => 10.0,                               -- IMPORTANT! Approx 77 MHz
     DIVCLK_DIVIDE => 1                                  -- Division value for all output clocks (1-52)
  )
     port map (
     CLKFBOUT => clk_feedback, 
     CLKOUT0  => clock_x10_unbuffered,
     CLKOUT1  => clock_x2_unbuffered,
     CLKOUT2  => clock_x1_unbuffered,
     CLKOUT3  => open,
     CLKOUT4  => open,
     CLKOUT5  => open,
     LOCKED   => pll_locked,      
     CLKFBIN  => clk_feedback,    
     CLKIN    => hdmi_clk_buffered, 
     RST      => '0'              -- 1-bit input: Reset input
  );

  BUFG_pclockx2  : BUFG port map ( I => clock_x2_unbuffered,  O => clock_x2);
  BUFG_pclock    : BUFG port map ( I => clock_x1_unbuffered,  O => clock_x1);
  BUFG_pclockx10 : BUFG port map ( I => clock_x10_unbuffered, O => clock_x10 );


------------------------------------------------
-- Buffer the clocks ready to go the serialisers
------------------------------------------------
BUFPLL_inst : BUFPLL
  generic map (
     DIVIDE => 5,         -- DIVCLK divider (1-8) !!!! IMPORTANT TO CHANGE THIS AS NEEDED !!!!
     ENABLE_SYNC => TRUE  -- Enable synchrnonization between PLL and GCLK (TRUE/FALSE) -- should be true
  )
  port map (
     IOCLK        => ioclock,               -- Clock used to receive bits
     LOCK         => open,                 
     SERDESSTROBE => serdes_strobe,         -- Clock use to load data into SERDES 
     GCLK         => clock_x2,              -- Global clock use as a reference for serdes_strobe
     LOCKED       => pll_locked,            -- When the upstream PLL is locked 
     PLLIN        => clock_x10_unbuffered   -- Clock to use for bit capture - this must be unbuffered
  );

----------------------------------------
-- c0 channel input - Carries the RED channel
----------------------------------------
input_channel_c0: input_channel GENERIC MAP(
     fixed_delay     => 30
   ) PORT MAP(
     clk_fabric      => clock_x1,
     clk_fabric_x2   => clock_x2,
     clk_input       => ioclock,
     strobe          => serdes_strobe,
     tmds_p          => hdmi_c0_p,
     tmds_n          => hdmi_c0_n,
     invert          => '0',
     framing         => framing,
     data_out        => c0_d,
     control         => c0_c,
     active_data     => c0_active,
     sync_seen       => open,
     adjust_delay    => '0',
     increase_delay  => '0',
     reset_delay     => reset_delay,
     start_calibrate => start_calibrate,
     calibrate_busy  => open
  );   

----------------------------------------
-- c1 channel input - Carries the BLUE channel
----------------------------------------

input_channel_c1: input_channel GENERIC MAP(
     fixed_delay     => 40
   ) PORT MAP(
     clk_fabric      => clock_x1,
     clk_fabric_x2   => clock_x2,
     clk_input       => ioclock,
     strobe          => serdes_strobe,
     tmds_p          => hdmi_c1_n,
     tmds_n          => hdmi_c1_p,
     invert          => '1',
     framing         => framing,
     data_out        => c1_d,
     control         => c1_c,
     active_data     => c1_active,
     sync_seen       => open,
     adjust_delay    => '0',
     increase_delay  => '0',
     reset_delay     => reset_delay,
     start_calibrate => start_calibrate,
     calibrate_busy  => open
  );   

----------------------------------------
-- c2 channel input - Carries the GREEN channel and syncs
----------------------------------------
input_channel_c2: input_channel GENERIC MAP(
     fixed_delay     => 30
   )  PORT MAP(
     clk_fabric      => clock_x1,
     clk_fabric_x2   => clock_x2,
     clk_input       => ioclock,
     strobe          => serdes_strobe,
     tmds_p          => hdmi_c2_n,
     tmds_n          => hdmi_c2_p,
     invert          => '1',
     framing         => framing,
     data_out        => c2_d,
     control         => c2_c,
     active_data     => c2_active,
     sync_seen       => sync_seen,
     adjust_delay    => '0',
     increase_delay  => '0',
     reset_delay     => reset_delay,
     start_calibrate => start_calibrate,
     calibrate_busy  => open
  );   

calibrate_preocess: process (clock_x2)
  begin
     if rising_edge(clock_x2) then
        if cal_start_count = "10000000" then
           start_calibrate <= '0';
        else
           start_calibrate <= '0';
        end if;
        if cal_start_count = "11111100" then
           reset_delay <= '0';
        else
           reset_delay <= '0';
        end if;

        if cal_start_count /= "11111111" then
           cal_start_count <= cal_start_count + 1;
        end if;
     end if;
  end process;

process(clock_x1) 
  begin
     if rising_edge(clock_x1) then
        -- Work out what we need to do to frame the TMDS data correctly
        if sync_seen = '1' then
           ------------------------------------------------------------
           -- We've just seen a sync codeword, so restart the counter
           -- This means that we are in sync
           ------------------------------------------------------------
           since_sync  <= (others => '0');
        elsif since_sync = "111111111111111" then
           ------------------------------------------------------------
           -- We haven't seen a sync in 16383 pixel cycles, so it can't 
           -- be in sync. By incrementing 'framing' we bitslip one bit.
           --            
           -- The 16k number is special, as they two sync codewords
           -- being looked for will not be seen during the VSYNC period
           -- (assuming that you are looking in the channel that 
           -- includes the encoded HSYNC/VSYNC signals 
           ------------------------------------------------------------
           if framing = "1001" then
              framing <= (others =>'0');
           else
              framing <= std_logic_vector(unsigned(framing) + 1);
           end if;
           since_sync  <= since_sync + 1;
        else
           ------------------------------------------------------------
           -- Keep counting and hoping for a sync codeword
           ------------------------------------------------------------
           since_sync  <= since_sync + 1;
        end if;

     end if;
  end process;
end Behavioral;

input_channel.vhd
----------------------------------------------------------------------------------
-- 
-- Module Name:    input_channel - Behavioral 
-- Description:    The end-to-end processing of a TMDS input channel
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
library UNISIM;
use UNISIM.VComponents.all;


entity input_channel is
  GENERIC(
        fixed_delay     : in natural
     );
   Port ( clk_fabric      : in  STD_LOGIC;
          clk_fabric_x2   : in  STD_LOGIC;
          clk_input       : in  STD_LOGIC;
          strobe          : in  STD_LOGIC;
          tmds_p          : in  STD_LOGIC;
          tmds_n          : in  STD_LOGIC;
          invert          : in  STD_LOGIC;
          framing         : in  std_logic_vector(3 downto 0);
          data_out        : out STD_LOGIC_VECTOR (7 downto 0);
          control         : out STD_LOGIC_VECTOR (1 downto 0);
          active_data     : out std_logic;
          sync_seen       : out std_logic;

          adjust_delay    : IN  std_logic;
          increase_delay  : IN  std_logic;
          reset_delay     : IN  std_logic;
          start_calibrate : IN  std_logic;          
          calibrate_busy  : OUT std_logic
);
end input_channel;

architecture Behavioral of input_channel is

  COMPONENT input_serialiser
  PORT(
     clk_fabric_x2 : IN  std_logic;
     clk_input     : IN  std_logic;
     strobe        : IN  std_logic;
     ser_input     : IN  std_logic;          
     ser_data      : OUT std_logic_vector(4 downto 0)
     );
  END COMPONENT;

  COMPONENT gearbox
  PORT(
     clk_fabric_x2 : IN  std_logic;
     framing       : IN  std_logic_vector(3 downto 0);
     invert        : IN  std_logic;
     data_in       : IN  std_logic_vector(4 downto 0);
     data_out      : OUT std_logic_vector(9 downto 0)
     );
  END COMPONENT;

  COMPONENT tmds_decode
  PORT(
     clk         : IN  std_logic;
     data_in     : IN  std_logic_vector(9 downto 0);          
     data_out    : OUT std_logic_vector(7 downto 0);
     c           : OUT std_logic_vector(1 downto 0);
     active_data : OUT std_logic
     );
  END COMPONENT;

  signal serial_data         : std_logic;
  signal raw_tmds_word       : std_logic_vector(9 downto 0);          
  signal half_words          : std_logic_vector(4 downto 0);          
begin

diff_input : IBUFDS
  generic map (
     DIFF_TERM    => FALSE,
     IBUF_LOW_PWR => TRUE,
     IOSTANDARD   => "TMDS_33")
  port map (
     O  => serial_data,
     I  => tmds_p,
     IB => tmds_n
  );

i_input_serialiser: input_serialiser PORT MAP(
     clk_fabric_x2 => clk_fabric_x2,
     clk_input     => clk_input,
     strobe        => strobe,
     ser_input     => serial_data,
     ser_data      => half_words
  );

i_gearbox: gearbox PORT MAP(
     clk_fabric_x2 => clk_fabric_x2,
     invert        => invert,
     framing       => framing,
     data_in       => half_words,
     data_out      => raw_tmds_word
  );

i_tmds_decode: tmds_decode PORT MAP(
     clk         => clk_fabric,
     data_in     => raw_tmds_word,
     data_out    => data_out,
     c           => control,
     active_data => active_data 
  );

look_for_sync: process (clk_fabric)
  begin
     if rising_edge(clk_fabric) then
        ------------------------------------------------------------
        -- Is the TMDS data one of two special sync codewords?
        ------------------------------------------------------------
        if raw_tmds_word = "1101010100" or raw_tmds_word = "0010101011" then
           sync_seen <= '1';
        else
           sync_seen <= '0';
        end if;
     end if;
  end process;
end Behavioral;

gearbox.vhd
This 'gearbox' takes 5-bit data at 2x the pixel clock, and converts it to 10-bit data at the pixel clock.
----------------------------------------------------------------------------------
--
-- Module Name:    Gearbox - Behavioral 
-- Project Name:   DVI-I Input
-- Description:  Receives the 5-bits-per-cycle data from the serialisers at twice
--               the pixel clock, then 'downshifts' the data to 10-bit words.
--
--               The 'framing' signal allows to bit-slip to different word
--               framing, allowing the design to hunt for the sync codewords.
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity gearbox is
   Port ( clk_fabric_x2 : in  STD_LOGIC;
          invert        : in  STD_LOGIC;
          framing       : in  std_logic_vector(3 downto 0);
          data_in       : in  std_logic_vector(4 downto 0);
          data_out      : out std_logic_vector(9 downto 0));
end gearbox;

architecture Behavioral of gearbox is
  signal every_other : std_logic := '0';
  signal joined      : std_logic_vector(14 downto 0);
begin

process(clk_fabric_x2) 
  begin
     if rising_edge(clk_fabric_x2) then
        if every_other = '1' then
           case framing is
              when "0000" => data_out <= joined( 9 downto 0);
              when "0001" => data_out <= joined(10 downto 1);
              when "0010" => data_out <= joined(11 downto 2);
              when "0011" => data_out <= joined(12 downto 3);
              when "0100" => data_out <= joined(13 downto 4);
              when others => NULL;
           end case;
        else
           case framing is
              when "0101" => data_out <= joined( 9 downto 0);
              when "0110" => data_out <= joined(10 downto 1);
              when "0111" => data_out <= joined(11 downto 2);
              when "1000" => data_out <= joined(12 downto 3);
              when "1001" => data_out <= joined(13 downto 4);
              when others => NULL;
           end case;
        end if;
        if invert = '1' then 
           joined <= data_in & joined(joined'high downto 5) ;
        else
           joined <= (data_in xor "11111") & joined(joined'high downto 5) ;
        end if;
        every_other <= not every_other;
     end if;
  end process;

end Behavioral;

tmds_decode.vhd
----------------------------------------------------------------------------------
-- 
-- Module Name:    tmds_decode - Behavioral 
--
-- Description: TMDS decode as per Digital Display Working Groups Digital Visual 
--              Interface Revision 1.0 section 3.3.3
--
-- This doesn't seem 100% correct - "elsif sometimes_inverted(8) = '0' then" should
-- be "elsif sometimes_inverted(8) = '1' then" according to the standard.
-- 
-- However it does actually work!
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity tmds_decode is
   Port ( clk         : in  STD_LOGIC;
          data_in     : in  STD_LOGIC_VECTOR (9 downto 0);
          data_out    : out  STD_LOGIC_VECTOR (7 downto 0);
          c           : out  STD_LOGIC_VECTOR (1 downto 0);
          active_data : out std_logic);
end tmds_decode;

architecture Behavioral of tmds_decode is
  signal data_delayed       : STD_LOGIC_VECTOR(9 downto 0);
  signal sometimes_inverted : STD_LOGIC_VECTOR(8 downto 0);
  signal next_c             : STD_LOGIC_VECTOR(1 downto 0);
  signal next_active_data   : STD_LOGIC;
begin

process(clk)
  begin
     if rising_edge(clk) then

        c           <= next_c;
        active_data <= next_active_data;

        if next_active_data = '0' then
           data_out <= (others => '0');
        elsif sometimes_inverted(8) = '0' then
           data_out(0) <= sometimes_inverted(0);
           data_out(1) <= sometimes_inverted(1) XOR sometimes_inverted(0);
           data_out(2) <= sometimes_inverted(2) XOR sometimes_inverted(1);
           data_out(3) <= sometimes_inverted(3) XOR sometimes_inverted(2);
           data_out(4) <= sometimes_inverted(4) XOR sometimes_inverted(3);
           data_out(5) <= sometimes_inverted(5) XOR sometimes_inverted(4);
           data_out(6) <= sometimes_inverted(6) XOR sometimes_inverted(5);
           data_out(7) <= sometimes_inverted(7) XOR sometimes_inverted(6);
        else
           data_out(0) <= sometimes_inverted(0);
           data_out(1) <= sometimes_inverted(1) XNOR sometimes_inverted(0);
           data_out(2) <= sometimes_inverted(2) XNOR sometimes_inverted(1);
           data_out(3) <= sometimes_inverted(3) XNOR sometimes_inverted(2);
           data_out(4) <= sometimes_inverted(4) XNOR sometimes_inverted(3);
           data_out(5) <= sometimes_inverted(5) XNOR sometimes_inverted(4);
           data_out(6) <= sometimes_inverted(6) XNOR sometimes_inverted(5);
           data_out(7) <= sometimes_inverted(7) XNOR sometimes_inverted(6);
        end if;

        if data_delayed(9) = '1' then
           sometimes_inverted <= data_delayed(8 downto 0) xor "011111111";
        else
           sometimes_inverted <= data_delayed(8 downto 0);
        end if;

        case data_in is
           when "0010101011" => next_c <= "01"; next_active_data <= '0';
           when "1101010100" => next_c <= "00"; next_active_data <= '0';
           when "0101010100" => next_c <= "10"; next_active_data <= '0';
           when "1010101011" => next_c <= "11"; next_active_data <= '0';
           when others       => next_c <= "00"; next_active_data <= '1';
        end case;

        data_delayed <= data_in;
     end if;
  end process;
end Behavioral;

input_serialiser.vhd
----------------------------------------------------------------------------------
-- 
-- Module Name: input_serialiser 
--
-- Description: A 5-bits per cycle SDR input serialiser
--
--              Maybe in the future the 'bitslip' funciton can be implemented.
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
library UNISIM;
use UNISIM.VComponents.all;

entity input_serialiser is
   Port ( clk_fabric_x2 : in  STD_LOGIC;
          clk_input     : in  STD_LOGIC;
          strobe        : in  STD_LOGIC;
          ser_data      : out  STD_LOGIC_VECTOR (4 downto 0);
          ser_input     : in STD_LOGIC);
end input_serialiser;

architecture Behavioral of input_serialiser is
  signal clk0,     clk1,     clkdiv : std_logic;
  signal cascade : std_logic;
  signal bitslip : std_logic := '0';
begin
  clkdiv <= clk_fabric_x2;
  clk0   <= clk_input;
  clk1   <= '0';

ISERDES2_master : ISERDES2
  generic map (
     BITSLIP_ENABLE => TRUE,         -- Enable Bitslip Functionality (TRUE/FALSE)
     DATA_RATE      => "SDR",        -- Data-rate ("SDR" or "DDR")
     DATA_WIDTH     => 5,            -- Parallel data width selection (2-8)
     INTERFACE_TYPE => "RETIMED",    -- "NETWORKING", "NETWORKING_PIPELINED" or "RETIMED" 
     SERDES_MODE    => "MASTER"      -- "NONE", "MASTER" or "SLAVE" 
  )
  port map (
     CFB0      => open,      -- 1-bit output: Clock feed-through route output
     CFB1      => open,      -- 1-bit output: Clock feed-through route output
     DFB       => open,       -- 1-bit output: Feed-through clock output
     FABRICOUT => open,      -- 1-bit output: Unsynchrnonized data output
     INCDEC    => open,      -- 1-bit output: Phase detector output
     -- Q1 - Q4: 1-bit (each) output: Registered outputs to FPGA logic
     Q1        => ser_data(1),
     Q2        => ser_data(2),
     Q3        => ser_data(3),
     Q4        => ser_data(4),
     SHIFTOUT  => cascade,   -- 1-bit output: Cascade output signal for master/slave I/O
     VALID     => open,      -- 1-bit output: Output status of the phase detector
     BITSLIP   => bitslip ,   -- 1-bit input: Bitslip enable input
     CE0       => '1',        -- 1-bit input: Clock enable input
     CLK0      => clk0,       -- 1-bit input: I/O clock network input
     CLK1      => clk1,       -- 1-bit input: Secondary I/O clock network input
     CLKDIV    => clkdiv,     -- 1-bit input: FPGA logic domain clock input
     D         => ser_input,  -- 1-bit input: Input data
     IOCE      => strobe,     -- 1-bit input: Data strobe input
     RST       => '0',        -- 1-bit input: Asynchronous reset input
     SHIFTIN   => '0'         -- 1-bit input: Cascade input signal for master/slave I/O
  );

ISERDES2_slave : ISERDES2
  generic map (
     BITSLIP_ENABLE => TRUE,         -- Enable Bitslip Functionality (TRUE/FALSE)
     DATA_RATE      => "SDR",        -- Data-rate ("SDR" or "DDR")
     DATA_WIDTH     => 5,            -- Parallel data width selection (2-8)
     INTERFACE_TYPE => "RETIMED",    -- "NETWORKING", "NETWORKING_PIPELINED" or "RETIMED" 
     SERDES_MODE    => "SLAVE"       -- "NONE", "MASTER" or "SLAVE" 
  )
  port map (
     CFB0      => open,      -- 1-bit output: Clock feed-through route output
     CFB1      => open,      -- 1-bit output: Clock feed-through route output
     DFB       => open,      -- 1-bit output: Feed-through clock output
     FABRICOUT => open,    -- 1-bit output: Unsynchrnonized data output
     INCDEC    => open,    -- 1-bit output: Phase detector output
     -- Q1 - Q4: 1-bit (each) output: Registered outputs to FPGA logic
     Q1        => open,
     Q2        => open,
     Q3        => open,
     Q4        => ser_data(0),
     SHIFTOUT  => open,      -- 1-bit output: Cascade output signal for master/slave I/O
     VALID     => open,      -- 1-bit output: Output status of the phase detector
     BITSLIP   => bitslip,   -- 1-bit input: Bitslip enable input
     CE0       => '1',       -- 1-bit input: Clock enable input
     CLK0      => clk0,      -- 1-bit input: I/O clock network input
     CLK1      => clk1,      -- 1-bit input: Secondary I/O clock network input
     CLKDIV    => clkdiv,    -- 1-bit input: FPGA logic domain clock input
     D         => '0',       -- 1-bit input: Input data
     IOCE      => '1',       -- 1-bit input: Data strobe input
     RST       => '0',       -- 1-bit input: Asynchronous reset input
     SHIFTIN   => cascade    -- 1-bit input: Cascade input signal for master/slave I/O
  );

end Behavioral;

Спасибо. Но тут маленькая, но очень неприятная проблема. Здесь активно применяются примитивы, существующие только у Xilinx. Данный проект без примитивов на альтеру не перенести. И меня больше всего интересует алгоритм работы блоков:

Который "избавляется" от jitter. И как работает проскальзывание битов ( bitslip).

Нашёл практически готовое текстовое описание DVI рессивера для Xilinx. Но в нём разобраться практически невозможно, ибо там FIFO память присутствует, там присутствует 1_to_5 desserilaiser, и без общего алгоритма работы приёмника всё это понять очень сложно. Пытаюсь это сделать, читаю их дадашиты, но очень сильно мешает то, что даташиты на английском. А у меня, к сожалению английский хромает.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

пробовали? (стр. 5 "Supports Digital Visual Interface (DVI)")

Не пока не пробовал.

Я хочу сам разобраться с алгоритмами. Чтобы понимать как все это работает. Не хочу просто брать готовое, и ни фига не понимать.

Изменено пользователем Flip-fl0p

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Можете меня больно ударить. Но мой мозг не хочет понимать, каким образом в https://www.altera.com/en_US/pdfs/literature/an/an236.pdf определяет битовый интервал. Вот хоть убейте не понимаю. Смысл то понятен, что при помощии 8 частот сдвинутых друг от друга мы семплируем бит данных. Но как в итоге выбирается нужная частота я не понимаю..... Судя по прочитанному, они сначала выбирают необходимую частоту из 8 сгенерированных, а потом уже проверяют данные в регистрах. Это как так ? Как можно семплировать данные, не зная что там передается ?

Попытался применить встроенный LVDS приемник (ALTLVDS_RX) но что-то он мне какой-то бред выдает. И в настройках частоты там должна строго указываться частота, с какой скоростью приходят данные. Или номинальная частота работы десерилайзера ?

Изменено пользователем Flip-fl0p

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Про паттерны Вам уже писали в 12 посте. Поиском в документе, Вами приведенном, ключевое слово pattern - известная последовательность. Это если режим DPA, если CDR, то там принцип другой.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Про паттерны Вам уже писали в 12 посте. Поиском в документе, Вами приведенном, ключевое слово pattern - известная последовательность. Это если режим DPA, если CDR, то там принцип другой.

 

Ели кратко то сначала для каждой линии находим положение фронтов битового интервала относительно тактовой (10х пиксельной) двигая автоматом IOdelay на входной ножке, а затем ставим задержку в середину найденного битового интервала. Вот это меня и смущает. Абсолютно непонятно как это реализовать, поскольку нету у Altera примитива IOdealy.

А в том апноте, что я читал применяется несколько другой алгоритм, через несколько частот семплирующих один бит. Чтобы сравнить что-то с контрольным словом, сначала надо это что-то принять. Вот мне и непонятно, как они выбрали из 8 частот ту по которой идет запись в регистры.

Изменено пользователем Flip-fl0p

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А в том апноте, что я читал применяется несколько другой алгоритм, через несколько частот семплирующих один бит. Чтобы сравнить что-то с контрольным словом, сначала надо это что-то принять. Вот мне и непонятно, как они выбрали из 8 частот ту по которой идет запись в регистры.

В той документашке используется готовая корка под названием serdes и там принцип немного другой - на pll формируется 8 частот, сдвинутых относительно друг друга на 45 градусов. По тестовой последовательности определяется центр окна данных последовательным перебором частот - это первый этап синхронизации, затем по другой последовательности определяется порядок компоновки разрядов в слове - 2 этап синхронизации.

То что Вы выделили жирным шрифтом - это может быть и не serdes, а просто скажем altdq_dqs, в котором задействован вход core_delayctrlin (6 бит вроде), с помощью которого можно перебрать разные задержки на входе (после пина). Принцип работы схожий - по известной тестовой последовательности выбирается центр окна данных.

PS/ Сам я уже не работал с альтерой больше 2-х лет, поэтому может чего и напутал.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Битовый интервал вы задаете сами, исходя из своей задачи путем программирования PLL. Эта та частота, на которой

в вашей системе идет прием данных. На PLL подается частота кадра (frame clk, допустим 100 Mhz) И повышается на

число принимаемых бит (как пример 8 бит). На выходе PLL имеем частоту 800 Mhz (период бита 1.25нс) ,

c которой происходит прием данных в SERDES. Это и есть частота семплирования.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...