From 6eb25882ba9344efbaf77b3f9d9da10d52c5cd78 Mon Sep 17 00:00:00 2001 From: Jens Ahrensfeld Date: Thu, 2 Oct 2008 13:37:55 +0000 Subject: [PATCH] Intital revision git-svn-id: http://moon:8086/svn/vhdl/trunk@24 cc03376c-175c-47c8-b038-4cd826a8556b --- .../ddr_sdr_v1_5/ise9/sdram_ctrl_top.prj | 13 + lib/SDRAM/ddr_sdr_v1_5/sim/ModelSim SE .lnk | Bin 0 -> 685 bytes lib/SDRAM/ddr_sdr_v1_5/sim/compile_simprim.do | 6 + lib/SDRAM/ddr_sdr_v1_5/sim/compile_unisim.do | 6 + .../sim/tb_sdram_ctrl_frontend_wb.fdo | 28 + .../sim/tb_sdram_ctrl_frontend_wb.wdo | 31 + .../ddr_sdr_v1_5/src/ddr_phy_virtex4.vhd | 389 +++++ lib/SDRAM/ddr_sdr_v1_5/src/fifo_sync.vhd | 111 ++ lib/SDRAM/ddr_sdr_v1_5/src/mt46v16m16.vhd | 1320 +++++++++++++++++ lib/SDRAM/ddr_sdr_v1_5/src/reset_virtex4.vhd | 111 ++ lib/SDRAM/ddr_sdr_v1_5/src/sdram_cmd.vhd | 269 ++++ lib/SDRAM/ddr_sdr_v1_5/src/sdram_config.vhd | 74 + lib/SDRAM/ddr_sdr_v1_5/src/sdram_ctrl.vhd | 487 ++++++ .../src/sdram_ctrl_frontend_wb.vhd | 283 ++++ lib/SDRAM/ddr_sdr_v1_5/src/sdram_ctrl_top.vhd | 248 ++++ lib/SDRAM/ddr_sdr_v1_5/src/sdram_types.vhd | 133 ++ .../src/tb_sdram_ctrl_frontend_wb.vhd | 495 +++++++ 17 files changed, 4004 insertions(+) create mode 100644 lib/SDRAM/ddr_sdr_v1_5/ise9/sdram_ctrl_top.prj create mode 100644 lib/SDRAM/ddr_sdr_v1_5/sim/ModelSim SE .lnk create mode 100644 lib/SDRAM/ddr_sdr_v1_5/sim/compile_simprim.do create mode 100644 lib/SDRAM/ddr_sdr_v1_5/sim/compile_unisim.do create mode 100644 lib/SDRAM/ddr_sdr_v1_5/sim/tb_sdram_ctrl_frontend_wb.fdo create mode 100644 lib/SDRAM/ddr_sdr_v1_5/sim/tb_sdram_ctrl_frontend_wb.wdo create mode 100644 lib/SDRAM/ddr_sdr_v1_5/src/ddr_phy_virtex4.vhd create mode 100644 lib/SDRAM/ddr_sdr_v1_5/src/fifo_sync.vhd create mode 100644 lib/SDRAM/ddr_sdr_v1_5/src/mt46v16m16.vhd create mode 100644 lib/SDRAM/ddr_sdr_v1_5/src/reset_virtex4.vhd create mode 100644 lib/SDRAM/ddr_sdr_v1_5/src/sdram_cmd.vhd create mode 100644 lib/SDRAM/ddr_sdr_v1_5/src/sdram_config.vhd create mode 100644 lib/SDRAM/ddr_sdr_v1_5/src/sdram_ctrl.vhd create mode 100644 lib/SDRAM/ddr_sdr_v1_5/src/sdram_ctrl_frontend_wb.vhd create mode 100644 lib/SDRAM/ddr_sdr_v1_5/src/sdram_ctrl_top.vhd create mode 100644 lib/SDRAM/ddr_sdr_v1_5/src/sdram_types.vhd create mode 100644 lib/SDRAM/ddr_sdr_v1_5/src/tb_sdram_ctrl_frontend_wb.vhd diff --git a/lib/SDRAM/ddr_sdr_v1_5/ise9/sdram_ctrl_top.prj b/lib/SDRAM/ddr_sdr_v1_5/ise9/sdram_ctrl_top.prj new file mode 100644 index 0000000..334db73 --- /dev/null +++ b/lib/SDRAM/ddr_sdr_v1_5/ise9/sdram_ctrl_top.prj @@ -0,0 +1,13 @@ +vhdl work "../../../misc/utils_pkg.vhd" +vhdl work "../src/sdram_config.vhd" +vhdl work "../../../FIFO/src/fifo_ctrl_pkg.vhd" +vhdl work "../src/sdram_types.vhd" +vhdl work "../../../FIFO/src/sync_fifo_ctrl.vhd" +vhdl work "../../../FIFO/src/dpram.vhd" +vhdl work "../src/sdram_ctrl.vhd" +vhdl work "../src/sdram_cmd.vhd" +vhdl work "../src/reset_virtex4.vhd" +vhdl work "../src/fifo_sync.vhd" +vhdl work "../src/ddr_phy_virtex4.vhd" +vhdl work "../src/clockgen_virtex4.vhd" +vhdl work "../src/sdram_ctrl_top.vhd" diff --git a/lib/SDRAM/ddr_sdr_v1_5/sim/ModelSim SE .lnk b/lib/SDRAM/ddr_sdr_v1_5/sim/ModelSim SE .lnk new file mode 100644 index 0000000000000000000000000000000000000000..e0d2d274aefd1f8fd1aca03e3f0e15554b2b3c3e GIT binary patch literal 685 zcmah_OGq106g}eyy67U(5o{L3F8Z zMCh*4B6iV&i*CAYQz$Lcm2}Z|BS@DmRHZvOch8)6k^mI7g&BD7 zW{f`}Y7F1%funucSDwFceo4gVw&m0PPYSlKx;GU!U!=IAqC0bxKG1%~gm3rz72FAh zo?S<9B&J{7@~Q;--8vYpZg(J)P2bJNS9o+At!TsXySI_er-`UGqw-b;W!RWy&cot1 zdDex=CPO`PCVWVxN5_))SNa3t5ezmt>XF|f5e=D=BSi*-lSMep1U4tP}S}SpoA(vFx#b{-$-FoxNN1PTV!>(08cQa*sww$*tQ%^|& zj#-$?4F|#n-F=0ASyeBl5rd8@9WdyI&JcJ+oWdxwh|?*Z9fNM?P-$Y7?&L7UPDA&@ zhMJuRM7ib{9t+1TH$IqWrq)m9Z}!~V{n4U+U3$4)&42rNEqK_m@dcf)jrBkO>&q9m L13P_0yUBVEexI1< literal 0 HcmV?d00001 diff --git a/lib/SDRAM/ddr_sdr_v1_5/sim/compile_simprim.do b/lib/SDRAM/ddr_sdr_v1_5/sim/compile_simprim.do new file mode 100644 index 0000000..16b23bb --- /dev/null +++ b/lib/SDRAM/ddr_sdr_v1_5/sim/compile_simprim.do @@ -0,0 +1,6 @@ +vlib simprim + +vcom -93 -work simprim F:/Xilinx9/vhdl/src/simprims/simprim_Vcomponents_mti.vhd +vcom -93 -work simprim F:/Xilinx9/vhdl/src/simprims/simprim_Vpackage_mti.vhd +vcom -93 -work simprim F:/Xilinx9/vhdl/src/simprims/simprim_SMODEL_mti.vhd +vcom -93 -work simprim F:/Xilinx9/vhdl/src/simprims/simprim_VITAL_mti.vhd diff --git a/lib/SDRAM/ddr_sdr_v1_5/sim/compile_unisim.do b/lib/SDRAM/ddr_sdr_v1_5/sim/compile_unisim.do new file mode 100644 index 0000000..d35d8c9 --- /dev/null +++ b/lib/SDRAM/ddr_sdr_v1_5/sim/compile_unisim.do @@ -0,0 +1,6 @@ +vlib unisim + +vcom -93 -work unisim F:/Xilinx9/vhdl/src/unisims/unisim_vpkg.vhd +vcom -93 -work unisim F:/Xilinx9/vhdl/src/unisims/unisim_vcomp.vhd +vcom -93 -work unisim F:/Xilinx9/vhdl/src/unisims/unisim_smodel.vhd +vcom -93 -work unisim F:/Xilinx9/vhdl/src/unisims/unisim_vital.vhd diff --git a/lib/SDRAM/ddr_sdr_v1_5/sim/tb_sdram_ctrl_frontend_wb.fdo b/lib/SDRAM/ddr_sdr_v1_5/sim/tb_sdram_ctrl_frontend_wb.fdo new file mode 100644 index 0000000..c7f5f7f --- /dev/null +++ b/lib/SDRAM/ddr_sdr_v1_5/sim/tb_sdram_ctrl_frontend_wb.fdo @@ -0,0 +1,28 @@ +## NOTE: Do not edit this file. +## + +vlib work +vcom -explicit -93 "../../../FIFO/src/fifo_ctrl_pkg.vhd" +vcom -explicit -93 "../../../misc/dpram_1w1r_dist.vhd" +vcom -explicit -93 "../../../FIFO/src/sync_fifo_ctrl.vhd" +vcom -explicit -93 "../../../misc/utils_pkg.vhd" +vcom -explicit -93 "../../../misc/clockgen_virtex4.vhd" +vcom -explicit -93 "../src/fifo_sync.vhd" +vcom -explicit -93 "../src/sdram_config.vhd" +vcom -explicit -93 "../src/sdram_types.vhd" +vcom -explicit -93 "../src/reset_virtex4.vhd" +vcom -explicit -93 "../src/sdram_cmd.vhd" +vcom -explicit -93 "../src/sdram_ctrl.vhd" +vcom -explicit -93 "../src/ddr_phy_virtex4.vhd" +vcom -explicit -93 "../src/sdram_ctrl_top.vhd" +vcom -explicit -93 "../src/sdram_ctrl_frontend_wb.vhd" +vcom -explicit -93 "../src/mt46v16m16.vhd" +vcom -explicit -93 "../src/tb_sdram_ctrl_frontend_wb.vhd" + +#restart -force +vsim -t 1ps -lib work tb_sdram_ctrl_frontend_wb +do {tb_sdram_ctrl_frontend_wb.wdo} +view wave +view structure +view signals +run 40us diff --git a/lib/SDRAM/ddr_sdr_v1_5/sim/tb_sdram_ctrl_frontend_wb.wdo b/lib/SDRAM/ddr_sdr_v1_5/sim/tb_sdram_ctrl_frontend_wb.wdo new file mode 100644 index 0000000..f2b1282 --- /dev/null +++ b/lib/SDRAM/ddr_sdr_v1_5/sim/tb_sdram_ctrl_frontend_wb.wdo @@ -0,0 +1,31 @@ +onerror {resume} +quietly WaveActivateNextPane {} 0 +add wave -noupdate -format Logic /tb_sdram_ctrl_frontend_wb/clk_o +add wave -noupdate -format Logic /tb_sdram_ctrl_frontend_wb/rst_o +add wave -noupdate -format Logic /tb_sdram_ctrl_frontend_wb/cyc_o +add wave -noupdate -format Logic /tb_sdram_ctrl_frontend_wb/stb_o +add wave -noupdate -format Logic /tb_sdram_ctrl_frontend_wb/we_o +add wave -noupdate -format Literal /tb_sdram_ctrl_frontend_wb/sel_o +add wave -noupdate -format Logic /tb_sdram_ctrl_frontend_wb/ack_i +add wave -noupdate -format Logic /tb_sdram_ctrl_frontend_wb/rdy_i +add wave -noupdate -format Literal -radix hexadecimal /tb_sdram_ctrl_frontend_wb/addr_o +add wave -noupdate -format Literal -radix hexadecimal /tb_sdram_ctrl_frontend_wb/dat_i +add wave -noupdate -format Literal -radix hexadecimal /tb_sdram_ctrl_frontend_wb/dat_o +add wave -noupdate -format Literal -radix hexadecimal /tb_sdram_ctrl_frontend_wb/dout_reg +add wave -noupdate -format Literal /tb_sdram_ctrl_frontend_wb/dout_cnt +TreeUpdate [SetDefaultTree] +WaveRestoreCursors {{Cursor 1} {7168067 ps} 0} +configure wave -namecolwidth 150 +configure wave -valuecolwidth 100 +configure wave -justifyvalue left +configure wave -signalnamewidth 1 +configure wave -snapdistance 10 +configure wave -datasetprefix 0 +configure wave -rowmargin 4 +configure wave -childrowmargin 2 +configure wave -gridoffset 0 +configure wave -gridperiod 1 +configure wave -griddelta 40 +configure wave -timeline 0 +update +WaveRestoreZoom {7132020 ps} {7288781 ps} diff --git a/lib/SDRAM/ddr_sdr_v1_5/src/ddr_phy_virtex4.vhd b/lib/SDRAM/ddr_sdr_v1_5/src/ddr_phy_virtex4.vhd new file mode 100644 index 0000000..f5ab332 --- /dev/null +++ b/lib/SDRAM/ddr_sdr_v1_5/src/ddr_phy_virtex4.vhd @@ -0,0 +1,389 @@ +------------------------------------------------------------------------- +-- Project: SDRAM controller +-- This file: DDR physical layer (Virtex-4 specific) +-- +-- Copyright (C) 2007 J. Ahrensfeld +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +-- For questions and ideas, please contact the author at jens@jayfield.org +-- +-------------------------------------------------------------------------- + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.numeric_std.ALL; + +use work.sdram_config.all; +use work.sdram_types.all; + +Library UNISIM; +use UNISIM.vcomponents.all; + +entity ddr_phy is + Port ( + sys_rst : in STD_LOGIC; + sys_clk0 : in STD_LOGIC; + sys_clk270 : in STD_LOGIC; + u_tag_in : in user_tag_t; + u_tag_rd : out user_tag_t; + u_tag_wr : out user_tag_t; + read_clk : in STD_LOGIC; + phy_ctrl : in phy_ctrl_t; + part_ctrl : in part_ctrl_t; + sdr_data_w : in unsigned(SDR_DATA_WIDTH-1 downto 0); + sdr_dm_wr_in : in unsigned(SDR_DM_WIDTH-1 downto 0); + sdr_dm_rd_in : in unsigned(SDR_DM_WIDTH-1 downto 0); + sdr_dm_rd_out : out unsigned(SDR_DM_WIDTH-1 downto 0); + sdr_data_r : out unsigned(SDR_DATA_WIDTH-1 downto 0); + sdr_data_vld : out STD_LOGIC; + sdr_data_req_w : out STD_LOGIC; + sdr_data_req_r : out STD_LOGIC; + part_clk_p : out STD_LOGIC; + part_clk_n : out STD_LOGIC; + part_dm : out unsigned(DDR_DM_WIDTH-1 downto 0); + part_dqs : inout unsigned(DDR_DQS_WIDTH-1 downto 0); + part_data : inout unsigned(DDR_DATA_WIDTH-1 downto 0); + part_ba : out unsigned(DDR_BANK_WIDTH-1 downto 0); + part_addr : out unsigned(DDR_ADDR_WIDTH-1 downto 0); + part_cs_n : out STD_LOGIC; + part_we_n : out STD_LOGIC; + part_cas_n : out STD_LOGIC; + part_ras_n : out STD_LOGIC; + part_cke : out STD_LOGIC + ); +end ddr_phy; + +architecture tech of ddr_phy is + + signal dqs_drive : std_logic; + signal drive : std_logic; + signal dqs : unsigned(DDR_DQS_WIDTH-1 downto 0); + signal dqs_zen : unsigned(DDR_DQS_WIDTH-1 downto 0); + signal dqs_rst : std_logic; + signal ddr_data_w : unsigned(DDR_DATA_WIDTH-1 downto 0); + signal data_r : unsigned(SDR_DATA_WIDTH-1 downto 0); + signal data_reg_r : unsigned(SDR_DATA_WIDTH-1 downto 0); + signal drive270 : unsigned(DDR_DATA_WIDTH-1 downto 0); + signal part_ctrl_reg : part_ctrl_t; + signal we_reg : std_logic; + signal read_en : std_logic; + + type u_tag_array_t is array (natural range 0 to 4) of user_tag_t; + signal u_tag_pipe : u_tag_array_t; + + type dm_out_array_t is array (natural range 0 to 4) of unsigned(SDR_DM_WIDTH-1 downto 0); + signal dm_out_pipe : dm_out_array_t; + +begin + +------------------------------------------------------------------------------------------------------------------------------------------------ +utag_pipe: + process(sys_rst, sys_clk0) + begin + if rising_edge(sys_clk0) then + for i in u_tag_pipe'length-1 downto 1 loop + u_tag_pipe(i) <= u_tag_pipe(i-1); + end loop; + if phy_ctrl.utag_we = '1' then + u_tag_pipe(0) <= u_tag_in; + end if; + end if; + end process; + +dmout_pipe: + process(sys_rst, sys_clk0) + begin + if rising_edge(sys_clk0) then + for i in dm_out_pipe'length-1 downto 1 loop + dm_out_pipe(i) <= dm_out_pipe(i-1); + end loop; + if phy_ctrl.utag_we = '1' then + dm_out_pipe(0) <= sdr_dm_rd_in; + end if; + end if; + end process; + +WE_REGISTER: + process(sys_rst, sys_clk0) + begin + if sys_rst = '1' then + we_reg <= '0'; + elsif rising_edge(sys_clk0) then + we_reg <= phy_ctrl.we; + end if; + end process; + +DATA_DRIVE_GEN: + process(sys_clk0) + begin + if falling_edge(sys_clk0) then + dqs_rst <= not we_reg; + drive <= we_reg; + end if; + end process; + +DQS_DRIVE_GEN: + process(sys_clk0) + variable p : unsigned(1 downto 0); + begin + if rising_edge(sys_clk0) then + if phy_ctrl.drive_en = '1' then + p := (others => '1'); + else + p := p(p'left-1 downto 0) & '0'; + end if; + end if; + dqs_drive <= p(p'left); + end process; + +------------------------------------------------------------------------------------------------------------------------------------------------ +-- SDRAM Clock +ODDR_clk_p : ODDR + generic map + ( + DDR_CLK_EDGE => "OPPOSITE_EDGE", -- "OPPOSITE_EDGE" or "SAME_EDGE" + INIT => '0', -- Initial value for Q port ('1' or '0') + SRTYPE => "SYNC" -- Reset Type ("ASYNC" or "SYNC") + ) + port map ( + Q => part_clk_p, -- 1-bit DDR output + C => sys_clk0, -- 1-bit clock input + CE => '1', -- 1-bit clock enable input + D1 => '1', -- 1-bit data input (positive edge) + D2 => '0', -- 1-bit data input (negative edge) + R => '0', -- 1-bit reset input + S => '0' -- 1-bit set input + ); + +ODDR_clk_n : ODDR + generic map + ( + DDR_CLK_EDGE => "OPPOSITE_EDGE", -- "OPPOSITE_EDGE" or "SAME_EDGE" + INIT => '0', -- Initial value for Q port ('1' or '0') + SRTYPE => "SYNC" -- Reset Type ("ASYNC" or "SYNC") + ) + port map ( + Q => part_clk_n, -- 1-bit DDR output + C => sys_clk0, -- 1-bit clock input + CE => '1', -- 1-bit clock enable input + D1 => '0', -- 1-bit data input (positive edge) + D2 => '1', -- 1-bit data input (negative edge) + R => '0', -- 1-bit reset input + S => '0' -- 1-bit set input + ); + +------------------------------------------------------------------------------------------------------------------------------------------------ +-- Data OUT DDR-FFs +gen_ddr_data_out: + for n in 0 to DDR_DATA_WIDTH-1 generate + begin + ODDR_data : ODDR + generic map + ( + DDR_CLK_EDGE => "SAME_EDGE", -- "OPPOSITE_EDGE" or "SAME_EDGE" + INIT => '0', -- Initial value for Q port ('1' or '0') + SRTYPE => "SYNC" -- Reset Type ("ASYNC" or "SYNC") + ) + port map ( + Q => ddr_data_w(n), -- 1-bit DDR output + C => sys_clk270, -- 1-bit clock input + CE => '1', -- 1-bit clock enable input + D1 => sdr_data_w(n + DDR_DATA_WIDTH), -- 1-bit data input (positive edge) + D2 => sdr_data_w(n), -- 1-bit data input (negative edge) + R => '0', -- 1-bit reset input + S => '0' -- 1-bit set input + ); + end generate gen_ddr_data_out; + +-- Sample tristate on clock90 + process (sys_clk270) + begin + if rising_edge(sys_clk270) then + for n in 0 to DDR_DATA_WIDTH-1 loop + drive270(n) <= drive; + end loop; + end if; + end process; + +-- Output mux +out_mux_data: + for n in 0 to DDR_DATA_WIDTH-1 generate + part_data(n) <= ddr_data_w(n) when drive270(n) = '1' else 'Z'; + end generate; + +------------------------------------------------------------------------------------------------------------------------------------------------ +-- Data-mask OUT DDR-FFs +gen_ddr_dm_out: + for n in 0 to DDR_DM_WIDTH-1 generate + begin + ODDR_dm : ODDR + generic map + ( + DDR_CLK_EDGE => "SAME_EDGE", -- "OPPOSITE_EDGE" or "SAME_EDGE" + INIT => '0', -- Initial value for Q port ('1' or '0') + SRTYPE => "SYNC" -- Reset Type ("ASYNC" or "SYNC") + ) + port map ( + Q => part_dm(n), -- 1-bit DDR output + C => sys_clk270, -- 1-bit clock input + CE => '1', -- 1-bit clock enable input + D1 => sdr_dm_wr_in(n + DDR_DM_WIDTH), -- 1-bit data input (positive edge) + D2 => sdr_dm_wr_in(n), -- 1-bit data input (negative edge) + R => '0', -- 1-bit reset input + S => '0' -- 1-bit set input + ); + end generate gen_ddr_dm_out; + +------------------------------------------------------------------------------------------------------------------------------------------------ +-- DQS OUT DDR-FFs +gen_dqs_out: + for n in 0 to DDR_DQS_WIDTH-1 generate + begin + ODDR_dqs : ODDR + generic map + ( + DDR_CLK_EDGE => "OPPOSITE_EDGE", -- "OPPOSITE_EDGE" or "SAME_EDGE" + INIT => '0', -- Initial value for Q port ('1' or '0') + SRTYPE => "SYNC" -- Reset Type ("ASYNC" or "SYNC") + ) + port map ( + Q => dqs(n), -- 1-bit DDR output + C => sys_clk0, -- 1-bit clock input + CE => '1', -- 1-bit clock enable input + D2 => '0', -- 1-bit data input (positive edge) + D1 => '1', -- 1-bit data input (negative edge) + R => dqs_rst, -- 1-bit reset input + S => '0' -- 1-bit set input + ); + end generate gen_dqs_out; + +-- Tristate-Control fuer dqs + process (sys_clk0) is + variable zctrl : boolean; + begin + if rising_edge(sys_clk0) then + if dqs_drive = '1' then + zctrl := false; + else + zctrl := true; + end if; + if zctrl then + dqs_zen <= (others => '1'); + else + dqs_zen <= (others => '0'); + end if; + end if; + end process; + +-- Tristate-Buffer fuer dqs +gen_out_mux_dqs: + for n in 0 to DDR_DQS_WIDTH-1 generate + part_dqs(n) <= 'Z' when dqs_zen(n)='1' else dqs(n); + end generate gen_out_mux_dqs; + +------------------------------------------------------------------------------------------------------------------------------------------------ + process (sys_rst, sys_clk0) is + begin + if sys_rst = '1' then + part_ctrl_reg.cmd <= COMMAND(SD_DESELECT); + part_ctrl_reg.ba <= (others=>'0'); + part_ctrl_reg.addr <= (others=>'0'); + part_ctrl_reg.cke <= '0'; + elsif rising_edge(sys_clk0) then + part_ctrl_reg <= part_ctrl; + end if; + end process; + + process (sys_clk0) is + begin + if falling_edge(sys_clk0) then + part_ras_n <= part_ctrl_reg.cmd.ras_n; + part_cas_n <= part_ctrl_reg.cmd.cas_n; + part_we_n <= part_ctrl_reg.cmd.we_n; + part_cs_n <= part_ctrl_reg.cmd.cs_n; + part_ba <= part_ctrl_reg.ba; + part_addr <= part_ctrl_reg.addr; + part_cke <= part_ctrl_reg.cke; + end if; + end process; + +----------------------------------------------------------------- +-- READ DATA Processing +----------------------------------------------------------------- +gen_ddr_data_in: + for n in 0 to DDR_DATA_WIDTH-1 generate + begin + IDDR_data : IDDR + generic map + ( + DDR_CLK_EDGE => "SAME_EDGE", -- "OPPOSITE_EDGE", "SAME_EDGE" or "SAME_EDGE_PIPELINED" + INIT_Q1 => '0', -- Initial value of Q1: '0' or '1' + INIT_Q2 => '0', -- Initial value of Q2: '0' or '1' + SRTYPE => "SYNC" -- Set/Reset type: "SYNC" or "ASYNC" + ) + port map + ( + Q1 => data_r(n), -- 1-bit output for positive edge of clock + Q2 => data_r(n + DDR_DATA_WIDTH), -- 1-bit output for negative edge of clock + C => read_clk, -- 1-bit clock input + CE => read_en, -- 1-bit clock enable input + D => part_data(n), -- 1-bit DDR data input + R => '0', -- 1-bit reset + S => '0' -- 1-bit set + ); + end generate; + + +data_sample_stage: + process (sys_clk0) + begin + if falling_edge(sys_clk0) then + data_reg_r <= data_r; + end if; + end process; + +misc_flags_and_data_out: + process (sys_rst, sys_clk0) + variable p : unsigned(3 downto 0); + begin + if sys_rst = '1' then + p := (others => '0'); + read_en <= '0'; + sdr_data_vld <= '0'; + sdr_data_req_w <= '0'; + sdr_data_req_r <= '0'; + elsif rising_edge(sys_clk0) then + sdr_data_r <= data_reg_r; + if p(3) = '1' then + u_tag_rd <= u_tag_pipe(4); + sdr_dm_rd_out <= dm_out_pipe(4); + end if; + if phy_ctrl.we = '1' then + u_tag_wr <= u_tag_pipe(0); + end if; + sdr_data_req_w <= phy_ctrl.we; + sdr_data_req_r <= phy_ctrl.re; + sdr_data_vld <= p(3); + read_en <= p(1); + if phy_ctrl.re = '1' then + p := p(p'left-1 downto 0) & '1'; + else + p := p(p'left-1 downto 0) & '0'; + end if; + end if; + end process; + +------------------------------------------------------------------------------------------ +end tech; diff --git a/lib/SDRAM/ddr_sdr_v1_5/src/fifo_sync.vhd b/lib/SDRAM/ddr_sdr_v1_5/src/fifo_sync.vhd new file mode 100644 index 0000000..79ce51f --- /dev/null +++ b/lib/SDRAM/ddr_sdr_v1_5/src/fifo_sync.vhd @@ -0,0 +1,111 @@ +------------------------------------------------------------------------- +-- Project: JCPU, a portable 8-bit RISC CPU written in VHDL +-- This file: Dual-ported register file with asynchrous read + +-- Copyright (C) 2007 J. Ahrensfeld + +-- This library is free software; you can redistribute it and/or +-- modify it under the terms of the GNU Lesser General Public +-- License as published by the Free Software Foundation; either +-- version 2.1 of the License, or (at your option) any later version. + +-- This library is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +-- Lesser General Public License for more details. + +-- You should have received a copy of the GNU Lesser General Public +-- License along with this library; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +-- For questions and ideas, please contact the author at jens@jayfield.org + +----------------------------------------------------------------------- + +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; + +use work.fifo_ctrl_pkg.all; + +entity fifo_sync is + Generic ( + addr_width : natural := 4; + data_width : natural := 8; + almost_full_thresh : integer := 12; + almost_empty_thresh : integer := 4 + ); + Port + ( + rst : in STD_LOGIC; + clk : in STD_LOGIC; + we : in STD_LOGIC; + re : in STD_LOGIC; + fifo_full : out STD_LOGIC; + fifo_empty : out STD_LOGIC; + fifo_afull : out STD_LOGIC; + fifo_aempty : out STD_LOGIC; + data_w : in unsigned (data_width-1 downto 0); + data_r : out unsigned (data_width-1 downto 0) + ); +end fifo_sync; + +architecture Behavioral of fifo_sync is + + signal mem_we : STD_LOGIC; + signal ptr_w : unsigned (addr_width-1 downto 0); + signal ptr_r : unsigned (addr_width-1 downto 0); + signal full : STD_LOGIC; + signal empty : STD_LOGIC; + signal almost_full : STD_LOGIC; + signal almost_empty : STD_LOGIC; + +begin + + mem_we <= we; + fifo_full <= full; + fifo_empty <= empty; + fifo_afull <= almost_full; + fifo_aempty <= almost_empty; + + inst_sync_fifo_ctrl: entity work.sync_fifo_ctrl + GENERIC MAP + ( + addr_width => addr_width, + almost_full_thresh => almost_full_thresh, + almost_empty_thresh => almost_empty_thresh + ) + PORT MAP + ( + rst => rst, + clk => clk, + we => we, + re => re, + ptr_w => ptr_w, + ptr_r => ptr_r, + fifo_full => full, + fifo_empty => empty, + fifo_afull => almost_full, + fifo_aempty => almost_empty + + ); + + inst_dpram_1w1r: entity work.dpram_1w1r_dist + GENERIC MAP ( + addr_width => addr_width, + data_width => data_width + ) + PORT MAP( + clka => clk, + clkb => clk, + en_a => '1', + en_b => '1', + we_a => mem_we, + addr_a => ptr_w, + addr_b => ptr_r, + din_a => data_w, + dout_b => data_r + ); + +end Behavioral; + diff --git a/lib/SDRAM/ddr_sdr_v1_5/src/mt46v16m16.vhd b/lib/SDRAM/ddr_sdr_v1_5/src/mt46v16m16.vhd new file mode 100644 index 0000000..356bb28 --- /dev/null +++ b/lib/SDRAM/ddr_sdr_v1_5/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/lib/SDRAM/ddr_sdr_v1_5/src/reset_virtex4.vhd b/lib/SDRAM/ddr_sdr_v1_5/src/reset_virtex4.vhd new file mode 100644 index 0000000..4f799c5 --- /dev/null +++ b/lib/SDRAM/ddr_sdr_v1_5/src/reset_virtex4.vhd @@ -0,0 +1,111 @@ +------------------------------------------------------------------------- +-- Project: SDRAM controller +-- This file: Reset generator (Virtex-4 specific) +-- +-- Copyright (C) 2007 J. Ahrensfeld +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +-- For questions and ideas, please contact the author at jens@jayfield.org +-- +-------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; + +Library UNISIM; +use UNISIM.vcomponents.all; + +entity reset is + port + ( + clk : in std_logic; + rst_in : in std_logic; + rst_out : out std_logic + ); +end; + +architecture tech of reset is + + signal rst : std_logic; + signal shift_pipe : std_logic_vector(3 downto 0); + attribute KEEP : string; + attribute KEEP of shift_pipe : signal is "TRUE"; + +begin + + rst <= shift_pipe(0); + +bufg_reset: bufg + port map + ( + o => rst_out, + i => rst + ); + +fdp0: fdp + generic map + ( + init => '1' + ) + port map + ( + d => rst_in, + c => clk, + pre => '0', + q => shift_pipe(3) + ); + +fdp1: fdp + generic map + ( + init => '1' + ) + port map + ( + + d => shift_pipe(3), + c => clk, + pre => '0', + q => shift_pipe(2) + ); + +fdp2: fdp + generic map + ( + init => '1' + ) + port map + ( + d => shift_pipe(2), + c => clk, + pre => '0', + q => shift_pipe(1) + ); + +fdp3: fdp + generic map + ( + init => '1' + ) + port map + ( + + d => shift_pipe(1), + c => clk, + pre => '0', + q => shift_pipe(0) + ); + +end tech; diff --git a/lib/SDRAM/ddr_sdr_v1_5/src/sdram_cmd.vhd b/lib/SDRAM/ddr_sdr_v1_5/src/sdram_cmd.vhd new file mode 100644 index 0000000..a50b6e8 --- /dev/null +++ b/lib/SDRAM/ddr_sdr_v1_5/src/sdram_cmd.vhd @@ -0,0 +1,269 @@ +------------------------------------------------------------------------- +-- Project: SDRAM controller +-- This file: SDRAM command controller +-- +-- Copyright (C) 2007 J. Ahrensfeld +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +-- For questions and ideas, please contact the author at jens@jayfield.org +-- +-------------------------------------------------------------------------- + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.numeric_std.ALL; + +use work.sdram_config.all; +use work.sdram_types.all; + +entity sdram_cmd is + Generic (BL : natural := 2); + Port ( + rst : in STD_LOGIC; + clk : in STD_LOGIC; + enable : in STD_LOGIC; + u_tag_in : in user_tag_t; + u_tag_out : out user_tag_t; + phy_ctrl : out phy_ctrl_t; + cmd : in sdr_cmd_t; + cmd_we : in STD_LOGIC; + cmd_ack : out STD_LOGIC; + col_addr : in col_addr_t; + mode_word : in mode_word_t; + sdr_cmd_ctrl : out sdr_cmd_lines_t; + sdr_addr : out sdr_addr_t; + sdr_ba : out sdr_ba_t + ); +end sdram_cmd; + +architecture behaviour of sdram_cmd is + + signal st_sdr, st_sdr_next : sdr_state_t; + + signal cc_preset : natural range 0 to 10; + signal cc_load_en : std_logic; + signal cycle_finished : std_logic; + + signal burst_preset : natural range 0 to 3; + signal burst_load_en : std_logic; + signal burst_finished : std_logic; + +begin + + u_tag_out <= u_tag_in; + +------------------------------------------------------------------------------------------ + +fsm_sdr_state: + process (st_sdr, cmd, cmd_we, cycle_finished, burst_finished, mode_word, enable, col_addr) + begin + st_sdr_next <= st_sdr; + sdr_cmd_ctrl <= COMMAND(SD_NOP); + + cc_load_en <= '0'; + cc_preset <= TIMING(cmd); + burst_load_en <= '0'; + cmd_ack <= '0'; + burst_preset <= BL/2-1; + phy_ctrl.re <= '0'; + phy_ctrl.drive_en <= '0'; + phy_ctrl.we <= '0'; + phy_ctrl.utag_we <= '0'; + sdr_addr <= mode_word(sdr_addr_t'left downto sdr_addr_t'right); + sdr_ba <= mode_word(mode_word_t'left downto mode_word_t'left-1); + + case st_sdr is + when PWR_DOWN => + sdr_cmd_ctrl <= COMMAND(SD_DESELECT); + if enable = '1' then + st_sdr_next <= IDLE; + end if; + + when PRECHARGE => + if cycle_finished = '1' then + st_sdr_next <= IDLE; + end if; + + when MODE => + if cycle_finished = '1' then + st_sdr_next <= IDLE; + end if; + + when IDLE => + if cmd_we = '1' then + cmd_ack <= '1'; + cc_load_en <= '1'; + cc_preset <= TIMING(cmd); + sdr_cmd_ctrl <= COMMAND(cmd); + case cmd is + when SD_PRE => + st_sdr_next <= PRECHARGE; + sdr_addr(BIT_PRE_ALL) <= mode_word(BIT_PRE_ALL); + when SD_LMR => + st_sdr_next <= MODE; + when SD_ACT => + st_sdr_next <= ROW_ACT; + when SD_AR => + st_sdr_next <= AUTO_REF; + when others => null; + end case; + end if; + + when ROW_ACT => + if cycle_finished = '1' then + if cmd_we = '1' then + cmd_ack <= '1'; + burst_load_en <= '1'; + cc_load_en <= '1'; + cc_preset <= TIMING(cmd); + sdr_cmd_ctrl <= COMMAND(cmd); + case cmd is + when SD_PRE => + st_sdr_next <= PRECHARGE; + when SD_READ => + phy_ctrl.utag_we <= '1'; + st_sdr_next <= READ; + sdr_addr(col_addr_t'range) <= col_addr; + when SD_WRITE => + phy_ctrl.utag_we <= '1'; + phy_ctrl.drive_en <= '1'; + st_sdr_next <= WRITE; + sdr_addr(col_addr_t'range) <= col_addr; + when others => null; + end case; + end if; + end if; + + when WRITE => + phy_ctrl.drive_en <= '1'; + phy_ctrl.we <= '1'; + if burst_finished = '1' then + if cmd_we = '1' and cmd = SD_WRITE then + sdr_addr(col_addr_t'range) <= col_addr; + cmd_ack <= '1'; + burst_load_en <= '1'; + sdr_cmd_ctrl <= COMMAND(cmd); + phy_ctrl.utag_we <= '1'; + else + phy_ctrl.drive_en <= '0'; + cc_load_en <= '1'; + cc_preset <= TIMING(SD_WRITE)+1; + st_sdr_next <= ROW_ACT; + end if; + end if; + + when READ => + phy_ctrl.re <= '1'; + if burst_finished = '1' then + if cmd_we = '1' and cmd = SD_READ then + sdr_addr(col_addr_t'range) <= col_addr; + cmd_ack <= '1'; + burst_load_en <= '1'; + sdr_cmd_ctrl <= COMMAND(cmd); + phy_ctrl.utag_we <= '1'; + else + cc_load_en <= '1'; + cc_preset <= TIMING(SD_READ); + st_sdr_next <= ROW_ACT; + end if; + end if; + + when WRITE_A => -- not implemented yet + cmd_ack <= '1'; + st_sdr_next <= IDLE; + + when READ_A => -- not implemented yet + cmd_ack <= '1'; + st_sdr_next <= IDLE; + + when BURST_STOP => -- not implemented yet + cmd_ack <= '1'; + st_sdr_next <= IDLE; + + when SELF_REF => -- not implemented yet + cmd_ack <= '1'; + st_sdr_next <= IDLE; + + when PRE_PWR_DOWN => -- not implemented yet + cmd_ack <= '1'; + st_sdr_next <= IDLE; + + when ACT_PWR_DOWN => -- not implemented yet + cmd_ack <= '1'; + st_sdr_next <= IDLE; + + when AUTO_REF => + if cycle_finished = '1' then + st_sdr_next <= IDLE; + end if; + + when others => + st_sdr_next <= IDLE; + end case; + + end process; + +fsm_sdr_state_next: + process (rst, clk) + begin + if rst = '1' then + st_sdr <= PWR_DOWN; + elsif rising_edge(clk) then + st_sdr <= st_sdr_next; + end if; + end process; + +------------------------------------------------------------------------------------------ +cycle_counter: + process (rst, clk) + variable cycle_cnt : natural range 0 to 10; + begin + if rst = '1' then + cycle_cnt := 0; + cycle_finished <= '0'; + elsif rising_edge(clk) then + cycle_finished <= '0'; + if cc_load_en = '1' then + cycle_cnt := cc_preset; + elsif cycle_cnt /= 0 then + cycle_cnt := cycle_cnt - 1; + else + cycle_finished <= '1'; + end if; + end if; + end process; + +------------------------------------------------------------------------------------------ +burst_counter: + process (rst, clk) + variable burst_cnt : natural range 0 to 3; + begin + if rst = '1' then + burst_cnt := 0; + elsif rising_edge(clk) then + burst_finished <= '0'; + if burst_load_en = '1' then + burst_cnt := burst_preset; + elsif burst_cnt /= 0 then + burst_cnt := burst_cnt - 1; + end if; + if burst_cnt = 0 then + burst_finished <= '1'; + end if; + end if; + end process; + +------------------------------------------------------------------------------------------ +end behaviour; diff --git a/lib/SDRAM/ddr_sdr_v1_5/src/sdram_config.vhd b/lib/SDRAM/ddr_sdr_v1_5/src/sdram_config.vhd new file mode 100644 index 0000000..b62e085 --- /dev/null +++ b/lib/SDRAM/ddr_sdr_v1_5/src/sdram_config.vhd @@ -0,0 +1,74 @@ +------------------------------------------------------------------------- +-- Project: SDRAM controller +-- This file: User SDRAM component adjustments +-- +-- Copyright (C) 2007 J. Ahrensfeld +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +-- For questions and ideas, please contact the author at jens@jayfield.org +-- +-------------------------------------------------------------------------- + +library IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; + +package sdram_config is + + constant DDR_DATA_WIDTH : positive := 16; -- External DDR-SDRAM Module data bus width + constant DDR_ADDR_WIDTH : positive := 13; -- number of address lines to DDR-SDRAM Device/Module + constant DDR_BANK_WIDTH : positive := 2; -- Number of BANK address lines of external DDR-SDRAM + constant DDR_ROW_ADDR_WIDTH : positive := 13; -- + constant DDR_COL_ADDR_WIDTH : positive := 9; -- + + constant LMR_REG_BASE : natural := 0; + constant LMR_REG_EXTENDED : natural := 1; + constant LMR_OP_NORMAL : natural := 0; + constant LMR_OP_RES_DLL : natural := 2; + constant LMR_BT_SEQ : natural := 0; + constant LMR_BT_ILVD : natural := 1; + constant LMR_BL2 : natural := 1; + constant LMR_BL4 : natural := 2; + constant LMR_BL8 : natural := 3; + constant LMR_CL2 : natural := 2; + constant LMR_CL3 : natural := 3; + constant LMR_CL2_5 : natural := 6; + + -- DDR SDRAM Hardware defined constants + constant BIT_AUTO_PRE : positive := 10; -- bit-position in column address for auto precharge (see Data Sheet) + constant BIT_PRE_ALL : positive := 10; -- bit-position in column address for precharge all (see Data Sheet) + constant ENABLE_PRE_ALL : std_logic := '1'; + constant ENABLE_AUTO_PRE : std_logic := '0'; + + -- DDR-SDR TIMING constants ------------------------------------------------------------------ + -- After REFRESH_CLOCKS a refresh cycle is necessary, 64ms / 8192 = max every 7.8125 us refesh + constant REFRESH_INTERVAL : real := 7.8125; -- us + + -- These values are for your SDRAM part (see datasheet) + constant TCAS : positive := 2; -- CAS latency [clocks] + constant TRP : positive := 2; -- precharge command period + constant TRAS : positive := 4; -- active to precharge delay + constant TRFC : positive := 8; -- auto refresh command period + constant TMRD : positive := 2; -- load mode register command cylce time + constant TRCD : positive := 2; -- active to read or write delay ! + constant TWR : positive := 2; -- write recovery time + + constant PWR_UP_WAIT : natural := 1; -- µs + + subtype user_tag_t is unsigned(3 downto 0); + + ---------------------------------------------------------------------------------------------- + +end sdram_config; diff --git a/lib/SDRAM/ddr_sdr_v1_5/src/sdram_ctrl.vhd b/lib/SDRAM/ddr_sdr_v1_5/src/sdram_ctrl.vhd new file mode 100644 index 0000000..dbb5b80 --- /dev/null +++ b/lib/SDRAM/ddr_sdr_v1_5/src/sdram_ctrl.vhd @@ -0,0 +1,487 @@ +------------------------------------------------------------------------- +-- Project: SDRAM controller +-- This file: SDRAM main controller and user I/F +-- +-- Copyright (C) 2007 J. Ahrensfeld +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +-- For questions and ideas, please contact the author at jens@jayfield.org +-- +-------------------------------------------------------------------------- + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.numeric_std.ALL; + +use work.sdram_config.all; +use work.sdram_types.all; +use work.utils_pkg.all; + +entity sdram_ctrl is + Generic + ( + f_sysclk : natural := 100E6; + BL : natural := 2 + ); + Port ( + rst : in STD_LOGIC; + clk : in STD_LOGIC; + u_busy : out STD_LOGIC; + u_tag_in : in user_tag_t; + u_tag_out : out user_tag_t; + u_addr : in user_addr_t; + u_cmd : in user_cmd_t; + u_cmd_we : in STD_LOGIC; + col_addr : out col_addr_t; + sdr_cmd_busy : in STD_LOGIC; + sdr_cmd : out sdr_cmd_t; + sdr_cmd_we : out STD_LOGIC; + sdr_mode : out mode_word_t; + sdr_cke : out STD_LOGIC + ); +end sdram_ctrl; + +architecture behaviour of sdram_ctrl is + + constant LMR_BURST_LEN : natural := NextExpBaseTwo(BL); + + type ctrl_state_t is (RESET, POWER_WAIT, INIT, INIT_WAIT, USER_READY, USER_WRITE_PRE, USER_WRITE_ACT, USER_WRITE, USER_READ_PRE, USER_READ_ACT, USER_READ, REFRESH); + signal st_ctrl, st_ctrl_next : ctrl_state_t; + + constant PWR_UP_CLOCK_INTERVAL : natural := PWR_UP_WAIT*(f_sysclk/1E6); + signal pwr_up_cnt : natural range 0 to PWR_UP_CLOCK_INTERVAL-1; + signal pwr_up_cnt_rst : std_logic; + signal pwr_up_finished : std_logic; + + signal cycle_cnt : natural range 0 to 255; + signal cc_preset : natural range 0 to 255; + signal cc_load_en : std_logic; + signal cycle_finished : std_logic; + + signal seq_cnt : natural range 0 to 31; + signal seq_rst_en : std_logic; + signal seq_cnt_en : std_logic; + + constant REFRESH_CLOCK_INTERVAL : natural := natural(REFRESH_INTERVAL*real(f_sysclk)/1.0E6); + signal refresh_cnt : natural range 0 to REFRESH_CLOCK_INTERVAL-1; + signal refresh_request : std_logic; + signal refresh_cnt_rst : std_logic; + + signal addr_reg_load_en : std_logic; + + signal u_tag_reg : user_tag_t; + signal bank_addr_reg : bank_addr_t; + signal row_addr_reg : row_addr_t; + signal col_addr_reg : col_addr_t; + + signal u_bank_addr : bank_addr_t; + signal u_row_addr : row_addr_t; + signal u_col_addr : col_addr_t; + + signal act_request : std_logic; + signal act_request_set : std_logic; + signal act_request_clr : std_logic; + + type init_seq_rom_t is array (0 to 14) of init_seq_t; + + constant init_seq_rom : init_seq_rom_t := + ( + ( + cmd => SD_NOP, + mode_word => (others => '0'), + wait_cycle => 0 + ), + ( + cmd => SD_PRE, + mode_word => "000010000000000", + wait_cycle => 0 + ), + ( + cmd => SD_NOP, + mode_word => (others => '0'), + wait_cycle => 0 + ), + ( + cmd => SD_LMR, + mode_word => to_unsigned(LMR_REG_EXTENDED, 2) & "0000000000010", + wait_cycle => 0 + ), + ( + cmd => SD_NOP, + mode_word => (others => '0'), + wait_cycle => 0 + ), + ( + cmd => SD_LMR, + mode_word => to_unsigned(LMR_REG_BASE, 2) & to_unsigned(LMR_OP_RES_DLL, 6) & to_unsigned(LMR_CL2, 3) & '0' & to_unsigned(LMR_BURST_LEN, 3), + wait_cycle => 200 + ), + ( + cmd => SD_NOP, + mode_word => (others => '0'), + wait_cycle => 0 + ), + ( + cmd => SD_PRE, + mode_word => "000010000000000", + wait_cycle => 0 + ), + ( + cmd => SD_NOP, + mode_word => (others => '0'), + wait_cycle => 0 + ), + ( + cmd => SD_AR, + mode_word => (others => '0'), + wait_cycle => 0 + ), + ( + cmd => SD_NOP, + mode_word => (others => '0'), + wait_cycle => 0 + ), + ( + cmd => SD_AR, + mode_word => (others => '0'), + wait_cycle => 0 + ), + ( + cmd => SD_NOP, + mode_word => (others => '0'), + wait_cycle => 0 + ), + ( + cmd => SD_LMR, + mode_word => to_unsigned(LMR_REG_BASE, 2) & to_unsigned(LMR_OP_NORMAL, 6) & to_unsigned(LMR_CL2, 3) & '0' & to_unsigned(LMR_BURST_LEN, 3), + wait_cycle => 200 + ), + ( + cmd => SD_NOP, + mode_word => (others => '0'), + wait_cycle => 0 + ) + + ); + +begin + + u_row_addr <= u_addr(user_addr_t'left downto user_addr_t'left-row_addr_t'length+1); + u_bank_addr <= u_addr(user_addr_t'left-row_addr_t'length downto user_addr_t'left-row_addr_t'length-bank_addr_t'length+1); + u_col_addr <= u_addr(user_addr_t'left-row_addr_t'length-bank_addr_t'length downto 0); + +------------------------------------------------------------------------------------------ +fsm_ctrl_state: + process (st_ctrl, u_tag_in, u_tag_reg, u_cmd, u_cmd_we, sdr_cmd_busy, pwr_up_finished, seq_cnt, cycle_finished, u_bank_addr, u_row_addr, bank_addr_reg, row_addr_reg, u_col_addr, col_addr_reg, refresh_request, act_request) + begin + + u_busy <= '1'; + pwr_up_cnt_rst <= '0'; + cc_preset <= init_seq_rom(seq_cnt).wait_cycle; + cc_load_en <= '0'; + sdr_cmd <= init_seq_rom(seq_cnt).cmd; + sdr_cmd_we <= '0'; + sdr_mode <= bank_addr_reg & row_addr_reg; + col_addr <= col_addr_reg; + sdr_cke <= '1'; + seq_cnt_en <= '0'; + seq_rst_en <= '0'; + addr_reg_load_en <= '0'; + refresh_cnt_rst <= '0'; + act_request_set <= '0'; + act_request_clr <= '0'; + u_tag_out <= u_tag_reg; + + st_ctrl_next <= st_ctrl; + case st_ctrl is + when RESET => + sdr_cke <= '0'; + pwr_up_cnt_rst <= '1'; + st_ctrl_next <= POWER_WAIT; + + when POWER_WAIT => + sdr_cke <= '0'; + if pwr_up_finished = '1' then + seq_rst_en <= '1'; + st_ctrl_next <= INIT; + end if; + + when INIT => + sdr_mode <= init_seq_rom(seq_cnt).mode_word; + sdr_cmd <= init_seq_rom(seq_cnt).cmd; + cc_preset <= init_seq_rom(seq_cnt).wait_cycle; + if seq_cnt = init_seq_rom_t'high then + act_request_set <= '1'; + refresh_cnt_rst <= '1'; + st_ctrl_next <= USER_READY; + elsif sdr_cmd_busy = '0' then + cc_load_en <= '1'; + sdr_cmd_we <= '1'; + st_ctrl_next <= INIT_WAIT; + end if; + + when INIT_WAIT => + if sdr_cmd_busy = '0' and cycle_finished = '1' then + seq_cnt_en <= '1'; + st_ctrl_next <= INIT; + end if; + + when USER_READY => + if sdr_cmd_busy = '0' then + if refresh_request = '1' then + sdr_mode(BIT_PRE_ALL) <= '1'; + sdr_cmd_we <= '1'; + sdr_cmd <= SD_PRE; + st_ctrl_next <= REFRESH; + else + u_busy <= '0'; + if u_cmd_we = '1' then + case u_cmd is + when UCMD_NOP => + sdr_cmd <= SD_NOP; + when UCMD_LMR => + sdr_cmd <= SD_NOP; + when UCMD_WRITE => + col_addr <= u_col_addr; + u_tag_out <= u_tag_in; + sdr_mode(BIT_AUTO_PRE) <= ENABLE_AUTO_PRE; + addr_reg_load_en <= '1'; + act_request_clr <= '1'; + sdr_cmd <= SD_WRITE; + if (u_row_addr /= row_addr_reg) or act_request = '1' then + st_ctrl_next <= USER_WRITE_PRE; + elsif (u_bank_addr /= bank_addr_reg) then + if ENABLE_PRE_ALL = '1' then + st_ctrl_next <= USER_WRITE_ACT; + else + st_ctrl_next <= USER_WRITE_PRE; + end if; + elsif sdr_cmd_busy = '0' then + sdr_cmd_we <= '1'; + else + st_ctrl_next <= USER_WRITE; + end if; + when UCMD_READ => + col_addr <= u_col_addr; + u_tag_out <= u_tag_in; + sdr_mode(BIT_AUTO_PRE) <= ENABLE_AUTO_PRE; + addr_reg_load_en <= '1'; + act_request_clr <= '1'; + sdr_cmd <= SD_READ; + if (u_row_addr /= row_addr_reg) or act_request = '1' then + st_ctrl_next <= USER_READ_PRE; + elsif (u_bank_addr /= bank_addr_reg) then + if ENABLE_PRE_ALL = '1' then + st_ctrl_next <= USER_READ_ACT; + else + st_ctrl_next <= USER_READ_PRE; + end if; + elsif sdr_cmd_busy = '0' then + sdr_cmd_we <= '1'; + else + st_ctrl_next <= USER_READ; + end if; + when others => null; + end case; + end if; + end if; + end if; + + when USER_WRITE_PRE => + sdr_cmd <= SD_PRE; + sdr_mode(BIT_PRE_ALL) <= ENABLE_PRE_ALL; + if sdr_cmd_busy = '0' then + sdr_cmd_we <= '1'; + st_ctrl_next <= USER_WRITE_ACT; + end if; + + when USER_WRITE_ACT => + sdr_cmd <= SD_ACT; + if sdr_cmd_busy = '0' then + sdr_cmd_we <= '1'; + st_ctrl_next <= USER_WRITE; + end if; + + when USER_WRITE => + sdr_cmd <= SD_WRITE; + sdr_mode(BIT_AUTO_PRE) <= ENABLE_AUTO_PRE; + if sdr_cmd_busy = '0' then + sdr_cmd_we <= '1'; + st_ctrl_next <= USER_READY; + end if; + + when USER_READ_PRE => + sdr_cmd <= SD_PRE; + sdr_mode(BIT_PRE_ALL) <= ENABLE_PRE_ALL; + if sdr_cmd_busy = '0' then + sdr_cmd_we <= '1'; + st_ctrl_next <= USER_READ_ACT; + end if; + + when USER_READ_ACT => + sdr_cmd <= SD_ACT; + if sdr_cmd_busy = '0' then + sdr_cmd_we <= '1'; + st_ctrl_next <= USER_READ; + end if; + + when USER_READ => + sdr_cmd <= SD_READ; + sdr_mode(BIT_AUTO_PRE) <= ENABLE_AUTO_PRE; + if sdr_cmd_busy = '0' then + sdr_cmd_we <= '1'; + st_ctrl_next <= USER_READY; + end if; + + when REFRESH => + sdr_cmd <= SD_AR; + if sdr_cmd_busy = '0' then + sdr_cmd_we <= '1'; + st_ctrl_next <= USER_READY; + refresh_cnt_rst <= '1'; + act_request_set <= '1'; + end if; + + when others => + st_ctrl_next <= RESET; + end case; + + end process; + +fsm_ctrl_state_next: + process (rst, clk) + begin + if rst = '1' then + st_ctrl <= RESET; + elsif rising_edge(clk) then + st_ctrl <= st_ctrl_next; + end if; + end process; + +------------------------------------------------------------------------------------------ +act_request_register: + process (rst, clk) + begin + if rst = '1' then + act_request <= '1'; + elsif rising_edge(clk) then + if act_request_set = '1' then + act_request <= '1'; + elsif act_request_clr = '1' then + act_request <= '0'; + end if; + end if; + end process; + +------------------------------------------------------------------------------------------ +user_addr_register: + process (rst, clk) + begin + if rst = '1' then + bank_addr_reg <= (others => '0'); + row_addr_reg <= (others => '0'); + col_addr_reg <= (others => '0'); + u_tag_reg <= (others => '0'); + elsif rising_edge(clk) then + if addr_reg_load_en = '1' then + bank_addr_reg <= u_bank_addr; + row_addr_reg <= u_row_addr; + col_addr_reg <= u_col_addr; + u_tag_reg <= u_tag_in; + end if; + end if; + end process; + +------------------------------------------------------------------------------------------ +power_up_counter: + process (rst, clk) + begin + if rst = '1' then + pwr_up_cnt <= 0; + pwr_up_finished <= '0'; + elsif rising_edge(clk) then + pwr_up_finished <= '0'; + if pwr_up_cnt_rst = '1' then + pwr_up_cnt <= PWR_UP_CLOCK_INTERVAL-1; + else + if pwr_up_cnt /= 0 then + pwr_up_cnt <= pwr_up_cnt - 1; + else + pwr_up_finished <= '1'; + end if; + end if; + end if; + end process; + + +------------------------------------------------------------------------------------------ +refresh_counter: + process (rst, clk) + begin + if rst = '1' then + refresh_cnt <= 0; + refresh_request <= '0'; + elsif rising_edge(clk) then + refresh_request <= '0'; + if refresh_cnt_rst = '1' then + refresh_cnt <= REFRESH_CLOCK_INTERVAL-1; + else + if refresh_cnt /= 0 then + refresh_cnt <= refresh_cnt - 1; + else + refresh_request <= '1'; + end if; + end if; + end if; + end process; + +------------------------------------------------------------------------------------------ +cycle_counter: + process (rst, clk) + begin + if rst = '1' then + cycle_cnt <= 0; + cycle_finished <= '0'; + elsif rising_edge(clk) then + cycle_finished <= '0'; + if cc_load_en = '1' then + cycle_cnt <= cc_preset; + elsif cycle_cnt /= 0 then + cycle_cnt <= cycle_cnt - 1; + else + cycle_finished <= '1'; + end if; + end if; + end process; + +------------------------------------------------------------------------------------------ +seq_counter: + process (rst, clk) + begin + if rst = '1' then + seq_cnt <= 0; + elsif rising_edge(clk) then + if seq_rst_en = '1' then + seq_cnt <= 0; + elsif seq_cnt_en = '1' then + if seq_cnt /= init_seq_rom_t'high then + seq_cnt <= seq_cnt + 1; + end if; + end if; + end if; + end process; + +------------------------------------------------------------------------------------------ +end behaviour; diff --git a/lib/SDRAM/ddr_sdr_v1_5/src/sdram_ctrl_frontend_wb.vhd b/lib/SDRAM/ddr_sdr_v1_5/src/sdram_ctrl_frontend_wb.vhd new file mode 100644 index 0000000..3a9aee5 --- /dev/null +++ b/lib/SDRAM/ddr_sdr_v1_5/src/sdram_ctrl_frontend_wb.vhd @@ -0,0 +1,283 @@ +------------------------------------------------------------------------- +-- Project: JCPU, a portable 8-bit RISC CPU written in VHDL +-- This file: cpu_embedded using cpu_core and rom +-- +-- Copyright (C) 2007 J. Ahrensfeld +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +-- For questions and ideas, please contact the author at jens@jayfield.org +-- +-------------------------------------------------------------------------- + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.numeric_std.ALL; + +use work.fifo_ctrl_pkg.all; +use work.sdram_config.all; +use work.sdram_types.all; + +entity sdram_ctrl_frontend_wb is + Generic + ( + BL : natural := 2; + f_sysclk : natural := 100E6; + fifo_depth : integer := 4 + ); + Port + ( + RST_I : in STD_LOGIC; + CLK_I : in STD_LOGIC; + CLK270_I : in STD_LOGIC; + CLK270VAR_I : in STD_LOGIC; + + CYC_I : in STD_LOGIC; + STB_I : in STD_LOGIC; + SEL_I : in unsigned(3 downto 0); + WE_I : in STD_LOGIC; + ACK_O : out STD_LOGIC; + RDY_O : out STD_LOGIC; + ADDR_I : in unsigned(31 downto 0); + DAT_I : in unsigned(31 downto 0); + DAT_O : out unsigned(31 downto 0); + + -- SDRAM signals + sd_clk_p : out STD_LOGIC; + sd_clk_n : out STD_LOGIC; + sd_cke : out STD_LOGIC; + sd_cs_n : out STD_LOGIC; + sd_cas_n : out STD_LOGIC; + sd_ras_n : out STD_LOGIC; + sd_we_n : out STD_LOGIC; + sd_addr : out sdr_addr_t; + sd_ba : out sdr_ba_t; + sd_dm : out unsigned(DDR_DM_WIDTH-1 downto 0); + sd_dqs : inout unsigned(DDR_DQS_WIDTH-1 downto 0); + sd_data : inout unsigned(DDR_DATA_WIDTH-1 downto 0) + + ); +end sdram_ctrl_frontend_wb; + +architecture struct of sdram_ctrl_frontend_wb is + + -- Number of user data words for simulation + signal u_addr : user_addr_t; + signal u_tag_in : user_tag_t; + signal u_tag_rd : user_tag_t; + signal u_tag_wr : user_tag_t; + signal u_cmd : user_cmd_t; + signal u_cmd_we : std_logic; + signal u_busy : std_logic; + signal u_data_w : unsigned(SDR_DATA_WIDTH-1 downto 0); + signal u_dm_wr_in : unsigned(SDR_DM_WIDTH-1 downto 0); + signal u_dm_rd_in : unsigned(SDR_DM_WIDTH-1 downto 0); + signal u_dm_rd_out : unsigned(SDR_DM_WIDTH-1 downto 0); + signal u_data_r : unsigned(SDR_DATA_WIDTH-1 downto 0); + signal u_data_vld : std_logic; + signal u_req_wr : std_logic; + signal rdy : std_logic; + + constant CAT_FIFO_WIDTH : integer := user_cmd_t'length + user_tag_t'length + DDR_ROW_ADDR_WIDTH + DDR_BANK_WIDTH + DDR_COL_ADDR_WIDTH + SDR_DM_WIDTH; + signal cat_fifo_din : unsigned(CAT_FIFO_WIDTH-1 downto 0); + signal cat_fifo_dout : unsigned(CAT_FIFO_WIDTH-1 downto 0); + signal cat_fifo_re : std_logic; + signal cat_fifo_we : std_logic; + signal cat_fifo_full : std_logic; + signal cat_fifo_empty : std_logic; +-- signal cat_fifo_almost_full : std_logic; +-- signal cat_fifo_almost_empty : std_logic; + + signal write_fifo_din : unsigned(SDR_DATA_WIDTH+SDR_DM_WIDTH-1 downto 0); + signal write_fifo_dout : unsigned(SDR_DATA_WIDTH+SDR_DM_WIDTH-1 downto 0); + signal write_fifo_re : std_logic; + signal write_fifo_we : std_logic; + signal write_fifo_full : std_logic; + signal write_fifo_empty : std_logic; +-- signal write_fifo_almost_full : std_logic; +-- signal write_fifo_almost_empty : std_logic; + + signal read_fifo_din : unsigned(SDR_DATA_WIDTH+SDR_DM_WIDTH-1 downto 0); + signal read_fifo_dout : unsigned(SDR_DATA_WIDTH+SDR_DM_WIDTH-1 downto 0); + signal read_fifo_re : std_logic; + signal read_fifo_we : std_logic; + signal read_fifo_full : std_logic; + signal read_fifo_empty : std_logic; +-- signal read_fifo_almost_full : std_logic; +-- signal read_fifo_almost_empty : std_logic; + + alias cmd_fifo_in is cat_fifo_din(CAT_FIFO_WIDTH-1 downto CAT_FIFO_WIDTH-user_cmd_t'length); + alias tag_fifo_in is cat_fifo_din(CAT_FIFO_WIDTH-user_cmd_t'length-1 downto CAT_FIFO_WIDTH-user_cmd_t'length-user_tag_t'length); + alias addr_fifo_in is cat_fifo_din(CAT_FIFO_WIDTH-user_cmd_t'length-user_tag_t'length-1 downto SDR_DM_WIDTH); + alias dm_rd_fifo_in is cat_fifo_din(SDR_DM_WIDTH-1 downto 0); + alias cmd_fifo_out is cat_fifo_dout(CAT_FIFO_WIDTH-1 downto CAT_FIFO_WIDTH-user_cmd_t'length); + alias tag_fifo_out is cat_fifo_dout(CAT_FIFO_WIDTH-user_cmd_t'length-1 downto CAT_FIFO_WIDTH-user_cmd_t'length-user_tag_t'length); + alias addr_fifo_out is cat_fifo_dout(CAT_FIFO_WIDTH-user_cmd_t'length-user_tag_t'length-1 downto SDR_DM_WIDTH); + alias dm_rd_fifo_out is cat_fifo_dout(SDR_DM_WIDTH-1 downto 0); + + alias write_fifo_dm_in is write_fifo_din(write_fifo_din'length-1 downto write_fifo_din'length-SDR_DM_WIDTH); + alias write_fifo_data_in is write_fifo_din(write_fifo_din'length-SDR_DM_WIDTH-1 downto 0); + alias write_fifo_dm_out is write_fifo_dout(write_fifo_dout'length-1 downto write_fifo_dout'length-SDR_DM_WIDTH); + alias write_fifo_data_out is write_fifo_dout(write_fifo_dout'length-SDR_DM_WIDTH-1 downto 0); + + alias read_fifo_dm_in is read_fifo_din(read_fifo_din'length-1 downto read_fifo_din'length-SDR_DM_WIDTH); + alias read_fifo_data_in is read_fifo_din(read_fifo_din'length-SDR_DM_WIDTH-1 downto 0); + alias read_fifo_dm_out is read_fifo_dout(read_fifo_dout'length-1 downto read_fifo_dout'length-SDR_DM_WIDTH); + alias read_fifo_data_out is read_fifo_dout(read_fifo_dout'length-SDR_DM_WIDTH-1 downto 0); + +begin + + -- Instantiate synchronous FIFO + inst_cat_fifo: entity work.fifo_sync + GENERIC MAP + ( + addr_width => fifo_depth, + data_width => CAT_FIFO_WIDTH + ) + PORT MAP + ( + rst => RST_I, + clk => CLK_I, + we => cat_fifo_we, + re => cat_fifo_re, + fifo_full => cat_fifo_full, + fifo_empty => cat_fifo_empty, + fifo_afull => open, + fifo_aempty => open, + data_w => cat_fifo_din, + data_r => cat_fifo_dout + ); + + -- Instantiate synchronous FIFO + inst_write_fifo: entity work.fifo_sync + GENERIC MAP + ( + addr_width => fifo_depth, + data_width => 2*DDR_DATA_WIDTH + SDR_DM_WIDTH + ) + PORT MAP + ( + rst => RST_I, + clk => CLK_I, + we => write_fifo_we, + re => write_fifo_re, + fifo_full => write_fifo_full, + fifo_empty => write_fifo_empty, + fifo_afull => open, + fifo_aempty => open, + data_w => write_fifo_din, + data_r => write_fifo_dout + ); + + -- Instantiate synchronous FIFO + inst_read_fifo: entity work.fifo_sync + GENERIC MAP + ( + addr_width => fifo_depth, + data_width => 2*DDR_DATA_WIDTH + SDR_DM_WIDTH + ) + PORT MAP + ( + rst => RST_I, + clk => CLK_I, + we => read_fifo_we, + re => read_fifo_re, + fifo_full => read_fifo_full, + fifo_empty => read_fifo_empty, + fifo_afull => open, + fifo_aempty => open, + data_w => read_fifo_din, + data_r => read_fifo_dout + ); + + -- DDR SDRAM Controller Core + inst_sdram_ctrl : entity work.sdram_ctrl_top + Generic map + ( + BL => BL, + f_sysclk => f_sysclk + ) + Port map + ( + + sys_rst_in => RST_I, + sys_clk0_in => CLK_I, + + sys_clk270_in => CLK270_I, + capture_clk270_in => CLK270VAR_I, + + -- User interface + u_data_vld => u_data_vld, + u_data_req_w => u_req_wr, + u_data_req_r => open, + u_tag_in => u_tag_in, + u_tag_rd => u_tag_rd, + u_tag_wr => u_tag_wr, + u_busy => u_busy, + u_addr => u_addr, + u_cmd => u_cmd, + u_cmd_we => u_cmd_we, + u_data_wr => u_data_w, + u_data_rd => u_data_r, + u_dm_wr_in => u_dm_wr_in, + u_dm_rd_in => u_dm_rd_in, + u_dm_rd_out => u_dm_rd_out, + + -- SDRAM signals + sd_clk_p => sd_clk_p, + sd_clk_n => sd_clk_n, + sd_cke => sd_cke, + sd_cs_n => sd_cs_n, + sd_cas_n => sd_cas_n, + sd_ras_n => sd_ras_n, + sd_we_n => sd_we_n, + sd_addr => sd_addr, + sd_ba => sd_ba, + sd_dm => sd_dm, + sd_dqs => sd_dqs, + sd_data => sd_data + + ); + +------------------------------------------------------------------------------------------ + RDY_O <= rdy and CYC_I; + rdy <= not (cat_fifo_full or write_fifo_full or read_fifo_full); + write_fifo_we <= STB_I and CYC_I and WE_I and rdy; + write_fifo_data_in <= DAT_I; + write_fifo_dm_in <= not SEL_I; + cat_fifo_we <= STB_I and CYC_I and rdy; + cmd_fifo_in <= UCMD_WRITE when WE_I = '1' else UCMD_READ; + addr_fifo_in <= ADDR_I(user_addr_t'range); + dm_rd_fifo_in <= not SEL_I; + tag_fifo_in <= (others=>'0'); + DAT_O <= read_fifo_data_out; + ACK_O <= write_fifo_we or (CYC_I and not (WE_I or read_fifo_empty)); + + u_cmd_we <= (not cat_fifo_empty) and (not u_busy); + u_cmd <= cmd_fifo_out; + u_addr <= addr_fifo_out; + u_dm_rd_in <= dm_rd_fifo_out; + u_dm_wr_in <= write_fifo_dm_out; + u_tag_in <= tag_fifo_out; + + write_fifo_re <= u_req_wr and (not write_fifo_empty); + cat_fifo_re <= u_cmd_we; + u_data_w <= write_fifo_data_out; + read_fifo_re <= (not read_fifo_empty); -- and dout_re; + read_fifo_we <= u_data_vld; + read_fifo_data_in <= u_data_r; + read_fifo_dm_in <= u_dm_rd_out; + + +end architecture struct; diff --git a/lib/SDRAM/ddr_sdr_v1_5/src/sdram_ctrl_top.vhd b/lib/SDRAM/ddr_sdr_v1_5/src/sdram_ctrl_top.vhd new file mode 100644 index 0000000..f742f83 --- /dev/null +++ b/lib/SDRAM/ddr_sdr_v1_5/src/sdram_ctrl_top.vhd @@ -0,0 +1,248 @@ +------------------------------------------------------------------------- +-- Project: SDRAM controller +-- This file: Top-level put all together +-- +-- Copyright (C) 2007 J. Ahrensfeld +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +-- For questions and ideas, please contact the author at jens@jayfield.org +-- +-------------------------------------------------------------------------- + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.numeric_std.ALL; + +use work.sdram_config.all; +use work.sdram_types.all; + +entity sdram_ctrl_top is + Generic + ( + BL : natural := 2; + f_sysclk : natural := 100E6 + ); + Port + ( + sys_rst_in : in STD_LOGIC; + sys_clk0_in : in STD_LOGIC; + sys_clk270_in : in STD_LOGIC; + capture_clk270_in : in STD_LOGIC; + + -- User interface + u_data_vld : out STD_LOGIC; + u_data_req_w : out STD_LOGIC; + u_data_req_r : out STD_LOGIC; + u_busy : out STD_LOGIC; + u_tag_in : in user_tag_t; + u_tag_rd : out user_tag_t; + u_tag_wr : out user_tag_t; + u_addr : in user_addr_t; + u_cmd : in user_cmd_t; + u_cmd_we : in STD_LOGIC; + u_data_wr : in unsigned(SDR_DATA_WIDTH-1 downto 0); + u_dm_wr_in : in unsigned(SDR_DM_WIDTH-1 downto 0); + u_dm_rd_in : in unsigned(SDR_DM_WIDTH-1 downto 0); + u_dm_rd_out : out unsigned(SDR_DM_WIDTH-1 downto 0); + u_data_rd : out unsigned(SDR_DATA_WIDTH-1 downto 0); + + -- SDRAM signals + sd_clk_p : out STD_LOGIC; + sd_clk_n : out STD_LOGIC; + sd_cke : out STD_LOGIC; + sd_cs_n : out STD_LOGIC; + sd_cas_n : out STD_LOGIC; + sd_ras_n : out STD_LOGIC; + sd_we_n : out STD_LOGIC; + sd_addr : out sdr_addr_t; + sd_ba : out sdr_ba_t; + sd_dm : out unsigned(DDR_DM_WIDTH-1 downto 0); + sd_dqs : inout unsigned(DDR_DQS_WIDTH-1 downto 0); + sd_data : inout unsigned(DDR_DATA_WIDTH-1 downto 0) + + ); +end sdram_ctrl_top; + +architecture rtl of sdram_ctrl_top is + + + signal phy_ctrl : phy_ctrl_t; + + signal u_tag : user_tag_t; + signal sd_cmd_in : sdr_cmd_t; + signal sd_cmd : sdr_cmd_t; + signal sd_cmd_we : std_logic; + signal cmd_ctrl : sdr_cmd_lines_t; + signal cke : std_logic; + signal ba : unsigned(DDR_BANK_WIDTH-1 downto 0); + signal addr : unsigned(DDR_ADDR_WIDTH-1 downto 0); + + -- Clock generator + + signal ctrl_rst : std_logic; + signal part_ctrl : part_ctrl_t; + + -- SD command FIFO + + constant CMD_FIFO_ADDR_WIDTH : positive := 2; + constant CMD_FIFO_DATA_WIDTH : positive := user_tag_t'length + 4 + mode_word_t'length + col_addr_t'length; + signal cmd_fifo_din : unsigned(CMD_FIFO_DATA_WIDTH-1 downto 0); + signal cmd_fifo_dout : unsigned(CMD_FIFO_DATA_WIDTH-1 downto 0); + signal cmd_fifo_re : std_logic; + signal cmd_fifo_we : std_logic; + signal cmd_fifo_full : std_logic; + signal cmd_fifo_empty : std_logic; + + alias tag_fifo_in is cmd_fifo_din(CMD_FIFO_DATA_WIDTH-1 downto CMD_FIFO_DATA_WIDTH-user_tag_t'length); + alias cmd_fifo_in is cmd_fifo_din(CMD_FIFO_DATA_WIDTH-user_tag_t'length-1 downto CMD_FIFO_DATA_WIDTH-user_tag_t'length-4); + alias mode_fifo_in is cmd_fifo_din(CMD_FIFO_DATA_WIDTH-user_tag_t'length-4-1 downto CMD_FIFO_DATA_WIDTH-user_tag_t'length-4-mode_word_t'length); + alias col_fifo_in is cmd_fifo_din(CMD_FIFO_DATA_WIDTH-user_tag_t'length-4-mode_word_t'length-1 downto 0); + + alias tag_fifo_out is cmd_fifo_dout(CMD_FIFO_DATA_WIDTH-1 downto CMD_FIFO_DATA_WIDTH-user_tag_t'length); + alias cmd_fifo_out is cmd_fifo_dout(CMD_FIFO_DATA_WIDTH-user_tag_t'length-1 downto CMD_FIFO_DATA_WIDTH-user_tag_t'length-4); + alias mode_fifo_out is cmd_fifo_dout(CMD_FIFO_DATA_WIDTH-user_tag_t'length-4-1 downto CMD_FIFO_DATA_WIDTH-user_tag_t'length-4-mode_word_t'length); + alias col_fifo_out is cmd_fifo_dout(CMD_FIFO_DATA_WIDTH-user_tag_t'length-4-mode_word_t'length-1 downto 0); + +begin + + --------------------------------- + part_ctrl.cmd <= cmd_ctrl; + part_ctrl.ba <= ba; + part_ctrl.addr <= addr; + part_ctrl.cke <= cke; + + --------------------------------- + sd_cmd_we <= not cmd_fifo_empty; + cmd_fifo_in <= to_unsigned(sd_cmd_in, 4); + sd_cmd <= sdr_cmd_t(to_integer(cmd_fifo_out)); + + --------------------------------- + inst_reset: entity work.reset + port map + ( + clk => sys_clk0_in, + rst_in => sys_rst_in, + rst_out => ctrl_rst + ); + + -- Main controller + inst_sdram_ctrl : entity work.sdram_ctrl + Generic map + ( + f_sysclk => 100E6, + BL => BL + ) + Port map + ( + rst => ctrl_rst, + clk => sys_clk0_in, + u_busy => u_busy, + u_tag_in => u_tag_in, + u_tag_out => tag_fifo_in, + u_cmd => u_cmd, + u_cmd_we => u_cmd_we, + u_addr => u_addr, + sdr_cmd_busy => cmd_fifo_full, + sdr_cmd => sd_cmd_in, + sdr_cmd_we => cmd_fifo_we, + col_addr => col_fifo_in, + sdr_mode => mode_fifo_in, + sdr_cke => cke + ); + + -- Instantiate synchronous FIFO + inst_sd_cmd_fifo: entity work.fifo_sync + GENERIC MAP + ( + addr_width => CMD_FIFO_ADDR_WIDTH, + data_width => CMD_FIFO_DATA_WIDTH, + almost_full_thresh => 2**(CMD_FIFO_ADDR_WIDTH-1), + almost_empty_thresh => 2**(CMD_FIFO_ADDR_WIDTH-1) + ) + PORT MAP + ( + rst => ctrl_rst, + clk => sys_clk0_in, + we => cmd_fifo_we, + re => cmd_fifo_re, + fifo_full => cmd_fifo_full, + fifo_empty => cmd_fifo_empty, + fifo_afull => open, + fifo_aempty => open, + data_w => cmd_fifo_din, + data_r => cmd_fifo_dout + ); + + -- DDR SDRAM command fsm + inst_sdram_cmd : entity work.sdram_cmd + Generic map + ( + BL => BL + ) + Port map + ( + rst => ctrl_rst, + clk => sys_clk0_in, + u_tag_in => tag_fifo_out, + u_tag_out => u_tag, + phy_ctrl => phy_ctrl, + enable => cke, + cmd => sd_cmd, + cmd_we => sd_cmd_we, + cmd_ack => cmd_fifo_re, + sdr_cmd_ctrl => cmd_ctrl, + col_addr => col_fifo_out, + mode_word => mode_fifo_out, + sdr_ba => ba, + sdr_addr => addr + ); + + -- DDR phy + inst_ddr_phy : entity work.ddr_phy + Port map + ( + sys_rst => ctrl_rst, + sys_clk0 => sys_clk0_in, + sys_clk270 => sys_clk270_in, + u_tag_in => u_tag, + u_tag_rd => u_tag_rd, + u_tag_wr => u_tag_wr, + read_clk => capture_clk270_in, + phy_ctrl => phy_ctrl, + part_ctrl => part_ctrl, + sdr_data_req_w => u_data_req_w, + sdr_data_req_r => u_data_req_r, + sdr_data_w => u_data_wr, + sdr_dm_wr_in => u_dm_wr_in, + sdr_dm_rd_in => u_dm_rd_in, + sdr_dm_rd_out => u_dm_rd_out, + sdr_data_r => u_data_rd, + sdr_data_vld => u_data_vld, + part_clk_p => sd_clk_p, + part_clk_n => sd_clk_n, + part_addr => sd_addr, + part_ba => sd_ba, + part_dm => sd_dm, + part_dqs => sd_dqs, + part_data => sd_data, + part_cs_n => sd_cs_n, + part_we_n => sd_we_n, + part_cas_n => sd_cas_n, + part_ras_n => sd_ras_n, + part_cke => sd_cke + ); + +end architecture rtl; + diff --git a/lib/SDRAM/ddr_sdr_v1_5/src/sdram_types.vhd b/lib/SDRAM/ddr_sdr_v1_5/src/sdram_types.vhd new file mode 100644 index 0000000..d235d75 --- /dev/null +++ b/lib/SDRAM/ddr_sdr_v1_5/src/sdram_types.vhd @@ -0,0 +1,133 @@ +------------------------------------------------------------------------- +-- Project: SDRAM controller +-- This file: Type definitions +-- +-- Copyright (C) 2007 J. Ahrensfeld +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +-- For questions and ideas, please contact the author at jens@jayfield.org +-- +-------------------------------------------------------------------------- + +library IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; + +use work.sdram_config.all; + +package sdram_types is + + ----------------------------------------------------------------------------------------- + -- Table of Timing Parameters as a function of operation + + -- Derived constants from sdram_config + + constant DDR_DQS_WIDTH : positive := DDR_DATA_WIDTH / 8; -- Number of data strobe lines + constant DDR_DM_WIDTH : positive := DDR_DATA_WIDTH / 8; -- Number of Data Mask Lines + constant SDR_DATA_WIDTH : positive := 2*DDR_DATA_WIDTH; -- + constant SDR_DM_WIDTH : positive := 2*DDR_DM_WIDTH; -- + + subtype user_cmd_t is unsigned(1 downto 0); + constant UCMD_NOP : user_cmd_t := "00"; + constant UCMD_READ : user_cmd_t := "01"; + constant UCMD_WRITE : user_cmd_t := "10"; + constant UCMD_LMR : user_cmd_t := "11"; + + subtype sdr_cmd_t is natural range 0 to 9; + constant SD_DESELECT : sdr_cmd_t := 0; + constant SD_NOP : sdr_cmd_t := 1; + constant SD_LMR : sdr_cmd_t := 2; + constant SD_ACT : sdr_cmd_t := 3; + constant SD_READ : sdr_cmd_t := 4; + constant SD_WRITE : sdr_cmd_t := 5; + constant SD_PRE : sdr_cmd_t := 6; + constant SD_BST : sdr_cmd_t := 7; + constant SD_AR : sdr_cmd_t := 8; + constant SD_SR : sdr_cmd_t := 9; + + type sdr_state_t is (PWR_DOWN, PRECHARGE, MODE, IDLE, ROW_ACT, WRITE, WRITE_A, READ, READ_A, BURST_STOP, SELF_REF, AUTO_REF, PRE_PWR_DOWN, ACT_PWR_DOWN); + subtype user_addr_t is unsigned(DDR_BANK_WIDTH+DDR_ROW_ADDR_WIDTH+DDR_COL_ADDR_WIDTH-1 downto 0); + subtype sdr_addr_t is unsigned(DDR_ADDR_WIDTH-1 downto 0); + subtype sdr_ba_t is unsigned(DDR_BANK_WIDTH-1 downto 0); + subtype mode_word_t is unsigned(DDR_ADDR_WIDTH+DDR_BANK_WIDTH-1 downto 0); + + subtype bank_addr_t is unsigned(DDR_BANK_WIDTH-1 downto 0); + subtype row_addr_t is unsigned(DDR_ADDR_WIDTH-1 downto 0); + subtype col_addr_t is unsigned(8 downto 0); + + subtype cycle_cnt_t is natural range 0 to 10; + + type phy_ctrl_t is + record + drive_en : std_logic; + re : std_logic; + we : std_logic; + utag_we : std_logic; + end record phy_ctrl_t; + + type sdr_cmd_lines_t is + record + cs_n : std_logic; + ras_n : std_logic; + cas_n : std_logic; + we_n : std_logic; + end record sdr_cmd_lines_t; + + type part_ctrl_t is + record + cmd : sdr_cmd_lines_t; + ba : unsigned(DDR_BANK_WIDTH-1 downto 0); + addr : unsigned(DDR_ADDR_WIDTH-1 downto 0); + cke : std_logic; + end record part_ctrl_t; + + type part_cmd_array_t is array (sdr_cmd_t) of sdr_cmd_lines_t; + constant COMMAND : part_cmd_array_t := + -- command cs_n ras_qn cas_qn we_qn + ( SD_DESELECT => ( '1', '1', '1', '1'), + SD_NOP => ( '0', '1', '1', '1'), + SD_LMR => ( '0', '0', '0', '0'), + SD_ACT => ( '0', '0', '1', '1'), + SD_READ => ( '0', '1', '0', '1'), + SD_WRITE => ( '0', '1', '0', '0'), + SD_PRE => ( '0', '0', '1', '0'), + SD_BST => ( '0', '1', '1', '0'), + SD_AR => ( '0', '0', '0', '1'), + SD_SR => ( '0', '0', '0', '1') + ); + + type part_timing_array_t is array (sdr_cmd_t) of cycle_cnt_t; + constant TIMING : part_timing_array_t := + -- command cycle_cnt + ( SD_DESELECT => ( 0 ), + SD_NOP => ( 0 ), + SD_LMR => ( TMRD-1 ), + SD_ACT => ( TRCD-1 ), + SD_READ => ( TCAS-1 ), + SD_WRITE => ( TWR-1 ), + SD_PRE => ( TRP-1 ), + SD_BST => ( 0 ), + SD_AR => ( TRFC-1 ), + SD_SR => ( TRFC-1 ) + ); + + type init_seq_t is + record + cmd : sdr_cmd_t; + mode_word : mode_word_t; + wait_cycle : natural; + end record init_seq_t; + +end sdram_types; diff --git a/lib/SDRAM/ddr_sdr_v1_5/src/tb_sdram_ctrl_frontend_wb.vhd b/lib/SDRAM/ddr_sdr_v1_5/src/tb_sdram_ctrl_frontend_wb.vhd new file mode 100644 index 0000000..b55ced0 --- /dev/null +++ b/lib/SDRAM/ddr_sdr_v1_5/src/tb_sdram_ctrl_frontend_wb.vhd @@ -0,0 +1,495 @@ +------------------------------------------------------------------------- +-- Project: JCPU, a portable 8-bit RISC CPU written in VHDL +-- This file: cpu_embedded using cpu_core and rom +-- +-- Copyright (C) 2007 J. Ahrensfeld +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +-- For questions and ideas, please contact the author at jens@jayfield.org +-- +-------------------------------------------------------------------------- + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.numeric_std.ALL; + +use work.fifo_ctrl_pkg.all; +use work.sdram_config.all; +use work.sdram_types.all; + +entity tb_sdram_ctrl_frontend_wb is +end; + +architecture struct of tb_sdram_ctrl_frontend_wb is + + -- Number of user data words for simulation + constant CLK_PERIOD : time := 10 ns; + constant BURST_LEN : natural := 2; + + signal rst : std_logic := '1'; + signal clk : std_logic := '1'; + signal locked : std_logic; + signal error : std_logic; + signal clk_out : std_logic; + signal clk_fb : std_logic; + signal part_clk_p : std_logic; + signal part_clk_n : std_logic; + signal part_cke : std_logic; + signal part_cs_n : std_logic; + signal part_we_n : std_logic; + signal part_ras_n : std_logic; + signal part_cas_n : std_logic; + signal part_ba : unsigned(DDR_BANK_WIDTH-1 downto 0) := (others => '0'); + signal part_dm : unsigned(DDR_DM_WIDTH-1 downto 0) := (others => '0'); + signal part_dqs : unsigned(DDR_DQS_WIDTH-1 downto 0) := (others => '0'); + signal part_addr : unsigned(DDR_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal part_data : unsigned(DDR_DATA_WIDTH-1 downto 0) := (others => '0'); + + signal CLK_O : std_logic; + signal CLK270_O : std_logic; + signal CLK270VAR_O : std_logic; + signal RST_O : std_logic; + signal CYC_O : std_logic := '0'; + signal STB_O : std_logic := '0'; + signal WE_O : std_logic := '0'; + signal SEL_O : unsigned(3 downto 0) := (others => '1'); + signal ACK_I : std_logic; + signal RDY_I : std_logic; + signal ADDR_O : unsigned(31 downto 0) := (others => '-'); + signal DAT_I : unsigned(31 downto 0); + signal DAT_O : unsigned(31 downto 0) := (others => '-'); + signal dout_rst : std_logic := '0'; + signal dout_reg : unsigned(31 downto 0); + signal dout_cnt : natural range 0 to 255; + +begin + +inst_clockgen : entity work.clockgen + GENERIC MAP + ( + sys1_phaseshift => 0, + frequency_hz => 100E6 + ) + PORT MAP + ( + -- Clocks and Reset + rst => rst, -- external async reset, low active + clk_in => clk, -- system clock (e.g. 100MHz), from board + clk_fb_in => clk_fb, -- feedback clock + sys1_clk0_out => open, -- System clock #1 (e.g. clock for DDR-SDRAM data capture), dcm#1 output 0° + sys1_clk270_out => CLK270VAR_O, -- System clock #1 (e.g. clock for DDR-SDRAM data capture), dcm#1 output 270° + sys0_clk0_out => CLK_O, -- System clock #0, dcm#0 output 0° + sys0_clk270_out => CLK270_O, -- System clock #0, dcm#0 output 270° + locked_out => locked, -- DCM locked status + error_out => error + ); + + + clk_fb <= part_clk_p after 1 ns; + RST_O <= not locked; + + -- DDR SDRAM Controller Core + sdram_ctrl_frontend_wb : entity work.sdram_ctrl_frontend_wb + GENERIC MAP + ( + BL => BURST_LEN, + f_sysclk => 100E6, + fifo_depth => 2 + ) + PORT MAP + ( + RST_I => RST_O, + CLK_I => CLK_O, + CLK270_I => CLK270_O, + CLK270VAR_I => CLK270VAR_O, + + CYC_I => CYC_O, + STB_I => STB_O, + SEL_I => SEL_O, + WE_I => WE_O, + ACK_O => ACK_I, + RDY_O => RDY_I, + ADDR_I => ADDR_O, + DAT_I => DAT_O, + DAT_O => DAT_I, + + -- SDRAM signals + sd_clk_p => part_clk_p, + sd_clk_n => part_clk_n, + sd_cke => part_cke, + sd_cs_n => part_cs_n, + sd_cas_n => part_cas_n, + sd_ras_n => part_ras_n, + sd_we_n => part_we_n, + sd_addr => part_addr, + sd_ba => part_ba, + sd_dm => part_dm, + sd_dqs => part_dqs, + sd_data => part_data + + ); + + + -- MICRON DDR SDRAM Simulation Model +i_mt46v16m16_0 : entity work.mt46v16m16 + port map + ( + dq => std_logic_vector(part_data), + dqs => std_logic_vector(part_dqs), + addr => std_logic_vector(part_addr), + ba => std_logic_vector(part_ba), + clk => part_clk_p, + clk_n => part_clk_n, + cke => part_cke, + cs_n => part_cs_n, + ras_n => part_ras_n, + cas_n => part_cas_n, + we_n => part_we_n, + dm => std_logic_vector(part_dm) + ); + +CLK_GEN: process + begin + wait for CLK_PERIOD/2; + clk <= not clk; + end process; + +read_register: + process(CLK_O) + begin + if rising_edge(CLK_O) then + if dout_rst = '1' then + dout_cnt <= 0; + elsif ACK_I = '1' and WE_O = '0' then + dout_reg <= DAT_I; + dout_cnt <= dout_cnt + 1; + end if; + end if; + end process; + +------------------------------------------------------------------------------------------ + +STIMULUS: process + + begin + + wait for 3*CLK_PERIOD; + rst <= '0'; + + wait until RST_O = '0'; + -- 8 single cycles + CYC_O <= '1'; + STB_O <= '1'; + WE_O <= '1'; + DAT_O <= X"1234_0000"; + ADDR_O <= X"0000_0000"; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + DAT_O <= DAT_O + 1; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + STB_O <= '0'; + CYC_O <= '0'; + + + -- 8-word burst cycle + wait for 3*CLK_PERIOD; + dout_rst <= '1'; + wait until rising_edge(CLK_O); + dout_rst <= '0'; + CYC_O <= '1'; + STB_O <= '1'; + WE_O <= '0'; + ADDR_O <= X"0000_0000"; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + STB_O <= '0'; + + wait until rising_edge(CLK_O) and dout_cnt = 7; + CYC_O <= '0'; + + wait for 3*CLK_PERIOD; + wait until rising_edge(CLK_O); + -- 1-word burst cycle + CYC_O <= '1'; + STB_O <= '1'; + WE_O <= '1'; + SEL_O <= "0011"; + ADDR_O <= X"0000_0080"; + DAT_O <= X"DEADBEEF"; + wait until rising_edge(CLK_O) and RDY_I = '1'; + STB_O <= '0'; + CYC_O <= '0'; + + wait for 3*CLK_PERIOD; + wait until rising_edge(CLK_O); + -- 1-word burst cycle + CYC_O <= '1'; + STB_O <= '1'; + WE_O <= '0'; + ADDR_O <= X"0000_0080"; + wait until rising_edge(CLK_O) and RDY_I = '1'; + STB_O <= '0'; + wait until rising_edge(CLK_O) and ACK_I = '1'; + CYC_O <= '0'; + + -- 8-word burst cycle + wait for 3*CLK_PERIOD; + dout_rst <= '1'; + wait until rising_edge(CLK_O); + dout_rst <= '0'; + CYC_O <= '1'; + STB_O <= '1'; + WE_O <= '0'; + ADDR_O <= X"0000_0000"; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + ADDR_O <= ADDR_O + 4; + wait until rising_edge(CLK_O) and RDY_I = '1'; + STB_O <= '0'; + + wait until rising_edge(CLK_O) and dout_cnt = 54; + CYC_O <= '0'; + + wait; + + end process; + +end architecture struct;