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_in : in std_logic; s1_miso : in std_logic; s1_sync_in : in std_logic; -- s1_clk_out : out std_logic; s1_mosi : out std_logic; s1_sync_out : out std_logic; -- signal connected to external JK FF event_jk_j : out std_logic ); end lx_rocon_top; architecture Behavioral of lx_rocon_top is -- Reset signal signal reset_s : std_logic; signal init_s : 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; signal tumbl_ce_r : std_logic; -- Measurement (Master) signal meas_out_s : std_logic_vector(31 downto 0); signal meas_ce_s : std_logic; signal meas_ce_r : 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_ce_r : 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_ce_r : std_logic; -- LX Master (Tumbl) signal lxmaster_out_s : std_logic_vector(15 downto 0); signal lxmaster_ce_s : std_logic; signal lxmaster_ce_r : std_logic; -- LX function approximation signal lxfncapprox_out_s : std_logic_vector(31 downto 0); signal lxfncapprox_ce_s : std_logic; signal lxfncapprox_ce_r : 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 next_last_address_s : std_logic_vector(15 downto 0); signal next_address_hold_s : std_logic; signal address_hold_s : std_logic; signal last_rd_s : std_logic; signal next_last_rd_s : std_logic; signal last_bls_s : std_logic_vector(3 downto 0); -- prev bls_f_s (active 1) signal next_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 cs0_xc_f_s : std_logic; signal rd_f_s : std_logic; -- Filtered RD signal i_rd_s : std_logic; -- Internal bus RD (active 1) signal next_last_i_rd_s : std_logic; 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 data_f_s : std_logic_vector(31 downto 0); -- Filterred input data -- signal data_read_s : std_logic_vector(31 downto 0); -- Latched read data signal next_data_read_s : std_logic_vector(31 downto 0); -- Writing logic: signal bls_f_s : std_logic_vector(3 downto 0); -- Filtered BLS (active 1) signal i_bls_s : std_logic_vector(3 downto 0); -- Internal BLS (active 1) signal next_i_bls_s : std_logic_vector(3 downto 0); -- signal data_write_s : std_logic_vector(31 downto 0); -- Data broadcasted to write signal next_data_write_s : std_logic_vector(31 downto 0); -- 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; -- Interrupt event sources and processing signal lxmaster_rx_done_s : std_logic; signal lxmaster_rx_done_r : std_logic; signal lxmaster_rx_done_last_s : std_logic; signal lxmaster_rx_done_last_r : std_logic; -- signal s0 : std_logic; -- signal s1 : std_logic; -- signal s2 : std_logic; -- XST attributes attribute REGISTER_DUPLICATION : string; attribute REGISTER_DUPLICATION of rd : signal is "NO"; attribute REGISTER_DUPLICATION of rd_f_s : signal is "NO"; attribute REGISTER_DUPLICATION of bls : signal is "NO"; attribute REGISTER_DUPLICATION of bls_f_s : signal is "NO"; attribute REGISTER_DUPLICATION of address : signal is "NO"; attribute REGISTER_DUPLICATION of address_f_s : signal is "NO"; attribute REGISTER_DUPLICATION of cs0_xc : signal is "NO"; attribute REGISTER_DUPLICATION of cs0_xc_f_s : signal is "NO"; 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), ce_i => irc_proc_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(10 downto 0), ce_i => lxmaster_ce_s, data_i => tumbl_data_i_s(15 downto 0), data_o => lxmaster_out_s, bls_i => tumbl_bls_s(1 downto 0), -- rx_done_o => lxmaster_rx_done_s, -- clock_i => s1_clk_in, miso_i => s1_miso, sync_i => s1_sync_in, -- clock_o => s1_clk_out, mosi_o => s1_mosi, sync_o => s1_sync_out -- -- clock_i => s0, -- miso_i => s1, -- sync_i => not s2, -- -- clock_o => s0, -- mosi_o => s1, -- sync_o => s2 ); -- s1_clk_out <= s0; -- s1_mosi <= s1; -- s1_sync_out <= s2; function_approx: component lx_fncapprox port map ( reset_i => reset_s, clk_i => clk_50m, -- Data bus address_i => tumbl_address_s(4 downto 0), ce_i => lxfncapprox_ce_s, data_i => tumbl_data_i_s, data_o => lxfncapprox_out_s, bls_i => tumbl_bls_s ); -- Reset dff_reset: dff2 port map ( clk_i => clk_50m, d_i => init_s, q_o => reset_s ); -- Reset init_s <= not init; -- Signalling data_i_s <= data_write_s; -- 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.bus_taken <= master_tumbl_xmem_lock_s; tumbl_xmemb_i_s.bus_wait <= '0'; -- Bus update memory_bus_logic: process(cs0_xc_f_s, rd_f_s, last_rd_s, last_i_rd_s, bls_f_s, last_bls_s, data_f_s, data_write_s, data_o_s, data_read_s, last_address_s, address_f_s) begin -- Defaults next_address_hold_s <= '0'; -- Check if we have chip select if cs0_xc_f_s = '1' then -- Reading if rd_f_s = '1' then -- Internal read if last_rd_s = '0' or (last_address_s /= address_f_s) then i_rd_s <= '1'; next_last_i_rd_s <= '1'; else i_rd_s <= '0'; next_last_i_rd_s <= '0'; end if; if last_i_rd_s = '1' then -- Latch data we just read - they are valid in this cycle next_data_read_s <= data_o_s; else next_data_read_s <= data_read_s; end if; else -- -- Not reading, anything goes -- data_read_s <= (others => 'X'); next_data_read_s <= data_read_s; i_rd_s <= '0'; next_last_i_rd_s <= '0'; end if; next_last_rd_s <= rd_f_s; -- Data for write are captured only when BLS signals are stable if bls_f_s /= "0000" then next_data_write_s <= data_f_s; next_address_hold_s <= '1'; else next_data_write_s <= data_write_s; end if; if (bls_f_s /= "0000") or (rd_f_s = '1') then next_last_address_s <= address_f_s; else next_last_address_s <= last_address_s; end if; else next_last_rd_s <= '0'; i_rd_s <= '0'; next_last_i_rd_s <= '0'; next_i_bls_s <= "0000"; next_data_write_s <= data_write_s; next_data_read_s <= data_read_s; next_last_address_s <= last_address_s; end if; -- Data for write are captured at/before BLS signals are negated -- and actual write cycle takes place exacly after BLS negation if ((last_bls_s and not bls_f_s) /= "0000") or ((last_bls_s /= "0000") and (cs0_xc_f_s = '0')) then next_i_bls_s <= last_bls_s; next_last_bls_s <= "0000"; next_address_hold_s <= '1'; else next_i_bls_s <= "0000"; if cs0_xc_f_s = '1' then next_last_bls_s <= bls_f_s; else next_last_bls_s <= "0000" ; end if; end if; end process; -- Bus update memory_bus_update: process begin wait until clk_50m = '1' and clk_50m'event; address_hold_s <= next_address_hold_s; -- Synchronized external signals with main clock domain cs0_xc_f_s <= not cs0_xc; bls_f_s <= not bls; rd_f_s <= not rd; data_f_s <= data; if address_hold_s = '0' then address_f_s <= address; else address_f_s <= next_last_address_s; end if; -- Synchronoust state andvance to next period last_bls_s <= next_last_bls_s; last_rd_s <= next_last_rd_s; i_bls_s <= next_i_bls_s; last_i_rd_s <= next_last_i_rd_s; data_write_s <= next_data_write_s; last_address_s <= next_last_address_s; data_read_s <= next_data_read_s; -- Internal bus chipselects tumbl_ce_r <= tumbl_ce_s; meas_ce_r <= meas_ce_s; master_tumbl_xmem_ce_r <= master_tumbl_xmem_ce_s; -- -- ====================================================== -- TUMBL BUS -- ====================================================== -- Just copy these to their desired next state irc_proc_ce_r <= irc_proc_ce_s; lxmaster_ce_r <= lxmaster_ce_s; lxfncapprox_ce_r <= lxfncapprox_ce_s; end process; -- Do the actual wiring here memory_bus_wiring: process(i_rd_s, i_bls_s, address_f_s, tumbl_out_s, meas_out_s, master_tumbl_xmem_out_s, tumbl_ce_r, meas_ce_r, master_tumbl_xmem_ce_r, last_i_rd_s) begin -- Inactive by default tumbl_ce_s <= '0'; meas_ce_s <= '0'; master_tumbl_xmem_ce_s <= '0'; data_o_s <= (others => 'X'); if i_rd_s = '1' or i_bls_s /= "0000" 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'; elsif address_f_s(15 downto 2) = "00011111111111" then -- Measurement meas_ce_s <= '1'; elsif address_f_s(15) = '1' then -- Tumbl External BUS master_tumbl_xmem_ce_s <= '1'; end if; end if; if tumbl_ce_r = '1' then -- Tumbl data_o_s <= tumbl_out_s; elsif meas_ce_r = '1' then -- Measurement data_o_s <= meas_out_s; elsif master_tumbl_xmem_ce_r = '1' then -- Tumbl External BUS data_o_s <= master_tumbl_xmem_out_s; 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_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; 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_ce_s <= '0'; lxmaster_ce_s <= '0'; lxfncapprox_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 FNC AP: 0x0C00 - 0x0C1F (32-bit address) -- LX MASTER: 0x1000 - 0x17FF (32-bit address) if addr_v(14 downto 5) = "0001000000" then irc_proc_ce_s <= '1'; elsif addr_v(14 downto 5) = "0001100000" then lxfncapprox_ce_s <= '1'; elsif addr_v(14 downto 11) = "0010" then lxmaster_ce_s <= '1'; end if; end if; end process; -- Inputs to Tumbl (enabling and address muxing) tumbl_bus_i: process(irc_proc_ce_r, irc_proc_out_s, lxmaster_ce_r, lxmaster_out_s, lxfncapprox_ce_r, lxfncapprox_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_r = '1' then tumbl_xmemb_i_s.data <= irc_proc_out_s; elsif lxmaster_ce_r = '1' then tumbl_xmemb_i_s.data(15 downto 0) <= lxmaster_out_s; tumbl_xmemb_i_s.data(31 downto 16) <= (others => '0'); elsif lxfncapprox_ce_r = '1' then tumbl_xmemb_i_s.data <= lxfncapprox_out_s; end if; master_tumbl_xmem_out_s <= tumbl_xmemb_i_s.data; end process; events_logic: process(lxmaster_rx_done_r, lxmaster_rx_done_last_r) begin event_jk_j <= lxmaster_rx_done_r or lxmaster_rx_done_last_r; lxmaster_rx_done_last_s <= lxmaster_rx_done_r; end process; events_update: process begin wait until clk_50m = '1' and clk_50m'event; lxmaster_rx_done_r <= lxmaster_rx_done_s; lxmaster_rx_done_last_r <= lxmaster_rx_done_last_s; end process; end Behavioral;