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, used to mark chip enable -- - data_in[31..0] The data coming to bus -- - data_out[31..0] The data coming from bus, multiplexed -- - bls[3..0] Write enable for respective bytes 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); -- irc0_a : in std_logic; irc0_b : in std_logic; irc0_index : in std_logic; irc0_mark : in std_logic; -- 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; -- irc5_a : in std_logic; irc5_b : in std_logic; irc5_index : in std_logic; irc5_mark : in std_logic; -- irc6_a : in std_logic; irc6_b : in std_logic; irc6_index : in std_logic; irc6_mark : in std_logic; -- irc7_a : in std_logic; irc7_b : in std_logic; irc7_index : in std_logic; irc7_mark : in std_logic; -- init : in std_logic; -- s1_clk_out : out std_logic; s1_sync_out : out std_logic; s1_mosi : out std_logic ); end lx_rocon_top; architecture Behavioral of lx_rocon_top is -- Reset signal signal reset_s : std_logic; signal init_f_s : std_logic; signal init_f_r : std_logic; -- Peripherals on the memory buses -- Master to Tumbl DMEM / IMEM (Master) signal tumbl_out_s : std_logic_vector(31 downto 0); signal tumbl_ce_s : std_logic; -- Measurement (Master) signal meas_out_s : std_logic_vector(31 downto 0); signal meas_ce_s : std_logic; -- Master to Tumbl XMEM signal master_tumbl_xmem_out_s : std_logic_vector(31 downto 0); signal master_tumbl_xmem_ce_s : std_logic; signal master_tumbl_xmem_lock_s : std_logic; -- IRC (Tumbl) signal irc_proc_out_s : std_logic_vector(31 downto 0); signal irc_proc_ce_s : std_logic; signal irc_proc_next_ce_s : std_logic; -- LX Master (Tumbl) signal lxmaster_out_s : std_logic_vector(15 downto 0); signal lxmaster_ce_s : std_logic; signal lxmaster_next_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 for Master CPU: -- 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 signal rd_f_s : std_logic; -- Filtered RD signal rd_d_s : std_logic; -- D over RD signal i_rd_s : std_logic; -- Internal bus RD (active 1) signal last_i_rd_s : std_logic; -- Delayed RD bus, used for latching -- signal address_f_s : std_logic_vector(15 downto 0); -- Filtered address signal address_d_s : std_logic_vector(15 downto 0); -- D over address -- signal data_read_s : std_logic_vector(31 downto 0); -- Latched read data -- 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 -- Tumbl: signal tumbl_bls_s : std_logic_vector(3 downto 0); signal tumbl_address_s : std_logic_vector(14 downto 0); signal tumbl_data_i_s : std_logic_vector(31 downto 0); -- signal tumbl_xmemb_o_s : CORE2DMEMB_Type; signal tumbl_xmemb_i_s : DMEMB2CORE_Type; signal tumbl_xmemb_sel_s : std_logic; begin -- Tumbl coprocessor memory_bus_tumbl: bus_tumbl port map ( clk_i => clk_50m, reset_i => reset_s, ce_i => tumbl_ce_s, bls_i => i_bls_s, address_i => address_f_s(11 downto 0), data_i => data_i_s, data_o => tumbl_out_s, -- xmemb_o => tumbl_xmemb_o_s, xmemb_i => tumbl_xmemb_i_s, xmemb_sel_o => tumbl_xmemb_sel_s ); -- Measurement memory_bus_measurement: bus_measurement port map ( clk_i => clk_50m, reset_i => reset_s, ce_i => meas_ce_s, address_i => address_f_s(1 downto 0), bls_i => i_bls_s, data_i => data_i_s, data_o => meas_out_s ); -- IRC interconnect memory_bus_irc: bus_irc port map ( reset_i => reset_s, -- clk_i => clk_50m, address_i => tumbl_address_s(4 downto 0), next_ce_i => irc_proc_next_ce_s, data_i => tumbl_data_i_s, data_o => irc_proc_out_s, bls_i => tumbl_bls_s, -- irc_i(0).a => irc0_a, irc_i(0).b => irc0_b, irc_i(0).index => irc0_index, irc_i(0).mark => irc0_mark, -- irc_i(1).a => irc1_a, irc_i(1).b => irc1_b, irc_i(1).index => irc1_index, irc_i(1).mark => irc1_mark, -- irc_i(2).a => irc2_a, irc_i(2).b => irc2_b, irc_i(2).index => irc2_index, irc_i(2).mark => irc2_mark, -- irc_i(3).a => irc3_a, irc_i(3).b => irc3_b, irc_i(3).index => irc3_index, irc_i(3).mark => irc3_mark, -- irc_i(4).a => irc4_a, irc_i(4).b => irc4_b, irc_i(4).index => irc4_index, irc_i(4).mark => irc4_mark, -- irc_i(5).a => irc5_a, irc_i(5).b => irc5_b, irc_i(5).index => irc5_index, irc_i(5).mark => irc5_mark, -- irc_i(6).a => irc6_a, irc_i(6).b => irc6_b, irc_i(6).index => irc6_index, irc_i(6).mark => irc6_mark, -- irc_i(7).a => irc7_a, irc_i(7).b => irc7_b, irc_i(7).index => irc7_index, irc_i(7).mark => irc7_mark ); -- LX Master memory_bus_lxmaster: bus_lxmaster port map ( reset_i => reset_s, -- clk_i => clk_50m, address_i => tumbl_address_s(9 downto 0), next_ce_i => lxmaster_next_ce_s, data_i => tumbl_data_i_s(15 downto 0), data_o => lxmaster_out_s, bls_i => tumbl_bls_s(1 downto 0), -- mosi_o => s1_mosi, clock_o => s1_clk_out, sync_o => s1_sync_out ); -- Filters bls_f_s <= bls when bls = bls_d_s else "1111"; rd_f_s <= rd when rd = rd_d_s else '1'; address_f_s <= address when address = address_d_s else last_address_s; -- Use last address on mismatch! -- Signalling data_i_s <= data_write_s when i_bls_s /= "0000" else (others => '0'); -- Tumbl tumbl_bls_s <= i_bls_s when (master_tumbl_xmem_lock_s = '1') else tumbl_xmemb_o_s.bls when (tumbl_xmemb_sel_s = '1') else "0000"; tumbl_address_s <= address_f_s(14 downto 0) when (master_tumbl_xmem_lock_s = '1') else tumbl_xmemb_o_s.addr when (tumbl_xmemb_sel_s = '1') else (others => '0'); tumbl_data_i_s <= data_i_s when (master_tumbl_xmem_lock_s = '1') else tumbl_xmemb_o_s.data when (tumbl_xmemb_sel_s = '1') else (others => '0'); -- tumbl_xmemb_i_s.int <= '0'; -- No interrupt -- Enable clken only when available for Tumbl tumbl_xmemb_i_s.clken <= not master_tumbl_xmem_lock_s; -- Bus update memory_bus_update: process begin wait until clk_50m = '1' and clk_50m'event; -- Defaults i_bls_s <= "0000"; i_rd_s <= '0'; -- Check if we have chip select if cs0_xc = '0' then -- Reading if rd_f_s = '0' then -- Internal read if (last_rd_s = '1' or last_address_s /= address_f_s) then i_rd_s <= '1'; end if; if i_rd_s = '0' and last_i_rd_s = '1' then -- Latch data we just read - they are valid in this cycle data_read_s <= data_o_s; end if; last_address_s <= address_f_s; 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 -- Internal write if (last_bls_s /= bls_f_s or last_address_s /= address_f_s) then i_bls_s <= not bls_f_s; end if; last_address_s <= address_f_s; 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'); last_address_s <= address_d_s; end if; -- Filters bls_d_s <= bls; rd_d_s <= rd; address_d_s <= address; -- last_i_rd_s <= i_rd_s; -- ====================================================== -- TUMBL BUS -- ====================================================== -- Just copy these to their desired next state irc_proc_ce_s <= irc_proc_next_ce_s; lxmaster_ce_s <= lxmaster_next_ce_s; -- Other init_f_s <= init; init_f_r <= init_f_s; end process; -- Do the actual wiring here memory_bus_wiring: process(cs0_xc, address_f_s, tumbl_out_s, meas_out_s, master_tumbl_xmem_out_s) begin -- Inactive by default tumbl_ce_s <= '0'; meas_ce_s <= '0'; master_tumbl_xmem_ce_s <= '0'; data_o_s <= (others => '0'); if cs0_xc = '0' then -- Memory Map (16-bit address @ 32-bit each) -- Each address is seen as 32-bit entry now -- 0x0000 - 0x0FFF: Tumbl IMEM / DMEM -- 0x1FFC - 0x1FFF: Measurement -- 0x8000 - 0x8FFF: Tumbl BUS if address_f_s < "0001000000000000" then -- Tumbl tumbl_ce_s <= '1'; data_o_s <= tumbl_out_s; elsif address_f_s(15 downto 2) = "00011111111111" then -- Measurement meas_ce_s <= '1'; data_o_s <= meas_out_s; elsif address_f_s(15) = '1' then -- Tumbl External BUS master_tumbl_xmem_ce_s <= '1'; data_o_s <= master_tumbl_xmem_out_s; end if; 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 -- Don't risk flipping (between data_o_s and latched data_read_s, it's better to wait) -- Maybe check this later. -- if last_i_rd_s = '1' then -- data <= data_o_s; -- else data <= data_read_s; -- end if; else -- IMPORTANT!!! data <= (others => 'Z'); end if; data_write_s <= data; end process; -- Outputs from Tumbl (enabling and address muxing) and Master CPU tumbl_bus_o: process(tumbl_xmemb_sel_s, tumbl_xmemb_o_s, master_tumbl_xmem_ce_s, address_f_s, i_rd_s, i_bls_s) variable addr_v : std_logic_vector(14 downto 0); -- This space is visible by both (32-bit) variable sel_v : std_logic; begin -- Defaults irc_proc_next_ce_s <= '0'; lxmaster_next_ce_s <= '0'; master_tumbl_xmem_lock_s <= '0'; -- addr_v := (others => '0'); sel_v := '0'; -- Check who is accessing if master_tumbl_xmem_ce_s = '1' and (i_rd_s = '1' or i_bls_s /= "0000") then -- Master blocks Tumbl master_tumbl_xmem_lock_s <= '1'; addr_v := address_f_s(14 downto 0); sel_v := '1'; else addr_v := tumbl_xmemb_o_s.addr; sel_v := '1'; end if; if sel_v = '1' then -- IRC: 0x0800 - 0x081F (32-bit address) -- LX MASTER: 0x0C00 - 0x0FFF (32-bit address) if addr_v(14 downto 5) = "0001000000" then irc_proc_next_ce_s <= '1'; elsif addr_v(14 downto 10) = "00011" then lxmaster_next_ce_s <= '1'; end if; end if; end process; -- Inputs to Tumbl (enabling and address muxing) tumbl_bus_i: process(irc_proc_ce_s, irc_proc_out_s, lxmaster_ce_s, lxmaster_out_s, tumbl_xmemb_i_s) begin tumbl_xmemb_i_s.data <= (others => 'X'); -- NOTE: This is input to Tumbl EXEQ - with MUL instruction for input > 18-bit, -- (i.e. more DSPs in a sequence), this already has tough timing constraints -- and SmartXplorer has to be used with XiSE or use Synplify. if irc_proc_ce_s = '1' then tumbl_xmemb_i_s.data <= irc_proc_out_s; elsif lxmaster_ce_s = '1' then tumbl_xmemb_i_s.data(15 downto 0) <= lxmaster_out_s; tumbl_xmemb_i_s.data(31 downto 16) <= (others => '0'); end if; master_tumbl_xmem_out_s <= tumbl_xmemb_i_s.data; end process; -- Reset initialization: process(init_f_s, init_f_r) begin reset_s <= (not init_f_s) and (not init_f_r); end process; end Behavioral;