-- ----------------------------------------------------------------------------- -- Copyright (c) 2013 Benjamin Krill -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. -- ----------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use work.dvi_package.all; entity sig_read is generic ( MEM_START_ADR : unsigned(29 downto 0) := "00" & x"0000000"; H_ACTIVE_PIXEL : unsigned(11 downto 0) := x"5a0"; H_BLANKING : unsigned(11 downto 0) := x"0dd"; H_SYNC_WIDTH : unsigned(11 downto 0) := x"03c"; H_SYNC_OFFSET : unsigned(11 downto 0) := x"050"; -- front porch V_ACTIVE_LINES : unsigned(11 downto 0) := x"21c"; V_BLANKING : unsigned(11 downto 0) := x"022"; V_SYNC_WIDTH : unsigned( 7 downto 0) := x"02"; V_SYNC_OFFSET : unsigned( 7 downto 0) := x"18" -- front porch ); port ( clk : in std_logic; rst_n : in std_logic; -- memory interface ddr2_clk : in std_logic; ddr2_cmd_en_o : out std_logic; ddr2_cmd_instr_o : out std_logic_vector( 2 downto 0); ddr2_cmd_bl_o : out std_logic_vector( 5 downto 0); ddr2_cmd_byte_addr_o : out std_logic_vector(29 downto 0); ddr2_cmd_empty_i : in std_logic; ddr2_cmd_full_i : in std_logic; ddr2_rd_en_o : out std_logic; ddr2_rd_data_i : in std_logic_vector(31 downto 0); ddr2_rd_full_i : in std_logic; ddr2_rd_empty_i : in std_logic; ddr2_rd_count_i : in std_logic_vector( 6 downto 0); ddr2_rd_overflow_i : in std_logic; ddr2_rd_error_i : in std_logic; -- display output en_stb_i : in std_logic; hsync_o : out std_logic; vsync_o : out std_logic; color_en_o : out std_logic; color_o : out color_t(COLOR_CNT-1 downto 0) ); end sig_read; architecture sig_read of sig_read is signal rst : std_logic; signal h_cnt : unsigned(11 downto 0); signal v_cnt : unsigned(11 downto 0); signal one_screen : std_logic; signal h_state : unsigned(1 downto 0); signal h_state_m : unsigned(1 downto 0); signal h_state_v : unsigned(1 downto 0); signal h_state_i : unsigned(1 downto 0); signal v_state : unsigned(1 downto 0); signal v_state_m : unsigned(1 downto 0); signal v_state_v : unsigned(1 downto 0); signal v_state_i : unsigned(1 downto 0); constant SYNC_OFF : unsigned(1 downto 0) := "00"; constant SYNC : unsigned(1 downto 0) := "01"; constant SYNC_BACK : unsigned(1 downto 0) := "10"; constant ACTIVE_LINE : unsigned(1 downto 0) := "11"; constant H_SYNC_BACK : unsigned(11 downto 0) := H_BLANKING - H_SYNC_OFFSET - H_SYNC_WIDTH; constant V_SYNC_BACK : unsigned(11 downto 0) := V_BLANKING - V_SYNC_OFFSET - V_SYNC_WIDTH; signal disp_rd_en : std_logic; signal disp_rd_data : color_t(COLOR_CNT-1 downto 0); signal px_fifo_rd_en : std_logic; signal px_fifo_full : std_logic; signal px_fifo_empty : std_logic; signal px_fifo_cnt : std_logic_vector(10 downto 0); signal px_fifo_dat_out : std_logic_vector(31 downto 0); -- memory signal mem_address : unsigned(27 downto 0); signal mem_burst_len : unsigned( 5 downto 0); signal mem_cmd_en : std_logic; signal mem_rd_en : std_logic; signal mem_rd_data : std_logic_vector(31 downto 0); signal mem_rd_cnt : unsigned( 6 downto 0); signal mem_fetch_cnt : unsigned( 5 downto 0); signal mem_read_cnt : unsigned( 6 downto 0); signal mem_read_wait : std_logic; signal new_line : std_logic; signal new_line_q0 : std_logic; signal new_line_q1 : std_logic; signal new_line_q2 : std_logic; signal new_line_q3 : std_logic; signal new_line_s : std_logic; begin rst <= not rst_n; -- ------------------------------------------------------------------------------- -- MEMORY -- ------------------------------------------------------------------------------- ddr2_cmd_byte_addr_o <= std_logic_vector(mem_address(27 downto 0) & "00"); ddr2_cmd_bl_o <= std_logic_vector(mem_burst_len); ddr2_cmd_instr_o <= "001"; -- only read from this interface ddr2_cmd_en_o <= mem_cmd_en; ddr2_rd_en_o <= mem_rd_en; mem_rd_cnt <= unsigned(ddr2_rd_count_i); new_line <= '1' when h_state_v = SYNC and v_state_v = ACTIVE_LINE else '0'; new_line_s <= new_line and new_line_q0 and not new_line_q1 and not new_line_q2; process (ddr2_clk, rst_n) begin if rst_n = '0' then mem_address <= (others => '0'); mem_cmd_en <= '0'; mem_burst_len <= (others => '0'); mem_fetch_cnt <= (others => '0'); h_state_m <= (others => '0'); h_state_v <= (others => '0'); v_state_m <= (others => '0'); v_state_v <= (others => '0'); new_line_q0 <= '0'; new_line_q1 <= '0'; new_line_q2 <= '0'; new_line_q3 <= '0'; mem_read_cnt <= (others => '0'); mem_read_wait <= '0'; elsif rising_edge(ddr2_clk) then new_line_q0 <= new_line; new_line_q1 <= new_line_q0; new_line_q2 <= new_line_q1; new_line_q3 <= new_line_q2; -- synchronizer h_state_m <= h_state; h_state_v <= h_state_m; v_state_m <= v_state; v_state_v <= v_state_m; -- calculate memory fetch count if new_line_s = '1' then mem_fetch_cnt <= H_ACTIVE_PIXEL(11 downto 6); elsif mem_cmd_en = '1' then mem_fetch_cnt <= mem_fetch_cnt - "1"; end if; -- wait state if mem_cmd_en = '1' then mem_read_wait <= '1'; elsif mem_read_cnt = "0101111" and mem_read_wait = '1' then mem_read_wait <= '0'; end if; -- mem raw read count if mem_read_cnt = x"40" and mem_rd_en = '1' then mem_read_cnt <= "0000001"; elsif mem_read_cnt = x"40" then mem_read_cnt <= (others => '0'); elsif mem_rd_en = '1' then mem_read_cnt <= mem_read_cnt + "1"; end if; mem_cmd_en <= '0'; if ddr2_cmd_full_i = '0' and mem_fetch_cnt /= "000000" and mem_cmd_en = '0' and mem_read_wait = '0' then mem_cmd_en <= '1'; mem_burst_len <= "111111"; end if; if v_state_v = SYNC then mem_address <= MEM_START_ADR(29 downto 2); elsif mem_cmd_en = '1' then mem_address <= mem_address + x"040"; end if; end if; end process; mem_rd_data <= ddr2_rd_data_i; mem_rd_en <= not ddr2_rd_empty_i; px_fifo_0: entity work.px_fifo port map ( wr_clk => ddr2_clk, rd_clk => clk, rst => rst, din => mem_rd_data, wr_en => mem_rd_en, rd_en => px_fifo_rd_en, dout => px_fifo_dat_out, full => px_fifo_full, empty => px_fifo_empty, rd_data_count => px_fifo_cnt ); px_fifo_rd_en <= disp_rd_en and not px_fifo_empty; disp_rd_en <= '1' when h_state = ACTIVE_LINE and v_state = ACTIVE_LINE else '0'; disp_rd_data <= (px_fifo_dat_out(23 downto 16), px_fifo_dat_out(15 downto 8), px_fifo_dat_out(7 downto 0)) when px_fifo_empty = '0' else (x"ff", x"00", x"00"); -- ------------------------------------------------------------------------------- -- DISPLAY -- ------------------------------------------------------------------------------- hsync_o <= '1' when h_state = SYNC and v_state = ACTIVE_LINE else '0'; vsync_o <= '1' when v_state = SYNC else '0'; color_en_o <= disp_rd_en; color_o <= disp_rd_data; --color_en_o <= '1' when h_state = ACTIVE_LINE and v_state = ACTIVE_LINE else '0'; --color_o <= ((others => v_cnt(3)), (others => v_cnt(2)), (others => v_cnt(1))); process (clk, rst_n) begin if rst_n = '0' then h_cnt <= x"000"; v_cnt <= x"000"; v_state <= "00"; v_state_i <= "00"; h_state <= "00"; h_state_i <= "00"; one_screen <= '0'; elsif rising_edge(clk) then if v_state = ACTIVE_LINE and v_cnt = x"000" then one_screen <= '0'; elsif en_stb_i = '1' then one_screen <= '1'; end if; if one_screen = '1' and h_cnt = x"000" then h_state <= h_state_i; case h_state_i is when SYNC_OFF => h_cnt <= H_SYNC_OFFSET-1; when SYNC => h_cnt <= H_SYNC_WIDTH-1; when SYNC_BACK => h_cnt <= H_SYNC_BACK-1; when ACTIVE_LINE => h_cnt <= H_ACTIVE_PIXEL-1; when others => h_cnt <= x"000"; end case; elsif h_cnt /= x"000" then h_cnt <= h_cnt - "1"; end if; if one_screen = '1' and h_cnt = x"000" then h_state_i <= h_state_i + "01"; end if; if one_screen = '1' and v_cnt = x"000" and h_state = SYNC_OFF then v_state <= v_state_i; case v_state_i is when SYNC_OFF => v_cnt <= x"0" & V_SYNC_OFFSET; when SYNC => v_cnt <= x"0" & V_SYNC_WIDTH; when SYNC_BACK => v_cnt <= V_SYNC_BACK; when ACTIVE_LINE => v_cnt <= V_ACTIVE_LINES; when others => v_cnt <= x"000"; end case; elsif v_cnt /= x"000" and (h_state = ACTIVE_LINE and h_cnt = x"000") then v_cnt <= v_cnt - "1"; end if; if one_screen = '1' and v_cnt = x"000" then v_state_i <= v_state_i + "01"; end if; end if; end process; end sig_read;