library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; library UNISIM; use UNISIM.vcomponents.all; entity dmac_ddr_natsu is port( -- DDR SDRAM CL=2 a : out std_logic_vector(12 downto 0); ba : out std_logic_vector(1 downto 0); cas : out std_logic; ras : out std_logic; we : out std_logic; ck_n : out std_logic; ck_p : out std_logic; cke : out std_logic; cs : out std_logic; dq : inout std_logic_vector(15 downto 0); ldm : out std_logic; ldqs : inout std_logic; udm : out std_logic; udqs : inout std_logic; -- DMAC in ready : out std_logic; burst : in std_logic; valid : in std_logic; write : in std_logic; cnt : in std_logic_vector(11 downto 0); dmadr : in std_logic_vector(31 downto 0); a_o : out std_logic_vector(11 downto 0); d_i : in std_logic_vector(31 downto 0); d_o : out std_logic_vector(31 downto 0); wre : out std_logic; done : out std_logic; -- clock nRST : in std_logic; clk100 : in std_logic; clk100_n : in std_logic ); end entity; architecture arc_dmac_ddr_natsu of dmac_ddr_natsu is signal clkdiv_cnt : std_logic_vector(4 downto 0); signal clkdiv_n16 : std_logic; signal clk_div16 : std_logic; type TYPE_st_init is ( INIT_RESET, INIT_MAKE_HiZ, INIT_START, INIT_1st_PALL, INIT_DLL_ENABLE, INIT_DLL_RESET, INIT_2nd_PALL, INIT_1st_REF, INIT_2nd_REF, INIT_MODE_SET, INIT_LAST_PALL, INIT_DONE); signal st_init : TYPE_st_init := INIT_RESET; signal init_cnt_11bit : std_logic_vector(10 downto 0); signal init_cnt_5bit : std_logic_vector(4 downto 0); signal init_a10 : std_logic; signal init_mreg : std_logic_vector(8 downto 0); constant MODEREG_DLL_ENABLE : std_logic_vector(8 downto 0) := "000000001"; constant MODEREG_DLL_RESET : std_logic_vector(8 downto 0) := '1' & '0' & "010" & '0' & "011"; constant MODEREG_START : std_logic_vector(8 downto 0) := '0' & '0' & "010" & '0' & "011"; signal init_ba : std_logic_vector(1 downto 0); signal init_cas : std_logic; signal init_ras : std_logic; signal init_we : std_logic; signal nclk_enable : std_logic; signal ref_need : std_logic; signal ref_exec : std_logic; signal ref_cnt_6bit : std_logic_vector(5 downto 0); type TYPE_st_ac is ( AC_PREINIT, AC_IDLE, AC_READ_WAIT0, AC_READ_WAIT1, AC_READ_WAIT2, AC_READ_WAIT3, AC_READ_WAIT4, AC_READ_WAIT5, AC_READ_WAIT6, AC_READ_WAIT7, AC_READ_WAIT8, AC_READ_WAIT9, AC_WRITE_WAIT0, AC_WRITE_WAIT1, AC_WRITE_WAIT2, AC_WRITE_WAIT3, AC_WRITE_WAIT4, AC_WRITE_WAIT5, AC_WRITE_WAIT6, AC_WRITE_WAIT7, AC_WRITE_WAIT8 ); signal st_ac : TYPE_st_ac := AC_PREINIT; signal ac_valid : std_logic; signal ac_proc : std_logic; signal ac_done : std_logic; signal ac_enable : std_logic; signal ac_write : std_logic; signal ac_data_i : std_logic_vector(31 downto 0); signal ac_data_o : std_logic_vector(31 downto 0); signal ac_addr : std_logic_vector(21 downto 0); signal ac_a : std_logic_vector(12 downto 0); signal ac_ba : std_logic_vector(1 downto 0); signal ac_cas : std_logic; signal ac_ras : std_logic; signal ac_we : std_logic; signal ac_bank : std_logic_vector(1 downto 0); signal ac_row : std_logic_vector(12 downto 0); signal ac_column : std_logic_vector(12 downto 0); signal ac_capt : std_logic_vector(15 downto 0); signal ac_push : std_logic_vector(15 downto 0); signal ac_ref_wait : std_logic_vector(2 downto 0); signal ac_nclk_ce : std_logic; type TYPE_st_dmac is ( DMAC_IDLE, DMAC_WRITE_ONE_WAIT, DMAC_WRITE_ONE, DMAC_WRITE_DONE, DMAC_READ_ONE, DMAC_READ_BURST ); signal st_dmac : TYPE_st_dmac := DMAC_IDLE; signal dmac_ddr_target : std_logic_vector(21 downto 0); signal dmac_ddr_cnt : std_logic_vector(11 downto 0); signal dmac_end : std_logic_vector(11 downto 0); begin ------------------------------------------------------------------- -- DMAC Body ------------------------------------------------------------------- dmacseq : process(clk100) begin if rising_edge(clk100) then wre <= '0'; done <= '0'; if nRST = '0' then st_dmac <= DMAC_IDLE; else case st_dmac is when DMAC_IDLE => dmac_ddr_cnt <= (others => '0'); dmac_ddr_target <= dmadr(21 downto 0); ac_addr <= dmadr(21 downto 0); ac_write <= write; dmac_end <= cnt; if valid = '1' then if write = '1' then st_dmac <= DMAC_WRITE_ONE_WAIT; a_o <= (others => '0'); else ac_valid <= '1'; if burst = '1' then st_dmac <= DMAC_READ_BURST; else st_dmac <= DMAC_READ_ONE; end if; end if; end if; when DMAC_WRITE_ONE_WAIT => st_dmac <= DMAC_WRITE_ONE; when DMAC_WRITE_ONE => ac_valid <= '1'; ac_data_i <= d_i; st_dmac <= DMAC_WRITE_DONE; when DMAC_WRITE_DONE => if ac_proc = '1' then ac_valid <= '0'; end if; if ac_done = '1' then done <= '1'; st_dmac <= DMAC_IDLE; end if; when DMAC_READ_ONE => if ac_proc = '1' then ac_valid <= '0'; end if; if ac_done = '1' then d_o <= ac_data_o; a_o <= dmac_ddr_cnt; wre <= '1'; done <= '1'; st_dmac <= DMAC_IDLE; end if; when DMAC_READ_BURST => if ac_proc = '1' then ac_valid <= '0'; end if; if ac_done = '1' then d_o <= ac_data_o; a_o <= dmac_ddr_cnt; wre <= '1'; dmac_ddr_cnt <= dmac_ddr_cnt + 1; if dmac_ddr_cnt = dmac_end then done <= '1'; st_dmac <= DMAC_IDLE; else ac_valid <= '1'; ac_addr <= dmac_ddr_target + 1; dmac_ddr_target <= dmac_ddr_target + 1; end if; end if; end case; end if; end if; end process; ------------------------------------------------------------------- -- INIT/ACCESS MUX ------------------------------------------------------------------- cas <= ac_cas when st_init = INIT_DONE else init_cas; ras <= ac_ras when st_init = INIT_DONE else init_ras; we <= ac_we when st_init = INIT_DONE else init_we; ba <= ac_ba when st_init = INIT_DONE else init_ba; a <= ac_a when st_init = INIT_DONE else "00" & init_a10 & '0' & init_mreg; cs <= '0'; ck_p <= clk100; ck_n <= clk100_n; ldqs <= clk100_n when nclk_enable = '1' else 'Z'; udqs <= clk100_n when nclk_enable = '1' else 'Z'; ldm <= '0'; udm <= '0'; ------------------------------------------------------------------- -- ACCESS ------------------------------------------------------------------- ac_bank <= ac_addr(21 downto 20); ac_row <= ac_addr(19 downto 7); ac_column(12 downto 11) <= "00"; ac_column(10) <= '1'; -- always pre-chargeing access ac_column(9 downto 3) <= ac_addr(6 downto 0); ac_column(2 downto 0) <= "000"; -- nclk ddraccess : process(clk100) begin if rising_edge(clk100) then ref_exec <= '0'; ac_done <= '0'; ac_proc <= '0'; ac_ras <= '1'; ac_cas <= '1'; ac_we <= '1'; if nRST = '0' then st_ac <= AC_PREINIT; else case st_ac is when AC_PREINIT => if st_init = INIT_DONE then st_ac <= AC_IDLE; ac_ref_wait <= "000"; end if; when AC_IDLE => nclk_enable <= '0'; if ac_ref_wait = 0 then if ref_need = '1' then -- issue REF ref_exec <= '1'; ac_ras <= '0'; ac_cas <= '0'; ac_we <= '1'; ac_ref_wait <= "111"; elsif ac_valid = '1' then if ac_write = '1' then st_ac <= AC_WRITE_WAIT0; else st_ac <= AC_READ_WAIT0; end if; -- issue ACT ac_proc <= '1'; ac_ras <= '0'; ac_cas <= '1'; ac_we <= '1'; ac_ba <= ac_bank; ac_a <= ac_row; end if; else ac_ref_wait <= ac_ref_wait -1; end if; when AC_READ_WAIT0 => st_ac <= AC_READ_WAIT1; when AC_READ_WAIT1 => -- issue READ ac_cas <= '0'; ac_ras <= '1'; ac_we <= '1'; ac_ba <= ac_bank; ac_a <= ac_column; st_ac <= AC_READ_WAIT2; when AC_READ_WAIT2 => st_ac <= AC_READ_WAIT3; when AC_READ_WAIT3 => st_ac <= AC_READ_WAIT4; when AC_READ_WAIT4 => st_ac <= AC_READ_WAIT5; when AC_READ_WAIT5 => st_ac <= AC_READ_WAIT6; when AC_READ_WAIT6 => ac_capt<=dq; st_ac <= AC_READ_WAIT7; when AC_READ_WAIT7 => ac_data_o(15 downto 0)<=ac_capt; st_ac <= AC_READ_WAIT8; when AC_READ_WAIT8 => ac_capt<=dq; st_ac <= AC_READ_WAIT9; when AC_READ_WAIT9 => ac_data_o(31 downto 16)<=ac_capt; ac_done<='1'; st_ac <= AC_IDLE; when AC_WRITE_WAIT0 => st_ac <= AC_WRITE_WAIT1; when AC_WRITE_WAIT1 => -- issue WRITE ac_cas <= '0'; ac_ras <= '1'; ac_we <= '0'; ac_ba <= ac_bank; ac_a <= ac_column; st_ac <= AC_WRITE_WAIT2; dq <= ac_data_i(15 downto 0); nclk_enable <= '1'; when AC_WRITE_WAIT2 => --dq <= ac_push; st_ac <= AC_WRITE_WAIT3; when AC_WRITE_WAIT3 => st_ac <= AC_WRITE_WAIT4; when AC_WRITE_WAIT4 => st_ac <= AC_WRITE_WAIT5; dq <= ac_data_i(31 downto 16); when AC_WRITE_WAIT5 => st_ac <= AC_WRITE_WAIT6; when AC_WRITE_WAIT6 => st_ac <= AC_WRITE_WAIT7; when AC_WRITE_WAIT7 => st_ac <= AC_WRITE_WAIT8; when AC_WRITE_WAIT8 => nclk_enable <= '0'; dq <= (others => 'Z'); ac_done <= '1'; st_ac <= AC_IDLE; end case; end if; end if; end process; ------------------------------------------------------------------- -- REFRESH ------------------------------------------------------------------- ddrref : process(clk100) begin if rising_edge(clk100) then if ref_exec = '1' then ref_need <= '0'; end if; if clk_div16 = '1' then ref_cnt_6bit <= ref_cnt_6bit + 1; if ref_cnt_6bit = 47 then ref_cnt_6bit <= (others => '0'); ref_need <= '1'; end if; end if; end if; end process; ------------------------------------------------------------------- -- INIT ------------------------------------------------------------------- ddrinit : process(clk100) begin if rising_edge(clk100) then ready <= '0'; if nRST = '0' then st_init <= INIT_RESET; else -- SET NOP cmd by default init_cas <= '1'; init_ras <= '1'; init_we <= '1'; case st_init is when INIT_RESET => init_cnt_11bit <= (others => '0'); init_cnt_5bit <= (others => '0'); cke <= '0'; if clk_div16 = '1' then st_init <= INIT_MAKE_HiZ; end if; when INIT_MAKE_HiZ => if clk_div16 = '1' then init_cnt_11bit <= init_cnt_11bit + 1; end if; if init_cnt_11bit = 1250 then st_init <= INIT_START; cke <= '1'; end if; when INIT_START => if clk_div16 = '1' then -- wasteful delay st_init <= INIT_1st_PALL; -- issue PALL init_a10 <= '1'; init_cas <= '1'; init_ras <= '0'; init_we <= '0'; end if; when INIT_1st_PALL => if clk_div16 = '1' then -- issue EMRS init_cas <= '0'; init_ras <= '0'; init_we <= '0'; init_a10 <= '0'; init_ba <= "10"; init_mreg <= MODEREG_DLL_ENABLE; st_init <= INIT_DLL_ENABLE; end if; when INIT_DLL_ENABLE => if clk_div16 = '1' then -- issue MRS init_cas <= '0'; init_ras <= '0'; init_we <= '0'; init_a10 <= '0'; init_ba <= "00"; init_mreg <= MODEREG_DLL_RESET; st_init <= INIT_DLL_RESET; end if; when INIT_DLL_RESET => if clk_div16 = '1' then -- at least 200 clk to stable DLL init_cnt_5bit <= init_cnt_5bit + 1; end if; if init_cnt_5bit = 16 then -- issue PALL init_a10 <= '1'; init_cas <= '1'; init_ras <= '0'; init_we <= '0'; st_init <= INIT_2nd_PALL; end if; when INIT_2nd_PALL => if clk_div16 = '1' then -- issue REF init_cas <= '0'; init_ras <= '0'; init_we <= '1'; st_init <= INIT_1st_REF; end if; when INIT_1st_REF => if clk_div16 = '1' then -- issue REF init_cas <= '0'; init_ras <= '0'; init_we <= '1'; st_init <= INIT_2nd_REF; end if; when INIT_2nd_REF => if clk_div16 = '1' then -- issue MRS init_ras <= '0'; init_we <= '0'; init_a10 <= '0'; init_ba <= "00"; init_mreg <= MODEREG_START; st_init <= INIT_MODE_SET; end if; when INIT_MODE_SET => if clk_div16 = '1' then -- issue PALL init_a10 <= '1'; init_cas <= '1'; init_ras <= '0'; init_we <= '0'; st_init <= INIT_LAST_PALL; end if; when INIT_LAST_PALL => if clk_div16 = '1' then st_init <= INIT_DONE; end if; when INIT_DONE => ready <= '1'; end case; end if; end if; end process; -- CLK div x16 clk_div : process(clk100) begin if rising_edge(clk100) then clkdiv_cnt <= clkdiv_cnt + 1; clkdiv_n16 <= clkdiv_cnt(4); clk_div16 <= clkdiv_n16 xor clkdiv_cnt(4); end if; end process; end arc_dmac_ddr_natsu;