-- ----------------------------------------------------------------------------- -- 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.strm_package.all; entity strm_ddr2 is port ( clk : in std_logic; rst_n : in std_logic; debug : out std_logic_vector( 7 downto 0); -- streaming bus strm_in_data_i : in std_logic_vector(31 downto 0); strm_in_eop_i : in std_logic; strm_in_sop_i : in std_logic; strm_in_en_i : in std_logic; strm_in_busy_o : out std_logic; strm_out_req_o : out std_logic; strm_out_busy_i : in std_logic; strm_out_data_o : out std_logic_vector(31 downto 0); strm_out_eop_o : out std_logic; strm_out_en_o : out std_logic; -- memory interface 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_wr_en_o : out std_logic; ddr2_wr_mask_o : out std_logic_vector( 3 downto 0); ddr2_wr_data_o : out std_logic_vector(31 downto 0); ddr2_wr_full_i : in std_logic; ddr2_wr_empty_i : in std_logic; ddr2_wr_count_i : in std_logic_vector( 6 downto 0); ddr2_wr_underrun_i : in std_logic; ddr2_wr_error_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 ); end strm_ddr2; architecture strm_ddr2 of strm_ddr2 is type sm_strm_t is (IDLE, DDR2_ADDRESS, RECV, DDR2_READ, DDR2_RD_SIZE, DDR2_RD_WAIT, DDR2_RD_ADJ, DDR2_RD_REQ, IGNORE); signal sm_strm : sm_strm_t; signal rst : std_logic; signal strm_in_data : std_logic_vector(31 downto 0); signal strm_in_eop : std_logic; signal strm_in_sop : std_logic; signal strm_in_en : std_logic; signal strm_in_busy : std_logic; signal strm_type_vld : std_logic; signal strm_tag : std_logic_vector( 3 downto 0); signal strm_size : unsigned(23 downto 0); signal ddr2_wr_en : std_logic; signal ddr2_wr_mask : std_logic_vector( 3 downto 0); signal ddr2_wr_data : std_logic_vector(31 downto 0); signal dw_cnt : unsigned( 7 downto 0); signal dw_cnt_dec : unsigned( 7 downto 0); signal ddr2_adr : unsigned(27 downto 0); signal ddr2_size : unsigned(23 downto 0); signal ddr2_read_size : unsigned(23 downto 0); signal ddr2_cmd_en : std_logic; signal ddr2_cmd_instr : std_logic_vector( 2 downto 0); signal strm_out_size : unsigned(23 downto 0); signal strm_out_eop : std_logic; signal strm_out_hdr_en : std_logic; signal ddr2_rd_en : std_logic; signal read_cnt : unsigned(7 downto 0); begin rst <= not rst_n; ddr2_rd_en_o <= ddr2_rd_en; ddr2_cmd_en_o <= ddr2_cmd_en; ddr2_cmd_instr_o <= ddr2_cmd_instr; ddr2_wr_en_o <= ddr2_wr_en; ddr2_wr_mask_o <= ddr2_wr_mask; ddr2_wr_data_o <= ddr2_wr_data; strm_in_data <= strm_in_data_i; strm_in_eop <= strm_in_eop_i; strm_in_sop <= strm_in_sop_i; strm_in_en <= strm_in_en_i; strm_in_busy_o <= strm_in_busy; strm_in_busy <= ddr2_wr_full_i or ddr2_cmd_full_i; strm_type_vld <= strm_in_sop when strm_in_data(STRM_TYPE_HIGH downto STRM_TYPE_LOW) = STRM_TYPE_DDR2 else '0'; process (clk, rst_n) begin if rst_n = '0' then sm_strm <= IDLE; strm_tag <= (others => '0'); strm_size <= (others => '0'); ddr2_cmd_instr <= (others => '0'); ddr2_wr_en <= '0'; ddr2_wr_mask <= (others => '0'); ddr2_wr_data <= (others => '0'); dw_cnt <= (others => '0'); ddr2_adr <= (others => '0'); ddr2_size <= (others => '0'); ddr2_read_size <= (others => '0'); strm_out_size <= (others => '0'); read_cnt <= (others => '0'); strm_out_hdr_en <= '0'; elsif rising_edge(clk) then -- STRM SIZE if sm_strm = IDLE and strm_in_en = '1' then strm_tag <= strm_in_data(STRM_TAG_HIGH downto STRM_TAG_LOW); strm_size <= unsigned(strm_in_data(STRM_LENGTH_HIGH downto STRM_LENGTH_LOW)); end if; -- SAVE DDR2 ADDRESS if sm_strm = DDR2_ADDRESS and strm_in_en = '1' then ddr2_adr <= unsigned(strm_in_data(STRM_DDR2_ADR_HIGH downto STRM_DDR2_ADR_LOW)); elsif ddr2_cmd_en = '1' then ddr2_adr <= ddr2_adr + x"040"; end if; -- SAVE DDR2 READ SIZE if sm_strm = DDR2_RD_SIZE and strm_in_en = '1' then ddr2_size <= unsigned(strm_in_data(STRM_DDR2_SIZE_HIGH downto STRM_DDR2_SIZE_LOW)); strm_out_size <= unsigned(strm_in_data(STRM_DDR2_SIZE_HIGH downto STRM_DDR2_SIZE_LOW)); elsif sm_strm = DDR2_RD_REQ and ddr2_cmd_full_i = '0' then if ddr2_size > x"000040" then ddr2_size <= ddr2_size - x"40"; else ddr2_size <= (others => '0'); end if; end if; -- DDR2 DW COUNT if sm_strm = RECV or sm_strm = IDLE then if strm_in_en = '1' and ddr2_cmd_en = '1' then dw_cnt <= x"01"; elsif ddr2_cmd_en = '1' then dw_cnt <= (others => '0'); elsif strm_in_en = '1' then dw_cnt <= dw_cnt + "1"; end if; elsif sm_strm = DDR2_RD_ADJ and ddr2_cmd_full_i = '0' then if ddr2_size > x"000040" then dw_cnt <= x"40"; else dw_cnt <= ddr2_size(7 downto 0); end if; elsif strm_out_eop = '1' then dw_cnt <= (others => '0'); end if; -- DDR2 instruction if sm_strm = DDR2_ADDRESS and strm_in_en = '1' then if strm_in_data(STRM_DDR2_ACCESS) = STRM_DDR2_ACC_WRITE then ddr2_cmd_instr <= "000"; else ddr2_cmd_instr <= "001"; end if; end if; if sm_strm = IDLE then strm_out_hdr_en <= '1'; elsif sm_strm = DDR2_RD_WAIT and strm_out_busy_i = '0' then strm_out_hdr_en <= '0'; end if; -- RECV STATES case sm_strm is when IDLE => if strm_in_en = '1' then if strm_type_vld = '1' then sm_strm <= DDR2_ADDRESS; else sm_strm <= IGNORE; end if; end if; when DDR2_ADDRESS => if strm_in_en = '1' then if strm_in_data(STRM_DDR2_ACCESS) = STRM_DDR2_ACC_WRITE then sm_strm <= RECV; else sm_strm <= DDR2_RD_SIZE; end if; end if; -- DDR WRITE when RECV => if strm_in_eop = '1' and strm_in_en = '1' then sm_strm <= IDLE; end if; -- DDR READ when DDR2_RD_SIZE => if strm_in_en = '1' then if strm_in_eop = '1' then sm_strm <= DDR2_RD_ADJ; else sm_strm <= IGNORE; end if; end if; when DDR2_RD_ADJ => if ddr2_cmd_full_i = '0' then sm_strm <= DDR2_RD_REQ; end if; when DDR2_RD_REQ => sm_strm <= DDR2_RD_WAIT; when DDR2_RD_WAIT => if ddr2_rd_empty_i = '0' and strm_out_busy_i = '0' then sm_strm <= DDR2_READ; end if; when DDR2_READ => if ddr2_rd_empty_i = '1' and ddr2_size /= x"000000" and read_cnt = dw_cnt(6 downto 0) then sm_strm <= DDR2_RD_ADJ; elsif strm_out_eop = '1' then sm_strm <= IDLE; end if; -- COMMON IGNORE when IGNORE => if strm_in_eop = '1' and strm_in_en = '1' then sm_strm <= IDLE; end if; end case; -- DDR REGISTERS ddr2_wr_en <= '0'; if strm_in_en = '1' and sm_strm = RECV then ddr2_wr_en <= '1'; ddr2_wr_mask <= (others => '0'); ddr2_wr_data <= strm_in_data; end if; if ddr2_cmd_en = '1' then read_cnt <= (others => '0'); elsif ddr2_rd_en = '1' then read_cnt <= read_cnt + "1"; end if; -- STRM OUT REGISTERS if sm_strm = DDR2_RD_SIZE then ddr2_read_size <= x"000001"; elsif ddr2_rd_en = '1' then ddr2_read_size <= ddr2_read_size + "1"; end if; end if; end process; ddr2_cmd_en <= '1' when (sm_strm = RECV and dw_cnt = x"40") or ((sm_strm = DDR2_RD_REQ or sm_strm = IDLE) and dw_cnt /= x"00") else '0'; dw_cnt_dec <= dw_cnt - "1"; ddr2_cmd_bl_o <= std_logic_vector(dw_cnt_dec(5 downto 0)); ddr2_cmd_byte_addr_o <= std_logic_vector(ddr2_adr) & "00"; ddr2_rd_en <= not ddr2_rd_empty_i when sm_strm = DDR2_READ else '0'; strm_out_req_o <= not ddr2_rd_empty_i and strm_out_busy_i when sm_strm = DDR2_RD_WAIT else '0'; strm_out_en_o <= strm_out_hdr_en when sm_strm = DDR2_RD_WAIT and strm_out_busy_i = '0' else ddr2_rd_en; strm_out_eop <= ddr2_rd_en when ddr2_read_size >= strm_out_size and sm_strm = DDR2_READ else '0'; strm_out_eop_o <= strm_out_eop; strm_out_data_o <= STRM_TYPE_DDR2 & strm_tag & std_logic_vector(strm_out_size) when strm_out_hdr_en = '1' else ddr2_rd_data_i; end strm_ddr2;