-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--
-- Copyright 2025 VLSI Solution Oy
-- SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
--
-- Licensed under the Solderpad Hardware License v 2.1 (the "License");
-- you may not use this file except in compliance with the License, or,
-- at your option, the Apache License version 2.0.
-- You may obtain a copy of the License at
--
--    https://solderpad.org/licenses/SHL-2.1/
--
-- Unless required by applicable law or agreed to in writing, any work
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--                               RISCV core
--                                 V1.1
--
--
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

-- - - - - - - -
--  libraries
-- - - - - - - -
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use work.rv_pkg.all;


entity dbg_bridge is
  generic ( CLK_FREQ    : natural := 50000000;                -- default 50M
            UART_SPEED  : natural := 1000000;                 -- default 1M
            AXIDATA_W   : natural range 32 to 64 := 32 );     -- select 32 / 64
  port ( clk_i          : in  std_logic;
         xrst_i         : in  std_logic;
         vs_rst_cpu_i   : in  std_logic;        -- riscv core only, '1' if NC
         --  mem bist if
         --  (NOTE: mem count is 2x WAYS as there are tag/data rams)
         --  rd/wr select is 1-hot style in order like ...t1,d1,t0,d0
         mbist_ena_o    : out std_logic;
         imbist_rd_o    : out slv_03_00;        -- t1,d1,t0,d0
         imbist_wr_o    : out slv_03_00;        -- t1,d1,t0,d0
         dmbist_rd_o    : out slv_03_00;        -- t1,d1,t0,d0
         dmbist_wr_o    : out slv_03_00;        -- t1,d1,t0,d0
         mbist_addr_o   : out slv_12_00;        -- 8k ram max
         mbist_data_o   : out slv_t(AXIDATA_W-1 downto 0);
         mbist_data_i   : in  slv_t(AXIDATA_W-1 downto 0);
         --  AXI bus to DDR if
         mem_awready_i  : in  std_logic;
         mem_wready_i   : in  std_logic;
         mem_bvalid_i   : in  std_logic;
--       mem_bresp_i    : in slv_01_00;         -- NC
         mem_arready_i  : in  std_logic;
         mem_rvalid_i   : in  std_logic;
         mem_rdata_i    : in  slv_t(AXIDATA_W-1 downto 0);
--       mem_rresp_i    : in slv_01_00;         -- NC
         mem_awvalid_o  : out std_logic;
         mem_awaddr_o   : out slv_31_00;
         mem_wvalid_o   : out std_logic;
         mem_wdata_o    : out slv_t(AXIDATA_W-1 downto 0);
         mem_wstrb_o    : out slv_t(AXIDATA_W/8-1 downto 0);  -- 64b / 32b
         mem_bready_o   : out std_logic;
         mem_arvalid_o  : out std_logic;
         mem_araddr_o   : out slv_31_00;
         mem_rready_o   : out std_logic;
         --  pp io
         uart_rxd_i     : in  std_logic;
         uart_txd_o     : out std_logic;
         rv_cpu_xrst_o  : out std_logic;        -- cpu xreset  (cpu only, halt)
         rv_core_ena_o  : out std_logic         -- core enable (cpu/caches)
         );
end entity dbg_bridge;


architecture rtl of dbg_bridge is

  -- - - - - - - - - - - - -
  -- Config
  -- - - - - - - - - - - - -
 
  constant UART_DIVISOR_W : natural := log2(CLK_FREQ/UART_SPEED) + 1;
  constant UART_DIVIDER   : slv_t(UART_DIVISOR_W-1 downto 0) :=
    slv_t(to_unsigned((CLK_FREQ/UART_SPEED)-1, UART_DIVISOR_W));

  constant GPIO_ADDRESS  : slv_31_00 := X"F0000000";  -- 00
  constant STS_ADDRESS   : slv_31_00 := X"F0000004";  -- 01

  constant MBIST_CTRL    : slv_31_00 := X"F0000008";  -- 10
  --
  --
  -- target bits:
  --   dmbist_rd_i [27:24]     imbist_rd_i [23:20]
  --   dt1, dd1, dt0, dd0      it1, id1, it0, id0
  --
  -- address bits
  --   19:4  =>  16:4 cache data rams, 13:4 cache tag rams
  --
  -- IN READ PRIORITY IS IN ICACHE, LAST HIGH BIT TARGET RAM DATA IS RETURNED
  -- i.e. 0101 1111 => return icache data0 output
  --

  constant MBIST_IO      : slv_31_00 := X"F000000C";

  -- - - - - - - - - - - - -
  -- defines
  -- - - - - - - - - - - - -
  constant REQ_WRITE     : slv_07_00  := X"10";
  constant REQ_READ      : slv_07_00  := X"11";

  constant STATE_W       : natural                       := 5;
  constant STATE_R       : slv_04_00  := "00000";  -- range def

  constant STATE_IDLE    : slv_04_00  := "00000";  --& X"0";
  constant STATE_LEN     : slv_04_00  := "00001";  --& X"1";
  constant STATE_ADDR0   : slv_04_00  := "00010";  --& X"2";
  constant STATE_ADDR1   : slv_04_00  := "00011";  --& X"3";
  constant STATE_ADDR2   : slv_04_00  := "00100";  --& X"4";
  constant STATE_ADDR3   : slv_04_00  := "00101";  --& X"5";
  constant STATE_WRITE   : slv_04_00  := "00110";  --& X"6";
  constant STATE_WRITE2  : slv_04_00  := "00111";  --& X"7";  -- ! MBIST
  constant STATE_READ    : slv_04_00  := "01000";  --& X"8";
  constant STATE_READ2   : slv_04_00  := "01001";  --& X"9";  -- ! MBIST
  constant STATE_CHECK   : slv_04_00  := "01010";  --& X"A";  -- ! MBIST
  constant STATE_DATA0   : slv_04_00  := "01011";  --& X"B";
  constant STATE_DATA1   : slv_04_00  := "01100";  --& X"C";
  constant STATE_DATA2   : slv_04_00  := "01101";  --& X"D";
  constant STATE_DATA3   : slv_04_00  := "01110";  --& X"E";
  constant STATE_DATA4   : slv_04_00  := "01111";  --& X"F";  -- ! MBIST
  constant STATE_DATA5   : slv_04_00  := "10000";  --& X"0";  -- ! MBIST
  constant STATE_DATA6   : slv_04_00  := "10001";  --& X"1";  -- ! MBIST
  constant STATE_DATA7   : slv_04_00  := "10010";  --& X"2";  -- ! MBIST

  component dbg_bridge_uart
    generic ( UART_DIVISOR_W  : natural := 9 );
    port ( clk_i       : in  std_logic;
           xrst_i      : in  std_logic;
           -- Control
           bit_div_i   : in  slv_t(UART_DIVISOR_W-1 downto 0);
           stop_bits_i : in  std_logic;        -- 0 = 1, 1 = 2
           -- Transmit
           wr_i        : in  std_logic;
           data_i      : in  slv_07_00;
           tx_busy_o   : out std_logic;
           -- Receive
           rd_i        : in  std_logic;
           data_o      : out slv_07_00;
           rx_ready_o  : out std_logic;
           rx_err_o    : out std_logic;
           -- UART pins
           rxd_i       : in  std_logic;
           txd_o       : out std_logic );
  end component;

  component dbg_bridge_fifo is
    generic ( WIDTH   : natural := 8;
              DEPTH   : natural := 4;
              ADDR_W  : natural := 2 );
    port ( clk_i      : in  std_logic;
           xrst_i     : in  std_logic;
           --
           data_in_i  : in  slv_t(WIDTH-1 downto 0);
           push_i     : in  std_logic;
           pop_i      : in  std_logic;
           --
           data_out_o : out slv_t(WIDTH-1 downto 0);
           accept_o   : out std_logic;
           valid_o    : out std_logic );
  end component;


  -- - - - - - - - - - - - -
  -- Wires / Regs
  -- - - - - - - - - - - - -
  signal uart_wr_w          : std_logic;
  signal uart_wr_data_w     : slv_07_00;
  signal uart_wr_busy_w     : std_logic;

  signal uart_rd_w          : std_logic;
  signal uart_rd_data_w     : slv_07_00;
  signal uart_rd_valid_w    : std_logic;

  signal tx_valid_w         : std_logic;
  signal tx_data_w          : slv_07_00;
  signal tx_accept_w        : std_logic;
  signal read_skip_w        : std_logic;

  signal rx_valid_w         : std_logic;
  signal rx_data_w          : slv_07_00;
  signal rx_accept_w        : std_logic;

  signal mem_addr_q         : slv_31_00;
  signal mem_busy_q         : std_logic;
  signal mem_wr_q           : std_logic;

  signal len_q              : slv_07_00;

  --  byte Index
  signal data_idx_q         :slv_01_00;

  --  word storage
  signal data_w             : slv_31_00;
  signal data_h_q           : slv_31_00; -- high word when 64-bit data
  signal data_q             : slv_31_00;
  --  output FIFO
  -- - - - - - - - - - - - -
  signal uart_tx_pop_w      : std_logic;

  --  states
  signal state_q            : slv_t(STATE_R'range);
  signal next_state_r       : slv_t(STATE_R'range);

  --  AXI: Write Request
  signal mem_awvalid_q      : std_logic;
  signal mem_awvalid_r      : std_logic;

  signal mem_wvalid_q       : std_logic;
  signal mem_wvalid_r       : std_logic;

  --  AXI: Read Request
  signal mem_arvalid_q      : std_logic;
  signal mem_arvalid_r      : std_logic;

  --  write mask
  signal mem_sel_q          : slv_t(AXIDATA_W/8-1 downto 0);  -- 64b / 32b
  signal mem_sel_r          : slv_t(AXIDATA_W/8-1 downto 0);  -- 64b / 32b

  --  DBG
  signal magic_addr_w       : std_logic;

  --  cannot read output
  signal mem_awvalid_o_w    : std_logic;
  signal mem_wvalid_o_w     : std_logic;
  signal mem_arvalid_o_w    : std_logic;

  --  GPIO Outputs
  --    1: cpu reset
  --    0: cpu/cache enable (xreset)
  signal gpio_wr_q          : std_logic;
  signal gpio_output_q      : slv_t(1 downto 0);

  signal vs_xrst_cpu_i_q    : slv_01_00;
  signal rv_core_ena_w      : std_logic;

  --   9     - mbist error
  --   8     - mbist enable
  signal mbist_ena_q        : std_logic;
  signal mbist_rd_w         : std_logic;
  signal mbist_fill_q       : std_logic;        -- fill ram(s) from addr ->
  signal mbist_deco_q       : std_logic;        -- fill ram(s) with decoder data
  signal mbist_ad_inc_w     : std_logic;
  signal mbist_pattern_q    : slv_03_00;
  signal mbist_pattern_w    : slv_t(AXIDATA_W-1 downto 0);  -- 64b / 32b
  signal deco_ref_w         : unsigned(mbist_data_i'range);
  signal mbist_check_q      : slv_t(mbist_addr_o'range); -- 12:0
  signal mbist_error_q      : std_logic;
  signal mbist_error_w      : std_logic;
  signal mbist_tag_check_w  : std_logic;

  -- pragma translate_off
  type dbgstate_t is ( IDLE, LEN, ADDR0, ADDR1, ADDR2, ADDR3, WRITE, WRITE2,
                       READ, READ2, CHECK, DATA0, DATA1, DATA2, DATA3,
                       DATA4, DATA5, DATA6, DATA7, XXXX );
  signal dbgstate : dbgstate_t;
  -- pragma translate_on

begin

  -- pragma translate_off
  p_dbgst : process (state_q)
  begin
    case state_q is
      when STATE_IDLE   => dbgstate <= IDLE;
      when STATE_LEN    => dbgstate <= LEN;
      when STATE_ADDR0  => dbgstate <= ADDR0;
      when STATE_ADDR1  => dbgstate <= ADDR1;
      when STATE_ADDR2  => dbgstate <= ADDR2;
      when STATE_ADDR3  => dbgstate <= ADDR3;
      when STATE_WRITE  => dbgstate <= WRITE;
      when STATE_WRITE2 => dbgstate <= WRITE2;
      when STATE_READ   => dbgstate <= READ;
      when STATE_READ2  => dbgstate <= READ2;
      when STATE_CHECK  => dbgstate <= CHECK;
      when STATE_DATA0  => dbgstate <= DATA0;
      when STATE_DATA1  => dbgstate <= DATA1;
      when STATE_DATA2  => dbgstate <= DATA2;
      when STATE_DATA3  => dbgstate <= DATA3;
      when STATE_DATA4  => dbgstate <= DATA4;
      when STATE_DATA5  => dbgstate <= DATA5;
      when STATE_DATA6  => dbgstate <= DATA6;
      when STATE_DATA7  => dbgstate <= DATA7;
      when others       => dbgstate <= XXXX;
    end case;
  end process p_dbgst;
  -- pragma translate_on


  --
  -- ! ! NOTE: MBIST LOGIC CAN ONLY BE USED WHEN mbist_ena_q = '1'
  --
  -- mbist data read priority:
  --   IF IMBIST RD /= 0000 => read icache ram out data
  --   RETURN LAST HIGH BIT RAM DATA
  --
  --   imbist_rd_i,           dmbist_rd_i
  --   it1, id1, it0, id0     dt1, dd1, dt0, dd0
  --
  --   0111 1111  => return id0
  --   0101 1111  => return id0
  --   0100 1111  => return id1
  --
  --   0000 1111  => return dd0
  --   0000 1001  => return dd0
  --   0000 1010  => return dt0
  --   . . .
  --

  mbist_ena_o   <= mbist_ena_q;


  --                               dtarget itarget           address
  -- MBIST_IO  X"F000000C" : 0xF & [27:24] [23:20]  [19:17]  [16:4]  0xC

  -- target bits:
  --   dmbist_rd_i [27:24]     imbist_rd_i [23:20]   fill [19]
  --   dt1, dd1, dt0, dd0      it1, id1, it0, id0
  --
  -- address bits
  --   19:4  => 19 :   - fill 0 -> 8kW  (tag for 0 -> 1kW)
  --            18:17  - reserved
  --            16:4   - cache data rams, 13:4 cache tag rams
  --
  -- IN READ PRIORITY IS IN ICACHE, LAST HIGH BIT TARGET RAM DATA IS RETURNED
  -- i.e. 0101 1111 => return icache data0 output
  --
  g_axi64md : if ( AXIDATA_W = 64 ) generate
    p_mbist_dctrl64 : process ( gpio_wr_q, len_q, mem_addr_q, state_q, 
                                 data_h_q, data_q, mbist_fill_q, mbist_deco_q )
    begin
      mbist_data_o   <=  (others => '0');
      if ( (gpio_wr_q = '1' and len_q(2) = '0' and
            mem_addr_q(31 downto 28) = MBIST_IO(31 downto 28) and
            mem_addr_q(3 downto 0) = MBIST_IO(3 downto 0)) or
           state_q = STATE_WRITE2) then
        mbist_data_o(63 downto 32)  <= data_h_q;
        mbist_data_o(31 downto 0)   <= data_q;
        if (mbist_fill_q = '1' and mbist_deco_q = '1') then
          mbist_data_o               <= (others => '0');
          mbist_data_o(11 downto 0)  <= mem_addr_q(15 downto 4);
        end if;
      end if;
      --
    end process p_mbist_dctrl64;
  end generate g_axi64md;


  g_axi32md : if ( AXIDATA_W /= 64 ) generate
    p_mbist_dctrl32 : process ( gpio_wr_q, len_q, mem_addr_q, state_q, 
                                data_q, mbist_fill_q, mbist_deco_q)
    begin
      mbist_data_o   <=  (others => '0');
      if ( (gpio_wr_q = '1' and len_q(2) = '0' and
            mem_addr_q(31 downto 28) = MBIST_IO(31 downto 28) and
            mem_addr_q(3 downto 0) = MBIST_IO(3 downto 0)) or
           state_q = STATE_WRITE2) then
        mbist_data_o  <= data_q;
        if (mbist_fill_q = '1' and mbist_deco_q = '1') then
          mbist_data_o               <= (others => '0');
          mbist_data_o(11 downto 0)  <= mem_addr_q(15 downto 4);
        end if;
      end if;
      --
    end process p_mbist_dctrl32;
  end generate g_axi32md;


  p_mbist_ctrl : process ( gpio_wr_q, mem_addr_q, mbist_rd_w, len_q, state_q)
  begin
    dmbist_wr_o    <=  (others => '0');    -- t1, d1, t0, d0
    imbist_wr_o    <=  (others => '0');    -- t1, d1, t0, d0
    mbist_addr_o   <=  "0000000000000";    -- 12:0 8k ram, tag 9:0
    imbist_rd_o    <=  (others => '0');    -- t1, d1, t0, d0
    dmbist_rd_o    <=  (others => '0');    -- t1, d1, t0, d0
    mbist_ad_inc_w <= '0';
    if ( (gpio_wr_q = '1' and len_q(2) = '0' and
          mem_addr_q(31 downto 28) = MBIST_IO(31 downto 28) and
          mem_addr_q(3 downto 0) = MBIST_IO(3 downto 0)) or
         state_q = STATE_WRITE2) then
      dmbist_wr_o   <= mem_addr_q(27 downto 24);   -- D-cache t1, d1, t0, d0
      imbist_wr_o   <= mem_addr_q(23 downto 20);   -- I-cache t1, d1, t0, d0
      mbist_addr_o  <= mem_addr_q(16 downto 4);    -- 12:0 8k ram, tag 9:0
      if ( mem_addr_q(16 downto 13) /= "0000" ) then
        -- limit tag ram write to 1k
        dmbist_wr_o(3) <= '0';   -- D-cache t1, d1, t0, d0
        dmbist_wr_o(1) <= '0';   -- D-cache t1, d1, t0, d0
        imbist_wr_o(3) <= '0';   -- I-cache t1, d1, t0, d0
        imbist_wr_o(1) <= '0';   -- I-cache t1, d1, t0, d0
      end if;
      --
      mbist_addr_o  <= mem_addr_q(16 downto 4);    -- 12:0 8k ram, tag 9:0
      --
      if (unsigned(len_q) /= 0) then               -- multiple writes, fill = 1
        mbist_ad_inc_w <= '1';
      end if;
      --
      --
    end if;
    --
    if (mbist_rd_w = '1') then
      if (mem_addr_q(17) = '0') then
        dmbist_rd_o   <= mem_addr_q(27 downto 24);  -- D-cache t1, d1, t0, d0
        imbist_rd_o   <= mem_addr_q(23 downto 20);  -- I-cache t1, d1, t0, d0
        mbist_addr_o  <= mem_addr_q(16 downto 4);   -- 12:0 8k ram, tag 9:0
        if ( mem_addr_q(16 downto 13) /= "0000") then
          -- limit tag ram write to 1k
          dmbist_rd_o(3) <= '0';                    -- D-cache t1
          dmbist_rd_o(1) <= '0';                    -- D-cache t0
          imbist_rd_o(3) <= '0';                    -- I-cache t1
          imbist_rd_o(1) <= '0';                    -- I-cache t0
        end if;
      end if;
      --
      if (unsigned(len_q) /= 0) then                -- multiple reads, fill = 1
        mbist_ad_inc_w <= '1';
      end if;
    end if;
  end process p_mbist_ctrl;


  mbist_rd_w <= '1' when ((state_q = STATE_READ and
                           mem_addr_q(31 downto 28) = MBIST_IO(31 downto 28) and
                           mem_addr_q(3 downto 0)   = MBIST_IO(3 downto 0)) or
                          (state_q = STATE_READ2 and mbist_fill_q = '1') or
                          (state_q = STATE_CHECK and mbist_fill_q = '1') )
                else '0';



  -- tag rams are only 24 bits
  mbist_tag_check_w <= eq(state_q, STATE_CHECK) and
                       ( mem_addr_q(27) or mem_addr_q(25) or    -- dtag 1, 0
                         mem_addr_q(23) or mem_addr_q(21) );    -- itag 1, 0




  -- replicate to word
  g_axi32p : if ( AXIDATA_W /= 64 ) generate
    mbist_pattern_w <= ( mbist_pattern_q & mbist_pattern_q & mbist_pattern_q &
                         mbist_pattern_q & mbist_pattern_q & mbist_pattern_q &
                         mbist_pattern_q & mbist_pattern_q )
                       when (mbist_tag_check_w = '0')
                       else
                       ( X"0" & X"0"  &
                         mbist_pattern_q & mbist_pattern_q & mbist_pattern_q &
                         mbist_pattern_q & mbist_pattern_q & mbist_pattern_q );
  end generate g_axi32p;

  g_axi64p : if ( AXIDATA_W = 64 ) generate
    mbist_pattern_w <= ( mbist_pattern_q & mbist_pattern_q & mbist_pattern_q &
                         mbist_pattern_q & mbist_pattern_q & mbist_pattern_q &
                         mbist_pattern_q & mbist_pattern_q & mbist_pattern_q &
                         mbist_pattern_q & mbist_pattern_q & mbist_pattern_q &
                         mbist_pattern_q & mbist_pattern_q & mbist_pattern_q &
                         mbist_pattern_q )
                       when (mbist_tag_check_w = '0')
                       else
                       ( X"00000000" & X"0" & X"0"  &
                         mbist_pattern_q & mbist_pattern_q & mbist_pattern_q &
                         mbist_pattern_q & mbist_pattern_q & mbist_pattern_q );
  end generate g_axi64p;





  p_c_deco_ref : process (mem_addr_q)
    variable deco_ref_v : unsigned(mbist_data_i'range);
  begin
    deco_ref_v     := (others => '0');         -- 000... &  13:0
    deco_ref_v(mbist_addr_o'left+1 downto 0) :=
      unsigned(mem_addr_q(17 downto 4)) - 2;   -- 000... & 13:0 -> MAX 16k
    --
    deco_ref_w <= deco_ref_v;
  end process p_c_deco_ref;



  g_axi32d : if ( AXIDATA_W /= 64 ) generate
    -- NOTE state_q = STATE_CHECK  --> guaranteed mbist_fill_q = '1'
    mbist_error_w <= '1' when ( mbist_error_q = '1' or
                                (  state_q = STATE_CHECK and
                                   (( mbist_deco_q = '0'and
                                      data_q /= mbist_pattern_w ) or
                                    ( mbist_deco_q = '1' and
                                      unsigned(data_q) /= deco_ref_w )) ) )
                     else '0';
  end generate g_axi32d;

  g_axi64d : if ( AXIDATA_W = 64 ) generate
    -- NOTE state_q = STATE_CHECK  --> guaranteed mbist_fill_q = '1'
    mbist_error_w <= '1' when ( mbist_error_q = '1' or
                                (  state_q = STATE_CHECK and
                                   ( (mbist_deco_q = '0'and
                                      data_q /= mbist_pattern_w(31 downto 0) and
                                      data_h_q /= mbist_pattern_w(63 downto 32))
                                     or
                                     ( mbist_deco_q = '1' and
                                       unsigned(data_q) /=
                                       deco_ref_w(31 downto 0) )) ) )
                     else '0';
  end generate g_axi64d;






  p_mbist_check : process (clk_i)
  begin
    if ( rising_edge(clk_i) ) then
      if (xrst_i = '0' or mbist_ena_q = '0') then
        mbist_check_q  <= (others => '0');         -- 12:0
        mbist_error_q  <= '0';
      else
        if (state_q = STATE_READ2) then
          mbist_check_q  <= (others => '0');       -- 12:0
          mbist_error_q  <= '0';
        end if;
        if ( state_q = STATE_CHECK and next_state_r = STATE_CHECK and
             mbist_error_w = '0' ) then
          mbist_check_q <= inc1u(mbist_check_q);
        end if;
        if ( state_q = STATE_CHECK ) then
          mbist_error_q <= mbist_error_w or mbist_error_q;  -- sticky bit
        end if;
      end if;
    end if;
  end process p_mbist_check;



  p_cpurst_meta : process (clk_i)
  begin
    if ( rising_edge(clk_i) ) then
      if (xrst_i = '0') then
        vs_xrst_cpu_i_q <= "00";
      else
        vs_xrst_cpu_i_q <= vs_xrst_cpu_i_q(0) & (not vs_rst_cpu_i);
      end if;
    end if;
  end process p_cpurst_meta;

  -- - - - - - - - - - - - -
  -- GPIO Outputs
  -- - - - - - - - - - - - -
  p_gpwr : process (clk_i)
  begin
    if ( rising_edge(clk_i) ) then
      if (xrst_i = '0') then
        gpio_wr_q    <= '0';
      else
        --tso-- if (mem_addr_q = GPIO_ADDRESS and state_q = STATE_WRITE and
        if (state_q = STATE_WRITE and rx_valid_w = '1' and
            (data_idx_q = "11" or unsigned(len_q) = 1)) then
          gpio_wr_q  <= '1';
        else
          gpio_wr_q  <= '0';
        end if;
      end if;
    end if;
  end process p_gpwr;


  p_gpo : process (clk_i)
  begin
    if ( rising_edge(clk_i) ) then
      if (xrst_i = '0') then
        gpio_output_q   <= (others => '0');
        mbist_ena_q     <= '0';
        mbist_fill_q    <= '0';                     -- ! MBIST FILL BIT
        mbist_deco_q    <= '0';                     -- ! MBIST FILL DECODER BIT
        mbist_pattern_q <= X"0";
      else
        if (gpio_wr_q = '1') then
          case mem_addr_q is
            when GPIO_ADDRESS   =>
              gpio_output_q <= data_q(gpio_output_q'range);
            when MBIST_CTRL    =>                   --  X"F0000010"
              mbist_ena_q     <= data_q(8);
              mbist_pattern_q <= data_q(3 downto 0);
            when others =>
              null;
          end case;
          --  OVERRIDE MBIST REQUESTS IF CORE ENABLED
        end if;
        --
        --
        if (state_q = STATE_ADDR3 and rx_valid_w = '1' and
            mem_addr_q(31 downto 28) = MBIST_IO(31 downto 28) --  ) then
            --
            -- NOTE: reset/set these bits always when rd/wr to MBIST_*
            --
            and    -- ! early ( uart_rd_data_w(3:0)  NOT  mem_addr_q(3:0) )
            ( uart_rd_data_w(3 downto 0) = MBIST_IO(3 downto 0) or
              uart_rd_data_w(3 downto 0) = MBIST_CTRL(3 downto 0)) ) then
          mbist_fill_q <= mem_addr_q(19);  -- ! MBIST FILL BIT
          mbist_deco_q <= mem_addr_q(18);  -- ! MBIST FILL DECODER BIT
        --
        end if;
        if (mbist_ena_q = '0') then
          mbist_fill_q    <= '0';
          mbist_deco_q    <= '0';
          mbist_pattern_q <= X"0";
        end if;
        --
      end if;
    end if;
  end process p_gpo;



  rv_cpu_xrst_o    <= not gpio_output_q(1);

  rv_core_ena_w    <= gpio_output_q(0) or vs_xrst_cpu_i_q(1);   -- core xreset
  rv_core_ena_o    <= rv_core_ena_w;

  magic_addr_w <= '1' when ( mem_addr_q = GPIO_ADDRESS  or
                             mem_addr_q = STS_ADDRESS   or
                             mem_addr_q = MBIST_CTRL    or
                             ( mem_addr_q(31 downto 28) = MBIST_IO(31 downto 28)
                               and
                               mem_addr_q(3 downto 0) = MBIST_IO(3 downto 0))
                             ) else '0';




  -- - - - - - - - - - - - -
  -- UART core
  -- - - - - - - - - - - - -
  u_uart : dbg_bridge_uart
    generic map ( UART_DIVISOR_W => UART_DIVISOR_W )
    port map ( clk_i        => clk_i,
               xrst_i       => xrst_i,
               -- Control
               bit_div_i    => UART_DIVIDER,
               stop_bits_i  => '0',                       -- 0 = 1, 1 = 2
               -- Transmit
               wr_i         => uart_wr_w,
               data_i       => uart_wr_data_w,
               tx_busy_o    => uart_wr_busy_w,
               -- Receive
               rd_i         => uart_rd_w,
               data_o       => uart_rd_data_w,
               rx_ready_o   => uart_rd_valid_w,
               rx_err_o     => OPEN,                      -- uart_rx_error_w, NC
               -- UART pins
               rxd_i        => uart_rxd_i,
               txd_o        => uart_txd_o );


  -- - - - - - - - - - - - -
  -- Output FIFO
  -- - - - - - - - - - - - -
  uart_tx_pop_w <= not uart_wr_busy_w;

  u_fifo_tx : dbg_bridge_fifo
    generic map ( WIDTH  => 8,
                  DEPTH  => 8,
                  ADDR_W => 3 )
    port map ( clk_i     => clk_i,
               xrst_i     => xrst_i,
               -- In
               push_i     => tx_valid_w,
               data_in_i  => tx_data_w,
               accept_o   => tx_accept_w,
               -- Out
               pop_i      => uart_tx_pop_w,
               data_out_o => uart_wr_data_w,
               valid_o    => uart_wr_w );


  -- - - - - - - - - - - - -
  -- Input FIFO
  -- - - - - - - - - - - - -
  u_fifo_rx : dbg_bridge_fifo
    generic map ( WIDTH  => 8,
                  DEPTH  => 8,
                  ADDR_W => 3 )
    port map ( clk_i      => clk_i,
               xrst_i     => xrst_i,
               -- In
               push_i     => uart_rd_valid_w,
               data_in_i  => uart_rd_data_w,
               accept_o   => uart_rd_w,
               -- Out
               pop_i      => rx_accept_w,
               data_out_o => rx_data_w,
               valid_o    => rx_valid_w );


  -- - - - - - - - - - - - -
  -- States
  -- - - - - - - - - - - - -
  p_c_state : process (state_q, rx_valid_w, rx_data_w, mem_wr_q,
                       len_q, mem_bvalid_i, magic_addr_w, mem_rvalid_i,
                       read_skip_w, tx_accept_w, mbist_ena_q, mbist_fill_q,
                       mem_addr_q)
  begin
    --
    next_state_r <= state_q;
    --
    case state_q is
      -- - - - - - - - - - -
      -- IDLE:
      -- - - - - - - - - - -
      when STATE_IDLE =>
        if (rx_valid_w = '1') then
          case rx_data_w is
            when REQ_WRITE | REQ_READ =>
              next_state_r <= STATE_LEN;
            when others =>
              null;
          end case;
        end if;
      -- - - - - - - - - - -
      -- STATE_LEN
      -- - - - - - - - - - -
      when STATE_LEN =>
        if (rx_valid_w = '1') then
          next_state_r  <= STATE_ADDR0;
        end if;
       -- - - - - - - - - - -
       -- STATE_ADDR
       -- - - - - - - - - - -
      when STATE_ADDR0 => if (rx_valid_w = '1') then
                            next_state_r <= STATE_ADDR1;
                          end if;
      when STATE_ADDR1 => if (rx_valid_w = '1') then
                            next_state_r  <= STATE_ADDR2;
                          end if;
      when STATE_ADDR2 => if (rx_valid_w = '1') then
                            next_state_r  <= STATE_ADDR3;
                          end if;
      when STATE_ADDR3 =>
        if (rx_valid_w = '1' and mem_wr_q = '1') then
          next_state_r  <= STATE_WRITE;
        elsif (rx_valid_w = '1') then
          next_state_r  <= STATE_READ;
        end if;
      -- - - - - - - - - - -
      -- STATE_WRITE
      -- - - - - - - - - - -
      when STATE_WRITE =>
        if (len_q = X"00" and (mem_bvalid_i = '1' or magic_addr_w = '1')) then
          next_state_r  <= STATE_IDLE;
          if (mbist_ena_q = '1' and mbist_fill_q = '1' and
              mem_addr_q(16 downto 4) /= "0111111111111") then
            next_state_r  <= STATE_WRITE2;
          end if;
        else
          next_state_r  <= STATE_WRITE;
        end if;
      -- - - - - - - - - - -
      -- STATE_WRITE2 (mbist only)
      -- - - - - - - - - - -
      when STATE_WRITE2 =>
        if (mbist_ena_q = '0' or mbist_fill_q = '0' or
            mem_addr_q(15 downto 4) = "111111111111") then
          next_state_r  <= STATE_IDLE;
        end if;
      -- - - - - - - - - - -
      -- STATE_READ
      -- - - - - - - - - - -
      when STATE_READ =>
        -- Data ready
        if (mem_rvalid_i = '1' or magic_addr_w = '1') then
          if ( mbist_ena_q = '0' or mem_addr_q = MBIST_CTRL ) then
            next_state_r  <= STATE_DATA0;
          else
            next_state_r  <= STATE_READ2;  -- ram pipeline delay
          end if;
        end if;
      -- - - - - - - - - - -
      -- STATE_READ2 (mbist only)
      -- - - - - - - - - - -
      when STATE_READ2 =>
        -- mbist data ready
        next_state_r  <= STATE_DATA0;
        if (mbist_fill_q = '1') then
          next_state_r  <= STATE_CHECK;
        end if;
      -- - - - - - - - - - -
      -- STATE_READ2 (mbist only)
      -- - - - - - - - - - -
      when STATE_CHECK =>
--      if ( mem_addr_q(17 downto 4) = "10000000000001") then  -- 8k full (data)
        if ( mem_addr_q(16 downto 4) = "1000000000001") then   -- 4k full (data)
          next_state_r  <= STATE_DATA0;
        end if;
--      if ( mem_addr_q(17 downto 4) = "00010000000001") then  -- 1k full (tag)
        if ( mem_addr_q(16 downto 4) = "0001000000001") then   -- 0k5 full (tag)
          if ( mem_addr_q(21 downto 20) = "10" or                -- itag 0
               mem_addr_q(23 downto 20) = "1000" or              -- itag 1
               mem_addr_q(25 downto 20) = "100000" or            -- dtag 0
               mem_addr_q(27 downto 20) = "10000000" ) then      -- dtag 1
            next_state_r  <= STATE_DATA0;
          end if;
        end if;
      -- - - - - - - - - - -
      -- STATE_DATA
      -- - - - - - - - - - -
      when STATE_DATA0 =>
        if (read_skip_w = '1') then
          next_state_r  <= STATE_DATA1;
        elsif (tx_accept_w  = '1' and (len_q = X"00")) then
          next_state_r  <= STATE_IDLE;
        elsif (tx_accept_w = '1') then
          next_state_r  <= STATE_DATA1;
        end if;
      when STATE_DATA1 =>
        if (read_skip_w = '1') then
          next_state_r  <= STATE_DATA2;
        elsif (tx_accept_w  = '1' and (len_q = X"00")) then
          next_state_r  <= STATE_IDLE;
        elsif (tx_accept_w = '1') then
          next_state_r  <= STATE_DATA2;
        end if;
      when STATE_DATA2 =>
        if (read_skip_w = '1') then
          next_state_r  <= STATE_DATA3;
        elsif (tx_accept_w  = '1' and (len_q = X"00")) then
          next_state_r  <= STATE_IDLE;
        elsif (tx_accept_w = '1') then
          next_state_r  <= STATE_DATA3;
        end if;
      when STATE_DATA3 =>
        --X--
        if ( mbist_ena_q = '1' and tx_accept_w  = '1' and
             magic_addr_w = '1'and len_q = X"04" ) then   -- 64bit mem access
          next_state_r  <= STATE_DATA4;
        elsif (tx_accept_w  = '1' and (len_q /=  X"00")) then
          next_state_r  <= STATE_READ;
        elsif (tx_accept_w = '1') then
          next_state_r  <= STATE_IDLE;
        end if;


      when STATE_DATA4 =>
        if (tx_accept_w = '1') then
          next_state_r  <= STATE_DATA5;
        end if;
      when STATE_DATA5 =>
        if (tx_accept_w = '1') then
          next_state_r  <= STATE_DATA6;
        end if;
      when STATE_DATA6 =>
        if (tx_accept_w = '1') then
          next_state_r  <= STATE_DATA7;
        end if;
      when STATE_DATA7 =>
        if (tx_accept_w = '1') then
          next_state_r  <= STATE_IDLE;
        end if;
          

      when others =>
        next_state_r  <= STATE_IDLE;
    end case;
  end process p_c_state;


  -- State storage
  p_state : process (clk_i)
  begin
    if ( rising_edge(clk_i) ) then
      if (xrst_i = '0') then
        state_q <= STATE_IDLE;
      else
        state_q <= next_state_r;
      end if;
    end if;
  end process p_state;


  -- - - - - - - - - - - - -
  -- RD/WR to and from UART
  -- - - - - - - - - - - - -

  -- Write to UART TX buffer in the following states
  tx_valid_w <= '1' when ( ((state_q = STATE_DATA0) or
                            (state_q = STATE_DATA1) or
                            (state_q = STATE_DATA2) or
                            (state_q = STATE_DATA3) or
                            (state_q = STATE_DATA4) or
                            (state_q = STATE_DATA5) or
                            (state_q = STATE_DATA6) or
                            (state_q = STATE_DATA7) ) and read_skip_w = '0' )
                else '0';

  -- Accept data in the following states
  rx_accept_w <= '1' when ( (state_q = STATE_IDLE)  or
                            (state_q = STATE_LEN)   or
                            (state_q = STATE_ADDR0) or
                            (state_q = STATE_ADDR1) or
                            (state_q = STATE_ADDR2) or
                            (state_q = STATE_ADDR3) or
                            (state_q = STATE_WRITE and mem_busy_q = '0') )
                 else '0';


  -- - - - - - - - - - - - -
  -- Capture length
  -- - - - - - - - - - - - -
  p_len : process (clk_i)
  begin
    if ( rising_edge(clk_i) ) then
      if (xrst_i = '0') then
        len_q       <= X"00";
      else
        if (state_q = STATE_LEN and rx_valid_w = '1') then
          len_q(7 downto 0)  <= rx_data_w;
        elsif (state_q = STATE_WRITE and rx_valid_w = '1' and
               mem_busy_q = '0') then
          len_q       <= slv_t(unsigned(len_q) - 1);
        elsif (state_q = STATE_READ and
               ((mem_busy_q = '1' and mem_rvalid_i = '1') or
                magic_addr_w = '1')) then
          len_q  <= slv_t(unsigned(len_q) - 1);
        elsif (((state_q = STATE_DATA0) or (state_q = STATE_DATA1) or
                (state_q = STATE_DATA2)) and
               (tx_accept_w = '1' and read_skip_w = '0')) then
          len_q  <= slv_t(unsigned(len_q) - 1);
        end if;
      end if;
    end if;
  end process p_len;



  -- - - - - - - - - - - - -
  -- Capture addr
  -- - - - - - - - - - - - -
  p_maddr : process (clk_i)
  begin
    if ( rising_edge(clk_i) ) then
      if (xrst_i = '0') then
        mem_addr_q   <= (mem_addr_q'range => '0');
      else
        if (state_q = STATE_ADDR0 and rx_valid_w = '1') then
          mem_addr_q(31 downto 24) <= rx_data_w;
        elsif (state_q = STATE_ADDR1 and rx_valid_w = '1') then
          mem_addr_q(23 downto 16) <= rx_data_w;
        elsif (state_q = STATE_ADDR2 and rx_valid_w = '1') then
          mem_addr_q(15 downto 8)  <= rx_data_w;
        elsif (state_q = STATE_ADDR3 and rx_valid_w = '1') then
          mem_addr_q(7 downto 0)   <= rx_data_w;
          --  address increment on every access issued
        elsif ( (state_q = STATE_WRITE and
                 (mem_busy_q = '1' and mem_bvalid_i = '1')) or
                (state_q = STATE_READ and
                 (mem_busy_q  = '1'and mem_rvalid_i = '1')) )then
          mem_addr_q <= addu(mem_addr_q(31 downto 2),1) &  "00";       --  + 4
        elsif (  mbist_ad_inc_w = '1' or state_q = STATE_WRITE2 or
                 next_state_r = STATE_WRITE2) then
          mem_addr_q <= addu(mem_addr_q(31 downto 2), 4) & "00";       -- + 16
        end if;
      end if;
    end if;
  end process p_maddr;


  -- - - - - - - - - - - - -
  -- Data Index
  -- - - - - - - - - - - - -
  p_didx : process (clk_i)
  begin
    if ( rising_edge(clk_i) ) then
      if (xrst_i = '0') then
        data_idx_q    <= "00";
      else
        if (state_q = STATE_ADDR3) then
          data_idx_q  <= rx_data_w(1 downto 0);
        elsif (state_q = STATE_WRITE and
               rx_valid_w  = '1'and mem_busy_q = '0') then
          data_idx_q  <= inc1u(data_idx_q);
        elsif (((state_q = STATE_DATA0) or (state_q = STATE_DATA1) or
                (state_q = STATE_DATA2)) and tx_accept_w = '1' and
               (data_idx_q /= "00")) then
          data_idx_q  <= dec1u(data_idx_q);
        end if;
      end if;
    end if;
  end process p_didx;


  read_skip_w <= not_zero(data_idx_q);



  -- - - - - - - - - - - - -
  -- Data Sample
  -- - - - - - - - - - - - -
  p_data : process (clk_i)
  begin
    if ( rising_edge(clk_i) ) then
      if (xrst_i = '0') then
        data_h_q  <= X"00000000"; -- only when 64-bit data bus
        data_q    <= X"00000000";
      -- Write to memory
      else
        if (state_q = STATE_WRITE and rx_valid_w = '1' and
            mem_busy_q = '0') then
          if (mbist_ena_q = '1' and magic_addr_w = '1') then
            if (len_q(2 downto 0) = "100" or
                len_q(2 downto 0) = "011" or
                len_q(2 downto 0) = "010" or
                len_q(2 downto 0) = "001" ) then
              case data_idx_q is
                when "00" => data_q(7 downto 0)   <= rx_data_w;
                when "01" => data_q(15 downto 8)  <= rx_data_w;
                when "10" => data_q(23 downto 16) <= rx_data_w;
                when "11" => data_q(31 downto 24) <= rx_data_w;
                when others => null;
              end case;
            else
              case data_idx_q is
                when "00" => data_h_q(7 downto 0)   <= rx_data_w;
                when "01" => data_h_q(15 downto 8)  <= rx_data_w;
                when "10" => data_h_q(23 downto 16) <= rx_data_w;
                when "11" => data_h_q(31 downto 24) <= rx_data_w;
                when others => null;
              end case;
            end if;
          else
            case data_idx_q is
              when "00" => data_q(7 downto 0)   <= rx_data_w;
              when "01" => data_q(15 downto 8)  <= rx_data_w;
              when "10" => data_q(23 downto 16) <= rx_data_w;
              when "11" => data_q(31 downto 24) <= rx_data_w;
              when others => null;
            end case;
          end if;
        -- Read from GPIO Input?
        elsif (state_q = STATE_READ and mem_addr_q = GPIO_ADDRESS) then
          data_q <= X"FACE0000";
          data_q(gpio_output_q'range) <= gpio_output_q;
        -- Read from status register?
        elsif (state_q = STATE_READ and mem_addr_q = STS_ADDRESS) then
          data_q <= (X"CAFE" & (14 downto 0 => '0') & mem_busy_q);
        --
        elsif (state_q = STATE_READ and mem_addr_q = MBIST_CTRL) then
          -- read mbist control register
          data_q      <= (others => '0');
          data_q(9)   <= mbist_error_q;
          data_q(8)   <= mbist_ena_q;
        elsif ( state_q = STATE_READ2 ) then
          if (AXIDATA_W = 64) then
            data_h_q  <= mbist_data_i(63 downto 32);
            data_q    <= mbist_data_i(31 downto  0);
          else
            data_q    <= mbist_data_i;
          end if;

          

        elsif ( state_q = STATE_CHECK and next_state_r = STATE_DATA0) then
          data_h_q                    <= (others => '0');
          data_q                      <= (others => '0');
          -- report error and 1st address of mismatch
          data_q(mbist_check_q'range) <= mbist_check_q;
          data_q(23 downto 20)        <= mbist_error_w & mbist_error_w &
                                         mbist_error_w & mbist_error_w;
        elsif ( state_q = STATE_CHECK ) then
          if (AXIDATA_W = 64) then
            data_h_q  <= mbist_data_i(63 downto 32);
            data_q    <= mbist_data_i(31 downto  0);
          else
            data_q    <= mbist_data_i;
          end if;

        --
        -- Read from memory
        elsif (state_q = STATE_READ and mem_rvalid_i = '1') then
          data_q <= data_w;
        -- Shift data out (read response -> UART)
        elsif ( (state_q = STATE_DATA0 or state_q = STATE_DATA1 or
                 state_q = STATE_DATA2 or state_q = STATE_DATA3 or
                 state_q = STATE_DATA4 or state_q = STATE_DATA5 or
                 state_q = STATE_DATA6 ) and
                (tx_accept_w = '1' or read_skip_w = '1')) then
          --X-- data_q <= (X"00" & data_q(31 downto 8));
          data_q   <= (data_h_q(7 downto 0) & data_q(31 downto 8));
          data_h_q <= (X"00" & data_h_q(31 downto 8));
        elsif ( state_q = STATE_IDLE ) then
          data_h_q <= (others => '0');
        end if;
      end if;
    end if;
  end process p_data;
  

  tx_data_w  <= data_q(7 downto 0);


  -- - - - - - - - - - - - -
  -- AXI: Write Request
  -- - - - - - - - - - - - -
  p_c_axi_wreq : process (mem_awvalid_o_w, mem_awready_i, mem_awvalid_q,
                         state_q, rx_valid_w, data_idx_q, len_q, magic_addr_w,
                         mem_wvalid_o_w, mem_wready_i, mem_wvalid_q)
  begin
    mem_awvalid_r <= '0';
    mem_wvalid_r  <= '0';
    -- Hold
    if (mem_awvalid_o_w = '1' and  mem_awready_i = '0') then
      mem_awvalid_r <= mem_awvalid_q;
    elsif (mem_awvalid_o_w = '1') then
      mem_awvalid_r <= '0';
      -- Every 4th byte, issue bus access
    elsif (state_q = STATE_WRITE and rx_valid_w = '1' and
           (data_idx_q = "11" or unsigned(len_q) = 1)) then
      mem_awvalid_r <= not magic_addr_w;
    end if;
    -- Hold
    if (mem_wvalid_o_w = '1' and mem_wready_i = '0') then
      mem_wvalid_r <= mem_wvalid_q;
    elsif (mem_wvalid_o_w = '1') then
      mem_wvalid_r <= '0';
      -- Every 4th byte, issue bus access
    elsif (state_q = STATE_WRITE and rx_valid_w = '1' and
           (data_idx_q = "11" or unsigned(len_q) = 1)) then
      mem_wvalid_r <= not magic_addr_w;
    end if;
  end process p_c_axi_wreq;


  p_mvalid : process (clk_i)
  begin
    if ( rising_edge(clk_i) ) then
      if (xrst_i = '0') then
        mem_awvalid_q <= '0';
        mem_wvalid_q  <= '0';
      else
        mem_awvalid_q <= mem_awvalid_r;
        mem_wvalid_q  <= mem_wvalid_r;
      end if;
    end if;
  end process p_mvalid;


  mem_awvalid_o_w <= mem_awvalid_q;
  mem_awvalid_o   <= mem_awvalid_o_w;

  mem_wvalid_o_w  <= mem_wvalid_q;
  mem_wvalid_o    <= mem_wvalid_o_w;

  mem_awaddr_o    <= (mem_addr_q(31 downto 3) & "000") when (AXIDATA_W = 64)
                     else (mem_addr_q(31 downto 2) & "00");

  mem_bready_o    <= '1';


  -- - - - - - - - - - - - -
  -- AXI: Read Request
  -- - - - - - - - - - - - -
  p_c_axi_rreq : process (mem_arvalid_o_w, mem_arready_i, mem_arvalid_q,
                          mem_busy_q, state_q, magic_addr_w)
  begin
    mem_arvalid_r <= '0';
    -- Hold
    if (mem_arvalid_o_w = '1' and mem_arready_i = '0') then
      mem_arvalid_r <= mem_arvalid_q;
    elsif (mem_arvalid_o_w = '1') then
      mem_arvalid_r <= '0';
    elsif (state_q = STATE_READ and mem_busy_q = '0') then
      mem_arvalid_r <= not magic_addr_w;
    end if;
  end process p_c_axi_rreq;


  p_arvalid : process (clk_i)
  begin
    if ( rising_edge(clk_i) ) then
      if (xrst_i = '0') then
        mem_arvalid_q <= '0';
      else
        mem_arvalid_q <= mem_arvalid_r;
      end if;
    end if;
  end process p_arvalid;


  mem_arvalid_o_w <= mem_arvalid_q;
  mem_arvalid_o   <= mem_arvalid_o_w;

  mem_araddr_o    <= (mem_addr_q(31 downto 3) & "000") when (AXIDATA_W = 64)
                     else (mem_addr_q(31 downto 2) & "00");

  mem_rready_o    <= '1';


  -- - - - - - - - - - - - -
  -- Write mask
  -- - - - - - - - - - - - -
  g_axi32 : if ( AXIDATA_W /= 64 ) generate
  begin
    p_c_msel : process (data_idx_q, mem_addr_q)
      variable mem_sel_r_v : slv_t(mem_sel_r'range);
    begin
      mem_sel_r_v := "1111";
      --
      case data_idx_q is
        when "00" => mem_sel_r_v := "0001";
        when "01" => mem_sel_r_v := "0011";
        when "10" => mem_sel_r_v := "0111";
        when "11" => mem_sel_r_v := "1111";
        when others => null;
      end case;
      --
      case mem_addr_q(1 downto 0) is
        when "00" => mem_sel_r_v := mem_sel_r_v and "1111";
        when "01" => mem_sel_r_v := mem_sel_r_v and "1110";
        when "10" => mem_sel_r_v := mem_sel_r_v and "1100";
        when "11" => mem_sel_r_v := mem_sel_r_v and "1000";
        when others => null;
      end case;
      mem_sel_r <= mem_sel_r_v;
    end process p_c_msel;
    --
    mem_wdata_o <= data_q;
    data_w      <= mem_rdata_i;
    --
  end generate g_axi32;
  --
  --
  g_axi64 : if ( AXIDATA_W = 64 ) generate
  begin
    p_c_msel : process (data_idx_q, mem_addr_q)
      variable mem_sel_r_v : slv_03_00; -- slv_t(mem_sel_r'range);
    begin
      mem_sel_r_v := "1111";
      --
      case data_idx_q is
        when "00" => mem_sel_r_v := "0001";
        when "01" => mem_sel_r_v := "0011";
        when "10" => mem_sel_r_v := "0111";
        when "11" => mem_sel_r_v := "1111";
        when others => null;
      end case;
      --
      case mem_addr_q(1 downto 0) is
        when "00" => mem_sel_r_v := mem_sel_r_v and "1111";
        when "01" => mem_sel_r_v := mem_sel_r_v and "1110";
        when "10" => mem_sel_r_v := mem_sel_r_v and "1100";
        when "11" => mem_sel_r_v := mem_sel_r_v and "1000";
        when others => null;
      end case;
      if (mem_addr_q(2) = '0') then
        mem_sel_r <= "0000" & mem_sel_r_v;
      else
        mem_sel_r <= mem_sel_r_v & "0000";
      end if;
    end process p_c_msel;
    --
    mem_wdata_o <= data_q & data_q;
    data_w      <= mem_rdata_i(63 downto 32) when (mem_addr_q(2) = '1')
                   else mem_rdata_i(31 downto 0);
    --
  end generate g_axi64;



  p_msel : process (clk_i)
  begin
    if ( rising_edge(clk_i) ) then
      if (xrst_i = '0') then
        mem_sel_q    <= (others => '0');  -- X"0"
      -- Idle - reset for read requests
      else
        if (state_q = STATE_IDLE) then
          mem_sel_q   <= (others => '1'); -- "1111";
        -- Every 4th byte, issue bus access
        elsif (state_q = STATE_WRITE and rx_valid_w = '1' and
               (data_idx_q = "11" or unsigned(len_q) = 1)) then
          mem_sel_q   <= mem_sel_r;
        end if;
      end if;
    end if;
  end process p_msel;


  mem_wstrb_o  <= mem_sel_q;


  -- - - - - - - - - - - - -
  -- Write enable
  -- - - - - - - - - - - - -
  p_mwr : process (clk_i)
  begin
    if ( rising_edge(clk_i) ) then
      if (xrst_i = '0') then
        mem_wr_q    <= '0';
      else
        if (state_q = STATE_IDLE and rx_valid_w = '1') then
          if (rx_data_w = REQ_WRITE) then
            mem_wr_q <= '1';
          else
            mem_wr_q <= '0';
          end if;
        end if;
      end if;
    end if;
  end process p_mwr;


  -- - - - - - - - - - - - -
  -- Access in progress
  -- - - - - - - - - - - - -
  p_mbusy : process (clk_i)
  begin
    if ( rising_edge(clk_i) ) then
      if (xrst_i = '0') then
        mem_busy_q <= '0';
      else
        if (mem_arvalid_o_w = '1' or mem_awvalid_o_w = '1') then
          mem_busy_q <= '1';
        elsif (mem_bvalid_i = '1' or mem_rvalid_i = '1') then
          mem_busy_q <= '0';
        end if;
      end if;
    end if;
  end process p_mbusy;


end rtl;
