From 6aeae2e54ec4bda7cef0b1cf63151ea9f0784dc0 Mon Sep 17 00:00:00 2001 From: Pepping <pepping> Date: Thu, 23 Apr 2015 08:12:27 +0000 Subject: [PATCH] Initial commit --- libraries/io/ddr/src/vhdl/io_ddr_reg.vhd | 250 +++++++++++++++++++++++ libraries/io/ddr/src/vhdl/mms_io_ddr.vhd | 213 +++++++++++++++++++ 2 files changed, 463 insertions(+) create mode 100644 libraries/io/ddr/src/vhdl/io_ddr_reg.vhd create mode 100644 libraries/io/ddr/src/vhdl/mms_io_ddr.vhd diff --git a/libraries/io/ddr/src/vhdl/io_ddr_reg.vhd b/libraries/io/ddr/src/vhdl/io_ddr_reg.vhd new file mode 100644 index 0000000000..1c00111eaa --- /dev/null +++ b/libraries/io/ddr/src/vhdl/io_ddr_reg.vhd @@ -0,0 +1,250 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2011 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- 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 <http://www.gnu.org/licenses/>. +-- +------------------------------------------------------------------------------- + +-- RO read only (no VHDL present to access HW in write mode) +-- WO write only (no VHDL present to access HW in read mode) +-- WE write event (=WO) +-- WR write control, read control +-- RW read status, write control +-- RC read, clear on read +-- FR FIFO read +-- FW FIFO write +-- +-- wi Bits R/W Name Default Description |REG_DDR3| +-- ============================================================================= +-- 0 [0] WE burstbegin 0x0 +-- 1 [0] WO wr_not_rd 0x0 +-- 2 [0] RO done 0x1 +-- 3 [1..0] RO cal_result 0x1 cal_fail & cal_ok +-- 4 [0] RO waitrequest_n 0x1 +-- 5 [31..0] WO address 0x0 +-- 6 [31..0] WO burstsize 0x0 +-- 7 [0] WR flush 0x0 +-- ============================================================================= + +LIBRARY IEEE, common_lib, diag_lib; +USE IEEE.STD_LOGIC_1164.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE diag_lib.diag_pkg.ALL; + + +ENTITY io_ddr_reg IS + PORT ( + -- Clocks and reset + mm_rst : IN STD_LOGIC; -- reset synchronous with mm_clk + mm_clk : IN STD_LOGIC; -- memory-mapped bus clock + dp_rst : IN STD_LOGIC; -- reset synchronous with dp_clk + dp_clk : IN STD_LOGIC; -- other clock domain clock + + -- Memory Mapped Slave in mm_clk domain + sla_in : IN t_mem_mosi; -- actual ranges defined by c_mm_reg + sla_out : OUT t_mem_miso; -- actual ranges defined by c_mm_reg + + -- MM registers in st_clk domain + dvr_miso : IN t_mem_ctlr_miso; + dvr_mosi : OUT t_mem_ctlr_mosi + ); +END io_ddr_reg; + + +ARCHITECTURE rtl OF io_ddr_reg IS + + CONSTANT c_mm_reg : t_c_mem := (latency => 1, + adr_w => ceil_log2(8), + dat_w => c_word_w, -- Use MM bus data width = c_word_w = 32 for all MM registers + nof_dat => 8, + init_sl => '0'); + -- Registers in mm_clk domain + SIGNAL mm_dvr_miso : t_mem_ctlr_miso; + SIGNAL mm_dvr_mosi : t_mem_ctlr_mosi; + +BEGIN + + ------------------------------------------------------------------------------ + -- MM register access in the mm_clk domain + -- . Hardcode the shared MM slave register directly in RTL instead of using + -- the common_reg_r_w instance. Directly using RTL is easier when the large + -- MM register has multiple different fields and with different read and + -- write options per field in one MM register. + ------------------------------------------------------------------------------ + + p_mm_reg : PROCESS (mm_rst, mm_clk) + BEGIN + IF mm_rst = '1' THEN + sla_out <= c_mem_miso_rst; + mm_dvr_mosi <= c_mem_ctlr_mosi_rst; + + ELSIF rising_edge(mm_clk) THEN + -- Read access defaults + sla_out.rdval <= '0'; + mm_dvr_mosi.burstbegin <= '0'; + + -- Write access: set register value + IF sla_in.wr = '1' THEN + CASE TO_UINT(sla_in.address(c_mm_reg.adr_w-1 DOWNTO 0)) IS + -- Write Block Sync + WHEN 0 => + mm_dvr_mosi.burstbegin <= sla_in.wrdata(0); + WHEN 1 => + mm_dvr_mosi.wr <= sla_in.wrdata(0); + mm_dvr_mosi.rd <= NOT(sla_in.wrdata(0)); + WHEN 5 => + mm_dvr_mosi.address <= sla_in.wrdata(c_mem_ctlr_address_w-1 DOWNTO 0); + WHEN 6 => + mm_dvr_mosi.burstsize <= sla_in.wrdata(c_mem_ctlr_burstsize_w-1 DOWNTO 0); + WHEN 7 => + mm_dvr_mosi.flush <= sla_in.wrdata(0); + WHEN OTHERS => NULL; -- unused MM addresses + END CASE; + + -- Read access: get register value + ELSIF sla_in.rd = '1' THEN + sla_out <= c_mem_miso_rst; -- set unused rddata bits to '0' when read + sla_out.rdval <= '1'; -- c_mm_reg.latency = 1 + CASE TO_UINT(sla_in.address(c_mm_reg.adr_w-1 DOWNTO 0)) IS + -- Read Block Sync + WHEN 2 => + sla_out.rddata(0) <= mm_dvr_miso.done; + WHEN 3 => + sla_out.rddata(1 DOWNTO 0) <= mm_dvr_miso.cal_fail & mm_dvr_miso.cal_ok; + WHEN 4 => + sla_out.rddata(0) <= mm_dvr_miso.waitrequest_n; + WHEN 7 => + sla_out.rddata(0) <= mm_dvr_mosi.flush; + WHEN OTHERS => NULL; -- unused MM addresses + END CASE; + END IF; + END IF; + END PROCESS; + + ------------------------------------------------------------------------------ + -- Transfer register value between mm_clk and st_clk domain. + -- If the function of the register ensures that the value will not be used + -- immediately when it was set, then the transfer between the clock domains + -- can be done by wires only. Otherwise if the change in register value can + -- have an immediate effect then the bit or word value needs to be transfered + -- using: + -- + -- . common_async --> for single-bit level signal + -- . common_spulse --> for single-bit pulse signal + -- . common_reg_cross_domain --> for a multi-bit (a word) signal + -- + -- Typically always use a crossing component for the single bit signals (to + -- be on the safe side) and only use a crossing component for the word + -- signals if it is necessary (to avoid using more logic than necessary). + ------------------------------------------------------------------------------ + + u_spulse_en_evt : ENTITY common_lib.common_spulse + PORT MAP ( + in_rst => mm_rst, + in_clk => mm_clk, + in_pulse => mm_dvr_mosi.burstbegin, + in_busy => OPEN, + out_rst => dp_rst, + out_clk => dp_clk, + out_pulse => dvr_mosi.burstbegin + ); + + u_async_wr : ENTITY common_lib.common_async + GENERIC MAP ( + g_rst_level => '0' + ) + PORT MAP ( + rst => dp_rst, + clk => dp_clk, + din => mm_dvr_mosi.wr, + dout => dvr_mosi.wr + ); + + u_async_rd : ENTITY common_lib.common_async + GENERIC MAP ( + g_rst_level => '0' + ) + PORT MAP ( + rst => dp_rst, + clk => dp_clk, + din => mm_dvr_mosi.rd, + dout => dvr_mosi.rd + ); + + u_async_flush : ENTITY common_lib.common_async + GENERIC MAP ( + g_rst_level => '0' + ) + PORT MAP ( + rst => dp_rst, + clk => dp_clk, + din => mm_dvr_mosi.flush, + dout => dvr_mosi.flush + ); + + u_async_done : ENTITY common_lib.common_async + GENERIC MAP ( + g_rst_level => '0' + ) + PORT MAP ( + rst => mm_rst, + clk => mm_clk, + din => dvr_miso.done, + dout => mm_dvr_miso.done + ); + + u_async_waitrequest_n : ENTITY common_lib.common_async + GENERIC MAP ( + g_rst_level => '0' + ) + PORT MAP ( + rst => mm_rst, + clk => mm_clk, + din => dvr_miso.waitrequest_n, + dout => mm_dvr_miso.waitrequest_n + ); + + mm_dvr_miso.cal_fail <= dvr_miso.cal_fail; + mm_dvr_miso.cal_ok <= dvr_miso.cal_ok; + + u_cross_domain_addr : ENTITY common_lib.common_reg_cross_domain + PORT MAP ( + in_rst => mm_rst, + in_clk => mm_clk, + in_dat => mm_dvr_mosi.address, + in_done => OPEN, + out_rst => dp_rst, + out_clk => dp_clk, + out_dat => dvr_mosi.address, + out_new => OPEN + ); + + u_cross_domain_burstsize : ENTITY common_lib.common_reg_cross_domain + PORT MAP ( + in_rst => mm_rst, + in_clk => mm_clk, + in_dat => mm_dvr_mosi.burstsize, + in_done => OPEN, + out_rst => dp_rst, + out_clk => dp_clk, + out_dat => dvr_mosi.burstsize, + out_new => OPEN + ); + +END rtl; + diff --git a/libraries/io/ddr/src/vhdl/mms_io_ddr.vhd b/libraries/io/ddr/src/vhdl/mms_io_ddr.vhd new file mode 100644 index 0000000000..3a03de15ff --- /dev/null +++ b/libraries/io/ddr/src/vhdl/mms_io_ddr.vhd @@ -0,0 +1,213 @@ + +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2012 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- 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 <http://www.gnu.org/licenses/>. +-- +------------------------------------------------------------------------------- + +LIBRARY IEEE, technology_lib, tech_ddr_lib, common_lib, dp_lib; +USE IEEE.STD_LOGIC_1164.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE technology_lib.technology_select_pkg.ALL; +USE technology_lib.technology_pkg.ALL; +USE tech_ddr_lib.tech_ddr_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; + +ENTITY mms_io_ddr IS + GENERIC( + g_technology : NATURAL := c_tech_select_default; + g_tech_ddr : t_c_tech_ddr; + g_cross_domain_dvr_ctlr : BOOLEAN := TRUE; + g_cross_domain_delay_len : NATURAL := c_meta_delay_len; + g_wr_data_w : NATURAL := 32; + g_wr_fifo_depth : NATURAL := 256; -- >=16 , defined at DDR side of the FIFO, default 256 because 32b*256 fits in 1 M9K + g_rd_fifo_depth : NATURAL := 256; -- >=16 AND >g_tech_ddr.maxburstsize, defined at DDR side of the FIFO, default 256 because 32b*256 fits in 1 M9K + g_rd_fifo_af_margin : NATURAL := 4 + 1*64; -- < g_rd_fifo_depth and sufficient to fit one or more rd burst accesses of g_tech_ddr.maxburstsize each + g_rd_data_w : NATURAL := 32; + g_wr_flush_mode : STRING := "VAL"; -- "VAL", "SOP", "SYN" + g_wr_flush_use_channel : BOOLEAN := FALSE; + g_wr_flush_start_channel : NATURAL := 0; + g_wr_flush_nof_channels : POSITIVE := 1 + ); + PORT ( + -- DDR reference clock + ctlr_ref_clk : IN STD_LOGIC; + ctlr_ref_rst : IN STD_LOGIC; + + -- DDR controller clock domain + ctlr_clk_out : OUT STD_LOGIC; + ctlr_rst_out : OUT STD_LOGIC; + + ctlr_clk_in : IN STD_LOGIC; -- connect ctlr_clk_out to ctlr_clk_in at top level to avoid potential delta-cycle differences between the same clock + ctlr_rst_in : IN STD_LOGIC; -- connect ctlr_rst_out to ctlr_rst_in at top level + + -- MM clock + reset + mm_rst : IN STD_LOGIC := '1'; + mm_clk : IN STD_LOGIC := '0'; + + -- MM interface + reg_io_ddr_mosi : IN t_mem_mosi := c_mem_mosi_rst; -- register for DDR controller status info + reg_io_ddr_miso : OUT t_mem_miso; + + dvr_clk : IN STD_LOGIC; + dvr_rst : IN STD_LOGIC; + + -- Write FIFO clock domain + wr_clk : IN STD_LOGIC; + wr_rst : IN STD_LOGIC; + + wr_fifo_usedw : OUT STD_LOGIC_VECTOR(ceil_log2(g_wr_fifo_depth * (func_tech_ddr_ctlr_data_w(g_tech_ddr)/g_wr_data_w) )-1 DOWNTO 0); -- for monitoring purposes + wr_sosi : IN t_dp_sosi; + wr_siso : OUT t_dp_siso; + + -- Read FIFO clock domain + rd_clk : IN STD_LOGIC; + rd_rst : IN STD_LOGIC; + + rd_fifo_usedw : OUT STD_LOGIC_VECTOR(ceil_log2(g_rd_fifo_depth * (func_tech_ddr_ctlr_data_w(g_tech_ddr)/g_rd_data_w) )-1 DOWNTO 0); + rd_sosi : OUT t_dp_sosi; + rd_siso : IN t_dp_siso; + + term_ctrl_out : OUT t_tech_ddr3_phy_terminationcontrol; + term_ctrl_in : IN t_tech_ddr3_phy_terminationcontrol := c_tech_ddr3_phy_terminationcontrol_rst; + + -- DDR3 PHY external interface + phy3_in : IN t_tech_ddr3_phy_in := c_tech_ddr3_phy_in_x; + phy3_io : INOUT t_tech_ddr3_phy_io; + phy3_ou : OUT t_tech_ddr3_phy_ou; + + -- DDR4 PHY external interface + phy4_in : IN t_tech_ddr4_phy_in := c_tech_ddr4_phy_in_x; + phy4_io : INOUT t_tech_ddr4_phy_io; + phy4_ou : OUT t_tech_ddr4_phy_ou + ); +END mms_io_ddr; + + +ARCHITECTURE str OF mms_io_ddr IS + + SIGNAL ctlr_dvr_miso : t_mem_ctlr_miso; + SIGNAL ctlr_dvr_mosi : t_mem_ctlr_mosi; + + SIGNAL reg_io_ddr_mosi_arr : t_mem_mosi_arr(1 DOWNTO 0); + SIGNAL reg_io_ddr_miso_arr : t_mem_miso_arr(1 DOWNTO 0); + +BEGIN + + -- Combine the reg map of io_ddr and io_ddr_reg + u_mm_mux : ENTITY common_lib.common_mem_mux + GENERIC MAP ( + g_nof_mosi => 2, + g_mult_addr_w => ceil_log2(8) + ) + PORT MAP ( + mosi => reg_io_ddr_mosi, + miso => reg_io_ddr_miso, + mosi_arr => reg_io_ddr_mosi_arr, + miso_arr => reg_io_ddr_miso_arr + ); + + u_ddr_mem_ctrl : ENTITY work.io_ddr + GENERIC MAP( + g_technology => g_technology, + g_tech_ddr => g_tech_ddr, + g_cross_domain_dvr_ctlr => FALSE, + g_wr_data_w => g_wr_data_w, + g_wr_fifo_depth => g_wr_fifo_depth, + g_rd_fifo_depth => g_rd_fifo_depth, + g_rd_data_w => g_rd_data_w, + g_wr_flush_mode => g_wr_flush_mode, + g_wr_flush_use_channel => FALSE, + g_wr_flush_start_channel => 0, + g_wr_flush_nof_channels => 1 + ) + PORT MAP ( + -- DDR reference clock + ctlr_ref_clk => ctlr_ref_clk, + ctlr_ref_rst => ctlr_ref_rst, + + -- DDR controller clock domain + ctlr_clk_out => ctlr_clk_out, -- output clock of the ddr controller is used as DP clk. + ctlr_rst_out => ctlr_rst_out, + + ctlr_clk_in => ctlr_clk_in, + ctlr_rst_in => ctlr_rst_in, + + -- MM clock + reset + mm_rst => mm_rst, + mm_clk => mm_clk, + + -- MM register map for DDR controller status info + reg_io_ddr_mosi => reg_io_ddr_mosi_arr(0), + reg_io_ddr_miso => reg_io_ddr_miso_arr(0), + + -- Driver clock domain + dvr_clk => dvr_clk, + dvr_rst => dvr_rst, + + dvr_miso => ctlr_dvr_miso, + dvr_mosi => ctlr_dvr_mosi, + + -- Write FIFO clock domain + wr_clk => wr_clk, + wr_rst => wr_rst, + + wr_fifo_usedw => OPEN, + wr_sosi => wr_sosi, + wr_siso => wr_siso, + + -- Read FIFO clock domain + rd_clk => rd_clk, + rd_rst => rd_rst, + + rd_fifo_usedw => OPEN, + rd_sosi => rd_sosi, + rd_siso => rd_siso, + + term_ctrl_out => OPEN, + term_ctrl_in => OPEN, + + phy3_in => phy3_in, + phy3_io => phy3_io, + phy3_ou => phy3_ou, + + phy4_in => phy4_in, + phy4_io => phy4_io, + phy4_ou => phy4_ou + ); + + u_ddr_reg : ENTITY work.io_ddr_reg + PORT MAP( + -- Clocks and reset + mm_rst => mm_rst, + mm_clk => mm_clk, + dp_rst => dvr_rst, + dp_clk => dvr_clk, + + -- Memory Mapped Slave in mm_clk domain + sla_in => reg_io_ddr_mosi_arr(1), + sla_out => reg_io_ddr_miso_arr(1), + + -- MM registers in st_clk domain + dvr_miso => ctlr_dvr_miso, + dvr_mosi => ctlr_dvr_mosi + ); + +END str; + -- GitLab