diff options
Diffstat (limited to 'misc')
-rw-r--r-- | misc/ChangeLog | 5 | ||||
-rw-r--r-- | misc/arm7/src/arm7pkg.vhd | 31 | ||||
-rw-r--r-- | misc/arm7/src/arm7wb.vhd | 236 | ||||
-rw-r--r-- | misc/ddrsdram/simscripts/ddr_tb.do | 16 | ||||
-rw-r--r-- | misc/ddrsdram/simscripts/ddr_top.do | 104 | ||||
-rw-r--r-- | misc/ddrsdram/simsrc/ddr_tb.vhd | 301 | ||||
-rw-r--r-- | misc/ddrsdram/src/ddr_pkg.vhd | 107 | ||||
-rw-r--r-- | misc/ddrsdram/src/ddr_top.vhd | 743 | ||||
-rw-r--r-- | misc/ddrsdram/src/mt46v16m16.vhd | 1320 | ||||
-rw-r--r-- | misc/readme.txt | 20 | ||||
-rw-r--r-- | misc/wishbone/src/atomic32_access.vhd | 132 | ||||
-rw-r--r-- | misc/wishbone/src/wishbone_pkg.vhd | 52 |
12 files changed, 3067 insertions, 0 deletions
diff --git a/misc/ChangeLog b/misc/ChangeLog new file mode 100644 index 0000000..3225839 --- /dev/null +++ b/misc/ChangeLog @@ -0,0 +1,5 @@ +2008-06-18 Øyvind Harboe
+
+ * Various ZY2000 vhdl files of more general interest made
+ available as part of the ZPU project under the same
+ license(FreeBSD). Files should have headers updated.
diff --git a/misc/arm7/src/arm7pkg.vhd b/misc/arm7/src/arm7pkg.vhd new file mode 100644 index 0000000..4dcbb9c --- /dev/null +++ b/misc/arm7/src/arm7pkg.vhd @@ -0,0 +1,31 @@ +library IEEE; +use IEEE.STD_LOGIC_1164.all; +use IEEE.STD_LOGIC_UNSIGNED.ALL; +library work; +use work.wishbone_pkg.all; + +package arm7 is + + component arm7wb + generic( + simulate_io_time : boolean := false); + port ( areset : in std_logic; + cpu_clk : in std_logic; + cpu_clk_2x : in std_logic; + cpu_a_p : in std_logic_vector(23 downto 1); + cpu_wr_n_p : in std_logic_vector(1 downto 0); + cpu_cs_n_p : in std_logic_vector(3 downto 1); + cpu_oe_n_p : in std_logic; + cpu_d_p : inout std_logic_vector(15 downto 0); + cpu_wait_n_p : out std_logic; + + arm7_debug : out std_logic; + arm7_debug2 : out std_logic; + + wb_o : out wishbone_bus_in; + wb_i : in wishbone_bus_out); + end component; + +end arm7; + +
\ No newline at end of file diff --git a/misc/arm7/src/arm7wb.vhd b/misc/arm7/src/arm7wb.vhd new file mode 100644 index 0000000..85f0ef7 --- /dev/null +++ b/misc/arm7/src/arm7wb.vhd @@ -0,0 +1,236 @@ +library IEEE; +use IEEE.STD_LOGIC_1164.all; +use IEEE.STD_LOGIC_UNSIGNED.ALL; +library work; +use work.phi_config.all; +use work.wishbone_pkg.all; + +entity arm7wb is + generic( + simulate_io_time : boolean := false); + port ( areset : in std_logic; + cpu_clk : in std_logic; + cpu_clk_2x : in std_logic; + cpu_a_p : in std_logic_vector(23 downto 1); + cpu_wr_n_p : in std_logic_vector(1 downto 0); + cpu_cs_n_p : in std_logic_vector(3 downto 1); + cpu_oe_n_p : in std_logic; + cpu_d_p : inout std_logic_vector(15 downto 0); + cpu_wait_n_p : out std_logic; + + arm7_debug : out std_logic; + arm7_debug2 : out std_logic; + + wb_o : out wishbone_bus_in; + wb_i : in wishbone_bus_out); +end arm7wb; + +architecture behave of arm7wb is + +type cpu_state_type is (cpu_idle, cpu_cs, cpu_end); + +-- Input simulated delay +signal cpu_wr_n_p_del : std_logic_vector(1 downto 0); +signal cpu_a_p_del : std_logic_vector(23 downto 1); +signal cpu_d_p_del : std_logic_vector(15 downto 0); +signal cpu_cs_n_p_del : std_logic_vector(3 downto 1); +signal cpu_oe_n_p_del : std_logic; + +-- Clock phase detect signals +signal cpu_clk_toggle : std_logic; +signal cpu_clk_smp1 : std_logic; +signal cpu_clk_smp2 : std_logic; +signal cpu_clk_phase : std_logic; + +-- Internal version of control signal (for feedback) +signal arm7_din_int : std_logic_vector(15 downto 0); +signal arm7_dout_int : std_logic_vector(15 downto 0); +signal arm7_a_int : std_logic_vector(23 downto 1); +signal arm7_we_int : std_logic_vector(1 downto 0); +signal cyc_int : std_logic; +signal we_int : std_logic; +signal adr_reg : std_logic_vector(25 downto 24); + +-- Input sampled +signal cpu_a_smp : std_logic_vector(23 downto 1); +signal cpu_d_smp : std_logic_vector(15 downto 0); +signal cpu_cs_n : std_logic_vector(3 downto 1); +signal cpu_oe_n : std_logic; +signal cpu_wr_n : std_logic_vector(1 downto 0); + +-- Main FSM +signal cpu_state : cpu_state_type; + +constant Clock_2_Out : time := 5.5 ns; +constant Input_Setup : time := 2.5 ns; + +begin + + arm7_dout_int <= wb_i.dat(15 downto 0) when (arm7_a_int(1) = '0') else wb_i.dat(31 downto 16); + arm7_debug <= cpu_oe_n; + arm7_debug2 <= cpu_wr_n(0); + + -- Generate 64 MBytes address based on 3 CS_N signals from CPU + -- Memory map FPGA internal + -- 0x00000000 DDR 32 MBytes (CS_N2 and CS_N3) + -- 0x00200000 FPGA/Ethernet (CS_N1) + wb_o.adr(31 downto 26) <= "000000"; + wb_o.adr(25 downto 24) <= adr_reg; + wb_o.adr(23 downto 1) <= arm7_a_int(23 downto 1); + wb_o.adr(0) <= '0'; + + wb_o.dat <= (x"0000" & arm7_din_int) when (arm7_a_int(1) = '0') else (arm7_din_int & x"0000"); + wb_o.sel <= ("00" & arm7_we_int) when (arm7_a_int(1) = '0') else (arm7_we_int & "00"); + + wb_o.cyc <= cyc_int; + wb_o.stb <= cyc_int; + wb_o.we <= cpu_oe_n; + + iotimingon: + if simulate_io_time generate + begin + cpu_wr_n_p_del <= transport "XX" after 0 ns, cpu_wr_n_p after Input_Setup; + cpu_a_p_del <= transport "XXXXXXXXXXXXXXXXXXXXXXX" after 0 ns, cpu_a_p after Input_Setup; + cpu_d_p_del <= transport "XXXXXXXXXXXXXXXX" after 0 ns, cpu_d_p after Input_Setup; + cpu_cs_n_p_del <= transport "XXX" after 0 ns, cpu_cs_n_p after Input_Setup; + cpu_oe_n_p_del <= transport 'X' after 0 ns, cpu_oe_n_p after Input_Setup; + end generate; + + iotimingoff: + if not simulate_io_time generate + begin + cpu_wr_n_p_del <= cpu_wr_n_p; + cpu_a_p_del <= cpu_a_p; + cpu_d_p_del <= cpu_d_p; + cpu_cs_n_p_del <= cpu_cs_n_p; + cpu_oe_n_p_del <= cpu_oe_n_p; + end generate; + + process(cpu_clk, areset) -- Toggle FF with 1x clock to find phase + begin + if areset = '1' then + cpu_clk_toggle <= '0'; + elsif (cpu_clk'event and cpu_clk = '1') then + cpu_clk_toggle <= not(cpu_clk_toggle); + end if; + end process; + + process(cpu_clk_2x, areset) -- Find phase relationsship between 1x and 2x clock + begin + if areset = '1' then + cpu_clk_smp1 <= '0'; + cpu_clk_smp2 <= '1'; + cpu_clk_phase <= '0'; + elsif (cpu_clk_2x'event and cpu_clk_2x = '1') then + cpu_clk_smp1 <= cpu_clk_toggle; + cpu_clk_smp2 <= cpu_clk_smp1; + if cpu_clk_smp1 = '1' and cpu_clk_smp2 = '0' then + cpu_clk_phase <= '0'; + else + cpu_clk_phase <= not(cpu_clk_phase); + end if; + end if; + end process; + + process(cpu_clk_2x, areset) -- Sample input signals on 2x clock + begin + if areset = '1' then + cpu_d_smp <= "0000000000000000"; + cpu_cs_n <= "111"; + elsif (cpu_clk_2x = '1' and cpu_clk_2x'event) then + cpu_d_smp <= cpu_d_p_del; + cpu_cs_n <= cpu_cs_n_p_del; + end if; + end process; + + process(cpu_clk, areset) -- Sample input signals on 1x clock + begin + if areset = '1' then + cpu_a_smp <= "00000000000000000000000"; + cpu_oe_n <= '1'; + cpu_wr_n <= "11"; + elsif (cpu_clk = '1' and cpu_clk'event) then + cpu_a_smp <= cpu_a_p_del; + cpu_oe_n <= cpu_oe_n_p_del; + cpu_wr_n <= cpu_wr_n_p_del; + end if; + end process; + + arm7_din_int <= cpu_d_smp; + arm7_a_int <= cpu_a_smp; + arm7_we_int <= not(cpu_wr_n); + + process(cpu_clk, areset) + begin + if areset = '1' then + cpu_state <= cpu_idle; + cyc_int <= '0'; + we_int <= '0'; + adr_reg <= "00"; + cpu_d_p <= (others => 'Z'); + elsif (cpu_clk'event and cpu_clk = '1') then + + cyc_int <= '0'; + we_int <= '0'; + cpu_d_p <= (others => 'Z') after Clock_2_Out; + + + case cpu_state is + + when cpu_idle => + if cpu_oe_n = '1' then + we_int <= '1'; + end if; + if cpu_cs_n(1) = '0' then + cyc_int <= '1'; + adr_reg <= "10"; + cpu_state <= cpu_cs; + end if; + if cpu_cs_n(2) = '0' then + cyc_int <= '1'; + adr_reg <= "00"; + cpu_state <= cpu_cs; + end if; + if cpu_cs_n(3) = '0' then + cyc_int <= '1'; + adr_reg <= "01"; + cpu_state <= cpu_cs; + end if; + + when cpu_cs => + if cpu_oe_n = '0' then + cpu_d_p <= arm7_dout_int after Clock_2_Out; + if wb_i.ack = '1' then + cpu_state <= cpu_end; + else + cyc_int <= '1'; + end if; + else + if wb_i.ack = '0' then + cyc_int <= '1'; + we_int <= '1'; + else + cpu_state <= cpu_end; + end if; + end if; + + when others => + cpu_state <= cpu_idle; + + end case; + end if; + end process; + + process(cpu_clk_2x, areset) + begin + if areset = '1' then + cpu_wait_n_p <= '1'; + elsif (cpu_clk_2x'event and cpu_clk_2x = '1') then + cpu_wait_n_p <= '1' after Clock_2_Out; + if (cpu_state = cpu_cs and wb_i.ack = '0') then + cpu_wait_n_p <= '0' after Clock_2_Out; + end if; + end if; + end process; + +end behave; diff --git a/misc/ddrsdram/simscripts/ddr_tb.do b/misc/ddrsdram/simscripts/ddr_tb.do new file mode 100644 index 0000000..1f643f1 --- /dev/null +++ b/misc/ddrsdram/simscripts/ddr_tb.do @@ -0,0 +1,16 @@ +vlib work
+vcom -93 -explicit ../src/ddr_pkg.vhd
+vcom -93 -explicit ../src/ddr_top.vhd
+vcom -93 -explicit ../src/mt46v16m16.vhd
+vcom -93 -explicit ../simsrc/ddr_tb.vhd
+vsim -t 1ps ddr_tb
+view wave
+view signals
+radix hex
+add wave *
+add wave sim:/ddr_tb/ddr_ctrl/*
+force -freeze sim:/ddr_tb/areset 1 0
+run 10 ns
+force -freeze sim:/ddr_tb/areset 0 0
+when sim:/ddr_tb/break_out stop
+run 10 ms
\ No newline at end of file diff --git a/misc/ddrsdram/simscripts/ddr_top.do b/misc/ddrsdram/simscripts/ddr_top.do new file mode 100644 index 0000000..141e164 --- /dev/null +++ b/misc/ddrsdram/simscripts/ddr_top.do @@ -0,0 +1,104 @@ +vlib work
+vcom -93 -explicit ../src/ddr_pkg.vhd
+vcom -93 -explicit ../src/ddr_top.vhd
+vsim -t 1ps ddr_top
+view wave
+view signals
+radix hex
+# Add wave signals
+
+add wave -divider "System"
+add wave sim:/ddr_top/areset
+add wave sim:/ddr_top/cpu_clk
+add wave sim:/ddr_top/cpu_clk_2x
+add wave sim:/ddr_top/cpu_clk_4x
+add wave sim:/ddr_top/ddr_in_clk
+add wave sim:/ddr_top/ddr_in_clk_2x
+
+add wave -divider "Ctrl interface"
+add wave sim:/ddr_top/cpu_clk
+add wave sim:/ddr_top/ddr_data_read
+add wave sim:/ddr_top/ddr_data_write
+add wave sim:/ddr_top/ddr_req
+add wave sim:/ddr_top/ddr_rd_wr_n
+add wave sim:/ddr_top/ddr_req_len
+add wave sim:/ddr_top/ddr_read_en
+add wave sim:/ddr_top/ddr_write_en
+add wave sim:/ddr_top/ddr_command
+add wave sim:/ddr_top/ddr_command_we
+
+add wave -divider "DDR interface"
+add wave sim:/ddr_top/sdr_clk_p
+add wave sim:/ddr_top/sdr_clk_n_p
+add wave sim:/ddr_top/cke_q_p
+add wave sim:/ddr_top/cs_qn_p
+add wave sim:/ddr_top/ras_qn_p
+add wave sim:/ddr_top/cas_qn_p
+add wave sim:/ddr_top/we_qn_p
+add wave sim:/ddr_top/dm_q_p
+add wave sim:/ddr_top/dqs_q_p
+add wave sim:/ddr_top/ba_q_p
+add wave sim:/ddr_top/sdr_a_p
+add wave sim:/ddr_top/sdr_d_p
+
+add wave -divider "Internal signals"
+add wave sim:/ddr_top/clk2_phase
+add wave sim:/ddr_top/clk4_phase
+add wave sim:/ddr_top/ddr_state
+add wave sim:/ddr_top/sdr_oe_n
+add wave sim:/ddr_top/sdr_smp
+add wave sim:/ddr_top/sdr_d
+
+
+# Add input signals
+force -freeze sim:/ddr_top/cpu_clk_4x 1 0, 0 {1.875 ns} -r 3.75 ns
+run 100 ps
+force -freeze sim:/ddr_top/cpu_clk_2x 1 0, 0 {3.75 ns} -r 7.5 ns
+run 100 ps
+force -freeze sim:/ddr_top/cpu_clk 1 0, 0 {7.5 ns} -r 15 ns
+force -freeze sim:/ddr_top/ddr_in_clk 1 2ns, 0 {5.75 ns} -r 7.5 ns
+force -freeze sim:/ddr_top/ddr_in_clk_2x 0 0.125ns, 1 {2 ns} -r 3.75 ns
+
+force -freeze sim:/ddr_top/areset 1 0
+force -freeze sim:/ddr_top/ddr_command 0000 0
+force -freeze sim:/ddr_top/ddr_command_we 0 0
+force -freeze sim:/ddr_top/ddr_data_write 1234abcd 0
+force -freeze sim:/ddr_top/ddr_req 0 0
+force -freeze sim:/ddr_top/ddr_req_adr 000000 0
+force -freeze sim:/ddr_top/ddr_rd_wr_n 0 0
+force -freeze sim:/ddr_top/ddr_req_len 0 0
+
+# Start simulation
+run 45 ns
+force -freeze sim:/ddr_top/areset 0 0
+run 92 ns
+# DDR Command
+force -freeze sim:/ddr_top/ddr_command 000A 0
+force -freeze sim:/ddr_top/ddr_command_we 1 0
+run 15 ns
+force -freeze sim:/ddr_top/ddr_command 0000 0
+force -freeze sim:/ddr_top/ddr_command_we 0 0
+run 90 ns
+# DDR Read
+force -freeze sim:/ddr_top/ddr_req 1 0
+force -freeze sim:/ddr_top/ddr_req_adr 00ABCD 0
+force -freeze sim:/ddr_top/ddr_rd_wr_n 1 0
+force -freeze sim:/ddr_top/ddr_req_len 0 0
+run 15 ns
+force -freeze sim:/ddr_top/ddr_req 0 0
+force -freeze sim:/ddr_top/ddr_req_adr 000000 0
+force -freeze sim:/ddr_top/ddr_rd_wr_n 0 0
+force -freeze sim:/ddr_top/ddr_req_len 0 0
+run 150 ns
+# DDR Write
+force -freeze sim:/ddr_top/ddr_req 1 0
+force -freeze sim:/ddr_top/ddr_req_adr 00ABCD 0
+force -freeze sim:/ddr_top/ddr_rd_wr_n 0 0
+force -freeze sim:/ddr_top/ddr_req_len 0 0
+run 15 ns
+force -freeze sim:/ddr_top/ddr_req 0 0
+force -freeze sim:/ddr_top/ddr_req_adr 000000 0
+force -freeze sim:/ddr_top/ddr_rd_wr_n 0 0
+force -freeze sim:/ddr_top/ddr_req_len 0 0
+run 180 ns
+
diff --git a/misc/ddrsdram/simsrc/ddr_tb.vhd b/misc/ddrsdram/simsrc/ddr_tb.vhd new file mode 100644 index 0000000..92d1e4b --- /dev/null +++ b/misc/ddrsdram/simsrc/ddr_tb.vhd @@ -0,0 +1,301 @@ +library IEEE; +use IEEE.STD_LOGIC_1164.all; +use IEEE.STD_LOGIC_UNSIGNED.ALL; +library work; +use work.ddr.all; + +entity ddr_tb is + port ( areset : in std_logic; + break_out : out std_logic); +end ddr_tb; + +architecture behave of ddr_tb is + +signal cpu_clk : std_logic; +signal cpu_clk_2x : std_logic; +signal cpu_clk_4x : std_logic; +signal ddr_in_clk : std_logic; +signal ddr_in_clk_2x : std_logic; + +signal ddr_command : std_logic_vector(15 downto 0); +signal ddr_command_we : std_logic; + +signal ddr_data_read : std_logic_vector(31 downto 0); -- Data read from DDR SDRAM +signal ddr_data_write : std_logic_vector(35 downto 0); -- Data to be written to DDR SDRAM +signal ddr_req_adr : std_logic_vector(23 downto 1); -- Request address +signal ddr_req : std_logic; -- Request DDR SDRAM access +signal ddr_req_ack : std_logic; -- Request acknowledge +signal ddr_busy : std_logic; -- Request acknowledge +signal ddr_rd_wr_n : std_logic; -- Access type 1=READ, 0=WRITE +signal ddr_req_len : std_logic; -- Number of 16-bits words to transfer +signal ddr_read_en : std_logic; -- Enable signal for read data +signal ddr_write_en : std_logic; -- Enable (read) signal for data write +signal refresh_en : std_logic; + +signal sdr_clk_p : std_logic; -- ddr_sdram_clock +signal sdr_clk_n_p : std_logic; -- /ddr_sdram_clock +signal cke_q_p : std_logic; -- clock enable +signal cs_qn_p : std_logic; -- /chip select +signal ras_qn_p : std_logic; -- /ras +signal cas_qn_p : std_logic; -- /cas +signal we_qn_p : std_logic; -- /write enable +signal dm_q_p : std_logic_vector(1 downto 0); -- data mask bits, set to "00" +signal dqs_q_p : std_logic_vector(1 downto 0); -- data strobe, only for write +signal ba_q_p : std_logic_vector(1 downto 0); -- bank select +signal sdr_a_p : std_logic_vector(12 downto 0); -- address bus +signal sdr_d_p : std_logic_vector(15 downto 0); -- bidir data bus + +constant min_time : time := 1.875 ns; + +begin + + clock1: + process + begin + loop + cpu_clk_4x <= '1'; + wait for min_time; + cpu_clk_4x <= '0'; + wait for min_time; + end loop; + end process; + + clock2: + process + begin + loop + cpu_clk_2x <= '1' after 100 ps; + wait until rising_edge(cpu_clk_4x); + cpu_clk_2x <= '0' after 100 ps; + wait until rising_edge(cpu_clk_4x); + end loop; + end process; + + clock3: + process + begin + loop + cpu_clk <= '1' after 100 ps; + wait until rising_edge(cpu_clk_2x); + cpu_clk <= '0' after 100 ps; + wait until rising_edge(cpu_clk_2x); + end loop; + end process; + + ddr_in_clk_2x <= cpu_clk_4x after 1 ns; + + clock4: + process + begin + loop + ddr_in_clk <= '0' after 100 ps; + wait until rising_edge(ddr_in_clk_2x); + ddr_in_clk <= '1' after 100 ps; + wait until rising_edge(ddr_in_clk_2x); + end loop; + end process; + + inputdata: + process + begin + -- Wait until global reset released + loop + ddr_command <= x"0000"; + ddr_command_we <= '0'; + ddr_data_write <= x"000000000"; + ddr_req <= '0'; + ddr_req_adr <= "00000000000000000000000"; + ddr_rd_wr_n <= '0'; + ddr_req_len <= '0'; + break_out <= '0'; + refresh_en <= '0'; + + wait until falling_edge(areset); + + -- DDR initialization sequence + -- Wait more than 200 us + wait for 201000 ns; + + -- Send precharge command + wait until rising_edge(cpu_clk); + ddr_command <= x"8000"; + ddr_command_we <= '1'; + wait until rising_edge(cpu_clk); + ddr_command <= x"0000"; + ddr_command_we <= '0'; + + -- Wait for 1 us + wait for 1000 ns; + + -- Load extended mode register + -- Enable DLL + -- Normal drive strength + wait until rising_edge(cpu_clk); + ddr_command <= x"2000"; + ddr_command_we <= '1'; + wait until rising_edge(cpu_clk); + ddr_command <= x"0000"; + ddr_command_we <= '0'; + + -- Wait for 1 us + wait for 1000 ns; + + -- Load mode register + -- Burst length: 2 + -- Burst type: Sequential + -- Cas latency: 2 + -- Reset DLL + wait until rising_edge(cpu_clk); + ddr_command <= x"0121"; + ddr_command_we <= '1'; + wait until rising_edge(cpu_clk); + ddr_command <= x"0000"; + ddr_command_we <= '0'; + + -- Wait for 1 us + wait for 1000 ns; + + -- Send precharge command + wait until rising_edge(cpu_clk); + ddr_command <= x"8000"; + ddr_command_we <= '1'; + wait until rising_edge(cpu_clk); + ddr_command <= x"0000"; + ddr_command_we <= '0'; + + -- Enable refresh + refresh_en <= '1'; + + -- Wait 30 us (minimum 2 autorefresh cycles) + wait for 30000 ns; + + -- Load mode register + -- Burst length: 2 + -- Burst type: Sequential + -- Cas latency: 2 + -- Deactivate Reset DLL + wait until rising_edge(cpu_clk); + ddr_command <= x"0021"; + ddr_command_we <= '1'; + wait until rising_edge(cpu_clk); + ddr_command <= x"0000"; + ddr_command_we <= '0'; + + -- Wait for 2 us (DLL stable) + wait for 2000 ns; + + -- Write data to DDR + wait until rising_edge(cpu_clk_2x); + ddr_data_write <= x"312345678"; + ddr_req <= '1'; + ddr_req_adr <= "00000000000000000000000"; + ddr_rd_wr_n <= '0'; + ddr_req_len <= '0'; + wait until rising_edge(ddr_write_en); + wait until rising_edge(cpu_clk_2x); + ddr_req <= '0'; + ddr_req_adr <= "00000000000000000000000"; + ddr_rd_wr_n <= '0'; + ddr_req_len <= '0'; + ddr_data_write <= x"000000000"; + wait for 100 ns; + + -- Read data from DDR + wait until rising_edge(cpu_clk_2x); + ddr_req <= '1'; + ddr_req_adr <= "00000000000000000000000"; + ddr_rd_wr_n <= '1'; + ddr_req_len <= '0'; + wait until rising_edge(ddr_req_ack); + wait until rising_edge(cpu_clk_2x); + ddr_req <= '0'; + ddr_req_adr <= "00000000000000000000000"; + ddr_rd_wr_n <= '0'; + ddr_req_len <= '0'; + ddr_data_write <= x"000000000"; + + + + wait for 100 ns; + break_out <= '1'; + wait for 100 ns; + + end loop; + + end process; + + ddr_ctrl: + ddr_top port map( + areset => areset, + cpu_clk => cpu_clk, + cpu_clk_2x => cpu_clk_2x, + cpu_clk_4x => cpu_clk_4x, + ddr_in_clk => ddr_in_clk, + ddr_in_clk_2x => ddr_in_clk_2x, + + -- Command interface + ddr_command => ddr_command, + ddr_command_we => ddr_command_we, + refresh_en => refresh_en, + + -- Data interface signals + ddr_data_read => ddr_data_read, + ddr_data_write => ddr_data_write, + ddr_req_adr => ddr_req_adr, + ddr_req => ddr_req, + ddr_req_ack => ddr_req_ack, + ddr_busy => ddr_busy, + ddr_rd_wr_n => ddr_rd_wr_n, + ddr_req_len => ddr_req_len, + ddr_read_en => ddr_read_en, + ddr_write_en => ddr_write_en, + -- DDR SDRAM Signals + sdr_clk_p => sdr_clk_p, + sdr_clk_n_p => sdr_clk_n_p, + cke_q_p => cke_q_p, + cs_qn_p => cs_qn_p, + ras_qn_p => ras_qn_p, + cas_qn_p => cas_qn_p, + we_qn_p => we_qn_p, + dm_q_p => dm_q_p, + dqs_q_p => dqs_q_p, + ba_q_p => ba_q_p, + sdr_a_p => sdr_a_p, + sdr_d_p => sdr_d_p); + + myram: + MT46V16M16 generic map( + tCK => 7.500 ns, + tCH => 3.375 ns, -- 0.45*tCK + tCL => 3.375 ns, -- 0.45*tCK + tDH => 0.500 ns, + tDS => 0.500 ns, + tIH => 0.900 ns, + tIS => 0.900 ns, + tMRD => 15.000 ns, + tRAS => 40.000 ns, + tRAP => 20.000 ns, + tRC => 65.000 ns, + tRFC => 75.000 ns, + tRCD => 20.000 ns, + tRP => 20.000 ns, + tRRD => 15.000 ns, + tWR => 15.000 ns, + addr_bits => 13, + data_bits => 16, + cols_bits => 9) + port map( + Dq => sdr_d_p, + Dqs => dqs_q_p, + Addr => sdr_a_p, + Ba => ba_q_p, + Clk => sdr_clk_p, + Clk_n => sdr_clk_n_p, + Cke => cke_q_p, + Cs_n => cs_qn_p, + Ras_n => ras_qn_p, + Cas_n => cas_qn_p, + We_n => we_qn_p, + Dm => dm_q_p); + +end behave; diff --git a/misc/ddrsdram/src/ddr_pkg.vhd b/misc/ddrsdram/src/ddr_pkg.vhd new file mode 100644 index 0000000..af4a705 --- /dev/null +++ b/misc/ddrsdram/src/ddr_pkg.vhd @@ -0,0 +1,107 @@ +library IEEE; +use IEEE.STD_LOGIC_1164.all; +use IEEE.STD_LOGIC_UNSIGNED.ALL; + +package ddr is + + function mirror_bus32 ( org_sig : std_logic_vector) return std_logic_vector; + function mirror_bus4 ( org_sig : std_logic_vector) return std_logic_vector; + + component ddr_top + generic( + simulate_io_time : boolean := false); + port ( -- Asyncronous reset and clocks + areset : in std_logic; + cpu_clk : in std_logic; + cpu_clk_2x : in std_logic; + cpu_clk_4x : in std_logic; + ddr_in_clk : in std_logic; + ddr_in_clk_2x : in std_logic; + + -- Command interface + ddr_command : in std_logic_vector(15 downto 0); + ddr_command_we : in std_logic; + refresh_en : in std_logic; + + + -- Data interface signals + ddr_data_read : out std_logic_vector(31 downto 0); -- Data read from DDR SDRAM + ddr_data_write : in std_logic_vector(35 downto 0); -- Data to be written to DDR SDRAM + ddr_req_adr : in std_logic_vector(25 downto 1); -- Request address + ddr_req : in std_logic; -- Request DDR SDRAM access + ddr_busy : out std_logic; -- Request acknowledge + ddr_rd_wr_n : in std_logic; -- Access type 1=READ, 0=WRITE + ddr_req_len : in std_logic; -- Number of 16-bits words to transfer (0=2, 1=8) + ddr_read_en : out std_logic; -- Enable signal for read data + ddr_write_en : out std_logic; -- Enable (read) signal for data write + + -- DDR SDRAM Signals + sdr_clk_p : out std_logic; -- ddr_sdram_clock + sdr_clk_n_p : out std_logic; -- /ddr_sdram_clock + cke_q_p : out std_logic; -- clock enable + cs_qn_p : out std_logic; -- /chip select + ras_qn_p : inout std_logic; -- /ras + cas_qn_p : inout std_logic; -- /cas + we_qn_p : inout std_logic; -- /write enable + dm_q_p : out std_logic_vector(1 downto 0); -- data mask bits, set to "00" + dqs_q_p : out std_logic_vector(1 downto 0); -- data strobe, only for write + ba_q_p : out std_logic_vector(1 downto 0); -- bank select + sdr_a_p : out std_logic_vector(12 downto 0); -- address bus + sdr_d_p : inout std_logic_vector(15 downto 0)); -- bidir data bus + end component; + + component MT46V16M16 + GENERIC ( -- Timing for -75Z CL2 + tCK : TIME := 7.500 ns; + tCH : TIME := 3.375 ns; -- 0.45*tCK + tCL : TIME := 3.375 ns; -- 0.45*tCK + tDH : TIME := 0.500 ns; + tDS : TIME := 0.500 ns; + tIH : TIME := 0.900 ns; + tIS : TIME := 0.900 ns; + tMRD : TIME := 15.000 ns; + tRAS : TIME := 40.000 ns; + tRAP : TIME := 20.000 ns; + tRC : TIME := 65.000 ns; + tRFC : TIME := 75.000 ns; + tRCD : TIME := 20.000 ns; + tRP : TIME := 20.000 ns; + tRRD : TIME := 15.000 ns; + tWR : TIME := 15.000 ns; + addr_bits : INTEGER := 13; + data_bits : INTEGER := 16; + cols_bits : INTEGER := 9 + ); + PORT ( + Dq : INOUT STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + Dqs : INOUT STD_LOGIC_VECTOR (1 DOWNTO 0) := "ZZ"; + Addr : IN STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + Ba : IN STD_LOGIC_VECTOR (1 DOWNTO 0); + Clk : IN STD_LOGIC; + Clk_n : IN STD_LOGIC; + Cke : IN STD_LOGIC; + Cs_n : IN STD_LOGIC; + Ras_n : IN STD_LOGIC; + Cas_n : IN STD_LOGIC; + We_n : IN STD_LOGIC; + Dm : IN STD_LOGIC_VECTOR (1 DOWNTO 0) + ); + end component; + +end; + +package body ddr is + + function mirror_bus32 ( org_sig : std_logic_vector) return std_logic_vector is + begin + return (org_sig(7 downto 0) & org_sig(15 downto 8) & org_sig(23 downto 16) & org_sig(31 downto 24)); + end function mirror_bus32; + + function mirror_bus4 ( org_sig : std_logic_vector) return std_logic_vector is + begin + return (org_sig(0) & org_sig(1) & org_sig(2) & org_sig(3)); + end function mirror_bus4; + +end package body; + +
\ No newline at end of file diff --git a/misc/ddrsdram/src/ddr_top.vhd b/misc/ddrsdram/src/ddr_top.vhd new file mode 100644 index 0000000..2aceae9 --- /dev/null +++ b/misc/ddrsdram/src/ddr_top.vhd @@ -0,0 +1,743 @@ +library IEEE; +use IEEE.STD_LOGIC_1164.all; +use IEEE.STD_LOGIC_UNSIGNED.ALL; + +library UNISIM; +use UNISIM.vcomponents.all; + +entity ddr_top is + generic( + simulate_io_time : boolean := false); + port ( -- Asyncronous reset and clocks + areset : in std_logic; + cpu_clk : in std_logic; + cpu_clk_2x : in std_logic; + cpu_clk_4x : in std_logic; + ddr_in_clk : in std_logic; + ddr_in_clk_2x : in std_logic; + + -- Command interface + ddr_command : in std_logic_vector(15 downto 0); + ddr_command_we : in std_logic; + refresh_en : in std_logic; + + -- Data interface signals + ddr_data_read : out std_logic_vector(31 downto 0); -- Data read from DDR SDRAM + ddr_data_write : in std_logic_vector(35 downto 0); -- Data to be written to DDR SDRAM + ddr_req_adr : in std_logic_vector(25 downto 1); -- Request address + ddr_req : in std_logic; -- Request DDR SDRAM access + ddr_busy : out std_logic; -- Request acknowledge + ddr_rd_wr_n : in std_logic; -- Access type 1=READ, 0=WRITE + ddr_req_len : in std_logic; -- Number of 16-bits words to transfer (0=2, 1=8) + ddr_read_en : out std_logic; -- Enable signal for read data + ddr_write_en : out std_logic; -- Enable (read) signal for data write + + -- DDR SDRAM Signals + sdr_clk_p : out std_logic; -- ddr_sdram_clock + sdr_clk_n_p : out std_logic; -- /ddr_sdram_clock + cke_q_p : out std_logic; -- clock enable + cs_qn_p : out std_logic; -- /chip select + ras_qn_p : inout std_logic; -- /ras + cas_qn_p : inout std_logic; -- /cas + we_qn_p : inout std_logic; -- /write enable + dm_q_p : out std_logic_vector(1 downto 0); -- data mask bits, set to "00" + dqs_q_p : out std_logic_vector(1 downto 0); -- data strobe, only for write + ba_q_p : out std_logic_vector(1 downto 0); -- bank select + sdr_a_p : out std_logic_vector(12 downto 0); -- address bus + sdr_d_p : inout std_logic_vector(15 downto 0)); -- bidir data bus +end ddr_top; + +architecture behave of ddr_top is + +attribute keep : string; + +type clk4_type is array(0 to 15) of std_logic_vector(1 downto 0); + +signal cpu_clk_tog : std_logic; +signal ddr_cmd : std_logic_vector(15 downto 0); +signal ddr_cmd_we_smp : std_logic; +signal new_command : std_logic; + +signal cpu_clk_2x_smp1 : std_logic; +signal cpu_clk_2x_smp2 : std_logic; +signal cpu_clk_4x_smp1 : std_logic; +signal cpu_clk_4x_smp2 : std_logic; + +signal clk2_phase : std_logic; +signal clk4_phase : std_logic_vector(3 downto 0); +signal clk4_phase_short : clk4_type; +attribute keep of clk4_phase_short:signal is "true"; + +signal ddr_clk_tog : std_logic; +signal ddr_clk_smp1 : std_logic; +signal ddr_clk_smp2 : std_logic; +signal ddr_clk_phase : std_logic; + +signal smp_req_adr : std_logic_vector(25 downto 1); +signal smp_req_type : std_logic; +signal smp_req_len : std_logic; +signal ddr_write_en_int : std_logic; +signal ddr_read_en_int : std_logic; + +signal dqs_q : std_logic_vector(1 downto 0); +signal dqs_oe_n : std_logic_vector(1 downto 0); +attribute keep of dqs_oe_n:signal is "true"; +signal cas_qn : std_logic; +signal ras_qn : std_logic; +signal we_qn : std_logic; +signal ba_q : std_logic_vector(1 downto 0); +signal sdr_clk : std_logic; +signal sdr_clk_n : std_logic; +signal sdr_a : std_logic_vector(12 downto 0); +signal sdr_d : std_logic_vector(15 downto 0); +signal sdr_smp : std_logic_vector(35 downto 0); +signal sdr_oe_n : std_logic_vector(15 downto 0); +attribute keep of sdr_oe_n:signal is "true"; +signal sdr_oe_ctrl : std_logic_vector(15 downto 0); +attribute keep of sdr_oe_ctrl:signal is "true"; +signal sdr_wr_msw : std_logic_vector(17 downto 0); +attribute keep of sdr_wr_msw:signal is "true"; +signal dm_q : std_logic_vector(1 downto 0); + +signal nowin_idle_dqs : std_logic_vector(1 downto 0); +signal nowin_wr_nop1_d : std_logic_vector(15 downto 0); +signal nowin_wr_nop1_dqs : std_logic_vector(1 downto 0); +signal nowin_wr_nop1_dm : std_logic_vector(1 downto 0); +signal nowin_wr_nop2_dqs : std_logic_vector(1 downto 0); +signal nowin_wr_nop3_d : std_logic_vector(15 downto 0); +signal nowin_wr_nop3_dqs : std_logic_vector(1 downto 0); +attribute keep of nowin_idle_dqs:signal is "true"; +attribute keep of nowin_wr_nop1_d:signal is "true"; +attribute keep of nowin_wr_nop1_dqs:signal is "true"; +attribute keep of nowin_wr_nop1_dm:signal is "true"; +attribute keep of nowin_wr_nop2_dqs:signal is "true"; +attribute keep of nowin_wr_nop3_d:signal is "true"; +attribute keep of nowin_wr_nop3_dqs:signal is "true"; + +signal cas_n_smp : std_logic; +signal ras_n_smp : std_logic; +signal we_n_smp : std_logic; +signal read_start_sig : std_logic; +signal sdr_d_in : std_logic_vector(15 downto 0); +signal read_time_cnt : std_logic_vector(1 downto 0); +signal read_input_en : std_logic; +signal read_input_en_del : std_logic; +signal ddr_data_read_int : std_logic_vector(31 downto 0); + +signal refresh_pend : std_logic; +signal refresh_end : std_logic; +signal refresh_cnt : std_logic_vector(9 downto 0); +signal refresh_wait_cnt : std_logic_vector(3 downto 0); +signal refresh_wait_end : std_logic; + +signal cas_qn_p_del : std_logic; +signal ras_qn_p_del : std_logic; +signal we_qn_p_del : std_logic; +signal sdr_d_p_del : std_logic_vector(15 downto 0); + +signal saved_row : std_logic_vector(26 downto 11); +signal operation : std_logic_vector(1 downto 0); + +signal ddr_req_adr_int : std_logic_vector(25 downto 1); + +type state_type is (idle, act, act_nop1, act_nop2, rd_wr, rd_nop1, + rd_nop2,rd_nop3,rd_nop4, rd_nop5,pre, pre_nop1, pre_nop2, wr_nop1, wr_nop2, + wr_nop3, cmd, cpu_pre, refresh, refresh_wait); +signal ddr_state : state_type; + +constant Clk_to_Output : time := 2.2 ns; +constant Input_Setup : time := 2.5 ns; + +constant Refresh_Interval : std_logic_vector(9 downto 0) := "1111100110"; + +begin + + iotimingon: + if simulate_io_time generate + begin + cas_qn_p_del <= 'X' after 0 ns, cas_qn_p after Input_Setup; + ras_qn_p_del <= 'X' after 0 ns, ras_qn_p after Input_Setup; + we_qn_p_del <= 'X' after 0 ns, we_qn_p after Input_Setup; + sdr_d_p_del <= "XXXXXXXXXXXXXXXX" after 0 ns, sdr_d_p after Input_Setup; + end generate; + + iotimingoff: + if not simulate_io_time generate + begin + cas_qn_p_del <= cas_qn_p; + ras_qn_p_del <= ras_qn_p; + we_qn_p_del <= we_qn_p; + sdr_d_p_del <= sdr_d_p; + end generate; + + ddr_write_en <= ddr_write_en_int; + ddr_read_en <= ddr_read_en_int; + ddr_data_read <= ddr_data_read_int; + + ddr_req_adr_int <= (ddr_req_adr(24 downto 10) & '0' & ddr_req_adr(9 downto 1)) when (simulate_io_time) else ddr_req_adr; + + process(cpu_clk, areset) -- Toggle a flip-flop with cpu_clk, in order + begin -- to find phase relation with 2x and 4x clocks + if areset = '1' then + cpu_clk_tog <= '0'; + elsif (cpu_clk'event and cpu_clk = '1') then + cpu_clk_tog <= not(cpu_clk_tog); + end if; + end process; + + process(cpu_clk_2x, areset) -- Find phase relation between cpu_clk and cpu_clk_2x + begin + if areset = '1' then + cpu_clk_2x_smp1 <= '0'; + cpu_clk_2x_smp2 <= '0'; + clk2_phase <= '0'; + elsif (cpu_clk_2x'event and cpu_clk_2x = '1') then + cpu_clk_2x_smp1 <= cpu_clk_tog; + cpu_clk_2x_smp2 <= cpu_clk_2x_smp1; + if (cpu_clk_2x_smp1 = '1' and cpu_clk_2x_smp2 = '0') then + clk2_phase <= '0'; + else + clk2_phase <= not(clk2_phase); + end if; + end if; + end process; + + process(cpu_clk_4x, areset) -- Find phase relation between cpu_clk and cpu_clk_4x + begin + if areset = '1' then + cpu_clk_4x_smp1 <= '0'; + cpu_clk_4x_smp2 <= '0'; + clk4_phase <= "0000"; + clk4_phase_short(0) <= "00"; + clk4_phase_short(1) <= "00"; + clk4_phase_short(2) <= "00"; + clk4_phase_short(3) <= "00"; + clk4_phase_short(4) <= "00"; + clk4_phase_short(5) <= "00"; + clk4_phase_short(6) <= "00"; + clk4_phase_short(7) <= "00"; + clk4_phase_short(8) <= "00"; + clk4_phase_short(9) <= "00"; + clk4_phase_short(10) <= "00"; + clk4_phase_short(11) <= "00"; + clk4_phase_short(12) <= "00"; + clk4_phase_short(13) <= "00"; + clk4_phase_short(14) <= "00"; + clk4_phase_short(15) <= "00"; + elsif (cpu_clk_4x'event and cpu_clk_4x = '1') then + cpu_clk_4x_smp1 <= cpu_clk_tog; + cpu_clk_4x_smp2 <= cpu_clk_4x_smp1; + for i in 0 to 15 loop + if (cpu_clk_4x_smp1 = '1' and cpu_clk_4x_smp2 = '0') then + clk4_phase <= "0100"; + clk4_phase_short(i) <= "01"; + else + clk4_phase <= (clk4_phase(2 downto 0) & clk4_phase(3)); + clk4_phase_short(i) <= clk4_phase_short(i)(0) & clk4_phase_short(i)(1); + end if; + end loop; + end if; + end process; + + process(cpu_clk_4x, areset) -- + begin + if areset = '1' then + sdr_clk <= '0'; + sdr_clk_n <= '0'; + elsif (cpu_clk_4x'event and cpu_clk_4x = '1') then + if clk4_phase_short(0)(0) = '1' then + sdr_clk <= '1'; + else + sdr_clk <= '0'; + end if; + if clk4_phase_short(0)(1) = '1' then + sdr_clk_n <= '1'; + else + sdr_clk_n <= '0'; + end if; + end if; + end process; + + cke_q_p <= '1' after Clk_to_Output; + cs_qn_p <= '0' after Clk_to_Output; + + process(cpu_clk_4x, areset) -- + begin + if areset = '1' then + ras_qn_p <= '1'; + cas_qn_p <= '1'; + we_qn_p <= '1'; + dqs_q_p <= "ZZ"; + sdr_a_p <= "0000000000000"; + ba_q_p <= "00"; + sdr_clk_p <= '0'; + sdr_clk_n_p <= '1'; + elsif (cpu_clk_4x'event and cpu_clk_4x = '1') then + ras_qn_p <= transport ras_qn after Clk_to_Output; + cas_qn_p <= transport cas_qn after Clk_to_Output; + we_qn_p <= transport we_qn after Clk_to_Output; + if dqs_oe_n(0) = '0' then + dqs_q_p(0) <= transport dqs_q(0) after Clk_to_Output; + else + dqs_q_p(0) <= transport 'Z' after Clk_to_Output; + end if; + if dqs_oe_n(1) = '0' then + dqs_q_p(1) <= transport dqs_q(1) after Clk_to_Output; + else + dqs_q_p(1) <= transport 'Z' after Clk_to_Output; + end if; + sdr_a_p <= transport sdr_a after Clk_to_Output; + ba_q_p <= transport ba_q after Clk_to_Output; + sdr_clk_p <= transport sdr_clk after Clk_to_Output; + sdr_clk_n_p <= transport sdr_clk_n after Clk_to_Output; + end if; + end process; + + process(cpu_clk_2x, areset) -- + begin + if areset = '1' then + ddr_state <= idle; + ras_qn <= '1'; + cas_qn <= '1'; + we_qn <= '1'; + smp_req_adr <= (others => '0'); + smp_req_type <= '0'; + smp_req_len <= '0'; + sdr_a <= "XXXXXXXXXXXXX"; + ba_q <= "00"; + ddr_busy <= '1'; + saved_row <= "1000000000000000"; + ddr_write_en_int <= '0'; + ddr_read_en_int <= '0'; + nowin_idle_dqs <= "11"; + nowin_wr_nop1_d <= "0000000000000000"; + nowin_wr_nop1_dqs <= "00"; + nowin_wr_nop1_dm <= "00"; + nowin_wr_nop2_dqs <= "00"; + nowin_wr_nop3_d <= "0000000000000000"; + nowin_wr_nop3_dqs <= "00"; + elsif (cpu_clk_2x'event and cpu_clk_2x = '1') then + + -- Default values + ras_qn <= '1'; + cas_qn <= '1'; + we_qn <= '1'; + sdr_a <= "XXXXXXXXXXXXX"; + ddr_busy <= '1'; + ddr_write_en_int <= '0'; + ddr_read_en_int <= '0'; + + nowin_idle_dqs <= "00"; + nowin_wr_nop1_d <= "0000000000000000"; + nowin_wr_nop1_dqs <= "00"; + nowin_wr_nop1_dm <= "00"; + nowin_wr_nop2_dqs <= "00"; + nowin_wr_nop3_d <= "0000000000000000"; + nowin_wr_nop3_dqs <= "00"; + + case ddr_state is + when idle => + smp_req_adr <= ddr_req_adr_int; + smp_req_type <= ddr_rd_wr_n; + smp_req_len <= ddr_req_len; + ddr_busy <= '0'; + operation <= "00"; + if refresh_pend = '1' then + operation <= "01"; + ddr_state <= pre; + elsif new_command = '1' then + if ddr_cmd(15) = '1' then + operation <= "10"; + ddr_state <= cpu_pre; + else + ddr_state <= cmd; + end if; + elsif (ddr_req = '1' and ddr_req_adr_int(25 downto 11) = saved_row(25 downto 11) and saved_row(26) = '0') then + operation <= "11"; + ddr_write_en_int <= not(ddr_rd_wr_n); + ddr_state <= rd_wr; + elsif ddr_req = '1' then + operation <= "11"; + ddr_state <= pre; + else + ddr_state <= idle; + nowin_idle_dqs <= "11"; + end if; + when act => + sdr_a <= smp_req_adr(23 downto 11); + ba_q <= smp_req_adr(25 downto 24); + ras_qn <= '0'; + ddr_write_en_int <= not(smp_req_type); + ddr_state <= act_nop1; + when act_nop1 => + ddr_state <= act_nop2; + when act_nop2 => + ddr_state <= rd_wr; + when rd_wr => + sdr_a(10) <= '0'; -- Disable auto precharge + sdr_a(9 downto 0) <= smp_req_adr(10 downto 1); + ba_q <= smp_req_adr(25 downto 24); + saved_row <= '0' & smp_req_adr(25 downto 11); + cas_qn <= '0'; + we_qn <= smp_req_type; + if smp_req_type = '1' then + ddr_state <= rd_nop1; + else + ddr_state <= wr_nop1; + nowin_wr_nop1_d <= "1111111111111111"; + nowin_wr_nop1_dqs <= "11"; + nowin_wr_nop1_dm <= "11"; + end if; + when wr_nop1 => + ddr_state <= wr_nop2; + nowin_wr_nop2_dqs <= "11"; + when wr_nop2 => + ddr_state <= wr_nop3; + nowin_wr_nop3_d <= "1111111111111111"; + nowin_wr_nop3_dqs <= "11"; + when wr_nop3 => + nowin_idle_dqs <= "11"; + ddr_state <= idle; + when rd_nop1 => + ddr_state <= rd_nop2; + when rd_nop2 => + if operation /= "11" then + nowin_idle_dqs <= "11"; + ddr_state <= idle; + else + ddr_state <= rd_nop3; + end if; + when rd_nop3 => + ddr_state <= rd_nop4; + when rd_nop4 => + ddr_read_en_int <= '1'; + ddr_state <= rd_nop5; + when rd_nop5 => + nowin_idle_dqs <= "11"; + ddr_state <= idle; + when pre => + ras_qn <= '0'; + we_qn <= '0'; + sdr_a(10) <= '1'; -- Precharge all banks + ba_q <= smp_req_adr(25 downto 24); + ddr_state <= pre_nop1; + when pre_nop1 => + ddr_state <= pre_nop2; + when cmd => + cas_qn <= '0'; + ras_qn <= '0'; + we_qn <= '0'; + ba_q <= ddr_cmd(14 downto 13); + sdr_a <= ddr_cmd(12 downto 0); + nowin_idle_dqs <= "11"; + ddr_state <= idle; + when cpu_pre => + ddr_state <= pre; + when refresh => + cas_qn <= '0'; + ras_qn <= '0'; + saved_row(26) <= '1'; + ddr_state <= refresh_wait; + when refresh_wait => + if refresh_wait_end = '1' then + ddr_state <= pre_nop2; + end if; + when pre_nop2 => + if operation = "01" then + operation <= "10"; + ddr_state <= refresh; + elsif operation = "10" then + nowin_idle_dqs <= "11"; + ddr_state <= idle; + else + ddr_state <= act; + end if; + when others => + ddr_state <= idle; + nowin_idle_dqs <= "11"; + end case; + end if; + end process; + + process(cpu_clk, areset) -- + begin + if areset = '1' then + ddr_cmd <= "0000000000000000"; + elsif (cpu_clk'event and cpu_clk = '1') then + if ddr_command_we = '1' then + ddr_cmd <= ddr_command; + else + ddr_cmd <= ddr_cmd; + end if; + end if; + end process; + + process(cpu_clk_2x, areset) -- + begin + if areset = '1' then + ddr_cmd_we_smp <= '0'; + new_command <= '0'; + sdr_smp <= "000000000000000000000000000000000000"; + elsif (cpu_clk_2x'event and cpu_clk_2x = '1') then + ddr_cmd_we_smp <= ddr_command_we; + if ddr_command_we = '0' and ddr_cmd_we_smp = '1' then + new_command <= '1'; + elsif ddr_state = cmd or ddr_state = cpu_pre then + new_command <= '0'; + else + new_command <= new_command; + end if; + + if ddr_write_en_int = '1' then + sdr_smp <= ddr_data_write; + else + sdr_smp <= sdr_smp; + end if; + + end if; + end process; + + process(cpu_clk_4x, areset) -- + begin + if areset = '1' then + dqs_q <= "00"; + dqs_oe_n <= "11"; + sdr_oe_ctrl <= "1111111111111111"; + sdr_wr_msw <= "000000000000000000"; + elsif (cpu_clk_4x'event and cpu_clk_4x = '1') then + + for i in 0 to 15 loop + if nowin_wr_nop1_d(i) = '1' and clk4_phase_short(i)(0) = '1' then + sdr_oe_ctrl(i) <= '0'; + elsif nowin_wr_nop3_d(i) = '1' and clk4_phase_short(i)(0) = '1' then + sdr_oe_ctrl(i) <= '1'; + end if; + end loop; + + for i in 0 to 1 loop + if nowin_idle_dqs(i) = '1' or nowin_wr_nop3_dqs(i) = '1' then + dqs_oe_n(i) <= '1'; + elsif nowin_wr_nop1_dqs(i) = '1' then + dqs_oe_n(i) <= '0'; + end if; + end loop; + + for i in 0 to 1 loop + if (nowin_wr_nop2_dqs(i) = '1' and clk4_phase_short(i)(0) = '1') then + dqs_q(i) <= '1'; + else + dqs_q(i) <= '0'; + end if; + end loop; + + for i in 0 to 15 loop + if nowin_wr_nop1_d(i) = '1' and clk4_phase_short(i)(1) = '1' then + sdr_wr_msw(i) <= '1'; + else + sdr_wr_msw(i) <= '0'; + end if; + end loop; + + for i in 0 to 1 loop + if nowin_wr_nop1_dm(i) = '1' and clk4_phase_short(i)(1) = '1' then + sdr_wr_msw(i+16) <= '1'; + else + sdr_wr_msw(i+16) <= '0'; + end if; + end loop; + + end if; + end process; + + -- NOTE! DATA OUTPUT PATH. CLOCKED ON FALLING 4X CLOCK + process(cpu_clk_4x, areset) -- + begin + if areset = '1' then + sdr_d_p <= "ZZZZZZZZZZZZZZZZ"; + dm_q_p <= "11"; + sdr_oe_n <= "1111111111111111"; + sdr_d <= "0000000000000000"; + dm_q <= "11"; + elsif (cpu_clk_4x'event and cpu_clk_4x = '0') then + + for i in 0 to 15 loop + if sdr_oe_n(i) = '0' then + sdr_d_p(i) <= transport sdr_d(i) after Clk_to_Output; + else + sdr_d_p(i) <= transport 'Z' after Clk_to_Output; + end if; + end loop; + + dm_q_p <= transport dm_q after Clk_to_Output; + + for i in 0 to 15 loop + if sdr_oe_ctrl(i) = '0' then + sdr_oe_n(i) <= '0'; + else + sdr_oe_n(i) <= '1'; + end if; + end loop; + + for i in 0 to 15 loop + if sdr_wr_msw(i) = '1' then + sdr_d(i) <= sdr_smp(i); + else + sdr_d(i) <= sdr_smp(i+16); + end if; + end loop; + + for i in 0 to 1 loop + if sdr_wr_msw(i+16) = '1' then + dm_q(i) <= sdr_smp(i+32); + else + dm_q(i) <= sdr_smp(i+34); + end if; + end loop; + + end if; + end process; + + process(cpu_clk_2x, areset) -- + begin + if areset = '1' then + refresh_cnt <= "0000000000"; + refresh_pend <= '0'; + refresh_end <= '0'; + refresh_wait_cnt <= "0000"; + refresh_wait_end <= '0'; + elsif (cpu_clk_2x'event and cpu_clk_2x = '1') then + + if refresh_cnt = Refresh_Interval then + refresh_end <= '1'; + else + refresh_end <= '0'; + end if; + + if refresh_end = '1' then + refresh_cnt <= "0000000000"; + else + refresh_cnt <= refresh_cnt + '1'; + end if; + + if refresh_end = '1' and refresh_en = '1' then + refresh_pend <= '1'; + elsif ddr_state = refresh then + refresh_pend <= '0'; + else + refresh_pend <= refresh_pend; + end if; + + if ddr_state = refresh_wait then + refresh_wait_cnt <= refresh_wait_cnt + '1'; + else + refresh_wait_cnt <= "0000"; + end if; + + if refresh_wait_cnt = "1011" then + refresh_wait_end <= '1'; + else + refresh_wait_end <= '0'; + end if; + + end if; + end process; + + -- 911. THIS IS A DUMMY FOR FGPA IMPEMENTATION TESTING + + process(ddr_in_clk, areset) + begin + if areset = '1' then + ddr_clk_tog <= '0'; + elsif (ddr_in_clk'event and ddr_in_clk = '1') then + ddr_clk_tog <= not(ddr_clk_tog); + end if; + end process; + + process(ddr_in_clk_2x, areset) + begin + if areset = '1' then + ddr_clk_smp1 <= '0'; + ddr_clk_smp2 <= '0'; + ddr_clk_phase <= '0'; + elsif (ddr_in_clk_2x'event and ddr_in_clk_2x = '1') then + ddr_clk_smp1 <= ddr_clk_tog; + ddr_clk_smp2 <= ddr_clk_smp1; + if ddr_clk_smp1 = '1' and ddr_clk_smp2 = '0' then + ddr_clk_phase <= '0'; + else + ddr_clk_phase <= not(ddr_clk_phase); + end if; + end if; + end process; + + process(ddr_in_clk_2x, areset) + begin + if areset = '1' then + cas_n_smp <= '0'; + ras_n_smp <= '0'; + we_n_smp <= '0'; + read_start_sig <= '0'; + elsif (ddr_in_clk_2x'event and ddr_in_clk_2x = '1') then + cas_n_smp <= cas_qn_p_del; + ras_n_smp <= ras_qn_p_del; + we_n_smp <= we_qn_p_del; + if ras_n_smp = '1' and cas_n_smp = '0' and we_n_smp = '1' and ddr_clk_phase = '1' then + read_start_sig <= '1'; + else + read_start_sig <= '0'; + end if; + end if; + end process; + + process(ddr_in_clk_2x, areset) + begin + if areset = '1' then + sdr_d_in <= "0000000000000000"; + elsif (ddr_in_clk_2x'event and ddr_in_clk_2x = '1') then + sdr_d_in <= sdr_d_p_del; + end if; + end process; + + process(ddr_in_clk_2x, areset) + begin + if areset = '1' then + read_time_cnt <= "00"; + read_input_en <= '0'; + elsif (ddr_in_clk_2x'event and ddr_in_clk_2x = '1') then + + if read_start_sig = '1' then + read_time_cnt <= "01"; + elsif read_time_cnt = "00" then + read_time_cnt <= read_time_cnt; + else + read_time_cnt <= read_time_cnt + '1'; + end if; + + if read_time_cnt = "11" then + read_input_en <= '1'; + else + read_input_en <= '0'; + end if; + + read_input_en_del <= read_input_en; + + end if; + end process; + + process(ddr_in_clk_2x, areset) + begin + if areset = '1' then + ddr_data_read_int <= "00000000000000000000000000000000"; + elsif (ddr_in_clk_2x'event and ddr_in_clk_2x = '1') then + if read_input_en = '1' then + ddr_data_read_int(15 downto 0) <= sdr_d_in; + end if; + if read_input_en_del = '1' then + ddr_data_read_int(31 downto 16) <= sdr_d_in; + end if; + end if; + end process; + +end behave; + + diff --git a/misc/ddrsdram/src/mt46v16m16.vhd b/misc/ddrsdram/src/mt46v16m16.vhd new file mode 100644 index 0000000..356bb28 --- /dev/null +++ b/misc/ddrsdram/src/mt46v16m16.vhd @@ -0,0 +1,1320 @@ +----------------------------------------------------------------------------------------- +-- +-- File Name: MT46V16M16.VHD +-- Version: 2.1 +-- Date: January 14th, 2002 +-- Model: Behavioral +-- Simulator: NCDesktop - http://www.cadence.com +-- ModelSim PE - http://www.model.com +-- +-- Dependencies: None +-- +-- Author: Son P. Huynh +-- Email: sphuynh@micron.com +-- Phone: (208) 368-3825 +-- Company: Micron Technology, Inc. +-- Part Number: MT46V16M16 (4 Mb x 16 x 4 Banks) +-- +-- Description: Micron 256 Mb SDRAM DDR (Double Data Rate) +-- +-- Limitation: Doesn't model internal refresh counter +-- +-- Note: +-- +-- Disclaimer: THESE DESIGNS ARE PROVIDED "AS IS" WITH NO WARRANTY +-- WHATSOEVER AND MICRON SPECIFICALLY DISCLAIMS ANY +-- IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR +-- A PARTICULAR PURPOSE, OR AGAINST INFRINGEMENT. +-- +-- Copyright (c) 1998 Micron Semiconductor Products, Inc. +-- All rights researved +-- +-- Rev Author Date Changes +-- --- ---------------------------- ---------- ------------------------------------- +-- 2.1 Son P. Huynh 01/14/2002 - Fix Burst_counter +-- Micron Technology, Inc. +-- +-- 2.0 Son P. Huynh 11/08/2001 - Second release +-- Micron Technology, Inc. - Rewrote and remove SHARED VARIABLE +-- +----------------------------------------------------------------------------------------- + +LIBRARY IEEE; + USE IEEE.STD_LOGIC_1164.ALL; + USE IEEE.STD_LOGIC_UNSIGNED.ALL; + USE IEEE.STD_LOGIC_ARITH.ALL; + +ENTITY MT46V16M16 IS + GENERIC ( -- Timing for -75Z CL2 + tCK : TIME := 7.500 ns; + tCH : TIME := 3.375 ns; -- 0.45*tCK + tCL : TIME := 3.375 ns; -- 0.45*tCK + tDH : TIME := 0.500 ns; + tDS : TIME := 0.500 ns; + tIH : TIME := 0.900 ns; + tIS : TIME := 0.900 ns; + tMRD : TIME := 15.000 ns; + tRAS : TIME := 40.000 ns; + tRAP : TIME := 20.000 ns; + tRC : TIME := 65.000 ns; + tRFC : TIME := 75.000 ns; + tRCD : TIME := 20.000 ns; + tRP : TIME := 20.000 ns; + tRRD : TIME := 15.000 ns; + tWR : TIME := 15.000 ns; + addr_bits : INTEGER := 13; + data_bits : INTEGER := 16; + cols_bits : INTEGER := 9 + ); + PORT ( + Dq : INOUT STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + Dqs : INOUT STD_LOGIC_VECTOR (1 DOWNTO 0) := "ZZ"; + Addr : IN STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + Ba : IN STD_LOGIC_VECTOR (1 DOWNTO 0); + Clk : IN STD_LOGIC; + Clk_n : IN STD_LOGIC; + Cke : IN STD_LOGIC; + Cs_n : IN STD_LOGIC; + Ras_n : IN STD_LOGIC; + Cas_n : IN STD_LOGIC; + We_n : IN STD_LOGIC; + Dm : IN STD_LOGIC_VECTOR (1 DOWNTO 0) + ); +END MT46V16M16; + +ARCHITECTURE behave OF MT46V16M16 IS + -- Array for Read pipeline + TYPE Array_Read_cmnd IS ARRAY (8 DOWNTO 0) OF STD_LOGIC; + TYPE Array_Read_bank IS ARRAY (8 DOWNTO 0) OF STD_LOGIC_VECTOR (1 DOWNTO 0); + TYPE Array_Read_cols IS ARRAY (8 DOWNTO 0) OF STD_LOGIC_VECTOR (cols_bits - 1 DOWNTO 0); + + -- Array for Write pipeline + TYPE Array_Write_cmnd IS ARRAY (2 DOWNTO 0) OF STD_LOGIC; + TYPE Array_Write_bank IS ARRAY (2 DOWNTO 0) OF STD_LOGIC_VECTOR (1 DOWNTO 0); + TYPE Array_Write_cols IS ARRAY (2 DOWNTO 0) OF STD_LOGIC_VECTOR (cols_bits - 1 DOWNTO 0); + + -- Array for Auto Precharge + TYPE Array_Read_precharge IS ARRAY (3 DOWNTO 0) OF STD_LOGIC; + TYPE Array_Write_precharge IS ARRAY (3 DOWNTO 0) OF STD_LOGIC; + TYPE Array_Count_precharge IS ARRAY (3 DOWNTO 0) OF INTEGER; + + -- Array for Manual Precharge + TYPE Array_A10_precharge IS ARRAY (8 DOWNTO 0) OF STD_LOGIC; + TYPE Array_Bank_precharge IS ARRAY (8 DOWNTO 0) OF STD_LOGIC_VECTOR (1 DOWNTO 0); + TYPE Array_Cmnd_precharge IS ARRAY (8 DOWNTO 0) OF STD_LOGIC; + + -- Array for Burst Terminate + TYPE Array_Cmnd_bst IS ARRAY (8 DOWNTO 0) OF STD_LOGIC; + + -- Array for Memory Access + TYPE Array_ram_type IS ARRAY (2**cols_bits - 1 DOWNTO 0) OF STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0); + TYPE Array_ram_pntr IS ACCESS Array_ram_type; + TYPE Array_ram_stor IS ARRAY (2**addr_bits - 1 DOWNTO 0) OF Array_ram_pntr; + + -- Data pair + SIGNAL Dq_pair : STD_LOGIC_VECTOR (2 * data_bits - 1 DOWNTO 0); + SIGNAL Dm_pair : STD_LOGIC_VECTOR (3 DOWNTO 0); + + -- Mode Register + SIGNAL Mode_reg : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + + -- Command Decode Variables + SIGNAL Active_enable, Aref_enable, Burst_term, Ext_mode_enable : STD_LOGIC := '0'; + SIGNAL Mode_reg_enable, Prech_enable, Read_enable, Write_enable : STD_LOGIC := '0'; + + -- Burst Length Decode Variables + SIGNAL Burst_length_2, Burst_length_4, Burst_length_8, Burst_length_f : STD_LOGIC := '0'; + + -- Cas Latency Decode Variables + SIGNAL Cas_latency_15, Cas_latency_2, Cas_latency_25, Cas_latency_3, Cas_latency_4 : STD_LOGIC := '0'; + + -- Internal Control Signals + SIGNAL Cs_in, Ras_in, Cas_in, We_in : STD_LOGIC := '0'; + + -- System Clock + SIGNAL Sys_clk : STD_LOGIC := '0'; + + -- Dqs buffer + SIGNAL Dqs_out : STD_LOGIC_VECTOR (1 DOWNTO 0) := "ZZ"; + +BEGIN + -- Strip the strength + Cs_in <= To_X01 (Cs_n); + Ras_in <= To_X01 (Ras_n); + Cas_in <= To_X01 (Cas_n); + We_in <= To_X01 (We_n); + + -- Commands Decode + Active_enable <= NOT(Cs_in) AND NOT(Ras_in) AND Cas_in AND We_in; + Aref_enable <= NOT(Cs_in) AND NOT(Ras_in) AND NOT(Cas_in) AND We_in; + Burst_term <= NOT(Cs_in) AND Ras_in AND Cas_in AND NOT(We_in); + Ext_mode_enable <= NOT(Cs_in) AND NOT(Ras_in) AND NOT(Cas_in) AND NOT(We_in) AND Ba(0) AND NOT(Ba(1)); + Mode_reg_enable <= NOT(Cs_in) AND NOT(Ras_in) AND NOT(Cas_in) AND NOT(We_in) AND NOT(Ba(0)) AND NOT(Ba(1)); + Prech_enable <= NOT(Cs_in) AND NOT(Ras_in) AND Cas_in AND NOT(We_in); + Read_enable <= NOT(Cs_in) AND Ras_in AND NOT(Cas_in) AND We_in; + Write_enable <= NOT(Cs_in) AND Ras_in AND NOT(Cas_in) AND NOT(We_in); + + -- Burst Length Decode + Burst_length_2 <= NOT(Mode_reg(2)) AND NOT(Mode_reg(1)) AND Mode_reg(0); + Burst_length_4 <= NOT(Mode_reg(2)) AND Mode_reg(1) AND NOT(Mode_reg(0)); + Burst_length_8 <= NOT(Mode_reg(2)) AND Mode_reg(1) AND Mode_reg(0); + Burst_length_f <= (Mode_reg(2)) AND Mode_reg(1) AND Mode_reg(0); + + -- CAS Latency Decode + Cas_latency_15 <= Mode_reg(6) AND NOT(Mode_reg(5)) AND (Mode_reg(4)); + Cas_latency_2 <= NOT(Mode_reg(6)) AND Mode_reg(5) AND NOT(Mode_reg(4)); + Cas_latency_25 <= Mode_reg(6) AND Mode_reg(5) AND NOT(Mode_reg(4)); + Cas_latency_3 <= NOT(Mode_reg(6)) AND Mode_reg(5) AND Mode_reg(4); + Cas_latency_4 <= (Mode_reg(6)) AND NOT(Mode_reg(5)) AND NOT(Mode_reg(4)); + + -- Dqs buffer + Dqs <= Dqs_out; + + -- + -- System Clock + -- + int_clk : PROCESS (Clk, Clk_n) + VARIABLE ClkZ, CkeZ : STD_LOGIC := '0'; + begin + IF Clk = '1' AND Clk_n = '0' THEN + ClkZ := '1'; + CkeZ := Cke; + ELSIF Clk = '0' AND Clk_n = '1' THEN + ClkZ := '0'; + END IF; + Sys_clk <= CkeZ AND ClkZ; + END PROCESS; + + -- + -- Main Process + -- + state_register : PROCESS + -- Precharge Variables + VARIABLE Pc_b0, Pc_b1, Pc_b2, Pc_b3 : STD_LOGIC := '0'; + + -- Activate Variables + VARIABLE Act_b0, Act_b1, Act_b2, Act_b3 : STD_LOGIC := '1'; + + -- Data IO variables + VARIABLE Data_in_enable, Data_out_enable : STD_LOGIC := '0'; + + -- Internal address mux variables + VARIABLE Cols_brst : STD_LOGIC_VECTOR (2 DOWNTO 0); + VARIABLE Prev_bank : STD_LOGIC_VECTOR (1 DOWNTO 0) := "00"; + VARIABLE Bank_addr : STD_LOGIC_VECTOR (1 DOWNTO 0) := "00"; + VARIABLE Cols_addr : STD_LOGIC_VECTOR (cols_bits - 1 DOWNTO 0); + VARIABLE Rows_addr : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + VARIABLE B0_row_addr : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + VARIABLE B1_row_addr : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + VARIABLE B2_row_addr : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + VARIABLE B3_row_addr : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + + -- DLL Reset variables + VARIABLE DLL_enable : STD_LOGIC := '0'; + VARIABLE DLL_reset : STD_LOGIC := '0'; + VARIABLE DLL_done : STD_LOGIC := '0'; + VARIABLE DLL_count : INTEGER := 0; + + -- Timing Check + VARIABLE MRD_chk : TIME := 0 ns; + VARIABLE RFC_chk : TIME := 0 ns; + VARIABLE RRD_chk : TIME := 0 ns; + VARIABLE RAS_chk0, RAS_chk1, RAS_chk2, RAS_chk3 : TIME := 0 ns; + VARIABLE RAP_chk0, RAP_chk1, RAP_chk2, RAP_chk3 : TIME := 0 ns; + VARIABLE RC_chk0, RC_chk1, RC_chk2, RC_chk3 : TIME := 0 ns; + VARIABLE RCD_chk0, RCD_chk1, RCD_chk2, RCD_chk3 : TIME := 0 ns; + VARIABLE RP_chk0, RP_chk1, RP_chk2, RP_chk3 : TIME := 0 ns; + VARIABLE WR_chk0, WR_chk1, WR_chk2, WR_chk3 : TIME := 0 ns; + + -- Read pipeline variables + VARIABLE Read_cmnd : Array_Read_cmnd; + VARIABLE Read_bank : Array_Read_bank; + VARIABLE Read_cols : Array_Read_cols; + + -- Write pipeline variables + VARIABLE Write_cmnd : Array_Write_cmnd; + VARIABLE Write_bank : Array_Write_bank; + VARIABLE Write_cols : Array_Write_cols; + + -- Auto Precharge variables + VARIABLE Read_precharge : Array_Read_precharge := ('0' & '0' & '0' & '0'); + VARIABLE Write_precharge : Array_Write_precharge := ('0' & '0' & '0' & '0'); + VARIABLE Count_precharge : Array_Count_precharge := ( 0 & 0 & 0 & 0 ); + + -- Manual Precharge variables + VARIABLE A10_precharge : Array_A10_precharge; + VARIABLE Bank_precharge : Array_Bank_precharge; + VARIABLE Cmnd_precharge : Array_Cmnd_precharge; + + -- Burst Terminate variable + VARIABLE Cmnd_bst : Array_Cmnd_bst; + + -- Memory Banks + VARIABLE Bank0 : Array_ram_stor; + VARIABLE Bank1 : Array_ram_stor; + VARIABLE Bank2 : Array_ram_stor; + VARIABLE Bank3 : Array_ram_stor; + + -- Burst Counter + VARIABLE Burst_counter : STD_LOGIC_VECTOR (cols_bits - 1 DOWNTO 0); + + -- Internal Dqs initialize + VARIABLE Dqs_int : STD_LOGIC := '0'; + + -- Data buffer for DM Mask + VARIABLE Data_buf : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + + -- + -- Initialize empty rows + -- + PROCEDURE Init_mem (Bank : STD_LOGIC_VECTOR; Row_index : INTEGER) IS + VARIABLE i, j : INTEGER := 0; + BEGIN + IF Bank = "00" THEN + IF Bank0 (Row_index) = NULL THEN -- Check to see if row empty + Bank0 (Row_index) := NEW Array_ram_type; -- Open new row for access + FOR i IN (2**cols_bits - 1) DOWNTO 0 LOOP -- Filled row with zeros + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank0 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "01" THEN + IF Bank1 (Row_index) = NULL THEN + Bank1 (Row_index) := NEW Array_ram_type; + FOR i IN (2**cols_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank1 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "10" THEN + IF Bank2 (Row_index) = NULL THEN + Bank2 (Row_index) := NEW Array_ram_type; + FOR i IN (2**cols_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank2 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "11" THEN + IF Bank3 (Row_index) = NULL THEN + Bank3 (Row_index) := NEW Array_ram_type; + FOR i IN (2**cols_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank3 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + END IF; + END; + + -- + -- Burst Counter + -- + PROCEDURE Burst_decode IS + VARIABLE Cols_temp : STD_LOGIC_VECTOR (cols_bits - 1 DOWNTO 0) := (OTHERS => '0'); + BEGIN + -- Advance burst counter + Burst_counter := Burst_counter + 1; + + -- Burst Type + IF Mode_reg (3) = '0' THEN + Cols_temp := Cols_addr + 1; + ELSIF Mode_reg (3) = '1' THEN + Cols_temp (2) := Burst_counter (2) XOR Cols_brst (2); + Cols_temp (1) := Burst_counter (1) XOR Cols_brst (1); + Cols_temp (0) := Burst_counter (0) XOR Cols_brst (0); + END IF; + + -- Burst Length + IF Burst_length_2 = '1' THEN + Cols_addr (0) := Cols_temp (0); + ELSIF Burst_length_4 = '1' THEN + Cols_addr (1 DOWNTO 0) := Cols_temp (1 DOWNTO 0); + ELSIF Burst_length_8 = '1' THEN + Cols_addr (2 DOWNTO 0) := Cols_temp (2 DOWNTO 0); + ELSE + Cols_addr := Cols_temp; + END IF; + + -- Data counter + IF Burst_length_2 = '1' THEN + IF Burst_counter >= 2 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_4 = '1' THEN + IF Burst_counter >= 4 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_8 = '1' THEN + IF Burst_counter >= 8 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + END IF; + END; + + BEGIN + WAIT ON Sys_clk; + + -- + -- Manual Precharge Pipeline + -- + IF ((Sys_clk'EVENT AND Sys_clk = '0') OR (Sys_clk'EVENT AND Sys_clk = '1')) THEN + -- A10 Precharge Pipeline + A10_precharge(0) := A10_precharge(1); + A10_precharge(1) := A10_precharge(2); + A10_precharge(2) := A10_precharge(3); + A10_precharge(3) := A10_precharge(4); + A10_precharge(4) := A10_precharge(5); + A10_precharge(5) := A10_precharge(6); + A10_precharge(6) := A10_precharge(7); + A10_precharge(7) := A10_precharge(8); + A10_precharge(8) := '0'; + + -- Bank Precharge Pipeline + Bank_precharge(0) := Bank_precharge(1); + Bank_precharge(1) := Bank_precharge(2); + Bank_precharge(2) := Bank_precharge(3); + Bank_precharge(3) := Bank_precharge(4); + Bank_precharge(4) := Bank_precharge(5); + Bank_precharge(5) := Bank_precharge(6); + Bank_precharge(6) := Bank_precharge(7); + Bank_precharge(7) := Bank_precharge(8); + Bank_precharge(8) := "00"; + + -- Command Precharge Pipeline + Cmnd_precharge(0) := Cmnd_precharge(1); + Cmnd_precharge(1) := Cmnd_precharge(2); + Cmnd_precharge(2) := Cmnd_precharge(3); + Cmnd_precharge(3) := Cmnd_precharge(4); + Cmnd_precharge(4) := Cmnd_precharge(5); + Cmnd_precharge(5) := Cmnd_precharge(6); + Cmnd_precharge(6) := Cmnd_precharge(7); + Cmnd_precharge(7) := Cmnd_precharge(8); + Cmnd_precharge(8) := '0'; + + -- Terminate Read if same bank or all banks + IF ((Cmnd_precharge (0) = '1') AND + (Bank_precharge (0) = Bank_addr OR A10_precharge (0) = '1') AND + (Data_out_enable = '1')) THEN + Data_out_enable := '0'; + END IF; + END IF; + + -- + -- Burst Terminate Pipeline + -- + IF ((Sys_clk'EVENT AND Sys_clk = '0') OR (Sys_clk'EVENT AND Sys_clk = '1')) THEN + -- Burst Terminate pipeline + Cmnd_bst (0) := Cmnd_bst (1); + Cmnd_bst (1) := Cmnd_bst (2); + Cmnd_bst (2) := Cmnd_bst (3); + Cmnd_bst (3) := Cmnd_bst (4); + Cmnd_bst (4) := Cmnd_bst (5); + Cmnd_bst (5) := Cmnd_bst (6); + Cmnd_bst (6) := Cmnd_bst (7); + Cmnd_bst (7) := Cmnd_bst (8); + Cmnd_bst (8) := '0'; + + -- Terminate current Read + IF ((Cmnd_bst (0) = '1') AND (Data_out_enable = '1')) THEN + Data_out_enable := '0'; + END IF; + END IF; + + -- + -- Dq and Dqs Drivers + -- + IF ((Sys_clk'EVENT AND Sys_clk = '0') OR (Sys_clk'EVENT AND Sys_clk = '1')) THEN + -- Read Command Pipeline + Read_cmnd (0) := Read_cmnd (1); + Read_cmnd (1) := Read_cmnd (2); + Read_cmnd (2) := Read_cmnd (3); + Read_cmnd (3) := Read_cmnd (4); + Read_cmnd (4) := Read_cmnd (5); + Read_cmnd (5) := Read_cmnd (6); + Read_cmnd (6) := Read_cmnd (7); + Read_cmnd (7) := Read_cmnd (8); + Read_cmnd (8) := '0'; + + -- Read Bank Pipeline + Read_bank (0) := Read_bank (1); + Read_bank (1) := Read_bank (2); + Read_bank (2) := Read_bank (3); + Read_bank (3) := Read_bank (4); + Read_bank (4) := Read_bank (5); + Read_bank (5) := Read_bank (6); + Read_bank (6) := Read_bank (7); + Read_bank (7) := Read_bank (8); + Read_bank (8) := "00"; + + -- Read Column Pipeline + Read_cols (0) := Read_cols (1); + Read_cols (1) := Read_cols (2); + Read_cols (2) := Read_cols (3); + Read_cols (3) := Read_cols (4); + Read_cols (4) := Read_cols (5); + Read_cols (5) := Read_cols (6); + Read_cols (6) := Read_cols (7); + Read_cols (7) := Read_cols (8); + Read_cols (8) := (OTHERS => '0'); + + -- Initialize Read command + IF Read_cmnd (0) = '1' THEN + Data_out_enable := '1'; + Bank_addr := Read_bank (0); + Cols_addr := Read_cols (0); + Cols_brst := Cols_addr (2 DOWNTO 0); + Burst_counter := (OTHERS => '0'); + + -- Row address mux + CASE Bank_addr IS + WHEN "00" => Rows_addr := B0_row_addr; + WHEN "01" => Rows_addr := B1_row_addr; + WHEN "10" => Rows_addr := B2_row_addr; + WHEN OTHERS => Rows_addr := B3_row_addr; + END CASE; + END IF; + + -- Toggle Dqs during Read command + IF Data_out_enable = '1' THEN + Dqs_int := '0'; + IF Dqs_out = "00" THEN + Dqs_out <= "11"; + ELSIF Dqs_out = "11" THEN + Dqs_out <= "00"; + ELSE + Dqs_out <= "00"; + END IF; + ELSIF Data_out_enable = '0' AND Dqs_int = '0' THEN + Dqs_out <= "ZZ"; + END IF; + + -- Initialize Dqs for Read command + IF Read_cmnd (2) = '1' THEN + IF Data_out_enable = '0' THEN + Dqs_int := '1'; + Dqs_out <= "00"; + END IF; + END IF; + + -- Read Latch + IF Data_out_enable = '1' THEN + -- Initialize Memory + Init_mem (Bank_addr, CONV_INTEGER(Rows_addr)); + + -- Output Data + CASE Bank_addr IS + WHEN "00" => Dq <= Bank0 (CONV_INTEGER(Rows_addr)) (CONV_INTEGER(Cols_addr)); + WHEN "01" => Dq <= Bank1 (CONV_INTEGER(Rows_addr)) (CONV_INTEGER(Cols_addr)); + WHEN "10" => Dq <= Bank2 (CONV_INTEGER(Rows_addr)) (CONV_INTEGER(Cols_addr)); + WHEN OTHERS => Dq <= Bank3 (CONV_INTEGER(Rows_addr)) (CONV_INTEGER(Cols_addr)); + END CASE; + + -- Increase Burst Counter + Burst_decode; + ELSE + Dq <= (OTHERS => 'Z'); + END IF; + END IF; + + -- + -- Write FIFO and DM Mask Logic + -- + IF Sys_clk'EVENT AND Sys_clk = '1' THEN + -- Write command pipeline + Write_cmnd (0) := Write_cmnd (1); + Write_cmnd (1) := Write_cmnd (2); + Write_cmnd (2) := '0'; + + -- Write command pipeline + Write_bank (0) := Write_bank (1); + Write_bank (1) := Write_bank (2); + Write_bank (2) := "00"; + + -- Write column pipeline + Write_cols (0) := Write_cols (1); + Write_cols (1) := Write_cols (2); + Write_cols (2) := (OTHERS => '0'); + + -- Initialize Write command + IF Write_cmnd (0) = '1' THEN + Data_in_enable := '1'; + Bank_addr := Write_bank (0); + Cols_addr := Write_cols (0); + Cols_brst := Cols_addr (2 DOWNTO 0); + Burst_counter := (OTHERS => '0'); + + -- Row address mux + CASE Bank_addr IS + WHEN "00" => Rows_addr := B0_row_addr; + WHEN "01" => Rows_addr := B1_row_addr; + WHEN "10" => Rows_addr := B2_row_addr; + WHEN OTHERS => Rows_addr := B3_row_addr; + END CASE; + END IF; + + -- Write data + IF Data_in_enable = '1' THEN + -- Initialize memory + Init_mem (Bank_addr, CONV_INTEGER(Rows_addr)); + + -- Write first data + IF Dm_pair (1) = '0' OR Dm_pair (0) = '0' THEN + -- Data Buffer + CASE Bank_addr IS + WHEN "00" => Data_buf := Bank0 (CONV_INTEGER(Rows_addr)) (CONV_INTEGER(Cols_addr)); + WHEN "01" => Data_buf := Bank1 (CONV_INTEGER(Rows_addr)) (CONV_INTEGER(Cols_addr)); + WHEN "10" => Data_buf := Bank2 (CONV_INTEGER(Rows_addr)) (CONV_INTEGER(Cols_addr)); + WHEN OTHERS => Data_buf := Bank3 (CONV_INTEGER(Rows_addr)) (CONV_INTEGER(Cols_addr)); + END CASE; + + -- Perform DM Mask + IF Dm_pair (0) = '0' THEN + Data_buf ( 7 DOWNTO 0) := Dq_pair ( 7 DOWNTO 0); + END IF; + IF Dm_pair (1) = '0' THEN + Data_buf (15 DOWNTO 8) := Dq_pair (15 DOWNTO 8); + END IF; + + -- Write Data + CASE Bank_addr IS + WHEN "00" => Bank0 (CONV_INTEGER(Rows_addr)) (CONV_INTEGER(Cols_addr)) := Data_buf; + WHEN "01" => Bank1 (CONV_INTEGER(Rows_addr)) (CONV_INTEGER(Cols_addr)) := Data_buf; + WHEN "10" => Bank2 (CONV_INTEGER(Rows_addr)) (CONV_INTEGER(Cols_addr)) := Data_buf; + WHEN OTHERS => Bank3 (CONV_INTEGER(Rows_addr)) (CONV_INTEGER(Cols_addr)) := Data_buf; + END CASE; + END IF; + + -- Increase Burst Counter + Burst_decode; + + -- Write second data + IF Dm_pair (3) = '0' OR Dm_pair (2) = '0' THEN + -- Data Buffer + CASE Bank_addr IS + WHEN "00" => Data_buf := Bank0 (CONV_INTEGER(Rows_addr)) (CONV_INTEGER(Cols_addr)); + WHEN "01" => Data_buf := Bank1 (CONV_INTEGER(Rows_addr)) (CONV_INTEGER(Cols_addr)); + WHEN "10" => Data_buf := Bank2 (CONV_INTEGER(Rows_addr)) (CONV_INTEGER(Cols_addr)); + WHEN OTHERS => Data_buf := Bank3 (CONV_INTEGER(Rows_addr)) (CONV_INTEGER(Cols_addr)); + END CASE; + + -- Perform DM Mask + IF Dm_pair (2) = '0' THEN + Data_buf ( 7 DOWNTO 0) := Dq_pair (23 DOWNTO 16); + END IF; + IF Dm_pair (3) = '0' THEN + Data_buf (15 DOWNTO 8) := Dq_pair (31 DOWNTO 24); + END IF; + + -- Write Data + CASE Bank_addr IS + WHEN "00" => Bank0 (CONV_INTEGER(Rows_addr)) (CONV_INTEGER(Cols_addr)) := Data_buf; + WHEN "01" => Bank1 (CONV_INTEGER(Rows_addr)) (CONV_INTEGER(Cols_addr)) := Data_buf; + WHEN "10" => Bank2 (CONV_INTEGER(Rows_addr)) (CONV_INTEGER(Cols_addr)) := Data_buf; + WHEN OTHERS => Bank3 (CONV_INTEGER(Rows_addr)) (CONV_INTEGER(Cols_addr)) := Data_buf; + END CASE; + END IF; + + -- Increase Burst Counter + Burst_decode; + + -- tWR start and tWTR check + IF Dm_pair (3 DOWNTO 2) = "00" OR Dm_pair (1 DOWNTO 0) = "00" THEN + CASE Bank_addr IS + WHEN "00" => WR_chk0 := NOW; + WHEN "01" => WR_chk1 := NOW; + WHEN "10" => WR_chk2 := NOW; + WHEN OTHERS => WR_chk3 := NOW; + END CASE; + + -- tWTR check + ASSERT (Read_enable = '0') + REPORT "tWTR violation during Read" + SEVERITY WARNING; + END IF; + END IF; + END IF; + + -- + -- Auto Precharge Calculation + -- + IF Sys_clk'EVENT AND Sys_clk = '1' THEN + -- Precharge counter + IF Read_precharge (0) = '1' OR Write_precharge (0) = '1' THEN + Count_precharge (0) := Count_precharge (0) + 1; + END IF; + IF Read_precharge (1) = '1' OR Write_precharge (1) = '1' THEN + Count_precharge (1) := Count_precharge (1) + 1; + END IF; + IF Read_precharge (2) = '1' OR Write_precharge (2) = '1' THEN + Count_precharge (2) := Count_precharge (2) + 1; + END IF; + IF Read_precharge (3) = '1' OR Write_precharge (3) = '1' THEN + Count_precharge (3) := Count_precharge (3) + 1; + END IF; + + -- Read with AutoPrecharge Calculation + -- The device start internal precharge when: + -- 1. Meet tRAS requirement + -- 2. BL/2 cycles after command + IF ((Read_precharge(0) = '1') AND (NOW - RAS_chk0 >= tRAS)) THEN + IF ((Burst_length_2 = '1' AND Count_precharge(0) >= 1) OR + (Burst_length_4 = '1' AND Count_precharge(0) >= 2) OR + (Burst_length_8 = '1' AND Count_precharge(0) >= 4)) THEN + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + Read_precharge(0) := '0'; + END IF; + END IF; + IF ((Read_precharge(1) = '1') AND (NOW - RAS_chk1 >= tRAS)) THEN + IF ((Burst_length_2 = '1' AND Count_precharge(1) >= 1) OR + (Burst_length_4 = '1' AND Count_precharge(1) >= 2) OR + (Burst_length_8 = '1' AND Count_precharge(1) >= 4)) THEN + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + Read_precharge(1) := '0'; + END IF; + END IF; + IF ((Read_precharge(2) = '1') AND (NOW - RAS_chk2 >= tRAS)) THEN + IF ((Burst_length_2 = '1' AND Count_precharge(2) >= 1) OR + (Burst_length_4 = '1' AND Count_precharge(2) >= 2) OR + (Burst_length_8 = '1' AND Count_precharge(2) >= 4)) THEN + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW; + Read_precharge(2) := '0'; + END IF; + END IF; + IF ((Read_precharge(3) = '1') AND (NOW - RAS_chk3 >= tRAS)) THEN + IF ((Burst_length_2 = '1' AND Count_precharge(3) >= 1) OR + (Burst_length_4 = '1' AND Count_precharge(3) >= 2) OR + (Burst_length_8 = '1' AND Count_precharge(3) >= 4)) THEN + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW; + Read_precharge(3) := '0'; + END IF; + END IF; + + -- Write with AutoPrecharge Calculation + -- The device start internal precharge when: + -- 1. Meet tRAS requirement + -- 2. Two clock after last burst + -- Since tWR is time base, the model will compensate tRP + IF ((Write_precharge(0) = '1') AND (NOW - RAS_chk0 >= tRAS)) THEN + IF ((Burst_length_2 = '1' AND Count_precharge (0) >= 4) OR + (Burst_length_4 = '1' AND Count_precharge (0) >= 5) OR + (Burst_length_8 = '1' AND Count_precharge (0) >= 7)) THEN + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW - ((2 * tCK) - tWR); + Write_precharge(0) := '0'; + END IF; + END IF; + IF ((Write_precharge(1) = '1') AND (NOW - RAS_chk1 >= tRAS)) THEN + IF ((Burst_length_2 = '1' AND Count_precharge (1) >= 4) OR + (Burst_length_4 = '1' AND Count_precharge (1) >= 5) OR + (Burst_length_8 = '1' AND Count_precharge (1) >= 7)) THEN + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW - ((2 * tCK) - tWR); + Write_precharge(1) := '0'; + END IF; + END IF; + IF ((Write_precharge(2) = '1') AND (NOW - RAS_chk2 >= tRAS)) THEN + IF ((Burst_length_2 = '1' AND Count_precharge (2) >= 4) OR + (Burst_length_4 = '1' AND Count_precharge (2) >= 5) OR + (Burst_length_8 = '1' AND Count_precharge (2) >= 7)) THEN + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW - ((2 * tCK) - tWR); + Write_precharge(2) := '0'; + END IF; + END IF; + IF ((Write_precharge(3) = '1') AND (NOW - RAS_chk3 >= tRAS)) THEN + IF ((Burst_length_2 = '1' AND Count_precharge (3) >= 4) OR + (Burst_length_4 = '1' AND Count_precharge (3) >= 5) OR + (Burst_length_8 = '1' AND Count_precharge (3) >= 7)) THEN + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW - ((2 * tCK) - tWR); + Write_precharge(3) := '0'; + END IF; + END IF; + END IF; + + -- + -- DLL Counter + -- + IF Sys_clk'EVENT AND Sys_clk = '1' THEN + IF (DLL_Reset = '1' AND DLL_done = '0') THEN + DLL_count := DLL_count + 1; + IF (DLL_count >= 200) THEN + DLL_done := '1'; + END IF; + END IF; + END IF; + + -- + -- Control Logic + -- + IF Sys_clk'EVENT AND Sys_clk = '1' THEN + -- Auto Refresh + IF Aref_enable = '1' THEN + -- Auto Refresh to Auto Refresh + ASSERT (NOW - RFC_chk >= tRFC) + REPORT "tRFC violation during Auto Refresh" + SEVERITY WARNING; + + -- Precharge to Auto Refresh + ASSERT ((NOW - RP_chk0 >= tRP) AND (NOW - RP_chk1 >= tRP) AND + (NOW - RP_chk2 >= tRP) AND (NOW - RP_chk3 >= tRP)) + REPORT "tRP violation during Auto Refresh" + SEVERITY WARNING; + + -- Precharge to Auto Refresh + ASSERT (Pc_b0 = '1' AND Pc_b1 = '1' AND Pc_b2 = '1' AND Pc_b3 = '1') + REPORT "All banks must be Precharge before Auto Refresh" + SEVERITY WARNING; + + -- Record current tRFC time + RFC_chk := NOW; + END IF; + + -- Extended Load Mode Register + IF Ext_mode_enable = '1' THEN + IF (Pc_b0 = '1' AND Pc_b1 = '1' AND Pc_b2 = '1' AND Pc_b3 = '1') THEN + IF (Addr (0) = '0') THEN + DLL_enable := '1'; + ELSE + DLL_enable := '0'; + END IF; + END IF; + + -- Precharge to EMR + ASSERT (Pc_b0 = '1' AND Pc_b1 = '1' AND Pc_b2 = '1' AND Pc_b3 = '1') + REPORT "All bank must be Precharged before Extended Mode Register" + SEVERITY WARNING; + + -- Precharge to EMR + ASSERT ((NOW - RP_chk0 >= tRP) AND (NOW - RP_chk1 >= tRP) AND + (NOW - RP_chk2 >= tRP) AND (NOW - RP_chk3 >= tRP)) + REPORT "tRP violation during Extended Load Register" + SEVERITY WARNING; + + -- LMR/EMR to EMR + ASSERT (NOW - MRD_chk >= tMRD) + REPORT "tMRD violation during Extended Mode Register" + SEVERITY WARNING; + + -- Record current tMRD time + MRD_chk := NOW; + END IF; + + -- Load Mode Register + IF Mode_reg_enable = '1' THEN + -- Register mode + Mode_reg <= Addr; + + -- DLL Reset + IF (DLL_enable = '1' AND Addr (8) = '1') THEN + DLL_reset := '1'; + DLL_done := '0'; + DLL_count := 0; + ELSIF (DLL_enable = '1' AND DLL_reset = '0' AND Addr (8) = '0') THEN + ASSERT (FALSE) + REPORT "DLL is ENABLE: DLL RESET is require" + SEVERITY WARNING; + ELSIF (DLL_enable = '0' AND Addr (8) = '1') THEN + ASSERT (FALSE) + REPORT "DLL is DISABLE: DLL RESET will be ignored" + SEVERITY WARNING; + END IF; + + -- Precharge to LMR + ASSERT (Pc_b0 = '1' AND Pc_b1 = '1' AND Pc_b2 = '1' AND Pc_b3 = '1') + REPORT "All bank must be Precharged before Load Mode Register" + SEVERITY WARNING; + + -- Precharge to EMR + ASSERT ((NOW - RP_chk0 >= tRP) AND (NOW - RP_chk1 >= tRP) AND + (NOW - RP_chk2 >= tRP) AND (NOW - RP_chk3 >= tRP)) + REPORT "tRP violation during Load Mode Register" + SEVERITY WARNING; + + -- LMR/ELMR to LMR + ASSERT (NOW - MRD_chk >= tMRD) + REPORT "tMRD violation during Load Mode Register" + SEVERITY WARNING; + + -- Check for invalid Burst Length + ASSERT ((Addr (2 DOWNTO 0) = "001") OR -- BL = 2 + (Addr (2 DOWNTO 0) = "010") OR -- BL = 4 + (Addr (2 DOWNTO 0) = "011")) -- BL = 8 + REPORT "Invalid Burst Length during Load Mode Register" + SEVERITY WARNING; + + -- Check for invalid CAS Latency + ASSERT ((Addr (6 DOWNTO 4) = "010") OR -- CL = 2.0 + (Addr (6 DOWNTO 4) = "110")) -- CL = 2.5 + REPORT "Invalid CAS Latency during Load Mode Register" + SEVERITY WARNING; + + -- Record current tMRD time + MRD_chk := NOW; + END IF; + + -- Active Block (latch Bank and Row Address) + IF Active_enable = '1' THEN + -- Activate an OPEN bank can corrupt data + ASSERT ((Ba = "00" AND Act_b0 = '0') OR + (Ba = "01" AND Act_b1 = '0') OR + (Ba = "10" AND Act_b2 = '0') OR + (Ba = "11" AND Act_b3 = '0')) + REPORT "Bank is already activated - data can be corrupted" + SEVERITY WARNING; + + -- Activate Bank 0 + IF Ba = "00" AND Pc_b0 = '1' THEN + -- Activate to Activate (same bank) + ASSERT (NOW - RC_chk0 >= tRC) + REPORT "tRC violation during Activate Bank 0" + SEVERITY WARNING; + + -- Precharge to Active + ASSERT (NOW - RP_chk0 >= tRP) + REPORT "tRP violation during Activate Bank 0" + SEVERITY WARNING; + + -- Record Variables for checking violation + Act_b0 := '1'; + Pc_b0 := '0'; + B0_row_addr := Addr; + RC_chk0 := NOW; + RCD_chk0 := NOW; + RAS_chk0 := NOW; + RAP_chk0 := NOW; + END IF; + + -- Activate Bank 1 + IF Ba = "01" AND Pc_b1 = '1' THEN + -- Activate to Activate (same bank) + ASSERT (NOW - RC_chk1 >= tRC) + REPORT "tRC violation during Activate Bank 1" + SEVERITY WARNING; + + -- Precharge to Active + ASSERT (NOW - RP_chk1 >= tRP) + REPORT "tRP violation during Activate Bank 1" + SEVERITY WARNING; + + -- Record Variables for checking violation + Act_b1 := '1'; + Pc_b1 := '0'; + B1_row_addr := Addr; + RC_chk1 := NOW; + RCD_chk1 := NOW; + RAS_chk1 := NOW; + RAP_chk1 := NOW; + END IF; + + -- Activate Bank 2 + IF Ba = "10" AND Pc_b2 = '1' THEN + -- Activate to Activate (same bank) + ASSERT (NOW - RC_chk2 >= tRC) + REPORT "tRC violation during Activate Bank 2" + SEVERITY WARNING; + + -- Precharge to Active + ASSERT (NOW - RP_chk2 >= tRP) + REPORT "tRP violation during Activate Bank 2" + SEVERITY WARNING; + + -- Record Variables for checking violation + Act_b2 := '1'; + Pc_b2 := '0'; + B2_row_addr := Addr; + RC_chk2 := NOW; + RCD_chk2 := NOW; + RAS_chk2 := NOW; + RAP_chk2 := NOW; + END IF; + + -- Activate Bank 3 + IF Ba = "11" AND Pc_b3 = '1' THEN + -- Activate to Activate (same bank) + ASSERT (NOW - RC_chk3 >= tRC) + REPORT "tRC violation during Activate Bank 3" + SEVERITY WARNING; + + -- Precharge to Active + ASSERT (NOW - RP_chk3 >= tRP) + REPORT "tRP violation during Activate Bank 3" + SEVERITY WARNING; + + -- Record Variables for checking violation + Act_b3 := '1'; + Pc_b3 := '0'; + B3_row_addr := Addr; + RC_chk3 := NOW; + RCD_chk3 := NOW; + RAS_chk3 := NOW; + RAP_chk3 := NOW; + END IF; + + -- Activate Bank A to Activate Bank B + IF (Prev_bank /= Ba) THEN + ASSERT (NOW - RRD_chk >= tRRD) + REPORT "tRRD violation during Activate" + SEVERITY WARNING; + END IF; + + -- AutoRefresh to Activate + ASSERT (NOW - RFC_chk >= tRFC) + REPORT "tRFC violation during Activate" + SEVERITY WARNING; + + -- Record Variables for Checking Violation + RRD_chk := NOW; + Prev_bank := Ba; + END IF; + + -- Precharge Block - Consider NOP if bank already precharged or in process of precharging + IF Prech_enable = '1' THEN + -- EMR or LMR to Precharge + ASSERT (NOW - MRD_chk >= tMRD) + REPORT "tMRD violation during Precharge" + SEVERITY WARNING; + + -- Precharge Bank 0 + IF ((Addr (10) = '1' OR (Addr (10) = '0' AND Ba = "00")) AND Act_b0 = '1') THEN + Act_b0 := '0'; + Pc_b0 := '1'; + RP_chk0 := NOW; + + -- Activate to Precharge bank 0 + ASSERT (NOW - RAS_chk0 >= tRAS) + REPORT "tRAS violation during Precharge" + SEVERITY WARNING; + + -- tWR violation check for Write + ASSERT (NOW - WR_chk0 >= tWR) + REPORT "tWR violation during Precharge" + SEVERITY WARNING; + END IF; + + -- Precharge Bank 1 + IF ((Addr (10) = '1' OR (Addr (10) = '0' AND Ba = "01")) AND Act_b1 = '1') THEN + Act_b1 := '0'; + Pc_b1 := '1'; + RP_chk1 := NOW; + + -- Activate to Precharge + ASSERT (NOW - RAS_chk1 >= tRAS) + REPORT "tRAS violation during Precharge" + SEVERITY WARNING; + + -- tWR violation check for Write + ASSERT (NOW - WR_chk1 >= tWR) + REPORT "tWR violation during Precharge" + SEVERITY WARNING; + END IF; + + -- Precharge Bank 2 + IF ((Addr (10) = '1' OR (Addr (10) = '0' AND Ba = "10")) AND Act_b2 = '1') THEN + Act_b2 := '0'; + Pc_b2 := '1'; + RP_chk2 := NOW; + + -- Activate to Precharge + ASSERT (NOW - RAS_chk2 >= tRAS) + REPORT "tRAS violation during Precharge" + SEVERITY WARNING; + + -- tWR violation check for Write + ASSERT (NOW - WR_chk2 >= tWR) + REPORT "tWR violation during Precharge" + SEVERITY WARNING; + END IF; + + -- Precharge Bank 3 + IF ((Addr (10) = '1' OR (Addr (10) = '0' AND Ba = "11")) AND Act_b3 = '1') THEN + Act_b3 := '0'; + Pc_b3 := '1'; + RP_chk3 := NOW; + + -- Activate to Precharge + ASSERT (NOW - RAS_chk3 >= tRAS) + REPORT "tRAS violation during Precharge" + SEVERITY WARNING; + + -- tWR violation check for Write + ASSERT (NOW - WR_chk3 >= tWR) + REPORT "tWR violation during Precharge" + SEVERITY WARNING; + END IF; + + -- Pipeline for READ + IF CAS_latency_15 = '1' THEN + A10_precharge (3) := Addr(10); + Bank_precharge (3) := Ba; + Cmnd_precharge (3) := '1'; + ELSIF CAS_latency_2 = '1' THEN + A10_precharge (4) := Addr(10); + Bank_precharge (4) := Ba; + Cmnd_precharge (4) := '1'; + ELSIF CAS_latency_25 = '1' THEN + A10_precharge (5) := Addr(10); + Bank_precharge (5) := Ba; + Cmnd_precharge (5) := '1'; + ELSIF CAS_latency_3 = '1' THEN + A10_precharge (6) := Addr(10); + Bank_precharge (6) := Ba; + Cmnd_precharge (6) := '1'; + ELSIF CAS_latency_4 = '1' THEN + A10_precharge (8) := Addr(10); + Bank_precharge (8) := Ba; + Cmnd_precharge (8) := '1'; + END IF; + END IF; + + -- Burst Terminate + IF Burst_term = '1' THEN + -- Pipeline for Read + IF CAS_latency_15 = '1' THEN + Cmnd_bst (3) := '1'; + ELSIF CAS_latency_2 = '1' THEN + Cmnd_bst (4) := '1'; + ELSIF CAS_latency_25 = '1' THEN + Cmnd_bst (5) := '1'; + ELSIF CAS_latency_3 = '1' THEN + Cmnd_bst (6) := '1'; + ELSIF CAS_latency_4 = '1' THEN + Cmnd_bst (8) := '1'; + END IF; + + -- Terminate Write + ASSERT (Data_in_enable = '0') + REPORT "It's illegal to Burst Terminate a Write" + SEVERITY WARNING; + + -- Terminate Read with Auto Precharge + ASSERT (Read_precharge (0) = '0' AND Read_precharge (1) = '0' AND + Read_precharge (2) = '0' AND Read_precharge (3) = '0') + REPORT "It's illegal to Burst Terminate a Read with Auto Precharge" + SEVERITY WARNING; + END IF; + + -- Read Command + IF Read_enable = '1' THEN + -- CAS Latency Pipeline + IF Cas_latency_15 = '1' THEN + Read_cmnd (3) := '1'; + Read_bank (3) := Ba; + Read_cols (3) := Addr (8 DOWNTO 0); + ELSIF Cas_latency_2 = '1' THEN + Read_cmnd (4) := '1'; + Read_bank (4) := Ba; + Read_cols (4) := Addr (8 DOWNTO 0); + ELSIF Cas_latency_25 = '1' THEN + Read_cmnd (5) := '1'; + Read_bank (5) := Ba; + Read_cols (5) := Addr (8 DOWNTO 0); + ELSIF Cas_latency_3 = '1' THEN + Read_cmnd (6) := '1'; + Read_bank (6) := Ba; + Read_cols (6) := Addr (8 DOWNTO 0); + ELSIF Cas_latency_4 = '1' THEN + Read_cmnd (8) := '1'; + Read_bank (8) := Ba; + Read_cols (8) := Addr (8 DOWNTO 0); + END IF; + + -- Write to Read: Terminate Write Immediately + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + + -- Interrupting a Read with Auto Precharge (same bank only) + ASSERT (Read_precharge(CONV_INTEGER(Ba)) = '0') + REPORT "It's illegal to interrupt a Read with Auto Precharge" + SEVERITY WARNING; + + -- Activate to Read + ASSERT ((Ba = "00" AND Act_b0 = '1') OR + (Ba = "01" AND Act_b1 = '1') OR + (Ba = "10" AND Act_b2 = '1') OR + (Ba = "11" AND Act_b3 = '1')) + REPORT "Bank is not Activated for Read" + SEVERITY WARNING; + + -- Activate to Read without Auto Precharge + IF Addr (10) = '0' THEN + ASSERT ((Ba = "00" AND NOW - RCD_chk0 >= tRCD) OR + (Ba = "01" AND NOW - RCD_chk1 >= tRCD) OR + (Ba = "10" AND NOW - RCD_chk2 >= tRCD) OR + (Ba = "11" AND NOW - RCD_chk3 >= tRCD)) + REPORT "tRCD violation during Read" + SEVERITY WARNING; + END IF; + + -- Activate to Read with Auto Precharge + IF Addr (10) = '1' THEN + ASSERT ((Ba = "00" AND NOW - RAP_chk0 >= tRAP) OR + (Ba = "01" AND NOW - RAP_chk1 >= tRAP) OR + (Ba = "10" AND NOW - RAP_chk2 >= tRAP) OR + (Ba = "11" AND NOW - RAP_chk3 >= tRAP)) + REPORT "tRAP violation during Read" + SEVERITY WARNING; + END IF; + + -- Auto precharge + IF Addr (10) = '1' THEN + Read_precharge (Conv_INTEGER(Ba)) := '1'; + Count_precharge (Conv_INTEGER(Ba)) := 0; + END IF; + + -- DLL Check + IF (DLL_reset = '1') THEN + ASSERT (DLL_done = '1') + REPORT "DLL RESET not complete" + SEVERITY WARNING; + END IF; + END IF; + + -- Write Command + IF Write_enable = '1' THEN + -- Pipeline for Write + Write_cmnd (2) := '1'; + Write_bank (2) := Ba; + Write_cols (2) := Addr (8 DOWNTO 0); + + -- Interrupting a Write with Auto Precharge (same bank only) + ASSERT (Write_precharge(CONV_INTEGER(Ba)) = '0') + REPORT "It's illegal to interrupt a Write with Auto Precharge" + SEVERITY WARNING; + + -- Activate to Write + ASSERT ((Ba = "00" AND Act_b0 = '1') OR + (Ba = "01" AND Act_b1 = '1') OR + (Ba = "10" AND Act_b2 = '1') OR + (Ba = "11" AND Act_b3 = '1')) + REPORT "Bank is not Activated for Write" + SEVERITY WARNING; + + -- Activate to Write + ASSERT ((Ba = "00" AND NOW - RCD_chk0 >= tRCD) OR + (Ba = "01" AND NOW - RCD_chk1 >= tRCD) OR + (Ba = "10" AND NOW - RCD_chk2 >= tRCD) OR + (Ba = "11" AND NOW - RCD_chk3 >= tRCD)) + REPORT "tRCD violation during Write" + SEVERITY WARNING; + + -- Auto precharge + IF Addr (10) = '1' THEN + Write_precharge (Conv_INTEGER(Ba)) := '1'; + Count_precharge (Conv_INTEGER(Ba)) := 0; + END IF; + END IF; + END IF; + END PROCESS; + + -- + -- Dqs Receiver + -- + dqs_rcvrs : PROCESS + VARIABLE Dm_temp : STD_LOGIC_VECTOR (1 DOWNTO 0); + VARIABLE Dq_temp : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0); + BEGIN + WAIT ON Dqs; + -- Latch data at posedge Dqs + IF Dqs'EVENT AND Dqs (1) = '1' AND Dqs (0) = '1' THEN + Dq_temp := Dq; + Dm_temp := Dm; + END IF; + -- Latch data at negedge Dqs + IF Dqs'EVENT AND Dqs (1) = '0' AND Dqs (0) = '0' THEN + Dq_pair <= (Dq & Dq_temp); + Dm_pair <= (Dm & Dm_temp); + END IF; + END PROCESS; + + -- + -- Setup timing checks + -- + Setup_check : PROCESS + BEGIN + WAIT ON Sys_clk; + IF Sys_clk'EVENT AND Sys_clk = '1' THEN + ASSERT(Cke'LAST_EVENT >= tIS) + REPORT "CKE Setup time violation -- tIS" + SEVERITY WARNING; + ASSERT(Cs_n'LAST_EVENT >= tIS) + REPORT "CS# Setup time violation -- tIS" + SEVERITY WARNING; + ASSERT(Cas_n'LAST_EVENT >= tIS) + REPORT "CAS# Setup time violation -- tIS" + SEVERITY WARNING; + ASSERT(Ras_n'LAST_EVENT >= tIS) + REPORT "RAS# Setup time violation -- tIS" + SEVERITY WARNING; + ASSERT(We_n'LAST_EVENT >= tIS) + REPORT "WE# Setup time violation -- tIS" + SEVERITY WARNING; + ASSERT(Addr'LAST_EVENT >= tIS) + REPORT "ADDR Setup time violation -- tIS" + SEVERITY WARNING; + ASSERT(Ba'LAST_EVENT >= tIS) + REPORT "BA Setup time violation -- tIS" + SEVERITY WARNING; + END IF; + END PROCESS; + + -- + -- Hold timing checks + -- + Hold_check : PROCESS + BEGIN + WAIT ON Sys_clk'DELAYED (tIH); + IF Sys_clk'DELAYED (tIH) = '1' THEN + ASSERT(Cke'LAST_EVENT >= tIH) + REPORT "CKE Hold time violation -- tIH" + SEVERITY WARNING; + ASSERT(Cs_n'LAST_EVENT >= tIH) + REPORT "CS# Hold time violation -- tIH" + SEVERITY WARNING; + ASSERT(Cas_n'LAST_EVENT >= tIH) + REPORT "CAS# Hold time violation -- tIH" + SEVERITY WARNING; + ASSERT(Ras_n'LAST_EVENT >= tIH) + REPORT "RAS# Hold time violation -- tIH" + SEVERITY WARNING; + ASSERT(We_n'LAST_EVENT >= tIH) + REPORT "WE# Hold time violation -- tIH" + SEVERITY WARNING; + ASSERT(Addr'LAST_EVENT >= tIH) + REPORT "ADDR Hold time violation -- tIH" + SEVERITY WARNING; + ASSERT(Ba'LAST_EVENT >= tIH) + REPORT "BA Hold time violation -- tIH" + SEVERITY WARNING; + END IF; + END PROCESS; + +END behave; diff --git a/misc/readme.txt b/misc/readme.txt new file mode 100644 index 0000000..0ae1786 --- /dev/null +++ b/misc/readme.txt @@ -0,0 +1,20 @@ +These files are provided as is under a FreeBSD license. + +Patches most gratefully accepted to document this better. + +These are parts of the VHDL code that went into ZY2000 that +can be used on other FPGA brands and with other parts than +went into ZY2000. + +http://www.zylin.com/protoboard.htm + +The long term plan is to split out these from the ZPU project +into a DDR controller and ARM7 wishbone bridge +project on OpenCores.org and document them. + +Directories +=========== +arm7 - ARM7 wishbone interface +ddsdram - a generic ddr ram controller. Implemented for Xilinx + mt46v16m16 but +can be adapted to other FPGA brands and DRAM chips +wishbone - atomic 32 bit wishbone access inside FPGA and in ARM7 SW, over a 16 bit CPU databus
\ No newline at end of file diff --git a/misc/wishbone/src/atomic32_access.vhd b/misc/wishbone/src/atomic32_access.vhd new file mode 100644 index 0000000..9bc9825 --- /dev/null +++ b/misc/wishbone/src/atomic32_access.vhd @@ -0,0 +1,132 @@ +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.STD_LOGIC_UNSIGNED.ALL; + +library work; +--use work.phi_config.all; +use work.wishbone_pkg.all; + +entity atomic32_access is + port ( cpu_clk : in std_logic; + areset : in std_logic; + + -- Wishbone from CPU interface + wb_16_i : in wishbone_bus_in; + wb_16_o : out wishbone_bus_out; + + -- Wishbone to FPGA registers and ethernet core + wb_32_i : in wishbone_bus_out; + wb_32_o : out wishbone_bus_in); +end atomic32_access; + +architecture behave of atomic32_access is + +type eth_state_wr_type is (idle, lsb_msb, lsb, msb, write, ack, wait_st); +signal eth_state_wr : eth_state_wr_type; +type eth_state_rd_type is (idle, lsb_msb, lsb_read, lsb, wait_st2, msb); +signal eth_state_rd : eth_state_rd_type; +signal core_data : std_logic_vector(31 downto 0); +signal core_addr : std_logic_vector(31 downto 0); + +begin + process(cpu_clk, areset) + begin + if areset = '1' then + eth_state_wr <= idle; + eth_state_rd <= idle; + wb_32_o.stb <= '0'; + wb_32_o.cyc <= '0'; + wb_16_o.ack <= '0'; + core_data <= (others => '0'); + core_addr <= (others => '0'); + elsif (rising_edge(cpu_clk)) then + + case eth_state_wr is --write cycle + when idle => + if wb_16_i.cyc = '1' and wb_16_i.we = '1' then + eth_state_wr <= lsb_msb; + end if; + when lsb_msb => + if wb_16_i.adr(1) = '0' then + eth_state_wr <= lsb; + end if; + if wb_16_i.adr(1) = '1' then + eth_state_wr <= msb; + end if; + when lsb => + core_data(15 downto 0) <= wb_16_i.dat(15 downto 0); + wb_16_o.ack <= '1'; + eth_state_wr <= wait_st; + when msb => + core_data(31 downto 16) <= wb_16_i.dat(31 downto 16); + core_addr <= wb_16_i.adr(31 downto 2) & "00"; + eth_state_wr <= write; + when write => + wb_32_o.dat <= core_data; + wb_32_o.adr <= core_addr; + wb_32_o.sel <= "1111"; + wb_32_o.we <= '1'; + wb_32_o.stb <= '1'; + wb_32_o.cyc <= '1'; + eth_state_wr <= ack; + when ack => + if wb_32_i.ack = '1' then + wb_16_o.ack <= '1'; + eth_state_wr <= wait_st; + wb_32_o.stb <= '0'; + wb_32_o.cyc <= '0'; + wb_32_o.sel <= "0000"; + wb_32_o.we <= '0'; + end if; + when wait_st => + wb_16_o.ack <= '0'; + eth_state_wr <= idle; + when others => + eth_state_wr <= idle; + end case; + + case eth_state_rd is --read cycle + when idle => + if wb_16_i.cyc = '1' and wb_16_i.we = '0' then + core_addr <= wb_16_i.adr(31 downto 2) & "00"; + eth_state_rd <= lsb_msb; + end if; + when lsb_msb => + if wb_16_i.adr(1) = '0' then + wb_32_o.adr <= core_addr; + eth_state_rd <= lsb_read; + end if; + if wb_16_i.adr(1) = '1' then + wb_32_o.adr <= core_addr; + eth_state_rd <= msb; + end if; + when lsb_read => + wb_32_o.sel <= "1111"; + wb_32_o.we <= '0'; + wb_32_o.stb <= '1'; + wb_32_o.cyc <= '1'; + eth_state_rd <= lsb; + when lsb => + if wb_32_i.ack = '1' then + wb_32_o.sel <= "0000"; + wb_32_o.stb <= '0'; + wb_32_o.cyc <= '0'; + core_data <= wb_32_i.dat; + wb_16_o.dat <= x"0000" & wb_32_i.dat(15 downto 0); + wb_16_o.ack <= '1'; + eth_state_rd <= wait_st2; + end if; + when wait_st2 => + wb_16_o.ack <= '0'; + eth_state_rd <= idle; + when msb => + wb_16_o.ack <= '1'; + wb_16_o.dat <= core_data(31 downto 16) & x"0000"; + eth_state_rd <= wait_st2; + when others => + eth_state_rd <= idle; + end case; + end if; + end process; + +end behave;
\ No newline at end of file diff --git a/misc/wishbone/src/wishbone_pkg.vhd b/misc/wishbone/src/wishbone_pkg.vhd new file mode 100644 index 0000000..359a33f --- /dev/null +++ b/misc/wishbone/src/wishbone_pkg.vhd @@ -0,0 +1,52 @@ +library IEEE; +use IEEE.STD_LOGIC_1164.all; +use IEEE.STD_LOGIC_UNSIGNED.ALL; + +package wishbone_pkg is + + type wishbone_bus_in is record + adr : std_logic_vector(31 downto 0); + sel : std_logic_vector(3 downto 0); + we : std_logic; + dat : std_logic_vector(31 downto 0); -- Note! Data written with 'we' + cyc : std_logic; + stb : std_logic; + end record; + + type wishbone_bus_out is record + dat : std_logic_vector(31 downto 0); + ack : std_logic; + end record; + + type wishbone_bus is record + insig : wishbone_bus_in; + outsig : wishbone_bus_out; + end record; + + component atomic32_access is + port ( cpu_clk : in std_logic; + areset : in std_logic; + + -- Wishbone from CPU interface + wb_16_i : in wishbone_bus_in; + wb_16_o : out wishbone_bus_out; + -- Wishbone to FPGA registers and ethernet core + wb_32_i : in wishbone_bus_out; + wb_32_o : out wishbone_bus_in); + end component; + + component eth_access_corr is + port ( cpu_clk : in std_logic; + areset : in std_logic; + + -- Wishbone from Wishbone MUX + eth_raw_o : out wishbone_bus_out; + eth_raw_i : in wishbone_bus_in; + + -- Wishbone ethernet core + eth_slave_i : in wishbone_bus_out; + eth_slave_o : out wishbone_bus_in); + end component; + + +end wishbone_pkg; |