diff --git a/libraries/io/epcs/hdllib.cfg b/libraries/io/epcs/hdllib.cfg new file mode 100644 index 0000000000000000000000000000000000000000..b56099b66c3e53bb5876343c7c978c798d19ef56 --- /dev/null +++ b/libraries/io/epcs/hdllib.cfg @@ -0,0 +1,12 @@ +hdl_lib_name = epcs +hdl_library_clause_name = epcs_lib +hdl_lib_uses = common tech_flash + +build_sim_dir = $HDL_BUILD_DIR +build_synth_dir = + +synth_files = + $UNB/Firmware/modules/epcs/src/vhdl/epcs_reg.vhd + src/vhdl/mms_epcs.vhd + +test_bench_files = diff --git a/libraries/io/epcs/src/vhdl/mms_epcs.vhd b/libraries/io/epcs/src/vhdl/mms_epcs.vhd new file mode 100644 index 0000000000000000000000000000000000000000..56cdf8979047d71d9ea9d256a5233d67aa041441 --- /dev/null +++ b/libraries/io/epcs/src/vhdl/mms_epcs.vhd @@ -0,0 +1,331 @@ +------------------------------------------------------------------------------- +-- +-- 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/>. +-- +------------------------------------------------------------------------------- + +-- Note: To simulate this module, I've added an M25P128 simulation model (source: Numonyx) +-- to the generated ALTASMI_PARALLEL megafunction code, and hooked it up to the correct signals +-- internally. +-- Note 2: The simulation model requires real-life (long) powerup delays to be used. Refer to +-- /tb/vhdl/m25p128_model/lib/TimingData.vhd for the delays and references to the corresponding +-- table in the data sheet. These constants can be modified for faster simulation, but I've left them +-- as they were as simulating one page write and read is sufficient. + + +LIBRARY IEEE, common_lib, dp_lib, technology_lib, tech_flash_lib;; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE technology_lib.technology_select_pkg.ALL; + +ENTITY mms_epcs IS + GENERIC ( + g_technology : NATURAL := c_tech_select_default + g_sim : BOOLEAN := FALSE + ); + PORT ( + mm_rst : IN STD_LOGIC; + mm_clk : IN STD_LOGIC; + + epcs_clk : IN STD_LOGIC; + + -- General MM control: + epcs_mosi : IN t_mem_mosi := c_mem_mosi_rst; + epcs_miso : OUT t_mem_miso; + + -- Data path (epcs) -> MM status and data + dpmm_ctrl_mosi : IN t_mem_mosi := c_mem_mosi_rst; + dpmm_ctrl_miso : OUT t_mem_miso := c_mem_miso_rst; + + dpmm_data_mosi : IN t_mem_mosi := c_mem_mosi_rst; + dpmm_data_miso : OUT t_mem_miso := c_mem_miso_rst; + + -- MM -> data path (epcs) status and data + mmdp_ctrl_mosi : IN t_mem_mosi := c_mem_mosi_rst; + mmdp_ctrl_miso : OUT t_mem_miso := c_mem_miso_rst; + + mmdp_data_mosi : IN t_mem_mosi := c_mem_mosi_rst; + mmdp_data_miso : OUT t_mem_miso := c_mem_miso_rst + ); +END mms_epcs; + + +ARCHITECTURE str OF mms_epcs IS + + -- ASMI_PARALLEL supports page write mode of 256 bytes + CONSTANT c_epcs_page_size : NATURAL := 256; + CONSTANT c_user_data_w : NATURAL := c_word_w; + CONSTANT c_epcs_data_w : NATURAL := 8; + CONSTANT c_epcs_addr_w : NATURAL := 24; + + CONSTANT c_fifo_depth_bits : NATURAL := c_epcs_page_size*c_epcs_data_w; + -- FIFO depths relative to epcs and user data widths + CONSTANT c_epcs_fifo_depth : NATURAL := c_fifo_depth_bits / c_epcs_data_w *2; -- *2 because we need the full depth (without the *2) but we can't 'max out' the FIFO. + CONSTANT c_user_fifo_depth : NATURAL := c_fifo_depth_bits / c_user_data_w; + -- We want to monitor FIFO contents on the user side + SIGNAL user_to_epcs_fifo_usedw : STD_LOGIC_VECTOR(ceil_log2(c_user_fifo_depth)-1 DOWNTO 0); + SIGNAL epcs_to_user_fifo_usedw : STD_LOGIC_VECTOR(ceil_log2(c_epcs_fifo_depth/(c_word_w/c_epcs_data_w))-1 DOWNTO 0); + -- Signal to stop reading data from epcs flash when we've read one page size + SIGNAL epcs_to_user_fifo_wr_usedw : STD_LOGIC_VECTOR(ceil_log2(c_epcs_fifo_depth)-1 DOWNTO 0); + + SIGNAL epcs_rst : STD_LOGIC; + + -- Signals between FIFOs and ASMI_PARALLEL + SIGNAL epcs_in_addr : STD_LOGIC_VECTOR(c_epcs_addr_w-1 DOWNTO 0); + SIGNAL epcs_in_datain : STD_LOGIC_VECTOR(c_epcs_data_w-1 DOWNTO 0); + SIGNAL epcs_in_rden : STD_LOGIC; + SIGNAL epcs_in_read : STD_LOGIC; + SIGNAL epcs_in_shift_bytes : STD_LOGIC; + SIGNAL epcs_in_wren : STD_LOGIC; + SIGNAL epcs_in_write : STD_LOGIC; + SIGNAL epcs_in_sector_erase : STD_LOGIC; + + SIGNAL epcs_out_busy : STD_LOGIC; + SIGNAL epcs_out_data_valid : STD_LOGIC; + SIGNAL epcs_out_dataout : STD_LOGIC_VECTOR(c_epcs_data_w-1 DOWNTO 0); + + SIGNAL nxt_epcs_in_addr : STD_LOGIC_VECTOR(c_epcs_addr_w-1 DOWNTO 0); + SIGNAL nxt_epcs_in_datain : STD_LOGIC_VECTOR(c_epcs_data_w-1 DOWNTO 0); + SIGNAL nxt_epcs_in_rden : STD_LOGIC; + SIGNAL nxt_epcs_in_read : STD_LOGIC; + SIGNAL nxt_epcs_in_shift_bytes : STD_LOGIC; + SIGNAL nxt_epcs_in_wren : STD_LOGIC; + SIGNAL nxt_epcs_in_write : STD_LOGIC; + SIGNAL nxt_epcs_in_sector_erase : STD_LOGIC; + + SIGNAL nxt_epcs_out_data_valid : STD_LOGIC; + SIGNAL nxt_epcs_out_dataout : STD_LOGIC_VECTOR(c_epcs_data_w-1 DOWNTO 0); + + SIGNAL epcs_wr_sosi : t_dp_sosi; + SIGNAL epcs_wr_siso : t_dp_siso; + + SIGNAL epcs_rd_sosi : t_dp_sosi; + SIGNAL epcs_rd_siso : t_dp_siso; + + SIGNAL user_wr_sosi : t_dp_sosi; + SIGNAL user_wr_siso : t_dp_siso; + + SIGNAL user_rd_sosi : t_dp_sosi; + SIGNAL user_rd_siso : t_dp_siso; + + SIGNAL epcs_in_addr_from_reg : STD_LOGIC_VECTOR(c_epcs_addr_w-1 DOWNTO 0); + SIGNAL epcs_in_read_from_reg : STD_LOGIC; + SIGNAL epcs_in_rden_from_reg : STD_LOGIC; + SIGNAL epcs_in_write_from_reg : STD_LOGIC; + SIGNAL epcs_in_sector_erase_from_reg : STD_LOGIC; + + +BEGIN + + u_epcs_reg: ENTITY work.epcs_reg + PORT MAP ( + mm_rst => mm_rst, + mm_clk => mm_clk, + + epcs_rst => epcs_rst, + epcs_clk => epcs_clk, + + sla_in => epcs_mosi, + sla_out => epcs_miso, + + epcs_in_addr => epcs_in_addr_from_reg, + epcs_in_read_evt => epcs_in_read_from_reg, + epcs_in_rden => epcs_in_rden_from_reg, + epcs_in_write_evt => epcs_in_write_from_reg, + epcs_in_sector_erase_evt => epcs_in_sector_erase_from_reg, + + epcs_out_busy => epcs_out_busy + ); + + epcs_wr_siso.ready <= '1'; + + u_fifo_user_to_epcs : ENTITY dp_lib.dp_fifo_dc_mixed_widths + GENERIC MAP ( + g_wr_data_w => c_user_data_w, + g_rd_data_w => c_epcs_data_w, + g_use_ctrl => FALSE, + g_wr_fifo_size => c_user_fifo_depth + ) + PORT MAP ( + wr_rst => mm_rst, + wr_clk => mm_clk, + rd_rst => epcs_rst, + rd_clk => epcs_clk, + -- ST sink + snk_out => user_wr_siso, + snk_in => user_wr_sosi, + -- Monitor FIFO filling + wr_usedw => user_to_epcs_fifo_usedw, + rd_emp => OPEN, + -- ST source + src_in => epcs_wr_siso, + src_out => epcs_wr_sosi + ); + + u_fifo_epcs_to_user : ENTITY dp_lib.dp_fifo_dc_mixed_widths + GENERIC MAP ( + g_wr_data_w => c_epcs_data_w, + g_rd_data_w => c_user_data_w, + g_use_ctrl => FALSE, + g_wr_fifo_size => c_epcs_fifo_depth + ) + PORT MAP ( + wr_rst => epcs_rst, + wr_clk => epcs_clk, + rd_rst => mm_rst, + rd_clk => mm_clk, + -- ST sink + snk_out => epcs_rd_siso, + snk_in => epcs_rd_sosi, + -- Monitor FIFO filling + wr_usedw => epcs_to_user_fifo_wr_usedw, + rd_usedw => epcs_to_user_fifo_usedw, + rd_emp => OPEN, + -- ST source + src_in => user_rd_siso, + src_out => user_rd_sosi + ); + + u_asmi_parallel: ENTITY tech_flash_lib.tech_flash_asmi_parallel + GENERIC MAP ( + g_technology => g_technology + ) + PORT MAP ( + addr => epcs_in_addr, + clkin => epcs_clk, + datain => epcs_in_datain, + rden => epcs_in_rden, + read => epcs_in_read, + shift_bytes => epcs_in_shift_bytes, + wren => epcs_in_wren, + write => epcs_in_write, + sector_erase => epcs_in_sector_erase, + + busy => epcs_out_busy, + data_valid => nxt_epcs_out_data_valid, + dataout => nxt_epcs_out_dataout, + illegal_write => OPEN, + illegal_erase => OPEN + ); + + u_mms_dp_fifo_to_mm: ENTITY dp_lib.mms_dp_fifo_to_mm + GENERIC MAP( + g_rd_fifo_depth => c_epcs_fifo_depth/(c_word_w/c_epcs_data_w) + ) + PORT MAP ( + mm_rst => mm_rst, + mm_clk => mm_clk, + + rd_sosi => user_rd_sosi, + rd_siso => user_rd_siso, + + ctrl_mosi => dpmm_ctrl_mosi, + ctrl_miso => dpmm_ctrl_miso, + + data_mosi => dpmm_data_mosi, + data_miso => dpmm_data_miso, + + rd_usedw => epcs_to_user_fifo_usedw + ); + + u_mms_dp_fifo_from_mm: ENTITY dp_lib.mms_dp_fifo_from_mm + GENERIC MAP( + g_wr_fifo_depth => c_user_fifo_depth + ) + PORT MAP ( + mm_rst => mm_rst, + mm_clk => mm_clk, + + wr_sosi => user_wr_sosi, + + ctrl_mosi => mmdp_ctrl_mosi, + ctrl_miso => mmdp_ctrl_miso, + + data_mosi => mmdp_data_mosi, + data_miso => mmdp_data_miso, + + wr_usedw => user_to_epcs_fifo_usedw + ); + + -- Looking at the timing diagrams of the ALTASMI_PARALLEL megafunction, the interface actually + -- maps quite well on a DP streaming interface: + nxt_epcs_in_addr <= epcs_in_addr_from_reg; + nxt_epcs_in_datain <= epcs_wr_sosi.data(c_epcs_data_w-1 DOWNTO 0); + -- We only want to read out one page at a time. Our EPCS->user data FIFO is oversized (*2), so + -- we need to de-assert the read signal towards the EPCS based on usedw. + nxt_epcs_in_rden <= epcs_in_rden_from_reg WHEN UNSIGNED(epcs_to_user_fifo_wr_usedw)<c_epcs_page_size-1 ELSE '0'; + nxt_epcs_in_read <= epcs_in_read_from_reg; + nxt_epcs_in_shift_bytes <= epcs_wr_sosi.valid; + nxt_epcs_in_wren <= (epcs_wr_sosi.valid OR epcs_in_write_from_reg) OR epcs_in_sector_erase_from_reg; + nxt_epcs_in_sector_erase <= epcs_in_sector_erase_from_reg; + nxt_epcs_in_write <= epcs_in_write_from_reg; + + epcs_rd_sosi.data(c_epcs_data_w-1 DOWNTO 0) <= epcs_out_dataout; + epcs_rd_sosi.valid <= epcs_out_data_valid; + + -- The ASMI_PARALLEL requires that data is set up on the falling edge. The following rising + -- edge of the ASMI_PARALLEL's 20MHz clkin clocks in the data. The data is required to be held until + -- the next falling edge: + -- __ __ __ __ __ __ + -- _||_||_||_||_||_||_ + -- ____ + -- ________| |_______ + -- + -- All used components expect rising edge clocked signals, so we're reclocking the relevant signals + -- with falling-edge clocked registers: + p_epcs_clk: PROCESS(epcs_clk, epcs_rst) + BEGIN + IF epcs_rst='1' THEN + epcs_in_addr <= (OTHERS=>'0'); + epcs_in_datain <= (OTHERS=>'0'); + epcs_in_rden <= '0'; + epcs_in_read <= '0'; + epcs_in_shift_bytes <= '0'; + epcs_in_wren <= '0'; + epcs_in_write <= '0'; + epcs_in_sector_erase <= '0'; + + epcs_out_dataout <= (OTHERS=>'0'); + epcs_out_data_valid <= '0'; + ELSIF falling_edge(epcs_clk) THEN + epcs_in_addr <= nxt_epcs_in_addr; + epcs_in_datain <= nxt_epcs_in_datain; + epcs_in_rden <= nxt_epcs_in_rden; + epcs_in_read <= nxt_epcs_in_read; + epcs_in_shift_bytes <= nxt_epcs_in_shift_bytes; + epcs_in_wren <= nxt_epcs_in_wren; + epcs_in_write <= nxt_epcs_in_write; + epcs_in_sector_erase <= nxt_epcs_in_sector_erase; + + epcs_out_dataout <= nxt_epcs_out_dataout; + epcs_out_data_valid <= nxt_epcs_out_data_valid; + END IF; + END PROCESS; + + u_common_areset: ENTITY common_lib.common_areset + PORT MAP ( + in_rst => mm_rst, + clk => epcs_clk, + out_rst => epcs_rst + ); + +END str; + diff --git a/libraries/io/remu/hdllib.cfg b/libraries/io/remu/hdllib.cfg index e961bc8f5d63811c6b30ac115ea3dcc3b15c9584..363c70a0846649eb91332017d01abd7139b3bf2b 100644 --- a/libraries/io/remu/hdllib.cfg +++ b/libraries/io/remu/hdllib.cfg @@ -1,13 +1,12 @@ hdl_lib_name = remu hdl_library_clause_name = remu_lib -hdl_lib_uses = common +hdl_lib_uses = common tech_flash build_sim_dir = $HDL_BUILD_DIR build_synth_dir = synth_files = - src/ip/megawizard/remote_update/remote_update.vhd - src/vhdl/remu_reg.vhd + $UNB/Firmware/modules/remu/src/vhdl/remu_reg.vhd src/vhdl/mms_remu.vhd test_bench_files = diff --git a/libraries/io/remu/src/vhdl/mms_remu.vhd b/libraries/io/remu/src/vhdl/mms_remu.vhd new file mode 100644 index 0000000000000000000000000000000000000000..eaa04d5d526e25ac9ce9fb116bd433004e4a34ad --- /dev/null +++ b/libraries/io/remu/src/vhdl/mms_remu.vhd @@ -0,0 +1,145 @@ +------------------------------------------------------------------------------- +-- +-- 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, common_lib, technology_lib, tech_flash_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; + +ENTITY mms_remu IS + GENERIC MAP ( + g_technology : NATURAL := c_tech_select_default + ); + PORT ( + mm_rst : IN STD_LOGIC; + mm_clk : IN STD_LOGIC; + + epcs_clk : IN STD_LOGIC; + + -- MM registers + remu_mosi : IN t_mem_mosi := c_mem_mosi_rst; + remu_miso : OUT t_mem_miso + ); +END mms_remu; + + +ARCHITECTURE str OF mms_remu IS + + CONSTANT c_param_w : NATURAL := 3; + CONSTANT c_data_w : NATURAL := 24; + + SIGNAL epcs_rst : STD_LOGIC; + + SIGNAL remu_busy : STD_LOGIC; + SIGNAL remu_data_out : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0); + + SIGNAL fall_remu_reconfigure : STD_LOGIC; + SIGNAL fall_remu_read_param : STD_LOGIC; + SIGNAL fall_remu_write_param : STD_LOGIC; + SIGNAL fall_remu_param : STD_LOGIC_VECTOR(c_param_w-1 DOWNTO 0); + SIGNAL fall_remu_data_in : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0); + + SIGNAL nxt_fall_remu_reconfigure : STD_LOGIC; + SIGNAL nxt_fall_remu_read_param : STD_LOGIC; + SIGNAL nxt_fall_remu_write_param : STD_LOGIC; + SIGNAL nxt_fall_remu_param : STD_LOGIC_VECTOR(c_param_w-1 DOWNTO 0); + SIGNAL nxt_fall_remu_data_in : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0); + +BEGIN + + u_remu: ENTITY tech_flash_lib.tech_flash_remote_update + GENERIC MAP ( + g_technology => g_technology + ) + PORT MAP ( + clock => epcs_clk, + param => fall_remu_param, + read_param => fall_remu_read_param, + reconfig => fall_remu_reconfigure, + reset => epcs_rst, + reset_timer => '0', + busy => remu_busy, + data_out => remu_data_out, + write_param => fall_remu_write_param, + data_in => fall_remu_data_in + ); + + u_remu_reg: ENTITY work.remu_reg + PORT MAP ( + mm_rst => mm_rst, + mm_clk => mm_clk, + + epcs_rst => epcs_rst, + epcs_clk => epcs_clk, + + sla_in => remu_mosi, + sla_out => remu_miso, + + reconfigure => nxt_fall_remu_reconfigure, + read_param => nxt_fall_remu_read_param, + param => nxt_fall_remu_param, + busy => remu_busy, + + data_out => remu_data_out, + write_param => nxt_fall_remu_write_param, + data_in => nxt_fall_remu_data_in + ); + + -- The Remote Upgrade megafunction uses an ASMI_PARALLEL instance internally and therefore requires + -- the same clocking scheme as the EPCS module: + + -- The ASMI_PARALLEL requires that data is set up on the falling edge. The following rising + -- edge of the ASMI_PARALLEL's 20MHz clkin clocks in the data. The data is required to be held until + -- the next falling edge: + -- __ __ __ __ __ __ + -- _||_||_||_||_||_||_ + -- ____ + -- ________| |_______ + -- + -- All used components expect rising edge clocked signals, so we're reclocking the relevant signals + -- with falling-edge clocked registers: + p_epcs_clk: PROCESS(epcs_clk, epcs_rst) + BEGIN + IF epcs_rst='1' THEN + fall_remu_reconfigure <= '0'; + fall_remu_read_param <= '0'; + fall_remu_write_param <= '0'; + fall_remu_param <= (OTHERS=>'0'); + fall_remu_data_in <= (OTHERS=>'0'); + ELSIF falling_edge(epcs_clk) THEN + fall_remu_reconfigure <= nxt_fall_remu_reconfigure; + fall_remu_read_param <= nxt_fall_remu_read_param; + fall_remu_write_param <= nxt_fall_remu_write_param; + fall_remu_param <= nxt_fall_remu_param; + fall_remu_data_in <= nxt_fall_remu_data_in; + END IF; + END PROCESS; + + u_common_areset: ENTITY common_lib.common_areset + PORT MAP ( + in_rst => mm_rst, + clk => epcs_clk, + out_rst => epcs_rst + ); + +END str; +