library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; -- Disable next libraries for simulation in GHDL --library unisim; --use unisim.vcomponents.all; use work.lx_dad_pkg.all; -- lx_dad_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_dad_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); -- init : in std_logic; -- signal connected to external JK FF event_jk_j : out std_logic; -- signals to image sensor phi1 : out std_logic; phi2 : out std_logic; phi_rst : out std_logic; LED_1 : out std_logic; sck_o : out std_logic; cnv_o : out std_logic; phist : out std_logic; sck_i : in std_logic; SDI : in std_logic ); end lx_dad_top; architecture Behavioral of lx_dad_top is -- Reset signal signal reset_s : std_logic; signal init_s : std_logic; -- Peripherals on the memory buses -- Example memory signal example_out_s : std_logic_vector(31 downto 0); signal example_ce_s : std_logic; -- Measurement (Master) signal meas_out_s : std_logic_vector(31 downto 0); signal meas_ce_s : std_logic; -- Sensor timing signal sensor_ce_s : std_logic; signal sensor_out_s : std_logic_vector(31 downto 0); -- sensor memory if signal sens_mem_ce_s : std_logic; signal sens_mem_out_s : std_logic_vector(31 downto 0); signal sens_adr_s : std_logic_vector(10 downto 0); signal sens_data_s : std_logic_vector(31 downto 0); signal sens_i_bls_s : std_logic_vector(3 downto 0); signal sens_mem_int_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 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); -- 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 -- Example connection memory_bus_example: bus_example port map ( clk_i => clk_50m, reset_i => reset_s, ce_i => example_ce_s, bls_i => i_bls_s, address_i => address_f_s(11 downto 0), data_i => data_i_s, data_o => example_out_s -- -- -- additional externally connected signals goes there ); --Sensor clock generator sensor_if: clockgen port map ( clk_i => clk_50m, reset_i => reset_s, sck_i => sck_i, SDI => SDI, phi_st => phist, phi_1 => phi1, phi_2 => phi2, ph_rst => phi_rst, --LED => LED_1, sck_o => sck_o, cnv_o => cnv_o, mem_o => sens_data_s, addr_o => sens_adr_s, bls_o => sens_i_bls_s, ce_o => sens_mem_int_ce_s, addr_i => address_f_s(3 downto 0), data_i => data_i_s, ce_i => sensor_ce_s, bls_i => i_bls_s, data_o => sensor_out_s ); --sensor memory connection memory_bus_sensormem: bus_sensor port map ( clk_i => clk_50m, ce_i => sens_mem_ce_s, reset_i => reset_s, --led => LED_1, bls_i => i_bls_s, address_i => address_f_s(10 downto 0), data_i => data_i_s, data_o => sens_mem_out_s, ce_a_i => sens_mem_int_ce_s, adr_a_i => sens_adr_s, bls_a_i => sens_i_bls_s, dat_a_i => sens_data_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 ); -- 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; event_jk_j <= '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; end process; -- Do the actual wiring here memory_bus_wiring: process(cs0_xc_f_s, i_bls_s, address_f_s, example_out_s, meas_out_s, sensor_out_s, sens_mem_out_s, i_rd_s, last_i_rd_s) begin -- Inactive by default example_ce_s <= '0'; meas_ce_s <= '0'; sensor_ce_s <= '0'; sens_mem_ce_s <= '0'; data_o_s <= (others => '0'); 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: Example memory -- 0x1000 - 0x100F: Sensor timing -- 0x1FFC - 0x1FFF: Measurement -- 0x2000 - 0x3FFF: sensor memory -- 0x4000 - 0x8FFF: Free space if address_f_s < "0001000000000000" then -- Tumbl example_ce_s <= '1'; elsif address_f_s(15 downto 4) = "000100000000" then -- Sensor timing sensor_ce_s <= '1'; elsif address_f_s(15 downto 2) = "00011111111111" then -- Measurement meas_ce_s <= '1'; elsif address_f_s > "0001111111111111" and address_f_s < "0100000000000000" then -- sensor data sens_mem_ce_s <= '1'; end if; end if; if last_i_rd_s = '1' then if address_f_s < "0001000000000000" then -- Tumbl data_o_s <= example_out_s; elsif address_f_s(15 downto 2) = "00011111111111" then -- Measurement data_o_s <= meas_out_s; elsif address_f_s(15 downto 4) = "000100000000" then -- Sensor timing data_o_s <= sensor_out_s; elsif address_f_s > "0001111111111111" and address_f_s < "0100000000000000" then -- sensor data data_o_s <= sens_mem_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_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; end Behavioral;