--------------------------------------------------------------------------------
-- CERN (BE-CO-HT)
-- VME64x Core
-- http://www.ohwr.org/projects/vme64x-core
--------------------------------------------------------------------------------
--
-- unit name:     VME_bus (VME_bus.vhd)
--
-- author:        Pablo Alvarez Sanchez <pablo.alvarez.sanchez@cern.ch>
--                Davide Pedretti       <davide.pedretti@cern.ch>
--
-- description:
--
--   This block acts as interface between the VMEbus and the CR/CSR space or
--   WBbus.
--
--                      _________VME_bus__________
--                     |  __________________      |
--                     | |                  |  ___|
--                     | |                  | |   |
--                     | |      MAIN        | | W |
--                   V | |                  | | B | W
--                   M | |      FSM         | |   | B
--                   E | |                  | | M |
--                     | |                  | | A | B
--                   B | |__________________| | S | U
--                   U |  __________________  | T | S
--                   S | |                  | | E |
--                     | |   OTHER DATA &   | | R |
--                     | |   ADDR PROCESS   | |___|
--                     | |__________________|     |
--                     |__________________________|
--
--   The Access decode component decodes the address to check if the board is
--   the responding Slave. This component is of fundamental importance, indeed
--   only one Slave can answer to the Master!
--   In the right side you can see the WB Master who implements the Wb Pipelined
--   single read/write protocol.
--   Each VME board plugged in a slot acts as a VME slave module and it has only
--   one CR/CSR space (conforming with the specification) so only one FPGA at
--   time must drive the output lines on the VME bus; only one FPGA at time can
--   carry the vme64x core or other similar VME slave core.
--   Inside each component is possible read a more detailed description.
--
-- dependencies:
--
--------------------------------------------------------------------------------
-- GNU LESSER GENERAL PUBLIC LICENSE
--------------------------------------------------------------------------------
-- This source file is free software; you can redistribute it and/or modify it
-- under the terms of the GNU Lesser General Public License as published by the
-- Free Software Foundation; either version 2.1 of the License, or (at your
-- option) any later version. This source is distributed in the hope that it
-- will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
-- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-- See the GNU Lesser General Public License for more details. You should have
-- received a copy of the GNU Lesser General Public License along with this
-- source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html
--------------------------------------------------------------------------------
-- last changes: see log.
--------------------------------------------------------------------------------
-- TODO: -
--------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.vme64x_pack.all;

entity VME_bus is
  generic (
    g_CLOCK_PERIOD  : integer;
    g_WB_DATA_WIDTH : integer;
    g_WB_ADDR_WIDTH : integer
  );
  port (
    clk_i           : in  std_logic;
    rst_i           : in  std_logic;

    -- VME signals
    VME_AS_n_i      : in  std_logic;
    VME_LWORD_n_o   : out std_logic := '0';
    VME_LWORD_n_i   : in  std_logic;
    VME_RETRY_n_o   : out std_logic;
    VME_RETRY_OE_o  : out std_logic;
    VME_WRITE_n_i   : in  std_logic;
    VME_DS_n_i      : in  std_logic_vector(1 downto 0);
    VME_DTACK_n_o   : out std_logic;
    VME_DTACK_OE_o  : out std_logic;
    VME_BERR_n_o    : out std_logic;
    VME_ADDR_i      : in  std_logic_vector(31 downto 1);
    VME_ADDR_o      : out std_logic_vector(31 downto 1) := (others => '0');
    VME_ADDR_DIR_o  : out std_logic;
    VME_ADDR_OE_N_o : out std_logic;
    VME_DATA_i      : in  std_logic_vector(31 downto 0);
    VME_DATA_o      : out std_logic_vector(31 downto 0) := (others => '0');
    VME_DATA_DIR_o  : out std_logic;
    VME_DATA_OE_N_o : out std_logic;
    VME_AM_i        : in  std_logic_vector(5 downto 0);
    VME_IACK_n_i    : in  std_logic;  -- USE VME_IACK_n_i and NOT VME_IACKIN_n_i
                                      -- because VME_IACKIN_n_i is delayed the
                                      -- more you are away from Slots 0
    -- WB signals
    stb_o           : out std_logic;
    ack_i           : in  std_logic;
    dat_o           : out std_logic_vector(g_WB_DATA_WIDTH-1 downto 0);
    dat_i           : in  std_logic_vector(g_WB_DATA_WIDTH-1 downto 0);
    adr_o           : out std_logic_vector(g_WB_ADDR_WIDTH-1 downto 0);
    sel_o           : out std_logic_vector(3 downto 0);
    we_o            : out std_logic;
    cyc_o           : out std_logic;
    err_i           : in  std_logic;
    stall_i         : in  std_logic;

    -- Function decoder
    addr_decoder_i  : in  std_logic_vector(31 downto 0);
    addr_decoder_o  : out std_logic_vector(31 downto 0);
    decode_start_o  : out std_logic;
    decode_done_i   : in std_logic;
    am_o            : out std_logic_vector( 5 downto 0);
    decode_sel_i    : in  std_logic;

    --CR/CSR space signals:
    cr_csr_addr_o   : out std_logic_vector(18 downto 2);
    cr_csr_data_i   : in  std_logic_vector( 7 downto 0);
    cr_csr_data_o   : out std_logic_vector( 7 downto 0);
    cr_csr_we_o     : out std_logic;
    module_enable_i : in  std_logic;
    bar_i           : in  std_logic_vector(4 downto 0)
  );
end VME_bus;

architecture RTL of VME_bus is
  -- Local data
  signal s_locDataIn                : std_logic_vector(63 downto 0);
  signal s_locDataOut               : std_logic_vector(63 downto 0);

  -- VME latched signals
  signal s_ADDRlatched              : std_logic_vector(31 downto 1);
  signal s_LWORDlatched_n           : std_logic;
  signal s_DSlatched                : std_logic_vector(1 downto 0);
  signal s_AMlatched                : std_logic_vector(5 downto 0);

  type t_addressingType is (
    A24,
    A24_BLT,
    A24_MBLT,
    CR_CSR,
    A16,
    A32,
    A32_BLT,
    A32_MBLT,
    AM_Error
  );

  type t_transferType is (
    SINGLE,
    BLT,
    MBLT,
    error
  );

  -- Addressing type (depending on VME_AM_i)
  signal s_addressingType           : t_addressingType;
  signal s_transferType             : t_transferType;

  type t_mainFSMstates is (
    -- Wait until AS is asserted.
    IDLE,

    -- Reformat address according to AM.
    REFORMAT_ADDRESS,

    -- Decoding ADDR and AM (selecting card or conf).
    DECODE_ACCESS,

    -- Wait until DS is asserted.
    WAIT_FOR_DS,

    -- Wait until DS is stable (and asserted).
    LATCH_DS,

    -- Decode DS, generate WB request
    CHECK_TRANSFER_TYPE,

    -- Wait for WB reply
    MEMORY_REQ,

    -- For read cycle, put data on the bus
    DATA_TO_BUS,

    -- Assert DTACK
    DTACK_LOW,

    --  Increment address for block transfers
    INCREMENT_ADDR,

    --  Wait until AS is deasserted
    WAIT_END
  );

  -- Main FSM signals
  signal s_mainFSMstate             : t_mainFSMstates;
  signal s_memReq                   : std_logic;   -- Global memory request
  signal s_dataPhase                : std_logic;   -- for MBLT

  -- Access decode signals
  signal s_conf_sel                 : std_logic;   -- CR or CSR is addressed
  signal s_card_sel                 : std_logic;   -- WB memory is addressed

  -- Initialization signals
  signal s_is_d64                   : std_logic;

  --  Set on the cycle to decode access (ADDR + AM)
  signal s_err                      : std_logic;

  -- Calculate the number of LATCH DS states necessary to match the timing
  -- rule 2.39 page 113 VMEbus specification ANSI/IEEE STD1014-1987.
  -- (max skew for the slave is 20 ns)
  constant num_latchDS              : natural range 1 to 8 :=
    (20 + g_CLOCK_PERIOD - 1) / g_CLOCK_PERIOD;

  signal s_DS_latch_count           : unsigned (2 downto 0);
begin
  --  Consistency check.
  assert g_WB_DATA_WIDTH = 32 report "g_WB_DATA_WIDTH must be set to 32"
    severity failure;

  -- These output signals are connected to the buffers on the board
  -- SN74VMEH22501A Function table:  (A is fpga, B is VME connector)
  --   OEn | DIR | OUTPUT                 OEAB   |   OEBYn   |   OUTPUT
  --    H  |  X  |   Z                      L    |     H     |     Z
  --    L  |  H  | A to B                   H    |     H     |   A to B
  --    L  |  L  | B to A                   L    |     L     |   B to Y
  --                                        H    |     L     |A to B, B to Y |

  VME_DATA_OE_N_o <= '0'; -- Driven IFF DIR = 1
  VME_ADDR_OE_N_o <= '0'; -- Driven IFF DIR = 1

  ------------------------------------------------------------------------------
  -- Access Mode Decoders
  ------------------------------------------------------------------------------
  -- Type of data transfer decoder
  -- VME64 ANSI/VITA 1-1994...Table 2-2 "Signal levels during data transfers"
  -- A2 is used to select the D64 type  (D64 --> MBLT and 2edge cycles)
  -- VME DATA --> BIG ENDIAN


  -- These 5 bits are not sufficient to descriminate the D32 and D64 data
  -- transfer type; indeed the D32 access with A2 = '0' (eg 0x010)
  -- fall within D64 access --> The data transfer type have to be evaluated
  -- jointly with the address type.
  --
  -- Bytes position on VMEbus:
  --
  -- A24-31 | A16-23 | A08-15 | A00-07 | D24-31 | D16-23 | D08-15 | D00-07
  --        |        |        |        |        |        | BYTE 0 |
  --        |        |        |        |        |        |        | BYTE 1
  --        |        |        |        |        |        | BYTE 2 |
  --        |        |        |        |        |        |        | BYTE 3
  --        |        |        |        |        |        | BYTE 0 | BYTE 1
  --        |        |        |        |        |        | BYTE 2 | BYTE 3
  --        |        |        |        | BYTE 0 | BYTE 1 | BYTE 2 | BYTE 3
  -- BYTE 0 | BYTE 1 | BYTE 2 | BYTE 3 | BYTE 4 | BYTE 5 | BYTE 6 | BYTE 7

  -- Address modifier decoder
  -- Either the supervisor or user access modes are supported
  with s_AMlatched select s_addressingType <=
    A24      when c_AM_A24_S_SUP | c_AM_A24_S,
    A24_BLT  when c_AM_A24_BLT | c_AM_A24_BLT_SUP,
    A24_MBLT when c_AM_A24_MBLT | c_AM_A24_MBLT_SUP,
    CR_CSR   when c_AM_CR_CSR,
    A16      when c_AM_A16 | c_AM_A16_SUP,
    A32      when c_AM_A32 | c_AM_A32_SUP,
    A32_BLT  when c_AM_A32_BLT | c_AM_A32_BLT_SUP,
    A32_MBLT when c_AM_A32_MBLT | c_AM_A32_MBLT_SUP,
    AM_Error when others;

  -- Transfer type decoder
  with s_addressingType select s_transferType <=
    SINGLE when A24 | CR_CSR | A16 | A32,
    BLT    when A24_BLT | A32_BLT,
    MBLT   when A24_MBLT | A32_MBLT,
    error  when others;

  -- Used to drive the VME_ADDR_DIR_o
  s_is_d64 <= '1' when s_transferType = MBLT else '0';


  ------------------------------------------------------------------------------
  -- MAIN FSM
  ------------------------------------------------------------------------------
  p_VMEmainFSM : process (clk_i) is
    variable addr_word_incr : natural range 0 to 7;
  begin
    if rising_edge(clk_i) then
      if rst_i = '1' or VME_AS_n_i = '1' then
        -- FSM resetted after power up,
        -- software reset, manually reset,
        -- on rising edge of AS.
        s_memReq         <= '0';
        decode_start_o   <= '0';

        -- VME
        VME_DTACK_OE_o   <= '0';
        VME_DTACK_n_o    <= '1';
        VME_DATA_DIR_o   <= '0';
        VME_ADDR_DIR_o   <= '0';
        VME_BERR_n_o     <= '1';
        VME_ADDR_o    <= (others => '0');
        VME_LWORD_n_o <= '1';
        VME_DATA_o    <= (others => '0');
        
        s_dataPhase      <= '0';
        s_mainFSMstate   <= IDLE;

        -- WB
        sel_o            <= "0000";
        cyc_o            <= '0';
        stb_o            <= '0';
        s_err            <= '0';

        s_ADDRlatched    <= (others => '0');
        s_LWORDlatched_n <= '0';
        s_AMlatched      <= (others => '0');

        s_card_sel <= '0';
        s_conf_sel <= '0';
      else
        s_memReq         <= '0';
        decode_start_o   <= '0';
        VME_DTACK_OE_o   <= '0';
        VME_DTACK_n_o    <= '1';
        VME_DATA_DIR_o   <= '0';
        VME_ADDR_DIR_o   <= '0';
        s_dataPhase      <= '0';
        VME_BERR_n_o     <= '1';

        s_DS_latch_count <= "000";

        case s_mainFSMstate is

          when IDLE =>
            -- During the Interrupt ack cycle the Slave can't be accessed
            -- so if VME_IACK_n_i is asserted the FSM is in IDLE state.
            -- The VME_IACK_n_i signal is asserted by the Interrupt handler
            -- during all the Interrupt cycle.

            -- VITA-1 Rule 2.11
            -- Slaves MUST NOT respond to DTB cycles when IACK* is low.
            if VME_AS_n_i = '0' and VME_IACK_n_i = '1' then
              -- if AS falling edge --> start access
              s_mainFSMstate <= REFORMAT_ADDRESS;

              -- Store ADDR, AM and LWORD
              s_ADDRlatched    <= VME_ADDR_i;
              s_LWORDlatched_n <= VME_LWORD_n_i;
              s_AMlatched      <= VME_AM_i;

            else
              s_mainFSMstate <= IDLE;
            end if;

          when REFORMAT_ADDRESS =>
            -- Reformat address according to the mode (A16, A24, A32)
            -- FIXME: not needed if ADEM are correctly reduced to not compare
            -- MSBs of A16 or A24 addresses.
            case s_addressingType is
              when A16 =>
                s_ADDRlatched (31 downto 16) <= (others => '0');  -- A16
              when A24 | A24_BLT | A24_MBLT =>
                s_ADDRlatched (31 downto 24) <= (others => '0');  -- A24
              when others =>
                null;  -- A32
            end case;

            --  VITA-1 Rule 2.6
            --  A Slave MUST NOT respond with a falling edge on DTACK* during
            --  an unaligned transfer cycle, if it does not have UAT
            --  capability.
            if ((s_transferType = SINGLE or s_transferType = BLT)
                and s_LWORDlatched_n = '0' and s_ADDRlatched(1) = '1')
              or (s_transferType = MBLT and s_ADDRlatched(2 downto 1) /= "00")
            then
              -- unaligned.
              s_mainFSMstate <= WAIT_END;
            else
              if s_ADDRlatched(23 downto 19) = bar_i
                and s_AMlatched = c_AM_CR_CSR
              then
                -- conf_sel = '1' it means CR/CSR space addressed
                s_conf_sel <= '1';
                s_mainFSMstate <= WAIT_FOR_DS;
              else
                s_mainFSMstate <= DECODE_ACCESS;
                decode_start_o  <= '1';
              end if;
            end if;

          when DECODE_ACCESS =>
            -- check if this slave board is addressed.

            if decode_done_i = '1' then
              if decode_sel_i = '1' and module_enable_i = '1' then
                -- card_sel = '1' it means WB application addressed
                s_card_sel <= '1';
                s_mainFSMstate <= WAIT_FOR_DS;
                -- Keep only the local part of the address
                s_ADDRlatched <= addr_decoder_i (31 downto 1);
              else
                -- another board will answer; wait here the rising edge on
                -- VME_AS_i (done by top if).
                s_mainFSMstate <= WAIT_END;
              end if;
            else
              -- Not yet decoded.
              s_mainFSMstate <= DECODE_ACCESS;
            end if;

          when WAIT_FOR_DS =>
            -- wait until DS /= "11"
            VME_DTACK_OE_o   <= '1';
            VME_ADDR_DIR_o   <= (s_is_d64) and VME_WRITE_n_i;
            s_dataPhase      <= s_dataPhase;

            if VME_DS_n_i /= "11" then
              s_mainFSMstate <= LATCH_DS;
              s_DS_latch_count <= to_unsigned (num_latchDS - 1, 3);
            else
              s_mainFSMstate <= WAIT_FOR_DS;
            end if;

          when LATCH_DS =>
            -- this state is necessary indeed the VME master can assert the
            -- DS lines not at the same time
            VME_DTACK_OE_o   <= '1';
            -- VITA-1 Rule 2.53a
            -- During all read cycles [...], the responding slave MUST OT
            -- drive the D[] lines until DSA* goes low.
            VME_DATA_DIR_o   <= VME_WRITE_n_i;
            VME_ADDR_DIR_o   <= (s_is_d64) and VME_WRITE_n_i;
            s_dataPhase      <= s_dataPhase;
            if s_DS_latch_count = 0 then
              s_mainFSMstate <= CHECK_TRANSFER_TYPE;

              -- Read DS (which is delayed to avoid metastability).
              s_DSlatched    <= VME_DS_n_i;

              -- Read DATA (which are stable)
              s_locDataIn(63 downto 33) <= VME_ADDR_i;
              s_locDataIn(32)           <= VME_LWORD_n_i;
              if s_LWORDlatched_n = '1' and s_ADDRlatched(1) = '0' then
                -- Word/byte access with A1=0
                s_locDataIn(31 downto 16)  <= VME_DATA_i(15 downto 0);
                s_locDataIn(15 downto 0) <= VME_DATA_i(15 downto 0);
              else
                s_locDataIn(31 downto 0)  <= VME_DATA_i;
              end if;
            else
              s_mainFSMstate   <= LATCH_DS;
              s_DS_latch_count <= s_DS_latch_count - 1;
            end if;

          when CHECK_TRANSFER_TYPE =>
            VME_DTACK_OE_o   <= '1';
            VME_DATA_DIR_o   <= VME_WRITE_n_i;
            VME_ADDR_DIR_o   <= (s_is_d64) and VME_WRITE_n_i;
            s_dataPhase      <= s_dataPhase;

            --  Translate DS+LWORD+ADDR to WB byte selects
            if s_LWORDlatched_n = '0' then
              sel_o <= "1111";
            else
              sel_o <= "0000";
              case s_ADDRlatched(1) is
                when '0' =>
                  sel_o (3 downto 2) <= not s_DSlatched;
                when '1' =>
                  sel_o (1 downto 0) <= not s_DSlatched;
                when others =>
                  null;
              end case;
            end if;

            s_mainFSMstate <= MEMORY_REQ;
            s_memReq <= '1';
            cyc_o <= s_card_sel;
            stb_o <= s_card_sel;
            s_err <= '0';

          when MEMORY_REQ =>
            -- To request the memory CR/CSR or WB memory it is sufficient to
            -- generate a pulse on s_memReq signal
            VME_DTACK_OE_o   <= '1';
            VME_DATA_DIR_o   <= VME_WRITE_n_i;
            VME_ADDR_DIR_o   <= (s_is_d64) and VME_WRITE_n_i;
            s_dataPhase      <= s_dataPhase;

            cyc_o <= s_card_sel;
            stb_o <= s_card_sel and not stall_i;

            if s_conf_sel = '1'
              or (s_card_sel = '1' and (ack_i = '1' or err_i = '1'))
            then
              -- WB ack
              stb_o <= '0';
              s_err <= s_card_sel and err_i;
              if VME_WRITE_n_i = '0' or (s_card_sel and err_i) = '1' then
                -- Write cycle (or BERR)
                s_mainFSMstate <= DTACK_LOW;
              else
                -- Read cycle

                -- Mux (CS-CSR or WB)
                s_locDataOut <= (others => '0');
                if s_card_sel = '1' then
                  if s_LWORDlatched_n = '1' and s_ADDRlatched(1) = '0' then
                    -- Word/byte access with A1 = 0
                    s_locDataOut(15 downto 0) <= dat_i(31 downto 16);
                  else
                    s_locDataOut(31 downto 0) <= dat_i;
                  end if;
                elsif s_conf_sel = '1' then
                  s_locDataOut(7 downto 0) <= cr_csr_data_i;
                end if;

                s_mainFSMstate <= DATA_TO_BUS;
              end if;
            else
              s_mainFSMstate <= MEMORY_REQ;
            end if;

          when DATA_TO_BUS =>
            VME_DTACK_OE_o   <= '1';
            VME_DATA_DIR_o   <= VME_WRITE_n_i;
            VME_ADDR_DIR_o   <= (s_is_d64) and VME_WRITE_n_i;
            s_dataPhase      <= s_dataPhase;
            s_mainFSMstate   <= DTACK_LOW;

            -- VITA-1 Rule 2.54a
            -- During all read cycles, the responding Slave MUST NOT drive
            -- DTACK* low before it drives D[].
            if s_transferType = MBLT then
              VME_ADDR_o    <= s_locDataOut(63 downto 33);
              VME_LWORD_n_o <= s_locDataOut(32);
            end if;

            VME_DATA_o <= s_locDataOut(31 downto 0);

          when DTACK_LOW =>
            VME_DTACK_OE_o   <= '1';
            VME_DATA_DIR_o   <= VME_WRITE_n_i;
            VME_ADDR_DIR_o   <= (s_is_d64) and VME_WRITE_n_i;
            s_dataPhase      <= s_dataPhase;

            --  Set DTACK (or retry or berr)
            if s_err = '1' then
              VME_BERR_n_o  <= '0';
            else
              VME_DTACK_n_o <= '0';
            end if;

            -- VITA-1 Rule 2.57
            -- Once the responding Slave has driven DTACK* or BERR* low, it
            -- MUST NOT release them or drive DTACK* high until it detects
            -- both DS0* and DS1* high.
            if VME_DS_n_i = "11" then
              VME_DATA_DIR_o  <= '0';
              VME_BERR_n_o    <= '1';
              case s_transferType is
                when SINGLE =>
                  --  Cycle should be finished, but allow another access at
                  --  the same address (RMW).
                  s_mainFSMstate <= WAIT_FOR_DS;
                when BLT =>
                  s_mainFSMstate <= INCREMENT_ADDR;
                when MBLT =>
                  if s_dataPhase = '1' then
                    s_mainFSMstate <= INCREMENT_ADDR;
                  else
                    -- Address was got, now transfer data
                    s_dataPhase <= '1';
                    s_mainFSMstate <= WAIT_FOR_DS;
                  end if;
                when error =>
                  null;
              end case;
            else
              s_mainFSMstate <= DTACK_LOW;
            end if;

          when INCREMENT_ADDR =>
            VME_DTACK_OE_o   <= '1';
            VME_ADDR_DIR_o   <= (s_is_d64) and VME_WRITE_n_i;
            s_dataPhase      <= s_dataPhase;

            if s_LWORDlatched_n = '0' then
              if s_transferType = MBLT then
                addr_word_incr := 4;
              else
                addr_word_incr := 2;
              end if;
            else
              if s_DSlatched (0) = '0' then
                -- Next word for D16 or D08(O)
                addr_word_incr := 1;
              else
                addr_word_incr := 0;
              end if;
            end if;
            -- Only increment within the window, don't check the limit.
            -- BLT  --> limit = 256 bytes  (rule 2.12a ANSI/VITA 1-1994)
            -- MBLT --> limit = 2048 bytes (rule 2.78  ANSI/VITA 1-1994)
            s_ADDRlatched (11 downto 1) <= std_logic_vector
              (unsigned(s_ADDRlatched (11 downto 1)) + addr_word_incr);
            s_mainFSMstate   <= WAIT_FOR_DS;

          when WAIT_END =>
            -- Will stay here until AS is released.
            s_mainFSMstate <= WAIT_END;

          when others =>
            s_mainFSMstate <= IDLE;

        end case;
      end if;
    end if;
  end process;

  -- Retry is not supported
  VME_RETRY_n_o  <= '1';
  VME_RETRY_OE_o <= '0';

  -- WB Master
  adr_o <= "00" & s_ADDRlatched(31 downto 2);
  we_o <= not VME_WRITE_n_i;
  dat_o <= s_locDataIn(31 downto 0);
  
  -- Function Decoder
  addr_decoder_o <= s_ADDRlatched & '0';
  am_o           <= s_AMlatched;

  -- CR/CSR In/Out
  cr_csr_data_o <= s_locDataIn(7 downto 0);
  cr_csr_addr_o <= s_ADDRlatched(18 downto 2);

  cr_csr_we_o   <= '1' when s_memReq   = '1' and
                            s_conf_sel = '1' and
                            VME_WRITE_n_i = '0'
                            else '0';
end RTL;
