commit 2e79b67236e39f53e6f20e877aee3ed8537c995d Author: Benjamin Krill Date: Mon Sep 23 10:20:49 2013 +0200 initial commit diff --git a/DRAM16XN.vhd b/DRAM16XN.vhd new file mode 100644 index 0000000..939435a --- /dev/null +++ b/DRAM16XN.vhd @@ -0,0 +1,42 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library UNISIM; +use UNISIM.Vcomponents.all; + +entity DRAM16XN is + generic (data_width : integer := 20); + port ( + DATA_IN : in std_logic_vector(data_width-1 downto 0); + ADDRESS : in std_logic_vector(3 downto 0); + ADDRESS_DP : in std_logic_vector(3 downto 0); + WRITE_EN : in std_logic; + CLK : in std_logic; + + O_DATA_OUT_DP : out std_logic_vector(data_width-1 downto 0); + O_DATA_OUT : out std_logic_vector(data_width-1 downto 0) + ); +end DRAM16XN; + +architecture DRAM16XN of DRAM16XN is +begin + RAM: for I in 0 to data_width-1 generate + I_RAM16X1D: RAM16X1D + port map ( + D => DATA_IN(I), --insert input signal + WE => WRITE_EN, --insert Write Enable signal + WCLK => CLK, --insert Write Clock signal + A0 => ADDRESS(0), --insert Address 0 signal port SPO + A1 => ADDRESS(1), --insert Address 1 signal port SPO + A2 => ADDRESS(2), --insert Address 2 signal port SPO + A3 => ADDRESS(3), --insert Address 3 signal port SPO + DPRA0 => ADDRESS_DP(0), --insert Address 0 signal dual port DPO + DPRA1 => ADDRESS_DP(1), --insert Address 1 signal dual port DPO + DPRA2 => ADDRESS_DP(2), --insert Address 2 signal dual port DPO + DPRA3 => ADDRESS_DP(3), --insert Address 3 signal dual port DPO + SPO => O_DATA_OUT(I), --insert output signal SPO + DPO => O_DATA_OUT_DP(I) --insert output signal DPO + ); + end generate; +end DRAM16XN; diff --git a/chnlbond.vhd b/chnlbond.vhd new file mode 100644 index 0000000..b556e19 --- /dev/null +++ b/chnlbond.vhd @@ -0,0 +1,155 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.dvi_package.all; + +library UNISIM; +use UNISIM.Vcomponents.all; + +entity chnlbond is + port ( + clk : in std_logic; + rst_n : in std_logic; + rawdata_i : in std_logic_vector(9 downto 0); + psaligned_i : in std_logic; + other_valid_i : in std_logic_vector(1 downto 0); + other_ready_i : in std_logic_vector(1 downto 0); + ready_o : out std_logic; + sdata_o : out std_logic_vector(9 downto 0) + ); +end chnlbond; + +architecture chnlbond of chnlbond is + signal rawdata_vld : std_logic; + signal we : std_logic; + signal wa, ra : unsigned(3 downto 0); + signal dpfo_dout : std_logic_vector(9 downto 0); + signal sdata : std_logic_vector(9 downto 0); + signal rcvd_ctkn : std_logic; + signal rcvd_ctkn_q : std_logic; + signal blnkbgn : std_logic; + signal skip_line : std_logic; + signal next_blnkbgn : std_logic; + signal ready : std_logic; + signal rawdata_vld_q : std_logic; + signal rawdata_vld_s : std_logic; + signal ra_en : std_logic; +begin + sdata_o <= sdata; + ready_o <= ready; + rawdata_vld <= other_valid_i(0) and other_valid_i(1) and psaligned_i; + + -- ---------------------------------------------------------- + -- FIFO Write Control Logic + -- ---------------------------------------------------------- + process (clk, rst_n) + begin + if rst_n = '0' then + we <= '0'; + sdata <= (others => '0'); + wa <= (others => '0'); + elsif rising_edge(clk) then + we <= rawdata_vld; + if rawdata_vld = '1' then + wa <= wa + "1"; + else + wa <= (others => '0'); + end if; + + sdata <= dpfo_dout; + end if; + end process; + + -- ---------------------------------------------------------- + -- FIFO + -- ---------------------------------------------------------- + cbfifo_i: entity work.DRAM16XN + generic map ( data_width => 10 ) + port map ( + DATA_IN => rawdata_i, + ADDRESS => std_logic_vector(wa), + ADDRESS_DP => std_logic_vector(ra), + WRITE_EN => we, + CLK => clk, + O_DATA_OUT => open, + O_DATA_OUT_DP => dpfo_dout + ); + + -- ---------------------------------------------------------- + -- FIFO read Control Logic + -- ---------------------------------------------------------- + next_blnkbgn <= skip_line and blnkbgn; + process (clk, rst_n) + begin + if rst_n = '0' then + rcvd_ctkn <= '0'; + rcvd_ctkn_q <= '0'; + ready <= '0'; + skip_line <= '0'; + rawdata_vld_q <= '0'; + rawdata_vld_s <= '0'; + elsif rising_edge(clk) then + -- --------------------------- + -- Use blank period beginning + -- as a speical marker to + -- align all channel together + -- --------------------------- + rcvd_ctkn <= '0'; + if sdata = CTRLTOKEN0 or sdata = CTRLTOKEN1 + or sdata = CTRLTOKEN2 or sdata = CTRLTOKEN3 then + rcvd_ctkn <= '1'; + end if; + rcvd_ctkn_q <= rcvd_ctkn; + blnkbgn <= rcvd_ctkn and not rcvd_ctkn_q; + + -- --------------------------- + -- skip the current line + -- --------------------------- + if rawdata_vld = '0' then + skip_line <= '0'; + elsif blnkbgn = '1' then + skip_line <= '1'; + end if; + + -- --------------------------- + -- Declare my own readiness + -- --------------------------- + if rawdata_vld = '0' then + ready <= '0'; + elsif next_blnkbgn = '1' then + ready <= '1'; + end if; + rawdata_vld_q <= rawdata_vld; + rawdata_vld_s <= rawdata_vld and not rawdata_vld_q; + end if; + end process; + + -- ---------------------------------------------------------- + -- 1. FIFO flow through first when all channels are found valid(phase aligned) + -- 2. When the speical marker on my channel is found, the fifo read is hold + -- 3. Until the same markers are found across all three channels, the fifo read resumes + -- ---------------------------------------------------------- + process (clk, rst_n) + begin + if rst_n = '0' then + ra_en <= '0'; + ra <= (others => '0'); + elsif rising_edge(clk) then + if rawdata_vld_s = '1' or (other_ready_i(0) = '1' and other_ready_i(1) = '1' and ready = '1') then + ra_en <= '1'; + elsif next_blnkbgn = '1' and not (other_ready_i(0) = '1' and other_ready_i(1) = '1' and ready = '1') then + ra_en <= '0'; + end if; + + -- --------------------------- + -- FIFO Read Address Counter + -- --------------------------- + if rawdata_vld = '0' then + ra <= (others => '0'); + elsif ra_en = '1' then + ra <= ra + "1"; + end if; + end if; + end process; + +end chnlbond; diff --git a/convert_30to15_fifo.vhd b/convert_30to15_fifo.vhd new file mode 100644 index 0000000..53b061a --- /dev/null +++ b/convert_30to15_fifo.vhd @@ -0,0 +1,143 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.dvi_package.all; + +library UNISIM; +use UNISIM.Vcomponents.all; + +entity convert_30to15_fifo is + port ( + rst : in std_logic; + clk : in std_logic; + clkx2 : in std_logic; + data_i : in std_logic_vector(29 downto 0); -- input data for 2:1 serialisation + data_o : out std_logic_vector(14 downto 0) -- 5-bit data out + ); +end convert_30to15_fifo; + +architecture convert_30to15_fifo of convert_30to15_fifo is + signal wa : std_logic_vector( 3 downto 0); + signal wa_q : std_logic_vector( 3 downto 0); + signal ra : std_logic_vector( 3 downto 0); + signal ra_q : std_logic_vector( 3 downto 0); + signal data_int : std_logic_vector(29 downto 0); + + signal rstsync_q : std_logic; + signal rstsync : std_logic; + signal rstp : std_logic; + signal sync : std_logic; + signal syncn : std_logic; + signal db : std_logic_vector(29 downto 0); + signal mux : std_logic_vector(14 downto 0); + constant ADDR0 : std_logic_vector( 3 downto 0) := "0000"; + constant ADDR1 : std_logic_vector( 3 downto 0) := "0001"; + constant ADDR2 : std_logic_vector( 3 downto 0) := "0010"; + constant ADDR3 : std_logic_vector( 3 downto 0) := "0011"; + constant ADDR4 : std_logic_vector( 3 downto 0) := "0100"; + constant ADDR5 : std_logic_vector( 3 downto 0) := "0101"; + constant ADDR6 : std_logic_vector( 3 downto 0) := "0110"; + constant ADDR7 : std_logic_vector( 3 downto 0) := "0111"; + constant ADDR8 : std_logic_vector( 3 downto 0) := "1000"; + constant ADDR9 : std_logic_vector( 3 downto 0) := "1001"; + constant ADDR10 : std_logic_vector( 3 downto 0) := "1010"; + constant ADDR11 : std_logic_vector( 3 downto 0) := "1011"; + constant ADDR12 : std_logic_vector( 3 downto 0) := "1100"; + constant ADDR13 : std_logic_vector( 3 downto 0) := "1101"; + constant ADDR14 : std_logic_vector( 3 downto 0) := "1110"; + constant ADDR15 : std_logic_vector( 3 downto 0) := "1111"; +begin + -- -------------------------------------------------- + -- Here we instantiate a 16x10 Dual Port RAM + -- and fill first it with data aligned to + -- clk domain + -- -------------------------------------------------- + fdc_wa0: FDC port map (C => clk, D => wa_q(0), CLR => rst, Q => wa(0)); + fdc_wa1: FDC port map (C => clk, D => wa_q(1), CLR => rst, Q => wa(1)); + fdc_wa2: FDC port map (C => clk, D => wa_q(2), CLR => rst, Q => wa(2)); + fdc_wa3: FDC port map (C => clk, D => wa_q(3), CLR => rst, Q => wa(3)); + + process (wa) + begin + case wa is + when ADDR0 => wa_q <= ADDR1; + when ADDR1 => wa_q <= ADDR2; + when ADDR2 => wa_q <= ADDR3; + when ADDR3 => wa_q <= ADDR4; + when ADDR4 => wa_q <= ADDR5; + when ADDR5 => wa_q <= ADDR6; + when ADDR6 => wa_q <= ADDR7; + when ADDR7 => wa_q <= ADDR8; + when ADDR8 => wa_q <= ADDR9; + when ADDR9 => wa_q <= ADDR10; + when ADDR10 => wa_q <= ADDR11; + when ADDR11 => wa_q <= ADDR12; + when ADDR12 => wa_q <= ADDR13; + when ADDR13 => wa_q <= ADDR14; + when ADDR14 => wa_q <= ADDR15; + when others => wa_q <= ADDR0; + end case; + end process; + + fifo_u: entity work.DRAM16XN + generic map (data_width => 30) + port map ( + DATA_IN => data_i, + ADDRESS => wa, + ADDRESS_DP => ra, + WRITE_EN => '1', + CLK => clk, + O_DATA_OUT => open, + O_DATA_OUT_DP => data_int + ); + + -- -------------------------------------------------- + -- Here starts clk2x domain for fifo read out + -- FIFO read is set to be once every 2 cycles of clk2x in order + -- to keep up pace with the fifo write speed + -- Also FIFO read reset is delayed a bit in order to avoid + -- underflow. + -- -------------------------------------------------- + fdc_ra0: FDRE port map (C => clkx2, D => ra_q(0), R => rstp, CE => sync, Q => ra(0)); + fdc_ra1: FDRE port map (C => clkx2, D => ra_q(1), R => rstp, CE => sync, Q => ra(1)); + fdc_ra2: FDRE port map (C => clkx2, D => ra_q(2), R => rstp, CE => sync, Q => ra(2)); + fdc_ra3: FDRE port map (C => clkx2, D => ra_q(3), R => rstp, CE => sync, Q => ra(3)); + process (ra) + begin + case ra is + when ADDR0 => ra_q <= ADDR1; + when ADDR1 => ra_q <= ADDR2; + when ADDR2 => ra_q <= ADDR3; + when ADDR3 => ra_q <= ADDR4; + when ADDR4 => ra_q <= ADDR5; + when ADDR5 => ra_q <= ADDR6; + when ADDR6 => ra_q <= ADDR7; + when ADDR7 => ra_q <= ADDR8; + when ADDR8 => ra_q <= ADDR9; + when ADDR9 => ra_q <= ADDR10; + when ADDR10 => ra_q <= ADDR11; + when ADDR11 => ra_q <= ADDR12; + when ADDR12 => ra_q <= ADDR13; + when ADDR13 => ra_q <= ADDR14; + when ADDR14 => ra_q <= ADDR15; + when others => ra_q <= ADDR0; + end case; + end process; + + fdp_rst: FDP port map (C => clkx2, D => rst, PRE => rst, Q => rstsync); + fd_rstsync: FD port map (C => clkx2, D => rstsync, Q => rstsync_q); + fd_rstp: FD port map (C => clkx2, D => rstsync_q, Q => rstp); + sync_gen: FDR port map (Q => sync, C => clkx2, R => rstp, D => syncn); + syncn <= not sync; + + fd_db: for I in 0 to 29 generate + fd_db_I: FDE port map (C => clkx2, D => data_int(I), CE => sync, Q => db(I)); + end generate; + + mux <= db(14 downto 0) when sync = '0' else db(29 downto 15); + + fd_out: for I in 0 to 14 generate + fd_outI: FD port map (C => clkx2, D => mux(I), Q => data_o(I)); + end generate; + +end convert_30to15_fifo; diff --git a/decoder.vhd b/decoder.vhd new file mode 100644 index 0000000..729fc9d --- /dev/null +++ b/decoder.vhd @@ -0,0 +1,204 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.dvi_package.all; + +library UNISIM; +use UNISIM.Vcomponents.all; + +entity decoder is + port ( + rst_n : in std_logic; -- external reset input, e.g. reset button + pclk : in std_logic; -- pixel clock + pclkx2 : in std_logic; -- double pixel rate for gear box + pclkx10 : in std_logic; -- IOCLK + serdesstrobe_i : in std_logic; -- serdesstrobe for iserdes2 + din_p : in std_logic; -- data from dvi cable + din_n : in std_logic; -- data from dvi cable + other_valid_i : in std_logic_vector(1 downto 0); -- other has valid data now + other_ready_i : in std_logic_vector(1 downto 0); -- other has detected a valid starting pixel + + valid_o : out std_logic; -- I have valid data now + ready_o : out std_logic; -- I have detected a valid new pixel + psalgnerr : out std_logic; -- Phase alignment error + c0_o : out std_logic; + c1_o : out std_logic; + de_o : out std_logic; + sdout_o : out std_logic_vector(9 downto 0); + dout_o : out std_logic_vector(7 downto 0) + ); +end decoder; + +architecture decoder of decoder is + signal rst : std_logic; + signal rxclk : std_logic; + signal flipgear : std_logic; + signal flipgearx2 : std_logic; + signal toggle : std_logic; + signal rx_toggle : std_logic; + signal raw5bit : std_logic_vector(4 downto 0); + signal raw5bit_q : std_logic_vector(4 downto 0); + signal rawword : std_logic_vector(9 downto 0); + + signal bitslipx2 : std_logic; + signal bitslip_q : std_logic; + signal bitslip : std_logic; + signal psaligned : std_logic; + + signal rawdata : std_logic_vector(9 downto 0); + signal sdata : std_logic_vector(9 downto 0); + signal ready : std_logic; + signal c0 : std_logic; + signal c1 : std_logic; + signal de : std_logic; + signal dout : std_logic_vector(7 downto 0); + signal dout_c : std_logic_vector(7 downto 0); + signal sdout : std_logic_vector(9 downto 0); + signal data : std_logic_vector(7 downto 0); +begin + rst <= not rst_n; + valid_o <= psaligned; + ready_o <= ready; + c0_o <= c0; + c1_o <= c1; + de_o <= de; + dout_o <= dout; + sdout_o <= sdout; + + -- ---------------------------------------------------------- + -- 5-bit to 10-bit gear box + -- ---------------------------------------------------------- + rx_toggle <= toggle xor flipgearx2; -- reverse hi-lo position + + process (pclkx2, rst_n) + begin + if rst_n = '0' then + toggle <= '0'; + flipgearx2 <= '0'; + raw5bit_q <= (others => '0'); + elsif rising_edge(pclkx2) then + flipgearx2 <= flipgear; + raw5bit_q <= raw5bit; + toggle <= not toggle; + + -- gear from 5 bit to 10 bit + if rx_toggle = '1' then + rawword <= raw5bit & raw5bit_q; + end if; + end if; + end process; + + -- ---------------------------------------------------------- + -- bitslip signal sync to pclkx2 + -- ---------------------------------------------------------- + process (pclkx2, rst_n) + begin + if rst_n = '0' then + bitslip_q <= '0'; + bitslipx2 <= '0'; + elsif rising_edge(pclkx2) then + bitslip_q <= bitslip; + bitslipx2 <= bitslip and not bitslip_q; + end if; + end process; + + -- ---------------------------------------------------------- + -- 1:5 de-serializer working at x2 pclk rate + -- ---------------------------------------------------------- + des_0: entity work.serdes_1_to_5_diff_data + generic map ( + DIFF_TERM => false, + BITSLIP_ENABLE => true +-- DIFF_TERM => "FALSE", +-- BITSLIP_ENABLE => "TRUE" + ) + port map ( + rst => rst, + gclk => pclkx2, + rxioclk_i => pclkx10, + datain_p => din_p, + datain_n => din_n, + use_phase_detector_i => '1', + rxserdesstrobe_i => serdesstrobe_i, + bitslip_i => bitslipx2, + data_o => raw5bit + ); + + -- ---------------------------------------------------------- + -- Doing word boundary detection here + -- ---------------------------------------------------------- + rawdata <= rawword; + + -- ---------------------------------------------------------- + -- Phase Alignment Instance + -- ---------------------------------------------------------- + phsalgn_0: entity work.phsaligner + port map ( + rst_n => rst_n, + clk => pclk, + sdata_i => rawdata, + bitslip_o => bitslip, + flipgear_o => flipgear, + psaligned_o => psaligned + ); + + -- ---------------------------------------------------------- + -- Per Channel De-skew Instance + -- ---------------------------------------------------------- + cbnd: entity work.chnlbond + port map ( + clk => pclk, + rst_n => rst_n, + rawdata_i => rawdata, + psaligned_i => psaligned, + other_valid_i => other_valid_i, + other_ready_i => other_ready_i, + ready_o => ready, + sdata_o => sdata + ); + + -- ---------------------------------------------------------- + -- performs the 10B-8B decoding function defined in DVI 1.0 + -- Specification: Section 3.3.3, Figure 3-6, page 31. + -- ---------------------------------------------------------- + data <= not sdata(7 downto 0) when sdata(9) = '1' else sdata(7 downto 0); + dout_c(0) <= data(0); + dout_c(1) <= data(1) xor data(0) when sdata(8) = '1' else (data(1) xnor data(0)); + dout_c(2) <= data(2) xor data(1) when sdata(8) = '1' else (data(2) xnor data(1)); + dout_c(3) <= data(3) xor data(2) when sdata(8) = '1' else (data(3) xnor data(2)); + dout_c(4) <= data(4) xor data(3) when sdata(8) = '1' else (data(4) xnor data(3)); + dout_c(5) <= data(5) xor data(4) when sdata(8) = '1' else (data(5) xnor data(4)); + dout_c(6) <= data(6) xor data(5) when sdata(8) = '1' else (data(6) xnor data(5)); + dout_c(7) <= data(7) xor data(6) when sdata(8) = '1' else (data(7) xnor data(6)); + process (pclk, rst_n) + begin + if rst_n = '0' then + c0 <= '0'; + c1 <= '0'; + de <= '0'; + sdout <= (others => '0'); + dout <= (others => '0'); + elsif rising_edge(pclk) then + if ready = '1' and other_ready_i = "11" then + case sdata is + when CTRLTOKEN0 => + c0 <= '0'; c1 <= '0'; de <= '0'; + when CTRLTOKEN1 => + c0 <= '1'; c1 <= '0'; de <= '0'; + when CTRLTOKEN2 => + c0 <= '0'; c1 <= '1'; de <= '0'; + when CTRLTOKEN3 => + c0 <= '1'; c1 <= '1'; de <= '0'; + when others => + dout <= dout_c; de <= '1'; + end case; + sdout <= sdata; + else + c0 <= '0'; c1 <= '0'; de <= '0'; + sdout <= (others => '0'); + dout <= (others => '0'); + end if; + end if; + end process; + +end decoder; diff --git a/dvi_decoder.vhd b/dvi_decoder.vhd new file mode 100644 index 0000000..743bb8a --- /dev/null +++ b/dvi_decoder.vhd @@ -0,0 +1,171 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.dvi_package.all; + +library UNISIM; +use UNISIM.Vcomponents.all; + +entity dvi_decoder is + port ( + ext_rst : in std_logic; -- external reset input, e.g. reset button + + tmdsclk_p : in std_logic; -- tmds clock + tmdsclk_n : in std_logic; -- tmds clock + din_p : in std_logic_vector(COLOR_CNT-1 downto 0); -- data in + din_n : in std_logic_vector(COLOR_CNT-1 downto 0); -- data in + + reset_n : out std_logic; -- rx reset_n + pclk_o : out std_logic; -- regenerated pixel clock + pclkx2_o : out std_logic; -- double rate pixel clock + pclkx10_o : out std_logic; -- 10x pixel as IOCLK + + pll_lckd_o : out std_logic; -- send pll_lckd out so it can be fed into a different BUFPLL + serdesstrobe_o : out std_logic; -- BUFPLL serdesstrobe output + tmdsclk_o : out std_logic; -- TMDS cable clock + + hsync_o : out std_logic; -- hsync data + vsync_o : out std_logic; -- vsync data + dat_en_o : out std_logic; -- data enable + valid_o : out std_logic_vector(COLOR_CNT-1 downto 0); + ready_o : out std_logic_vector(COLOR_CNT-1 downto 0); + psalgnerr_o : out std_logic; + sdout_o : out sdat_t(COLOR_CNT-1 downto 0); + color_o : out color_t(COLOR_CNT-1 downto 0) -- pixel data out + ); +end dvi_decoder; + +architecture dvi_decoder of dvi_decoder is + signal rst_n : std_logic; + signal rxclk_b : std_logic; + signal rxclk : std_logic; + signal clkfbout : std_logic; + signal pclk : std_logic; + signal pclkx2 : std_logic; + signal pclkx10 : std_logic; + signal pllclk0 : std_logic; + signal pllclk1 : std_logic; + signal pllclk2 : std_logic; + signal pll_locked : std_logic; + signal bufpll_lock : std_logic; + signal serdesstrobe : std_logic; + + signal ready : std_logic_vector(COLOR_CNT-1 downto 0); + signal hsync : std_logic_vector(COLOR_CNT-1 downto 0); + signal vsync : std_logic_vector(COLOR_CNT-1 downto 0); + signal valid : std_logic_vector(COLOR_CNT-1 downto 0); + type matrix_t is array (natural range <>) of std_logic_vector(COLOR_CNT-2 downto 0); + signal other_ready : matrix_t(COLOR_CNT-1 downto 0); + signal other_valid : matrix_t(COLOR_CNT-1 downto 0); + signal psalgnerr : std_logic_vector(COLOR_CNT-1 downto 0); + signal dat_en : std_logic_vector(COLOR_CNT-1 downto 0); +begin + -- ---------------------------------------------------------- + -- I/O mapping + -- ---------------------------------------------------------- + rst_n <= bufpll_lock; + reset_n <= rst_n; + pclk_o <= pclk; + pclkx2_o <= pclkx2; + pclkx10_o <= pclkx10; + pll_lckd_o <= pll_locked; + serdesstrobe_o <= serdesstrobe; + valid_o <= valid; + ready_o <= ready; + psalgnerr_o <= psalgnerr(RED) or psalgnerr(GREEN) or psalgnerr(BLUE); + dat_en_o <= dat_en(BLUE); + hsync_o <= hsync(BLUE); + vsync_o <= vsync(BLUE); + + -- ---------------------------------------------------------- + -- clocking + -- ---------------------------------------------------------- + ibuf_rxclk: IBUFDS + generic map ( IOSTANDARD => "TMDS_33", DIFF_TERM => false ) + port map ( i => tmdsclk_p, ib => tmdsclk_n, o => rxclk_b ); + + bufio_tmdsclk_0: BUFIO2 + generic map ( DIVIDE_BYPASS => true, DIVIDE => 1 ) + port map ( DIVCLK => rxclk, IOCLK => open, SERDESSTROBE => open, I => rxclk_b ); + + tmdsclk_bufg: BUFG port map (I => rxclk, O => tmdsclk_o); + + -- PLL is used to generate three clocks: + -- 1. pclk: same rate as TMDS clock + -- 2. pclkx2: double rate of pclk used for 5:10 soft gear box and ISERDES DIVCLK + -- 3. pclkx10: 10x rate of pclk used as IO clock + PLL_ISERDES: PLL_BASE + generic map ( + CLKIN_PERIOD => 10.0, + CLKFBOUT_MULT => 10, -- set VCO to 10x of CLKIN + CLKOUT0_DIVIDE => 1, + CLKOUT1_DIVIDE => 10, + CLKOUT2_DIVIDE => 5, + COMPENSATION => "INTERNAL" + ) + port map ( + CLKFBOUT => clkfbout, + CLKOUT0 => pllclk0, + CLKOUT1 => pllclk1, + CLKOUT2 => pllclk2, + CLKOUT3 => open, + CLKOUT4 => open, + CLKOUT5 => open, + LOCKED => pll_locked, + CLKFBIN => clkfbout, + CLKIN => rxclk, + RST => ext_rst + ); + + --Pixel Rate clock buffer + pclkbufg: BUFG port map ( I => pllclk1, O => pclk); + -- 2x pclk is going to be used to drive IOSERDES2 DIVCLK + pclkx2bufg: BUFG port map (I => pllclk2, O => pclkx2); + + -- 10x pclk is used to drive IOCLK network so a bit rate reference + -- can be used by IOSERDES2 + ioclk_buf: BUFPLL + generic map( DIVIDE => 5 ) + port map ( + PLLIN => pllclk0, + GCLK => pclkx2, + LOCKED => pll_locked, + IOCLK => pclkx10, + SERDESSTROBE => serdesstrobe, + LOCK => bufpll_lock + ); + + -- ---------------------------------------------------------- + -- decoder mapping + -- ---------------------------------------------------------- + other_valid(RED) <= valid(BLUE) & valid(GREEN); + other_valid(GREEN) <= valid(BLUE) & valid(RED); + other_valid(BLUE) <= valid(RED) & valid(GREEN); + other_ready(RED) <= ready(BLUE) & ready(GREEN); + other_ready(GREEN) <= ready(BLUE) & ready(RED); + other_ready(BLUE) <= ready(RED) & ready(GREEN); + dec: for I in 0 to COLOR_CNT-1 generate + decoder: entity work.decoder + port map ( + rst_n => rst_n, + pclk => pclk, + pclkx2 => pclkx2, + pclkx10 => pclkx10, + serdesstrobe_i => serdesstrobe, + din_p => din_p(I), + din_n => din_n(I), + other_valid_i => other_valid(I), + other_ready_i => other_ready(I), + + valid_o => valid(I), + ready_o => ready(I), + psalgnerr => psalgnerr(I), + c0_o => hsync(I), + c1_o => vsync(I), + de_o => dat_en(I), + sdout_o => sdout_o(I), + dout_o => color_o(I) + ); + end generate dec; + +end dvi_decoder; diff --git a/dvi_encoder.vhd b/dvi_encoder.vhd new file mode 100644 index 0000000..5819e7a --- /dev/null +++ b/dvi_encoder.vhd @@ -0,0 +1,111 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.dvi_package.all; + +library UNISIM; +use UNISIM.Vcomponents.all; + +entity dvi_encoder is + port ( + rst_n : in std_logic; -- external reset input, e.g. reset button + pclk : in std_logic; -- pixel clock + pclkx2 : in std_logic; -- double pixel rate for gear box + pclkx10 : in std_logic; -- IOCLK + serdesstrobe_i : in std_logic; -- serdesstrobe for iserdes2 + color_i : in color_t(COLOR_CNT-1 downto 0); -- pixel data out + hsync_i : in std_logic; -- hsync data + vsync_i : in std_logic; -- vsync data + dat_en_i : in std_logic; -- data enable + tmds_p : out std_logic_vector(3 downto 0); -- tmds + tmds_n : out std_logic_vector(3 downto 0) -- tmds + ); +end dvi_encoder; + +architecture dvi_encoder of dvi_encoder is + signal rst : std_logic; + signal toggle : std_logic; + signal tmdsclkint : std_logic_vector(4 downto 0); + signal data : sdat_t(COLOR_CNT-1 downto 0); + signal sdata : std_logic_vector(29 downto 0); + type data_5bit_t is array(natural range <>) of std_logic_vector(4 downto 0); + signal tmds_data : data_5bit_t(3 downto 0); + signal tmdsint : std_logic_vector(3 downto 0); + signal tmds_clk : std_logic; +begin + rst <= not rst_n; + -- ---------------------------------------------------------- + -- Forward TMDS Clock Using OSERDES2 block + -- ---------------------------------------------------------- + process (pclkx2, rst_n) + begin + if rst_n = '0' then + toggle <= '0'; + tmdsclkint <= (others => '0'); + elsif rising_edge(pclkx2) then + toggle <= not toggle; + if toggle = '1' then + tmdsclkint <= (others => '1'); + else + tmdsclkint <= (others => '0'); + end if; + end if; + end process; + + clkout: entity work.serdes_n_to_1 + generic map (SF => 5) + port map ( + ioclk => pclkx10, + gclk => pclkx2, + rst => rst, + serdesstrobe_i => serdesstrobe_i, + data_i => tmdsclkint, + data_o => tmds_clk + ); + + TMDS3: OBUFDS port map (I => tmds_clk, O => tmds_p(3), OB => tmds_n(3)); -- clock + + -- ---------------------------------------------------------- + -- Forward TMDS Data: 3 channels + -- ---------------------------------------------------------- + forward: for I in 0 to COLOR_CNT-1 generate + oserdes_I: entity work.serdes_n_to_1 + generic map (SF => 5) + port map ( + ioclk => pclkx10, + gclk => pclkx2, + rst => rst, + serdesstrobe_i => serdesstrobe_i, + data_i => tmds_data(I), + data_o => tmdsint(I) + ); + + TMDS_I: OBUFDS port map (I => tmdsint(I), O => tmds_p(I), OB => tmds_n(I)); + + enc_I: entity work.encoder + port map ( + clk => pclk, + rst_n => rst_n, + data_i => color_i(I), + c0 => hsync_i, + c1 => vsync_i, + de => dat_en_i, + data_o => data(I) + ); + end generate; + + sdata <= data(RED)(9 downto 5) & data(GREEN)(9 downto 5) & data(BLUE)(9 downto 5) + & data(RED)(4 downto 0) & data(GREEN)(4 downto 0) & data(BLUE)(4 downto 0); + + pixel2x: entity work.convert_30to15_fifo + port map ( + rst => rst, + clk => pclk, + clkx2 => pclkx2, + data_i => sdata, + data_o(14 downto 10) => tmds_data(2), + data_o( 9 downto 5) => tmds_data(1), + data_o( 4 downto 0) => tmds_data(0) + ); + +end dvi_encoder; diff --git a/dvi_package.vhd b/dvi_package.vhd new file mode 100644 index 0000000..fdaa4ca --- /dev/null +++ b/dvi_package.vhd @@ -0,0 +1,18 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +package dvi_package is + constant COLOR_CNT : integer := 3; + constant RED : natural := 2; + constant GREEN : natural := 1; + constant BLUE : natural := 0; + + constant CTRLTOKEN0 : std_logic_vector(9 downto 0) := "1101010100"; + constant CTRLTOKEN1 : std_logic_vector(9 downto 0) := "0010101011"; + constant CTRLTOKEN2 : std_logic_vector(9 downto 0) := "0101010100"; + constant CTRLTOKEN3 : std_logic_vector(9 downto 0) := "1010101011"; + + type sdat_t is array (natural range <>) of std_logic_vector(9 downto 0); + type color_t is array (natural range <>) of std_logic_vector(7 downto 0); +end package; diff --git a/encoder.vhd b/encoder.vhd new file mode 100644 index 0000000..c6e4572 --- /dev/null +++ b/encoder.vhd @@ -0,0 +1,179 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.dvi_package.all; + +library UNISIM; +use UNISIM.Vcomponents.all; + +entity encoder is + port ( + clk : in std_logic; + rst_n : in std_logic; + data_i : in std_logic_vector(7 downto 0); + c0 : in std_logic; + c1 : in std_logic; + de : in std_logic; + data_o : out std_logic_vector(9 downto 0) + ); +end encoder; + +architecture encoder of encoder is + signal n1d : unsigned(3 downto 0); + signal data_iq : std_logic_vector(7 downto 0); + signal decision1 : std_logic; + signal q_m : std_logic_vector(8 downto 0); + signal n0q_m : unsigned(3 downto 0); -- number of 1s and 0s for q_m + signal n1q_m : unsigned(3 downto 0); -- number of 1s and 0s for q_m + signal n1q_i : unsigned(3 downto 0); -- number of 1s and 0s for q_m + signal cnt : unsigned(4 downto 0); -- disparity counter, MSB is the sign bit + signal decision2 : std_logic; + signal decision3 : std_logic; + type usigned_t is array(natural range <>) of unsigned(3 downto 0); + signal data_iu : usigned_t(7 downto 0); + signal q_mu : usigned_t(8 downto 0); + + signal de_q, de_reg : std_logic; + signal c0_q, c1_q : std_logic; + signal c0_reg, c1_reg : std_logic; + signal c1c0 : std_logic_vector(1 downto 0); + signal q_m_reg : std_logic_vector(8 downto 0); + signal data_oq : std_logic_vector(9 downto 0); +begin + -- ---------------------------------------------------------- + -- Counting number of 1s and 0s for each incoming pixel + -- component. Pipe line the result. + -- Register Data Input so it matches the pipe lined adder + -- output + -- ---------------------------------------------------------- + tounsigned0: for I in 0 to 7 generate + data_iu(I)(3 downto 1) <= "000"; + data_iu(I)(0 downto 0) <= unsigned(data_i(I downto I)); + end generate; + process (clk, rst_n) + begin + if rst_n = '0' then + n1d <= (others => '0'); + data_iq <= (others => '0'); + elsif rising_edge(clk) then + n1d <= data_iu(0) + data_iu(1) + data_iu(2) + data_iu(3) + + data_iu(4) + data_iu(5) + data_iu(6) + data_iu(7); + data_iq <= data_i; + end if; + end process; + + -- ---------------------------------------------------------- + -- Stage 1: 8 bit -> 9 bit + -- Refer to DVI 1.0 Specification, page 29, Figure 3-5 + -- ---------------------------------------------------------- + decision1 <= '1' when n1d > x"4" or (n1d = x"4" and data_iq(0) = '0') else '0'; + q_m(0) <= data_iq(0); + q_m(1) <= (q_m(0) xnor data_iq(1)) when decision1 = '1' else q_m(0) xor data_iq(1); + q_m(2) <= (q_m(1) xnor data_iq(2)) when decision1 = '1' else q_m(1) xor data_iq(2); + q_m(3) <= (q_m(2) xnor data_iq(3)) when decision1 = '1' else q_m(2) xor data_iq(3); + q_m(4) <= (q_m(3) xnor data_iq(4)) when decision1 = '1' else q_m(3) xor data_iq(4); + q_m(5) <= (q_m(4) xnor data_iq(5)) when decision1 = '1' else q_m(4) xor data_iq(5); + q_m(6) <= (q_m(5) xnor data_iq(6)) when decision1 = '1' else q_m(5) xor data_iq(6); + q_m(7) <= (q_m(6) xnor data_iq(7)) when decision1 = '1' else q_m(6) xor data_iq(7); + q_m(8) <= '0' when decision1 = '1' else '1'; + + -- ---------------------------------------------------------- + -- Stage 2: 9 bit -> 10 bit + -- Refer to DVI 1.0 Specification, page 29, Figure 3-5 + -- ---------------------------------------------------------- + tounsigned1: for I in 0 to 8 generate + q_mu(I)(3 downto 1) <= "000"; + q_mu(I)(0 downto 0) <= unsigned(q_m(I downto I)); + end generate; + n1q_i <= q_mu(0) + q_mu(1) + q_mu(2) + q_mu(3) + q_mu(4) + q_mu(5) + q_mu(6) + q_mu(7); + process (clk, rst_n) + begin + if rst_n = '0' then + n1q_m <= (others => '0'); + n0q_m <= (others => '0'); + elsif rising_edge(clk) then + n1q_m <= n1q_i; + n0q_m <= x"8" - n1q_i; + end if; + end process; + + decision2 <= '1' when cnt = "00000" or n1q_m = n0q_m else '0'; + -- ---------------------------------------------------------- + -- [(cnt > 0) and (N1q_m > N0q_m)] or [(cnt < 0) and (N0q_m > N1q_m)] + -- ---------------------------------------------------------- + decision3 <= '1' when (cnt(4) = '0' and n1q_m > n0q_m) or (cnt(4) = '1' and n0q_m > n1q_m) else '0'; + + -- -------------------------- + -- pipe line alignment + -- -------------------------- + process (clk, rst_n) + begin + if rst_n = '0' then + de_q <= '0'; + de_reg <= '0'; + c0_q <= '0'; + c0_reg <= '0'; + c1_q <= '0'; + c1_reg <= '0'; + q_m_reg <= (others => '0'); + elsif rising_edge(clk) then + de_q <= de; + de_reg <= de_q; + + c0_q <= c0; + c0_reg <= c0_q; + c1_q <= c1; + c1_reg <= c1_q; + + q_m_reg <= q_m; + end if; + end process; + + -- -------------------------- + -- 10-bit out + -- disparity counter + -- -------------------------- + process (clk, rst_n) + begin + if rst_n = '0' then + data_oq <= (others => '0'); + cnt <= (others => '0'); + elsif rising_edge(clk) then + if de_reg = '1' then + if decision2 = '1' then + data_oq(9) <= not q_m_reg(8); + data_oq(8) <= q_m_reg(8); + if q_m_reg(8) = '1' then + data_oq(7 downto 0) <= q_m_reg(7 downto 0); + cnt <= cnt + n1q_m - n0q_m; + else + data_oq(7 downto 0) <= not q_m_reg(7 downto 0); + cnt <= cnt + n0q_m - n1q_m; + end if; + elsif decision3 = '1' then + data_oq(9) <= '1'; + data_oq(8) <= q_m_reg(8); + data_oq(7 downto 0) <= not q_m_reg(7 downto 0); + cnt <= cnt + (q_m_reg(8) & '0') + (n0q_m - n1q_m); + else + data_oq(9) <= '0'; + data_oq(8) <= q_m_reg(8); + data_oq(7 downto 0) <= q_m_reg(7 downto 0); + cnt <= cnt - (not q_m_reg(8) & '0') + (n1q_m - n0q_m); + end if; + else + case c1c0 is + when "00" => data_oq <= CTRLTOKEN0; + when "01" => data_oq <= CTRLTOKEN1; + when "10" => data_oq <= CTRLTOKEN2; + when others => data_oq <= CTRLTOKEN3; + end case; + cnt <= (others => '0'); + end if; + end if; + end process; + c1c0 <= c1_reg & c0_reg; + + data_o <= data_oq; + +end encoder; diff --git a/phsaligner.vhd b/phsaligner.vhd new file mode 100644 index 0000000..72bb337 --- /dev/null +++ b/phsaligner.vhd @@ -0,0 +1,221 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.dvi_package.all; + +library UNISIM; +use UNISIM.Vcomponents.all; + +entity phsaligner is + generic ( + OPENEYE_CNT_WD : integer := 3; -- valid open eye counter width + CTKNCNTWD : integer := 7; -- Control Token Counter Width + SRCHTIMERWD : integer := 12 -- Idle Timer Width + ); + port ( + rst_n : in std_logic; + clk : in std_logic; + sdata_i : in std_logic_vector(9 downto 0); + flipgear_o : out std_logic; + bitslip_o : out std_logic; + psaligned_o : out std_logic + ); +end phsaligner; + +architecture phsaligner of phsaligner is + signal flipgear : std_logic; + signal bitslip : std_logic; + signal psaligned : std_logic; + + signal rcvd_ctkn : std_logic; + signal rcvd_ctkn_q : std_logic; + signal blnkbgn : std_logic; -- blank period begins + + signal ctkn_srh_timer : unsigned(SRCHTIMERWD-1 downto 0); + signal ctkn_srh_rst : std_logic; -- FSM output + signal ctkn_counter : unsigned(CTKNCNTWD-1 downto 0); + signal ctkn_cnt_rst : std_logic; -- FSM output + signal ctkn_srh_tout : std_logic; + signal ctkn_cnt_tout : std_logic; + + constant BLNKPRD_CNT_WD : integer := 1; + signal blnkprd_cnt : unsigned(BLNKPRD_CNT_WD-1 downto 0) := (others => '0'); + signal bitslip_cnt : unsigned(2 downto 0); + + type sm_t is (INIT, SEARCH, BITSLIPS, RCVDCTKN, BLNKPRD, PSALGND); + signal sm_c : sm_t; + signal sm_n : sm_t; +begin + flipgear_o <= flipgear; + bitslip_o <= bitslip; + psaligned_o <= psaligned; + -- ---------------------------------------------------------- + -- Control Token Detection + -- ---------------------------------------------------------- + process (clk, rst_n) + begin + if rst_n = '0' then + rcvd_ctkn <= '0'; + rcvd_ctkn_q <= '0'; + blnkbgn <= '0'; + elsif rising_edge(clk) then + rcvd_ctkn <= '0'; + if sdata_i = CTRLTOKEN0 or sdata_i = CTRLTOKEN1 + or sdata_i = CTRLTOKEN2 or sdata_i = CTRLTOKEN3 then + rcvd_ctkn <= '1'; + end if; + rcvd_ctkn_q <= rcvd_ctkn; + blnkbgn <= rcvd_ctkn and not rcvd_ctkn_q; + end if; + end process; + + -- ---------------------------------------------------------- + -- Control Token Search Timer + -- + -- DVI 1.0 Spec. says periodic blanking should start + -- no less than every 50ms or 20HZ + -- 2^24 of 74.25MHZ cycles is about 200ms + -- ---------------------------------------------------------- + process (clk, rst_n) + begin + if rst_n = '0' then + ctkn_srh_timer <= (others => '0'); + ctkn_srh_tout <= '0'; + elsif rising_edge(clk) then + if ctkn_srh_rst = '1' then + ctkn_srh_timer <= (others => '0'); + else + ctkn_srh_timer <= ctkn_srh_timer + "1"; + end if; + + ctkn_srh_tout <= '0'; + if ctkn_srh_timer = (SRCHTIMERWD-1 downto 0 => '1') then + ctkn_srh_tout <= '1'; + end if; + end if; + end process; + + -- ---------------------------------------------------------- + -- Contorl Token Event Counter + -- + -- DVI 1.0 Spec. says the minimal blanking period + -- is at least 128 pixels long in order to achieve + -- synchronization + -- + -- HDMI reduces this to as little as 8 + -- ---------------------------------------------------------- + process (clk, rst_n) + begin + if rst_n = '0' then + ctkn_counter <= (others => '0'); + ctkn_cnt_tout <= '0'; + elsif rising_edge(clk) then + if ctkn_cnt_rst = '1' then + ctkn_counter <= (others => '0'); + else + ctkn_counter <= ctkn_counter + "1"; + end if; + + ctkn_cnt_tout <= '0'; + if ctkn_srh_timer = (CTKNCNTWD-1 downto 0 => '1') then + ctkn_cnt_tout <= '1'; + end if; + end if; + end process; + + -- ---------------------------------------------------------- + -- Below starts the phase alignment state machine + -- ---------------------------------------------------------- + process (clk, rst_n) + begin + if rst_n = '0' then + sm_c <= INIT; + elsif rising_edge(clk) then + sm_c <= sm_n; + end if; + end process; + + -- ---------------------------------------------------------- + -- Counter counts number of blank period detected + -- in order to qualify the bitslip position + -- ---------------------------------------------------------- + process (clk, rst_n) + begin + if rst_n = '0' then + sm_n <= INIT; + elsif rising_edge(clk) then + case sm_c is + when INIT => + if ctkn_srh_tout = '1' then + sm_n <= SEARCH; + end if; + when SEARCH => + if blnkbgn = '1' then + sm_n <= RCVDCTKN; + elsif ctkn_srh_tout = '1' then + sm_n <= BITSLIPS; + end if; + when BITSLIPS => + sm_n <= SEARCH; + when RCVDCTKN => + if rcvd_ctkn = '1' then + if ctkn_cnt_tout = '1' then + sm_n <= BLNKPRD; + end if; + else + sm_n <= SEARCH; + end if; + when BLNKPRD => + if blnkprd_cnt = (BLNKPRD_CNT_WD-1 downto 0 => '1') then + sm_n <= PSALGND; + else + sm_n <= SEARCH; + end if; + when PSALGND => + sm_n <= PSALGND; -- Phase aligned so hang around here + end case; + end if; + end process; + + process (clk, rst_n) + begin + if rst_n = '0' then + psaligned <= '0'; -- phase alignment success flag + bitslip <= '0'; + ctkn_srh_rst <= '1'; -- control token search timer reset + ctkn_cnt_rst <= '1'; -- control token counter reset + bitslip_cnt <= (others => '0'); + flipgear <= '0'; + blnkprd_cnt <= (others => '0'); + elsif rising_edge(clk) then + case sm_c is + when INIT => + ctkn_srh_rst <= '0'; + ctkn_cnt_rst <= '1'; + psaligned <= '0'; + bitslip <= '0'; + bitslip_cnt <= (others => '0'); + flipgear <= '0'; + blnkprd_cnt <= (others => '0'); + when SEARCH => + ctkn_srh_rst <= '0'; + ctkn_cnt_rst <= '1'; + bitslip <= '0'; + psaligned <= '0'; + when BITSLIPS => + ctkn_srh_rst <= '1'; + bitslip <= '1'; + bitslip_cnt <= bitslip_cnt + "1"; + flipgear <= bitslip_cnt(2); -- bitslip has toggled for 4 times + when RCVDCTKN => + ctkn_srh_rst <= '0'; + ctkn_cnt_rst <= '0'; + when BLNKPRD => + blnkprd_cnt <= blnkprd_cnt + "1"; + when PSALGND => + psaligned <= '1'; + end case; + end if; + end process; + +end phsaligner; diff --git a/serdes_1_to_5_diff_data.vhd b/serdes_1_to_5_diff_data.vhd new file mode 100644 index 0000000..2eac03a --- /dev/null +++ b/serdes_1_to_5_diff_data.vhd @@ -0,0 +1,320 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library UNISIM; +use UNISIM.Vcomponents.all; + +entity serdes_1_to_5_diff_data is + generic ( + DIFF_TERM : boolean := true; + SIM_TAP_DELAY : integer := 49; + BITSLIP_ENABLE : boolean := false ); + port ( + rst : in std_logic; -- Reset line + gclk : in std_logic; -- Global clock + rxioclk_i : in std_logic; -- IO Clock network + datain_p : in std_logic; -- Input from LVDS receiver pin + datain_n : in std_logic; -- Input from LVDS receiver pin + use_phase_detector_i : in std_logic; -- '1' enables the phase detector logic + rxserdesstrobe_i : in std_logic; -- Parallel data capture strobe + bitslip_i : in std_logic; -- Bitslip control line + data_o : out std_logic_vector(4 downto 0) -- Output data + ); +end serdes_1_to_5_diff_data; + +architecture serdes_1_to_5_diff_data of serdes_1_to_5_diff_data is + type sm_cal_t is (IDLE, CALIBRATE, IODELAY_RST, IODELAY_WAIT, + IODELAY_WAIT_OCCASIONAL_ENABLE, CAL_SLAVE, + WAIT_COMMAND_ACCEPTED, IODELAY_WAIT_ALL); + signal sm_cal : sm_cal_t; + + signal cal_cnt : unsigned(8 downto 0); + signal cal_enable : std_logic; + signal data_in : std_logic; + signal data_cal_master : std_logic; + signal data_cal_sint : std_logic; + signal data_busy : std_logic; + signal data_busy_q : std_logic; + signal data_rst : std_logic; + signal data_flag : std_logic; + signal data_ce : std_logic; + signal data_inc : std_logic; + signal data_ce_int : std_logic; + signal data_valid : std_logic; + signal data_valid_q : std_logic; + signal data_incdec : std_logic; + signal data_incdec_q : std_logic; + signal pdcounter : unsigned(4 downto 0); + signal ddly_s : std_logic; + signal ddly_m : std_logic; + signal pd_edge : std_logic; + signal cascade : std_logic; +begin + -- ---------------------------------------------------------- + -- IDELAY Calibration FSM + -- ---------------------------------------------------------- + process (gclk, rst) + begin + if rst = '1' then + sm_cal <= IDLE; + cal_cnt <= (others => '0'); + cal_enable <= '0'; + data_cal_master <= '0'; + data_cal_sint <= '0'; + data_rst <= '0'; + elsif rising_edge(gclk) then + cal_cnt <= cal_cnt + 1; + if cal_cnt(8) = '1' then + cal_cnt <= (others => '0'); + end if; + cal_enable <= cal_enable; + if cal_cnt(5) = '1' then + cal_enable <= '1'; + end if; + + case sm_cal is + when IDLE => + if cal_enable = '1' then + data_cal_master <= '0'; + data_cal_sint <= '0'; + data_rst <= '0'; + if data_busy_q = '0' then + sm_cal <= CALIBRATE; + end if; + end if; + when CALIBRATE => + data_cal_master <= '1'; + data_cal_sint <= '1'; + if data_busy_q = '1' then + sm_cal <= IODELAY_RST; + end if; + when IODELAY_RST => + data_cal_master <= '0'; + data_cal_sint <= '0'; + if data_busy_q = '0' then + data_rst <= '1'; + sm_cal <= IODELAY_WAIT; + end if; + when IODELAY_WAIT => + data_rst <= '0'; + if data_busy_q = '0' then + sm_cal <= IODELAY_WAIT_OCCASIONAL_ENABLE; + end if; + when IODELAY_WAIT_OCCASIONAL_ENABLE => + if cal_cnt(8) = '1' then + sm_cal <= CAL_SLAVE; + end if; + when CAL_SLAVE => + if data_busy_q = '0' then + data_cal_sint <= '1'; + sm_cal <= WAIT_COMMAND_ACCEPTED; + end if; + when WAIT_COMMAND_ACCEPTED => + data_cal_sint <= '0'; + if data_busy_q = '1' then + sm_cal <= IODELAY_WAIT_ALL; + end if; + when IODELAY_WAIT_ALL => + data_cal_sint <= '0'; + if data_busy_q = '0' then + sm_cal <= IODELAY_WAIT_OCCASIONAL_ENABLE; + end if; + end case; + end if; + end process; + + -- Per-bit phase detection state machine + process (gclk, rst) + begin + if rst = '1' then + data_busy_q <= '0'; + data_flag <= '0'; + pdcounter <= "10000"; + elsif rising_edge(gclk) then + data_busy_q <= data_busy; + + if use_phase_detector_i = '1' then + data_incdec_q <= data_incdec; + data_valid_q <= data_valid; + + if data_ce_int = '1' then + data_ce <= '1'; + else + data_ce <= '0'; + end if; + + if sm_cal = IODELAY_WAIT_ALL then + data_flag <= '0'; + elsif sm_cal /= IODELAY_WAIT_OCCASIONAL_ENABLE or data_busy_q = '1' then + -- Reset filter if state machine issues a cal command or unit is busy + pdcounter <= "10000"; + data_ce_int <= '0'; + elsif pdcounter = "11111" and data_flag = '0' then + -- Filter has reached positive max - increment the tap count + data_ce_int <= '1'; + data_inc <= '1'; + data_flag <= '1'; + pdcounter <= "10000"; + elsif pdcounter = "00000" and data_flag = '0' then + -- Filter has reached negative max - decrement the tap count + data_ce_int <= '1'; + data_inc <= '0'; + data_flag <= '1'; + pdcounter <= "10000"; + elsif data_valid_q = '1' then + -- increment filter + data_ce_int <= '0'; + if data_incdec_q = '1' and pdcounter /= "11111" then + pdcounter <= pdcounter + "00001"; + elsif data_incdec_q = '0' and pdcounter /= "00000" then + -- decrement filter + pdcounter <= pdcounter + "11111"; + end if; + else + data_ce_int <= '0'; + end if; + else + data_ce <= '0'; + --data_inc <= '0'; + end if; + end if; + end process; + + data_in_0: IBUFDS + generic map ( DIFF_TERM => DIFF_TERM ) + port map ( I => datain_p, IB => datain_n, O => data_in ); + + -- ---------------------------------------------------------- + -- Master IDELAY + -- ---------------------------------------------------------- + iodelay_m: IODELAY2 + generic map ( + DATA_RATE => "SDR", + IDELAY_VALUE => 0, + IDELAY2_VALUE => 0, + IDELAY_MODE => "NORMAL", + ODELAY_VALUE => 0, + IDELAY_TYPE => "DIFF_PHASE_DETECTOR", + COUNTER_WRAPAROUND => "STAY_AT_LIMIT", --("WRAPAROUND"), + DELAY_SRC => "IDATAIN", + SERDES_MODE => "MASTER", + SIM_TAPDELAY_VALUE => SIM_TAP_DELAY) + port map ( + IDATAIN => data_in, -- data from IBUFDS + TOUT => open, -- tri-state signal to IOB + DOUT => open, -- output data to IOB + T => '1', -- tri-state control from OLOGIC/OSERDES2 + ODATAIN => '0', -- data from OLOGIC/OSERDES2 + DATAOUT => ddly_m, -- Output data 1 to ILOGIC/ISERDES2 + DATAOUT2 => open, -- Output data 2 to ILOGIC/ISERDES2 + IOCLK0 => rxioclk_i, -- High speed clock for calibration + IOCLK1 => '0', -- High speed clock for calibration + CLK => gclk, -- Fabric clock (GCLK) for control signals + CAL => data_cal_master, -- Calibrate control signal + INC => data_inc, -- Increment counter + CE => data_ce, -- Clock Enable + RST => data_rst, -- Reset delay line + BUSY => open -- output signal indicating sync circuit has finished / calibration has finished + ); + + -- ---------------------------------------------------------- + -- Slave IDELAY + -- ---------------------------------------------------------- + iodelay_s: IODELAY2 + generic map ( + DATA_RATE => "SDR", + IDELAY_VALUE => 0, + IDELAY2_VALUE => 0, + IDELAY_MODE => "NORMAL", + ODELAY_VALUE => 0, + IDELAY_TYPE => "DIFF_PHASE_DETECTOR", + COUNTER_WRAPAROUND => "WRAPAROUND", + DELAY_SRC => "IDATAIN", + SERDES_MODE => "SLAVE", + SIM_TAPDELAY_VALUE => SIM_TAP_DELAY) + port map ( + IDATAIN => data_in, -- data from IBUFDS + TOUT => open, -- tri-state signal to IOB + DOUT => open, -- output data to IOB + T => '1', -- tri-state control from OLOGIC/OSERDES2 + ODATAIN => '0', -- data from OLOGIC/OSERDES2 + DATAOUT => ddly_s, -- Slave output data to ILOGIC/ISERDES2 + DATAOUT2 => open, -- + IOCLK0 => rxioclk_i, -- High speed IO clock for calibration + IOCLK1 => '0', + CLK => gclk, -- Fabric clock (GCLK) for control signals + CAL => data_cal_sint, -- Calibrate control signal + INC => data_inc, -- Increment counter + CE => data_ce, -- Clock Enable + RST => data_rst, -- Reset delay line + BUSY => data_busy -- output signal indicating sync circuit has finished / calibration has finished +); + + -- ---------------------------------------------------------- + -- Master ISERDES + -- ---------------------------------------------------------- + iserdes_m: ISERDES2 + generic map ( + DATA_WIDTH => 5, + DATA_RATE => "SDR", + BITSLIP_ENABLE => BITSLIP_ENABLE, + SERDES_MODE => "MASTER", + INTERFACE_TYPE => "RETIMED") + port map ( + D => ddly_m, + CE0 => '1', + CLK0 => rxioclk_i, + CLK1 => '0', + IOCE => rxserdesstrobe_i, + RST => rst, + CLKDIV => gclk, + SHIFTIN => pd_edge, + BITSLIP => bitslip_i, + FABRICOUT => open, + Q4 => data_o(4), + Q3 => data_o(3), + Q2 => data_o(2), + Q1 => data_o(1), + DFB => open, + CFB0 => open, + CFB1 => open, + VALID => data_valid, + INCDEC => data_incdec, + SHIFTOUT => cascade + ); + + -- ---------------------------------------------------------- + -- Slave ISERDES + -- ---------------------------------------------------------- + iserdes_s: ISERDES2 + generic map ( + DATA_WIDTH => 5, + DATA_RATE => "SDR", + BITSLIP_ENABLE => BITSLIP_ENABLE, + SERDES_MODE => "SLAVE", + INTERFACE_TYPE => "RETIMED") + port map ( + D => ddly_s, + CE0 => '1', + CLK0 => rxioclk_i, + CLK1 => '0', + IOCE => rxserdesstrobe_i, + RST => rst, + CLKDIV => gclk, + SHIFTIN => cascade, + BITSLIP => bitslip_i, + FABRICOUT => open, + Q4 => data_o(0), + Q3 => open, + Q2 => open, + Q1 => open, + DFB => open, + CFB0 => open, + CFB1 => open, + VALID => open, + INCDEC => open, + SHIFTOUT => pd_edge + ); + +end serdes_1_to_5_diff_data; diff --git a/serdes_n_to_1.vhd b/serdes_n_to_1.vhd new file mode 100644 index 0000000..5c7aed4 --- /dev/null +++ b/serdes_n_to_1.vhd @@ -0,0 +1,108 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.dvi_package.all; + +library UNISIM; +use UNISIM.Vcomponents.all; + +entity serdes_n_to_1 is + generic ( SF : integer := 0 ); + port ( + ioclk : in std_logic; + gclk : in std_logic; + rst : in std_logic; + serdesstrobe_i : in std_logic; + data_i : in std_logic_vector(SF-1 downto 0); + data_o : out std_logic + ); +end serdes_n_to_1; + +architecture serdes_n_to_1 of serdes_n_to_1 is + signal cascade_di : std_logic; + signal cascade_do : std_logic; + signal cascade_ti : std_logic; + signal cascade_to : std_logic; + signal mdatain : std_logic_vector(8 downto 0); +begin + datir: for I in 0 to SF-1 generate + mdatain(I) <= data_i(I); + end generate; + dati0: for I in SF to 8 generate + mdatain(I) <= '0'; + end generate; + + oserdes_m: OSERDES2 + generic map ( + DATA_WIDTH => SF, -- SERDES word width. This should match the setting is BUFPLL + DATA_RATE_OQ => "SDR", -- , DDR + DATA_RATE_OT => "SDR", -- , DDR + SERDES_MODE => "MASTER", -- , MASTER, SLAVE + OUTPUT_MODE => "DIFFERENTIAL" + ) + port map ( + OQ => data_o, + OCE => '1', + CLK0 => ioclk, + CLK1 => '0', + IOCE => serdesstrobe_i, + RST => rst, + CLKDIV => gclk, + D4 => mdatain(7), + D3 => mdatain(6), + D2 => mdatain(5), + D1 => mdatain(4), + TQ => open, + T1 => '0', + T2 => '0', + T3 => '0', + T4 => '0', + TRAIN => '0', + TCE => '1', + SHIFTIN1 => '1', -- Dummy input in Master + SHIFTIN2 => '1', -- Dummy input in Master + SHIFTIN3 => cascade_do, -- Cascade output D data from slave + SHIFTIN4 => cascade_to, -- Cascade output T data from slave + SHIFTOUT1 => cascade_di, -- Cascade input D data to slave + SHIFTOUT2 => cascade_ti, -- Cascade input T data to slave + SHIFTOUT3 => open, -- Dummy output in Master + SHIFTOUT4 => open -- Dummy output in Master + ); + + oserdes_s: OSERDES2 + generic map ( + DATA_WIDTH => SF, -- SERDES word width. This should match the setting is BUFPLL + DATA_RATE_OQ => "SDR", -- , DDR + DATA_RATE_OT => "SDR", -- , DDR + SERDES_MODE => "SLAVE", -- , MASTER, SLAVE + OUTPUT_MODE => "DIFFERENTIAL" + ) + port map ( + OQ => open, + OCE => '1', + CLK0 => ioclk, + CLK1 => '0', + IOCE => serdesstrobe_i, + RST => rst, + CLKDIV => gclk, + D4 => mdatain(3), + D3 => mdatain(2), + D2 => mdatain(1), + D1 => mdatain(0), + TQ => open, + T1 => '0', + T2 => '0', + T3 => '0', + T4 => '0', + TRAIN => '0', + TCE => '1', + SHIFTIN1 => cascade_di, -- Cascade input D from Master + SHIFTIN2 => cascade_ti, -- Cascade input T from Master + SHIFTIN3 => '1', -- Dummy input in Slave + SHIFTIN4 => '1', -- Dummy input in Slave + SHIFTOUT1 => open, -- Dummy output in Slave + SHIFTOUT2 => open, -- Dummy output in Slave + SHIFTOUT3 => cascade_do, -- Cascade output D data to Master + SHIFTOUT4 => cascade_to -- Cascade output T data to Master + ); +end serdes_n_to_1;