library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; use ieee.numeric_std.all; library unisim; use unisim.vcomponents.all; use work.mbl_Pkg.all; use work.lx_rocon_pkg.all; -- lx_rocon_top - wires the modules with the outside world -- ====================================================== -- MASTER CPU EXTERNAL MEMORY BUS -- ====================================================== -- -- Master cpu memory bus has the following wires: -- -- - address[15..0] The address -- - data_in[31..0] The data coming to bus -- - data_out[31..0] The data coming from bus, multiplexed -- - rd Read enable, active LOW -- - bls[3..0] Write enable for respective bytes, active LOW -- In some cases, only WR is used -- - ta Transaction acknowledge (latches data out), active LOW, multiplexed -- -- ====================================================== -- TUMBL EXTERNAL MEMORY BUS -- ====================================================== entity lx_rocon_top is port ( -- External --clk_cpu : in std_logic; clk_50m : in std_logic; cs0_xc : in std_logic; rd : in std_logic; bls : in std_logic_vector(3 downto 0); address : in std_logic_vector(15 downto 0); data : inout std_logic_vector(31 downto 0); irc1_a : in std_logic; irc1_b : in std_logic; irc1_index : in std_logic; irc1_mark : in std_logic; irc2_a : in std_logic; irc2_b : in std_logic; irc2_index : in std_logic; irc2_mark : in std_logic; irc3_a : in std_logic; irc3_b : in std_logic; irc3_index : in std_logic; irc3_mark : in std_logic; irc4_a : in std_logic; irc4_b : in std_logic; irc4_index : in std_logic; irc4_mark : in std_logic; init : in std_logic ); end lx_rocon_top; architecture Behavioral of lx_rocon_top is -- Reset signal signal reset_s : std_logic; signal neg_init_s : std_logic; -- 100 MHz clock signal clk_100m_s : std_logic; signal clk_100m_fb_s : std_logic; signal clk_100m_locked_s : std_logic; -- Peripherals on the memory bus signal tumbl_out_s : std_logic_vector(31 downto 0); signal tumbl_ta_s : std_logic; signal tumbl_ce_s : std_logic; -- signal irc_reg_out_s : std_logic_vector(31 downto 0); signal irc_reg_ta_s : std_logic; signal irc_reg_ce_s : std_logic; -- signal calib_out_s : std_logic_vector(31 downto 0); signal calib_ta_s : std_logic; signal calib_ce_s : std_logic; -- Signals for external bus transmission signal data_i_s : std_logic_vector(31 downto 0); signal data_o_s : std_logic_vector(31 downto 0); -- Signals for internal transaction signal last_address_s : std_logic_vector(15 downto 0); signal last_rd_s : std_logic; signal last_bls_s : std_logic_vector(3 downto 0); -- Reading logic: -- Broadcast rd only till ta (transaction acknowledge) -- is received, then latch the data till the state of -- rd or address changes -- -- Data latching is synchronous - it's purpose is to -- provide stable data for CPU on the bus on high rise -- of trans. ack signal signal rd_f_s : std_logic; -- Filtered RD signal rd_d_s : std_logic; -- D over RD signal i_ta_s : std_logic; -- Internal bus TA (active 1) signal i_rd_s : std_logic; -- Internal bus RD (active 1) -- signal data_read_s : std_logic_vector(31 downto 0); -- Latched read data -- signal acked_s : std_logic; -- Writing logic: signal bls_f_s : std_logic_vector(3 downto 0); -- Filtered BLS signal bls_d_s : std_logic_vector(3 downto 0); -- D over BLS signal i_bls_s : std_logic_vector(3 downto 0); -- Internal BLS (active 1) -- signal data_write_s : std_logic_vector(31 downto 0); -- Data broadcasted to write begin -- Clocking clk_100m_dcm_sp : DCM_SP generic map ( clkdv_divide => 2.0, clkfx_divide => 1, clkfx_multiply => 2, clkin_divide_by_2 => false, clkin_period => 20.0, -- 50 MHz clkout_phase_shift => "NONE", clk_feedback => "1X", deskew_adjust => "SYSTEM_SYNCHRONOUS", dfs_frequency_mode => "LOW", dll_frequency_mode => "LOW", dss_mode => "NONE", duty_cycle_correction => true, factory_jf => X"c080", phase_shift => 0, startup_wait => false ) port map ( clk0 => clk_100m_fb_s, clk180 => open, clk270 => open, clk2x => clk_100m_s, clk2x180 => open, clk90 => open, clkdv => open, clkfx => open, clkfx180 => open, locked => clk_100m_locked_s, psdone => open, status => open, clkfb => clk_100m_fb_s, clkin => clk_50m, dssen => '0', psclk => '0', psen => '0', psincdec => '0', rst => neg_init_s ); -- IRC interconnect memory_bus_irc: bus_irc port map ( clk_i => clk_100m_s, reset_i => reset_s, address_i => address(3 downto 0), ce_i => irc_reg_ce_s, data_i => data_i_s(0), data_o => irc_reg_out_s, rd_i => i_rd_s, wr_i => i_bls_s(0), ta_o => irc_reg_ta_s, -- irc1_a_i => irc1_a, irc1_b_i => irc1_b, irc1_index_i => irc1_index, irc1_mark_i => irc1_mark, -- irc2_a_i => irc2_a, irc2_b_i => irc2_b, irc2_index_i => irc2_index, irc2_mark_i => irc2_mark, -- irc3_a_i => irc3_a, irc3_b_i => irc3_b, irc3_index_i => irc3_index, irc3_mark_i => irc3_mark, -- irc4_a_i => irc4_a, irc4_b_i => irc4_b, irc4_index_i => irc4_index, irc4_mark_i => irc4_mark ); -- Tumbl coprocessor memory_bus_tumbl: bus_tumbl port map ( clk_100m_i => clk_100m_s, clk_50m_i => clk_50m, reset_100m_i => reset_s, ce_100m_i => tumbl_ce_s, ta_100m_o => tumbl_ta_s, rd_100m_i => i_rd_s, bls_100m_i => i_bls_s, address_100m_i => address(11 downto 0), data_100m_i => data_i_s, data_100m_o => tumbl_out_s, -- XMEMB_50m_o => open, XMEMB_50m_i.clken => '1', XMEMB_50m_i.data => (others => '1'), XMEMB_50m_i.int => '0', XMEMB_sel_50m_o => open ); -- Calibration memory_bus_calibration: bus_calibration port map ( clk_i => clk_100m_s, reset_i => reset_s, ce_i => calib_ce_s, address_i => address(1 downto 0), rd_i => i_rd_s, bls_i => i_bls_s, ta_o => calib_ta_s, data_i => data_i_s, data_o => calib_out_s ); -- Filters --bls_f <= bls when bls = bls_d else "1111"; bls_f_s(0) <= bls(0) when bls(0) = bls_d_s(0) else '1'; bls_f_s(1) <= bls(2) when bls(2) = bls_d_s(2) else '1'; bls_f_s(2) <= bls(2) when bls(2) = bls_d_s(2) else '1'; bls_f_s(3) <= bls(3) when bls(3) = bls_d_s(3) else '1'; rd_f_s <= rd when rd = rd_d_s else '1'; -- Bus update memory_bus_update: process(clk_100m_s) begin if clk_100m_s = '1' and clk_100m_s'event then -- Set every signal to inactive state here irc_reg_ce_s <= '0'; tumbl_ce_s <= '0'; calib_ce_s <= '0'; i_rd_s <= '0'; i_bls_s <= (others => '0'); data_i_s <= (others => 'X'); -- Check if we have chip select if reset_s = '1' then acked_s <= '1'; i_ta_s <= '0'; data_read_s <= (others => '0'); elsif cs0_xc = '0' then -- Memory Map (16-bit address @ 32-bit each) -- Each address is seen as 32-bit entry now -- 0x0000 - 0x0FFF: Tumbl -- 0x8000 - 0x800F: IRC registers -- 0xFFFC - 0xFFFF: Calibration if address < "0001000000000000" then -- Tumbl tumbl_ce_s <= '1'; i_ta_s <= tumbl_ta_s; data_o_s <= tumbl_out_s; elsif address(15 downto 4) = "100000000000" then -- IRC irc_reg_ce_s <= '1'; i_ta_s <= irc_reg_ta_s; data_o_s <= irc_reg_out_s; elsif address(15 downto 2) = "11111111111111" then -- Calibration calib_ce_s <= '1'; i_ta_s <= calib_ta_s; data_o_s <= calib_out_s; end if; -- Reading if rd_f_s = '0' then if last_rd_s = '1' or last_address_s /= address then -- Getting something new -- Set internal RD to active and reset ack and latched data acked_s <= '0'; i_rd_s <= '1'; -- Data latching - synchronous data_read_s <= (others => 'X'); elsif i_rd_s = '1' and acked_s = '0' and i_ta_s = '1' then -- Got acknowledge, latch data acked_s <= '1'; data_read_s <= data_o_s; elsif acked_s = '0' then -- Ongoing read, keep the signal active i_rd_s <= '1'; data_read_s <= (others => 'X'); end if; last_address_s <= address; else -- Not reading, anything goes data_read_s <= (others => 'X'); end if; last_rd_s <= rd_f_s; -- Writing if bls_f_s /= "1111" then if last_bls_s /= bls_f_s or last_address_s /= address then -- Broadcast BLS for once cycle to write the data i_bls_s <= not bls_f_s; data_i_s <= data_write_s; end if; last_address_s <= address; end if; last_bls_s <= bls_f_s; else -- Set last read / bls to '1' if CS0 is not asserted last_rd_s <= '1'; last_bls_s <= (others => '1'); end if; -- Filters bls_d_s <= bls; rd_d_s <= rd; end if; end process; -- If RD and BLS is not high, we must keep DATA at high impedance -- or the FPGA collides with SDRAM (damaging each other) memory_bus_out: process(cs0_xc, rd, data, data_read_s) begin -- CS0 / RD / BLS are active LOW if cs0_xc = '0' and rd = '0' then data <= data_read_s; else -- IMPORTANT!!! data <= (others => 'Z'); end if; data_write_s <= data; end process; -- Reset initialization: process(init, clk_100m_locked_s) begin -- TODO: Proper reset (lacks filter and propagation with ack as we use PLL) neg_init_s <= not init; reset_s <= (not init) or (not clk_100m_locked_s); end process; end Behavioral;