--******************************************************************************
--*
--* @short VME Interface Block for the whole GMT Board. Located in the ROP Chip.
--*
--* The VME Interface decodes the upper four bits (23 downto 20) of the
--* VME address and generates the necessary vme_en signals for all the
--* chips on the board.
--*
--* The vme_en_xxx signals are asserted with a DSPULS. In write
--* cycles a vme_en_xxx is a pulse of one clock cycle length. In read cycles
--* the vme_en_xxx is cleared after a rising edge of DTACK or when the
--* DSSYNC from VME64 is cleared.
--*
--* For internal use in the ROP chip a vme_strobe_ROP is
--* generated when reading and when writing. This is needed in the
--* JTAGController since actions are triggered at the end of the strobe.
--*
--* DTACK_EXT is set after a rising edge of the dtack pulses from the
--* chips. It is cleared synchronously after a falling edge of DSSYNC
--* or asynchronously with DSCYC.
--*
--*
--* Check: is it worth clearing the inteternal vme_en_signals already with
--* the DTACK? Do we gain any speed?
--*
--* Check: is it worth clearing the esternal DTACK asynchonously with
--* DSCYC? Do we gain any speed?
--*
--* @diagram vme_waveforms.jpg VME Interface waveforms
--*
--* (Taurok, Noebauer - 29/09/2005) vme_en_XXX are delayed by one tick
--* to make them arrive well after the VME addresses
--******************************************************************************
--* @author SAKULIN Hannes <hsakulin@dsy-srv3.cern.ch>
--* @version $Revision: 1.7 $
--* @date $Date: 2005/11/22 14:45:42 $
--******************************************************************************
--/
library IEEE;
use IEEE.Std_logic_1164.all;
use IEEE.NUMERIC_STD.all;
use work.ROPVMEAddrMap.all;
entity ROPVMEInterface is
port (
-- VME port (from/to VME 64 chip)
-- vme addr and data will be buffered to get shorter traces on the board
vme_addr : in std_logic_vector(23 downto 1);
vme_wrall_mask : in std_logic_vector(9 downto 0);
-- VME64x chip signals :
BERR_EXT : out std_logic;
DTACK_EXT : out std_logic;
IRQ_X : out std_logic; -- currently not used
SINGLE_ACCESS : in std_logic; -- address mod indicates single access
BLT_ACCESS : in std_logic; -- address mod indicates block transfer
DSPULS : in std_logic; -- Strobe pulse 25 ns long, 25ns after
-- DSSYNC
DSCYC : in std_logic; -- AND of two VME strobes (not synced)
DSSYNC : in std_logic; -- DSCYC synchronized
WRITE_I : in std_logic; -- write from VME
RESET_MODE : in std_logic; -- currently not used
D08_O : in std_logic; -- currently not used
D08_E : in std_logic; -- currently not used
D16_EO : in std_logic; -- currently not used
ASCYC : in std_logic; -- currently not used
ASSYNC : in std_logic; -- currently not used
ASPULS : in std_logic; -- currently not used
-- VME signals to the other chips (including IRQ, but without BERR)
vme_en_INF : out std_logic;
vme_wr_INF : out std_logic;
vme_ndtack_INF : in std_logic;
vme_nirq_INF : in std_logic;
vme_en_INC : out std_logic;
vme_wr_INC : out std_logic;
vme_ndtack_INC : in std_logic;
vme_nirq_INC : in std_logic;
vme_en_IND : out std_logic;
vme_wr_IND : out std_logic;
vme_ndtack_IND : in std_logic;
vme_nirq_IND : in std_logic;
vme_en_INB : out std_logic;
vme_wr_INB : out std_logic;
vme_ndtack_INB : in std_logic;
vme_nirq_INB : in std_logic;
vme_en_AUF : out std_logic;
vme_wr_AUF : out std_logic;
vme_ndtack_AUF : in std_logic;
vme_nirq_AUF : in std_logic;
vme_en_LFB : out std_logic;
vme_wr_LFB : out std_logic;
vme_ndtack_LFB : in std_logic;
vme_nirq_LFB : in std_logic;
vme_en_LFF : out std_logic;
vme_wr_LFF : out std_logic;
vme_ndtack_LFF : in std_logic;
vme_nirq_LFF : in std_logic;
vme_en_AUB : out std_logic;
vme_wr_AUB : out std_logic;
vme_ndtack_AUB : in std_logic;
vme_nirq_AUB : in std_logic;
vme_en_SRT : out std_logic;
vme_wr_SRT : out std_logic;
vme_ndtack_SRT : in std_logic;
vme_nirq_SRT : in std_logic;
vme_strobe_ROP : out std_logic; -- used internally
-- strobe when writing and reading
vme_en_ROP : out std_logic; -- used internally
vme_wr_ROP : out std_logic;
vme_ndtack_ROP : in std_logic;
vme_nirq_ROP : in std_logic;
-- Clock and control
clk : in std_logic;
reset : in std_logic);
end;
architecture behavioral of ROPVMEInterface is
attribute syn_useioff : boolean;
attribute syn_useioff of behavioral : architecture is true;
signal SINGLE_ACCESS_reg : std_logic; -- address mod indicates single access
signal BLT_ACCESS_reg : std_logic; -- address mod indicates block transfer
signal DSSYNC_reg : std_logic; -- DSCYC cynchronized
signal DSSYNC_reg_d : std_logic;
signal DSSYNC_reg_d2 : std_logic;
signal WRITE_I_reg : std_logic; -- write from VME
signal dssync_pulse : std_logic;
signal vme_wr_ROP_reg : std_logic;
signal vme_wr_INF_reg : std_logic;
signal vme_wr_INC_reg : std_logic;
signal vme_wr_IND_reg : std_logic;
signal vme_wr_INB_reg : std_logic;
signal vme_wr_AUF_reg : std_logic;
signal vme_wr_LFF_reg : std_logic;
signal vme_wr_LFB_reg : std_logic;
signal vme_wr_AUB_reg : std_logic;
signal vme_wr_SRT_reg : std_logic;
signal s_vme_en_ROP : std_logic;
signal s_vme_en_INF : std_logic;
signal s_vme_en_INC : std_logic;
signal s_vme_en_IND : std_logic;
signal s_vme_en_INB : std_logic;
signal s_vme_en_AUF : std_logic;
signal s_vme_en_LFF : std_logic;
signal s_vme_en_LFB : std_logic;
signal s_vme_en_AUB : std_logic;
signal s_vme_en_SRT : std_logic;
signal s_vme_strobe_ROP : std_logic;
attribute syn_preserve : boolean;
attribute syn_preserve of vme_wr_ROP_reg : signal is true;
attribute syn_preserve of vme_wr_INF_reg : signal is true;
attribute syn_preserve of vme_wr_INC_reg : signal is true;
attribute syn_preserve of vme_wr_IND_reg : signal is true;
attribute syn_preserve of vme_wr_INB_reg : signal is true;
attribute syn_preserve of vme_wr_AUF_reg : signal is true;
attribute syn_preserve of vme_wr_LFF_reg : signal is true;
attribute syn_preserve of vme_wr_LFB_reg : signal is true;
attribute syn_preserve of vme_wr_AUB_reg : signal is true;
attribute syn_preserve of vme_wr_SRT_reg : signal is true;
signal nirq_ROP_reg : std_logic;
signal nirq_INF_reg : std_logic;
signal nirq_INC_reg : std_logic;
signal nirq_IND_reg : std_logic;
signal nirq_INB_reg : std_logic;
signal nirq_AUF_reg : std_logic;
signal nirq_LFF_reg : std_logic;
signal nirq_LFB_reg : std_logic;
signal nirq_AUB_reg : std_logic;
signal nirq_SRT_reg : std_logic;
signal ndtack_ROP_reg : std_logic;
signal ndtack_INF_reg : std_logic;
signal ndtack_INC_reg : std_logic;
signal ndtack_IND_reg : std_logic;
signal ndtack_INB_reg : std_logic;
signal ndtack_AUF_reg : std_logic;
signal ndtack_LFF_reg : std_logic;
signal ndtack_LFB_reg : std_logic;
signal ndtack_AUB_reg : std_logic;
signal ndtack_SRT_reg : std_logic;
signal dtack_or : std_logic;
signal dtack_or_d : std_logic;
function addr_match (
constant vme_addr : std_logic_vector;
constant address : integer) -- in bytes
return std_logic is
variable my_addr_vec : std_logic_vector(vme_addr'high downto 0);
variable retval : std_logic;
begin -- process vme_addr_decode
my_addr_vec := std_logic_vector( TO_UNSIGNED ( address, vme_addr'high+1 ) );
if my_addr_vec(vme_addr'range) = vme_addr(vme_addr'range) then
retval := '1';
else
retval := '0';
end if;
return retval;
end;
begin
-----------------------------------------------------------------------------
--* register (and delay) VME64 signals
-----------------------------------------------------------------------------
register_vme64: process (clk, reset) is
begin -- process register_vme64
if reset = '1' then
SINGLE_ACCESS_reg <= '0';
BLT_ACCESS_reg <= '0';
DSSYNC_reg <= '0';
DSSYNC_reg_d <= '0';
DSSYNC_reg_d2 <= '0';
WRITE_I_reg <= '0';
elsif clk'event and clk = '1' then -- rising clock edge
SINGLE_ACCESS_reg <= SINGLE_ACCESS;
BLT_ACCESS_reg <= BLT_ACCESS;
DSSYNC_reg <= DSSYNC;
DSSYNC_reg_d <= DSSYNC_reg;
DSSYNC_reg_d2 <= DSSYNC_reg_d;
WRITE_I_reg <= WRITE_I;
end if;
end process register_vme64;
dssync_pulse <= DSSYNC_reg and (not DSSYNC_reg_d2);
-----------------------------------------------------------------------------
--* register NIRQ and NDTACK inputs
-----------------------------------------------------------------------------
register_inputs: process (clk) is
begin -- process register_inputs
if clk'event and clk = '1' then -- rising clock edge
nirq_ROP_reg <= vme_nirq_ROP; ndtack_ROP_reg <= vme_ndtack_ROP;
nirq_INF_reg <= vme_nirq_INF; ndtack_INF_reg <= vme_ndtack_INF;
nirq_INC_reg <= vme_nirq_INC; ndtack_INC_reg <= vme_ndtack_INC;
nirq_IND_reg <= vme_nirq_IND; ndtack_IND_reg <= vme_ndtack_IND;
nirq_INB_reg <= vme_nirq_INB; ndtack_INB_reg <= vme_ndtack_INB;
nirq_AUF_reg <= vme_nirq_AUF; ndtack_AUF_reg <= vme_ndtack_AUF;
nirq_LFF_reg <= vme_nirq_LFF; ndtack_LFF_reg <= vme_ndtack_LFF;
nirq_LFB_reg <= vme_nirq_LFB; ndtack_LFB_reg <= vme_ndtack_LFB;
nirq_AUB_reg <= vme_nirq_AUB; ndtack_AUB_reg <= vme_ndtack_AUB;
nirq_SRT_reg <= vme_nirq_SRT; ndtack_SRT_reg <= vme_ndtack_SRT;
-- generate IRQ
IRQ_X <= ( not nirq_ROP_reg ) or
( not nirq_INF_reg ) or
( not nirq_INC_reg ) or
( not nirq_IND_reg ) or
( not nirq_INB_reg ) or
( not nirq_AUF_reg ) or
( not nirq_LFF_reg ) or
( not nirq_LFB_reg ) or
( not nirq_AUB_reg ) or
( not nirq_SRT_reg );
end if;
end process register_inputs;
-----------------------------------------------------------------------------
--* VME enable and strobe signal generation
-----------------------------------------------------------------------------
register_signals : process (clk, reset) is
variable vme_a2320 : std_logic_vector(23 downto 20);
begin -- process register_outputs
if reset = '1' then
s_vme_en_ROP <= '0';
s_vme_en_INF <= '0';
s_vme_en_INC <= '0';
s_vme_en_IND <= '0';
s_vme_en_INB <= '0';
s_vme_en_AUF <= '0';
s_vme_en_LFF <= '0';
s_vme_en_LFB <= '0';
s_vme_en_AUB <= '0';
s_vme_en_SRT <= '0';
s_vme_strobe_ROP <= '0';
elsif clk'event and clk = '1' then -- rising clock edge
if (SINGLE_ACCESS_reg = '1' or BLT_ACCESS_reg = '1' ) then
-- rise vme enable on ds pulse (2 cycles)
vme_a2320(23 downto 20) := vme_addr(23 downto 20);
if dssync_pulse = '1' then
s_vme_en_ROP <= addr_match(vme_a2320 , ROP_base) or (addr_match(vme_a2320 , ALL_base) and WRITE_I_reg and vme_wrall_mask(0));
s_vme_en_INF <= addr_match(vme_a2320 , INF_base) or (addr_match(vme_a2320 , ALL_base) and WRITE_I_reg and vme_wrall_mask(1));
s_vme_en_INC <= addr_match(vme_a2320 , INC_base) or (addr_match(vme_a2320 , ALL_base) and WRITE_I_reg and vme_wrall_mask(2));
s_vme_en_IND <= addr_match(vme_a2320 , IND_base) or (addr_match(vme_a2320 , ALL_base) and WRITE_I_reg and vme_wrall_mask(3));
s_vme_en_INB <= addr_match(vme_a2320 , INB_base) or (addr_match(vme_a2320 , ALL_base) and WRITE_I_reg and vme_wrall_mask(4));
s_vme_en_AUF <= addr_match(vme_a2320 , AUF_base) or (addr_match(vme_a2320 , ALL_base) and WRITE_I_reg and vme_wrall_mask(5));
s_vme_en_LFF <= addr_match(vme_a2320 , LFF_base) or (addr_match(vme_a2320 , ALL_base) and WRITE_I_reg and vme_wrall_mask(6));
s_vme_en_LFB <= addr_match(vme_a2320 , LFB_base) or (addr_match(vme_a2320 , ALL_base) and WRITE_I_reg and vme_wrall_mask(7));
s_vme_en_AUB <= addr_match(vme_a2320 , AUB_base) or (addr_match(vme_a2320 , ALL_base) and WRITE_I_reg and vme_wrall_mask(8));
s_vme_en_SRT <= addr_match(vme_a2320 , SRT_base) or (addr_match(vme_a2320 , ALL_base) and WRITE_I_reg and vme_wrall_mask(9));
-- clear after one clock when writing, or upon DTACK, or when cleared
-- from VME
elsif ( dssync_pulse = '0' and WRITE_I_reg = '1' ) or
( DSSYNC_reg = '0' ) then
s_vme_en_ROP <= '0';
s_vme_en_INF <= '0';
s_vme_en_INC <= '0';
s_vme_en_IND <= '0';
s_vme_en_INB <= '0';
s_vme_en_AUF <= '0';
s_vme_en_LFF <= '0';
s_vme_en_LFB <= '0';
s_vme_en_AUB <= '0';
s_vme_en_SRT <= '0';
end if;
-- rise vme strobe on ds pulse
if dssync_pulse = '1' then
s_vme_strobe_ROP <= addr_match(vme_addr(23 downto 20), ROP_base);
-- clear strobe or upon DTACK, or when cleared from VME
elsif ( DSSYNC_reg = '0' ) then
s_vme_strobe_ROP <= '0';
end if;
end if;
end if;
end process register_signals;
-- Connect VME signals to outputs: vme_en_XXX are delayed by one tick
-- to make them arrive well after the VME addresses
register_outputs : process (clk, reset) is
begin -- process register_outputs
if reset = '1' then
vme_en_ROP <= '0';
vme_en_INF <= '0';
vme_en_INC <= '0';
vme_en_IND <= '0';
vme_en_INB <= '0';
vme_en_AUF <= '0';
vme_en_LFF <= '0';
vme_en_LFB <= '0';
vme_en_AUB <= '0';
vme_en_SRT <= '0';
vme_strobe_ROP <= '0';
elsif clk'event and clk = '1' then -- rising clock edge
vme_en_ROP <= s_vme_en_ROP;
vme_en_INF <= s_vme_en_INF;
vme_en_INC <= s_vme_en_INC;
vme_en_IND <= s_vme_en_IND;
vme_en_INB <= s_vme_en_INB;
vme_en_AUF <= s_vme_en_AUF;
vme_en_LFF <= s_vme_en_LFF;
vme_en_LFB <= s_vme_en_LFB;
vme_en_AUB <= s_vme_en_AUB;
vme_en_SRT <= s_vme_en_SRT;
vme_strobe_ROP <= s_vme_strobe_ROP;
end if;
end process register_outputs;
-----------------------------------------------------------------------------
--* register VME wr signals
-----------------------------------------------------------------------------
register_vme_wr: process (clk, reset) is
begin
if reset = '1' then
vme_wr_ROP_reg <= '0';
vme_wr_INF_reg <= '0';
vme_wr_INC_reg <= '0';
vme_wr_INB_reg <= '0';
vme_wr_IND_reg <= '0';
vme_wr_AUF_reg <= '0';
vme_wr_LFF_reg <= '0';
vme_wr_LFB_reg <= '0';
vme_wr_AUB_reg <= '0';
vme_wr_SRT_reg <= '0';
elsif clk'event and clk = '1' then -- rising clock edge
vme_wr_ROP_reg <= WRITE_I_reg;
vme_wr_INF_reg <= WRITE_I_reg;
vme_wr_INC_reg <= WRITE_I_reg;
vme_wr_INB_reg <= WRITE_I_reg;
vme_wr_IND_reg <= WRITE_I_reg;
vme_wr_AUF_reg <= WRITE_I_reg;
vme_wr_LFF_reg <= WRITE_I_reg;
vme_wr_LFB_reg <= WRITE_I_reg;
vme_wr_AUB_reg <= WRITE_I_reg;
vme_wr_SRT_reg <= WRITE_I_reg;
end if;
end process register_vme_wr;
vme_wr_ROP <= vme_wr_ROP_reg;
vme_wr_INF <= vme_wr_INF_reg;
vme_wr_INC <= vme_wr_INC_reg;
vme_wr_INB <= vme_wr_INB_reg;
vme_wr_IND <= vme_wr_IND_reg;
vme_wr_AUF <= vme_wr_AUF_reg;
vme_wr_LFF <= vme_wr_LFF_reg;
vme_wr_LFB <= vme_wr_LFB_reg;
vme_wr_AUB <= vme_wr_AUB_reg;
vme_wr_SRT <= vme_wr_SRT_reg;
-----------------------------------------------------------------------------
-- DTACK generation
-----------------------------------------------------------------------------
dtack_or <= ( not ndtack_ROP_reg ) or
( not ndtack_INF_reg ) or
( not ndtack_INC_reg ) or
( not ndtack_IND_reg ) or
( not ndtack_INB_reg ) or
( not ndtack_AUF_reg ) or
( not ndtack_LFF_reg ) or
( not ndtack_LFB_reg ) or
( not ndtack_AUB_reg ) or
( not ndtack_SRT_reg ) ;
--* delay or'ed DTACK
delay_dtack_or: process (clk, reset) is
begin -- process delay_dtack_or
if reset = '1' then
dtack_or_d <= '0';
elsif clk'event and clk = '1' then -- rising clock edge
dtack_or_d <= dtack_or;
end if;
end process delay_dtack_or;
-----------------------------------------------------------------------------
--* register dtack and clear asynchronously when DSCYC = 0
-----------------------------------------------------------------------------
register_dtack: process (clk, reset, DSCYC) is
begin -- process register_dtack
if reset = '1' or DSCYC = '0' then
DTACK_EXT <= '0';
elsif clk'event and clk = '1' then -- rising clock edge
-- set DTACK on rising flank from chips
if dtack_or = '1' and dtack_or_d = '0' then
DTACK_EXT <= '1';
-- clear DTACK on falling edge of DSSYNC
elsif DSSYNC_reg = '0' and DSSYNC_reg_d = '1' then
DTACK_EXT <= '0';
end if;
end if;
end process register_dtack;
-----------------------------------------------------------------------------
-- Bus error generation
-----------------------------------------------------------------------------
BERR_EXT <= '0';
end architecture behavioral;