-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--
-- 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;

-- pragma translate_off
use std.textio.all;
library std_developerskit;
use std_developerskit.std_iopak.all;
-- pragma translate_on

entity rv_soc_tb is
    generic ( AXIDATA_W   : natural range 32 to 64 := 32;     -- 32b/64b alowed
              CLK_FREQ    : natural := 50000000;              -- default 50M
              UART_SPEED  : natural :=  1000000;              -- default 1M
              NR_GPIOS    : integer range 1 to 32 := 16 );    -- 
end entity rv_soc_tb;


architecture rtl of rv_soc_tb is
  
  constant CLK_CYCLE       : time    := 1000000 us / CLK_FREQ;
  constant UART_CYCLES     : natural := (CLK_FREQ/UART_SPEED)-1;


  -- THESE ARE JUST FOR DEBUG
  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));
--  slv_t(to_unsigned(CLK_FREQ/RV_UART_SPEED, UART_DIVISOR_W));

  constant UART_BIT_TIME  : time := (CLK_FREQ/UART_SPEED) *  CLK_CYCLE;


  signal dbg_bit_time     : time := UART_BIT_TIME;
  signal dbg_rddata32_w   : slv_31_00;
  signal dbg_rddata64_w   : slv_63_00;
  signal dbg_vs_rxbyte_w  : slv_07_00;



  component rv_soc
    generic ( AXIDATA_W   : natural range 32 to 64 := 32;  -- 32b/64b alowed
              CLK_FREQ    : natural := 50000000;           -- default 50M
              UART_SPEED  : natural :=  1000000;           -- default 1M
              NR_GPIOS    : integer range 1 to 32 := 9 +6 );
    port ( clk_i          : in  std_logic;
           xrst_i         : in  std_logic;                 -- syncr reset
           --
           --  NOTE: vs_rst_cpu_i is actually "enable", synchronized to clk_i
           vs_rst_cpu_i    : in  std_logic;                -- riscv core only
           --
           xmem_awready_i  : in  std_logic;                -- xmem
           xmem_wready_i   : in  std_logic;
           xmem_bvalid_i   : in  std_logic;
           xmem_bresp_i    : in  slv_01_00;
           xmem_bid_i      : in  slv_03_00;
           xmem_arready_i  : in  std_logic;
           xmem_rvalid_i   : in  std_logic;
           xmem_rdata_i    : in  slv_t(AXIDATA_W-1 downto 0);
           xmem_rresp_i    : in  slv_01_00;
           xmem_rid_i      : in  slv_03_00;
           xmem_rlast_i    : in  std_logic;
           xmem_awvalid_o  : out std_logic;
           xmem_awaddr_o   : out slv_31_00;
           xmem_awid_o     : out slv_03_00;
           xmem_awlen_o    : out slv_07_00;
           xmem_awburst_o  : out slv_01_00;
           xmem_wvalid_o   : out std_logic;
           xmem_wdata_o    : out slv_t(AXIDATA_W-1 downto 0);
           xmem_wstrb_o    : out slv_t(AXIDATA_W/8-1 downto 0);
           xmem_wlast_o    : out std_logic;
           xmem_bready_o   : out std_logic;
           xmem_arvalid_o  : out std_logic;
           xmem_araddr_o   : out slv_31_00;
           xmem_arid_o     : out slv_03_00;
           xmem_arlen_o    : out slv_07_00;
           xmem_arburst_o  : out slv_01_00;
           xmem_rready_o   : out std_logic;
           --
           pll_cfg_i       : in  slv_08_00;
           --
           uart_txd_i      : in  std_logic;                -- io pins
           uart_rxd_o      : out std_logic;
           uart2_txd_i     : in  std_logic;
           uart2_rxd_o     : out std_logic;
           --
           spi_clk_o       : out std_logic;
           spi_cs_o        : out std_logic;
           spi_miso_i      : in  std_logic;
           spi_mosi_o      : out std_logic;
           spi_mosi_i      : in  std_logic;
           --
           gpio_i          : in  slv_t(NR_GPIOS-1 downto 0);
           gpio_o          : out slv_t(NR_GPIOS-1 downto 0);
           gpio_xena_o     : out slv_t(NR_GPIOS-1 downto 0);
           gpio_pdena_o    : out slv_t(NR_GPIOS-1 downto 0);
           gpio_puena_o    : out slv_t(NR_GPIOS-1 downto 0) );
  end component;


  component axi_sram
    generic ( AXIDATA_W   : natural range 32 to 64 := 32;
              ram_size_g  : natural := 16*1024; -- in 32bit words, NOT FOR MIF
              -- NOTE: if mif file is not given then :
              --    "mif_file_name" : init mem with boot code
              --    "-linear_data-" : linear data is used (0,1,2,3...)
              --    "-zero_data-"   : mem array is reset (all bits '0')
              --    "-one_data-"    : mem array is set   (all bits '1')
              --    "-unknown-"     : else all mem is 'U'
              mif_file_g  : string  := "-unknown-" ); -- edit if mif file used
    port ( clk_i          : in  std_logic;
           xrst_i         : in  std_logic; -- xreset
           --
           --  AXI slave if INPUTS (16)
           --
           axi_awvalid_i  : in  std_logic;
           axi_awaddr_i   : in  slv_31_00;
           axi_awid_i     : in  slv_03_00;
           axi_awlen_i    : in  slv_07_00;
           axi_awburst_i  : in  slv_01_00;
           axi_wvalid_i   : in  std_logic;
           axi_wdata_i    : in  slv_t(AXIDATA_W-1 downto 0);
           axi_wstrb_i    : in  slv_t(AXIDATA_W/8-1 downto 0);
           axi_wlast_i    : in  std_logic;
           axi_bready_i   : in  std_logic;
           axi_arvalid_i  : in  std_logic;
           axi_araddr_i   : in  slv_31_00;
           axi_arid_i     : in  slv_03_00;
           axi_arlen_i    : in  slv_07_00;
           axi_arburst_i  : in  slv_01_00;
           axi_rready_i   : in  std_logic;
           --
           --  AXI slave if OUTPUTS (11)
           --
           axi_awready_o  : out std_logic;
           axi_wready_o   : out std_logic;
           axi_bvalid_o   : out std_logic;
           axi_bresp_o    : out slv_01_00;
           axi_bid_o      : out slv_03_00;
           axi_arready_o  : out std_logic;
           axi_rvalid_o   : out std_logic;
           axi_rdata_o    : out slv_t(AXIDATA_W-1 downto 0);
           axi_rresp_o    : out slv_01_00;
           axi_rid_o      : out slv_03_00;
           axi_rlast_o    : out std_logic );
  end component;


  signal clk_i           : std_logic := '0';
  signal xrst_i          : std_logic;                      -- syncr reset
  signal vs_rst_cpu_i    : std_logic;    
  signal xmem_awready_i  : std_logic;                      -- xmem AX if
  signal xmem_wready_i   : std_logic;
  signal xmem_bvalid_i   : std_logic;
  signal xmem_bresp_i    : slv_01_00;
  signal xmem_bid_i      : slv_03_00;
  signal xmem_arready_i  : std_logic;
  signal xmem_rvalid_i   : std_logic;
  signal xmem_rdata_i    : slv_t(AXIDATA_W-1 downto 0);
  signal xmem_rresp_i    : slv_01_00;
  signal xmem_rid_i      : slv_03_00;
  signal xmem_rlast_i    : std_logic;
  signal xmem_awvalid_o  : std_logic;
  signal xmem_awaddr_o   : slv_31_00;
  signal xmem_awid_o     : slv_03_00;
  signal xmem_awlen_o    : slv_07_00;
  signal xmem_awburst_o  : slv_01_00;
  signal xmem_wvalid_o   : std_logic;
  signal xmem_wdata_o    : slv_t(AXIDATA_W-1 downto 0);
  signal xmem_wstrb_o    : slv_t(AXIDATA_W/8-1 downto 0);
  signal xmem_wlast_o    : std_logic;
  signal xmem_bready_o   : std_logic;
  signal xmem_arvalid_o  : std_logic;
  signal xmem_araddr_o   : slv_31_00;
  signal xmem_arid_o     : slv_03_00;
  signal xmem_arlen_o    : slv_07_00;
  signal xmem_arburst_o  : slv_01_00;
  signal xmem_rready_o   : std_logic;
  --
  signal uart_txd_i      : std_logic;                       -- io pins
  signal uart_rxd_o      : std_logic;
  signal uart2_txd_i     : std_logic;
  signal uart2_rxd_o     : std_logic;
  --
  signal spi_miso_i      : std_logic;
  signal spi_clk_o       : std_logic;
  signal spi_cs_o        : std_logic;
  signal spi_mosi_o      : std_logic;
  signal spi_mosi_i      : std_logic;
  --
  signal gpio_i          : slv_t(NR_GPIOS-1 downto 0);
  signal gpio_o          : slv_t(NR_GPIOS-1 downto 0);
  signal gpio_xena_o     : slv_t(NR_GPIOS-1 downto 0);
  signal gpio_pdena_o    : slv_t(NR_GPIOS-1 downto 0);
  signal gpio_puena_o    : slv_t(NR_GPIOS-1 downto 0);

begin


  clk_i   <= not clk_i after 20 ns / 2;
  xrst_i  <= '0', '1' after 73 ns;


  u_rv_soc: rv_soc
    generic map ( AXIDATA_W   => AXIDATA_W,
                  CLK_FREQ    => CLK_FREQ,                   -- default 50M
                  UART_SPEED  => UART_SPEED,                 -- default 1M
                  NR_GPIOS    => NR_GPIOS )
    port map ( clk_i           => clk_i,
               xrst_i          => xrst_i,                    -- syncr reset
               -- NOTE: vs_rst_cpu_i is actually "enable", synchronized to clk_i
               vs_rst_cpu_i     => vs_rst_cpu_i,             -- riscv core only
               --
               xmem_awready_i  => xmem_awready_i,            -- xmem
               xmem_wready_i   => xmem_wready_i,
               xmem_bvalid_i   => xmem_bvalid_i,
               xmem_bresp_i    => xmem_bresp_i,
               xmem_bid_i      => xmem_bid_i,
               xmem_arready_i  => xmem_arready_i,
               xmem_rvalid_i   => xmem_rvalid_i,
               xmem_rdata_i    => xmem_rdata_i,
               xmem_rresp_i    => xmem_rresp_i,
               xmem_rid_i      => xmem_rid_i,
               xmem_rlast_i    => xmem_rlast_i,
               xmem_awvalid_o  => xmem_awvalid_o,
               xmem_awaddr_o   => xmem_awaddr_o,
               xmem_awid_o     => xmem_awid_o,
               xmem_awlen_o    => xmem_awlen_o,
               xmem_awburst_o  => xmem_awburst_o,
               xmem_wvalid_o   => xmem_wvalid_o,
               xmem_wdata_o    => xmem_wdata_o,
               xmem_wstrb_o    => xmem_wstrb_o,
               xmem_wlast_o    => xmem_wlast_o,
               xmem_bready_o   => xmem_bready_o,
               xmem_arvalid_o  => xmem_arvalid_o,
               xmem_araddr_o   => xmem_araddr_o,
               xmem_arid_o     => xmem_arid_o,
               xmem_arlen_o    => xmem_arlen_o,
               xmem_arburst_o  => xmem_arburst_o,
               xmem_rready_o   => xmem_rready_o,
               --
               pll_cfg_i       => (others => '0'),
               --
               uart_txd_i      => uart_txd_i,                -- io pins
               uart_rxd_o      => uart_rxd_o,
               uart2_txd_i     => uart2_txd_i,
               uart2_rxd_o     => uart2_rxd_o,
               --
               spi_clk_o       => spi_clk_o,
               spi_cs_o        => spi_cs_o,
               spi_miso_i      => spi_miso_i,
               spi_mosi_o      => spi_mosi_o,
               spi_mosi_i      => spi_mosi_i,
               --
               gpio_i          => gpio_i,
               gpio_xena_o     => gpio_xena_o,
               gpio_o          => gpio_o,
               gpio_pdena_o    => gpio_pdena_o,
               gpio_puena_o    => gpio_puena_o );


  uart_txd_i     <= 'H';                                     -- io pins
--uart_rxd_o
  uart2_txd_i    <= 'H';
--uart2_rxd_o
  --
--spi_clk_o
--spi_cs_o
--spi_mosi_o
  --
  gpio_i         <= "LLLLLLLLLLLLLLLL";
--gpio_xena_o    -- 15:0
--gpio_o         -- 15:0


  u_axi_sram : axi_sram
    generic map ( AXIDATA_W    => AXIDATA_W,
                  ram_size_g   => 16*1024,   -- in 32bit words, NOT FOR MIF
                  -- NOTE: if mif file is not given then :
                  --    "mif_file_name" : init mem with boot code
                  --    "-linear_data-" : linear data is used (0,1,2,3...)
                  --    "-zero_data-"   : mem array is reset (all bits '0')
                  --    "-one_data-"    : mem array is set   (all bits '1')
                  --    "-unknown-"     : else all mem is 'U'
                  --
                  -- Linux 4.20 kerner image,  edit if other mif file used
                  mif_file_g    => "../rtl/tb/linux_riscv_soc.elf.mif" )
              --  mif_file_g    => "-linear_data-" )
    port map ( clk_i            => clk_i,
               xrst_i           => xrst_i,
               --
               -- AXI slave if INPUTS (16)
               --
               axi_awvalid_i    => xmem_awvalid_o,
               axi_awaddr_i     => xmem_awaddr_o,
               axi_awid_i       => xmem_awid_o,
               axi_awlen_i      => xmem_awlen_o,
               axi_awburst_i    => xmem_awburst_o,
               axi_wvalid_i     => xmem_wvalid_o,
               axi_wdata_i      => xmem_wdata_o,
               axi_wstrb_i      => xmem_wstrb_o,
               axi_wlast_i      => xmem_wlast_o,
               axi_bready_i     => xmem_bready_o,
               axi_arvalid_i    => xmem_arvalid_o,
               axi_araddr_i     => xmem_araddr_o,
               axi_arid_i       => xmem_arid_o,
               axi_arlen_i      => xmem_arlen_o,
               axi_arburst_i    => xmem_arburst_o,
               axi_rready_i     => xmem_rready_o,
               --
               -- AXI slave if OUTPUTS (11)
               --
               axi_awready_o    => xmem_awready_i,
               axi_wready_o     => xmem_wready_i,
               axi_bvalid_o     => xmem_bvalid_i,
               axi_bresp_o      => xmem_bresp_i,
               axi_bid_o        => xmem_bid_i,
               axi_arready_o    => xmem_arready_i,
               axi_rvalid_o     => xmem_rvalid_i,
               axi_rdata_o      => xmem_rdata_i,
               axi_rresp_o      => xmem_rresp_i,
               axi_rid_o        => xmem_rid_i,
               axi_rlast_o      => xmem_rlast_i );






  p_test : process
    --
    --
    variable pattern4_v   : slv_03_00;
    variable pattern32_v  : slv_31_00;
    variable rd_cmd_v     : slv_31_00;
    --
    --
    ---  - - - - - - ! ! ! ! ! RISCV UART ROUTINES ! ! ! ! ! - - - - - - -
    --
    --
    procedure sendbyte ( byte : in slv_07_00 ) is
      variable tmpdata_v    : slv_t(1+7+1 downto 0);  -- start + data + stop
    begin
      uart_txd_i      <= '1';
      tmpdata_v  := '1' & byte & '0';      -- stop bit, data, start bit
      wait on clk_i until clk_i = '1';
      for ii in 0 to tmpdata_v'high loop
        uart_txd_i <= tmpdata_v(ii);       -- sending start bit, data, stop bit
        wait for 1 ps;
        wait for 1 ps;
        if (ii < tmpdata_v'high) then
          -- wait for UART_BIT_TIME_c;
          for jj in 0 to UART_CYCLES loop
            wait on clk_i until clk_i = '1';
          end loop;
        else
          -- stop bit sending released earlier
          -- wait for UART_BIT_TIME_c*3/4;    -- ! ! idle, should be enough
          for jj in 0 to UART_CYCLES loop
            wait on clk_i until clk_i = '1';
          end loop;
        end if;
      end loop;
      -- wait for 1 ps;
    end sendbyte;
    --
    --
    --
    procedure receivebyte ( signal byte : out slv_07_00 ) is
      variable tmpdata_v : slv_07_00;
      variable timeout_v : natural;
    begin
      tmpdata_v  := X"00";                 -- received byte
      timeout_v  := 0;
      while uart_rxd_o = '1' loop
        wait on clk_i until clk_i = '1';
        timeout_v  := timeout_v + 1;
        if (timeout_v * CLK_CYCLE > 1 ms) then
          report "  ERROR: Stuck in uart receivebyte for 1 ms !"
            severity ERROR;
          timeout_v  := 0;
        end if;
      end loop;
      --
      -- wait for UART_BIT_TIME/2;         -- ! ! in middle of start bit
      for jj in 0 to UART_CYCLES/2 loop
        wait on clk_i until clk_i = '1';
      end loop;
      for ii in 0 to tmpdata_v'high loop
        -- wait for UART_BIT_TIME_c;
        for jj in 0 to UART_CYCLES loop
          wait on clk_i until clk_i = '1';
        end loop;
        tmpdata_v(ii) := uart_rxd_o;                       -- received bit
      end loop;
      --
      -- wait for UART_BIT_TIME_c;
      for jj in 0 to UART_CYCLES loop
        wait on clk_i until clk_i = '1';
      end loop;
      assert (uart_rxd_o = '1') report "ERROR: Stop bit error!"
        severity FAILURE;
      --
      byte <= tmpdata_v;
      wait for 0 ns;
    end receivebyte;
    --
    --
    --
    -- REQ_WRITE = X"10",  LEN, ADDR3,2,1,0,  DATA0,1,2,3
    -- REQ_READ  = X"11";  LEN, ADDR3,2,1,0
    --
    procedure wr_word ( cmd : slv_07_00;             -- wr: 0x10, rd: 0x11
                        len : slv_07_00;             -- 4: 32 bits
                        adr : slv_31_00;             -- addr
                        dat : slv_31_00 ) is         -- data
    begin
      sendbyte(cmd);
      sendbyte(len);
      --
      sendbyte(adr(31 downto 24));                   -- ! ! NOTE: MSB BYTE 1ST
      sendbyte(adr(23 downto 16));
      sendbyte(adr(15 downto 8));
      sendbyte(adr(7  downto 0));
      --
      sendbyte(dat(7  downto 0));                    -- ! ! NOTE: LSB BYTE 1ST
      sendbyte(dat(15 downto 8));
      sendbyte(dat(23 downto 16));
      sendbyte(dat(31 downto 24));
      -- wait for 1 ps;
    end wr_word;
    --
    --
    --
    procedure rd_word ( cmd           : slv_07_00;         -- wr:0x10, rd:0x11
                        len           : slv_07_00;         -- 4: 32 bits
                        adr           : slv_31_00;
                        signal data32 : out slv_31_00) is  -- addr
    begin
      sendbyte(cmd);
      sendbyte(len);
      --
      sendbyte(adr(31 downto 24));                   -- ! ! NOTE: MSB BYTE 1ST
      sendbyte(adr(23 downto 16));
      sendbyte(adr(15 downto 8));
      sendbyte(adr(7  downto 0));
      --
      receivebyte(data32( 7 downto  0));             -- ! ! NOTE: LSB BYTE 1ST
      receivebyte(data32(15 downto  8));
      receivebyte(data32(23 downto 16));
      receivebyte(data32(31 downto 24));
      wait for 0 ps;
    end rd_word;
    --
    --
    --
    -- REQ_WRITE = X"10",  LEN, ADDR3,2,1,0,  DATA0,1,2,3
    -- REQ_READ  = X"11";  LEN, ADDR3,2,1,0
    --
    procedure wr_word64 ( cmd : slv_07_00;             -- wr: 0x10, rd: 0x11
                          len : slv_07_00;             -- 4: 32 bits
                          adr : slv_31_00;             -- addr
                          dat : slv_63_00) is          -- data
    begin
      sendbyte(cmd);
      sendbyte(len);
      --
      sendbyte(adr(31 downto 24));                   -- ! ! NOTE: MSB BYTE 1ST
      sendbyte(adr(23 downto 16));
      sendbyte(adr(15 downto 8));
      sendbyte(adr(7  downto 0));
      --
      sendbyte(dat(7  downto 0));                    -- ! ! NOTE: LSB BYTE 1ST
      sendbyte(dat(15 downto 8));
      sendbyte(dat(23 downto 16));
      sendbyte(dat(31 downto 24));
      sendbyte(dat(39 downto 32));
      sendbyte(dat(47 downto 40));
      sendbyte(dat(55 downto 48));
      sendbyte(dat(63 downto 56));
      -- wait for 1 ps;
    end wr_word64;
    --
    --
    --
    procedure rd_word64 ( cmd           : slv_07_00;         -- wr:0x10, rd:0x11
                          len           : slv_07_00;         -- 4: 32 bits
                          adr           : slv_31_00;
                          signal data64 : out slv_63_00) is  -- addr
    begin
      sendbyte(cmd);
      sendbyte(len);
      --
      sendbyte(adr(31 downto 24));                   -- ! ! NOTE: MSB BYTE 1ST
      sendbyte(adr(23 downto 16));
      sendbyte(adr(15 downto 8));
      sendbyte(adr(7  downto 0));
      --
      receivebyte(data64( 7 downto  0));             -- ! ! NOTE: LSB BYTE 1ST
      receivebyte(data64(15 downto  8));
      receivebyte(data64(23 downto 16));
      receivebyte(data64(31 downto 24));
      receivebyte(data64(39 downto 32));
      receivebyte(data64(47 downto 40));
      receivebyte(data64(55 downto 48));
      receivebyte(data64(63 downto 56));
      wait for 0 ps;
    end rd_word64;

  begin
    vs_rst_cpu_i <= '1';

    pattern4_v   := (others => '0');
    pattern32_v  := (others => '0');
    rd_cmd_v     := (others => '0');
    -- riscv uart
    uart_txd_i   <= 'H';
    uart_rxd_o   <= 'Z';

    spi_miso_i   <= '0';
    spi_mosi_i   <= '0';
    
    wait on xrst_i until xrst_i = '1';
    wait for 10*CLK_CYCLE;
    wait on clk_i until clk_i = '1';
    
    wait for 3 ns;


    --
    --
    -- RISCV BOOT
    --
    --
    if (  1   >0) then
      -- enable riscv core (release from reset)
      wr_word(X"10", X"04", X"F0000000", X"00000001");
      while (TRUE) loop
        wait on clk_i until clk_i = '1';
      end loop;
    end if;




    --
    --
    --
    -- RISCV CACHE WR / RD TESTS
    --
    --
    --
    if (  0   >0) then

      -- enable mbist (read/write cache instead of DDR)
      -- ! ! ! MBIST MUST BE ENABLED AS IT CONNECTS RAMS TO DBG UART
      wr_word(X"10", X"04", X"F0000008", X"00000100");


      -- ! ! !
      -- ! ! ! NOTE : 64 bit data word order in RAM is flipped in write
      -- ! ! !        I.e. X"12345678FACE0000" is written in ram as
      -- ! ! !             X"FACE0000" & X"12345678"
      -- ! ! !


      -- ! ! ! MBIST __IO__ ADDRESS
      wr_word64(X"10", X"08", X"F010000C", X"12345678FACE0000"); -- idat0
      wr_word64(X"10", X"08", X"F01000AC", X"BEEFBEEFCAFECAFE"); -- idat0
      --
      wr_word64(X"10", X"08", X"F0403FFC", X"BEEF1111FACE0001"); -- idat1
      --
      wr_word64(X"10", X"08", X"F1007FFC", X"CAFE0000FACE0002"); -- ddat0
      --
      wr_word64(X"10", X"08", X"F400FFFC", X"FEDCBA98FACE0003"); -- ddat1

      rd_cmd_v := X"F010000C" or (slv_t(to_unsigned(   0*16,32))); --ad<<4 idat0
      rd_word64(X"11", X"08", rd_cmd_v, dbg_rddata64_w);   -- idat0
      assert (dbg_rddata64_w = X"FACE000012345678")
        report "  FATAL: idata0 read failed!"
        severity FAILURE;

      rd_cmd_v := X"F040000C" or (slv_t(to_unsigned(1023*16,32))); --ad<<4 idat1
      rd_word64(X"11", X"08", rd_cmd_v, dbg_rddata64_w);   -- idat1
      assert (dbg_rddata64_w = X"FACE0001BEEF1111")
        report "  FATAL: idata1 read failed!"
        severity FAILURE;

      rd_cmd_v := X"F100000C" or (slv_t(to_unsigned(2047*16,32))); --ad<<4 ddat0
      rd_word64(X"11", X"08", rd_cmd_v, dbg_rddata64_w);   -- ddat0
      assert (dbg_rddata64_w = X"FACE0002CAFE0000")
        report "  FATAL: ddata0 read failed!"
        severity FAILURE;

      rd_cmd_v := X"F400000C" or (slv_t(to_unsigned(4095*16,32))); --ad<<4 ddat1
      rd_word64(X"11", X"08", rd_cmd_v, dbg_rddata64_w);   -- ddat1
      assert (dbg_rddata64_w = X"FACE0003FEDCBA98")
        report "  FATAL: ddata1 read failed!"
        severity FAILURE;


      -- ! ! ! MBIST __IO__ ADDRESS
      wr_word(X"10", X"04", X"F020000C", X"00FACE00"); -- itag0
      wr_word(X"10", X"04", X"F080080C", X"00ACE551"); -- itag1
      wr_word(X"10", X"04", X"F200100C", X"00BADAA2"); -- dtag0
      wr_word(X"10", X"04", X"F8001FFC", X"0034FACE"); -- dtag1
      --
      rd_cmd_v := X"F020000C" or (slv_t(to_unsigned(  0*16,32))); -- <<4 itag0
      rd_word(X"11", X"04", rd_cmd_v, dbg_rddata32_w); -- itag0
      assert (dbg_rddata32_w = X"00FACE00")
        report "  FATAL: itag0 read failed!"
        severity FAILURE;

      rd_cmd_v := X"F080000C" or (slv_t(to_unsigned(128*16,32))); -- <<4 itag1
      rd_word(X"11", X"04", rd_cmd_v, dbg_rddata32_w); -- itag1
      assert (dbg_rddata32_w = X"00ACE551")
        report "  FATAL: itag1 read failed!"
        severity FAILURE;

      rd_cmd_v := X"F200000C" or (slv_t(to_unsigned(256*16,32))); -- <<4 dtag0
      rd_word(X"11", X"04", rd_cmd_v, dbg_rddata32_w); -- dtag0
      assert (dbg_rddata32_w = X"00BADAA2")
        report "  FATAL: dtag0 read failed!"
        severity FAILURE;

      rd_cmd_v := X"F800000C" or (slv_t(to_unsigned(511*16,32))); -- <<4 dtag1
      rd_word(X"11", X"04", rd_cmd_v, dbg_rddata32_w); -- dtag1
      assert (dbg_rddata32_w = X"0034FACE")
        report "  FATAL: dtag1 read failed!"
        severity FAILURE;

      report "  RD / WR tests done!"
        severity FAILURE;
    end if;




    
    while (TRUE) loop
      wait on clk_i until clk_i = '1';
    end loop;

  end process p_test;




  
end rtl;
