-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--
-- 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 ram_bridge is
  generic ( AXIDATA_W           : natural range 32 to 64 := 32;
            SUPPORT_FIXED_BURST : boolean := false;
            SUPPORT_WRAP_BURST  : boolean := false );
  port ( clk_i          : in  std_logic;
         xrst_i         : in  std_logic;              -- xreset
         --
         ram_accept_i   : in  std_logic;
         ram_rdata_i    : in  slv_t(AXIDATA_W-1 downto 0);
         ram_wr_o       : out slv_t(AXIDATA_W/8-1 downto 0);   -- 64b / 32b
         ram_rd_o       : out std_logic;
         ram_addr_o     : out slv_31_00;
         ram_wdata_o    : out slv_t(AXIDATA_W-1 downto 0);
         --
         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);   -- 64b / 32b
         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_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 entity ram_bridge;


architecture rtl of ram_bridge is

  -- - - - - - - - - - - - -
  -- calculate_addr_next
  -- - - - - - - - - - - - -
  function calculate_addr_next ( addr   : slv_31_00;
                                 axtype : slv_01_00;
                                 axlen  : slv_07_00 ) return slv_31_00 is
    variable mask_v : slv_31_00;
    variable tmp_v  : slv_31_00;
  begin
    mask_v := X"00000000";
    tmp_v  := X"00000000";
    if (axtype = "00" and SUPPORT_FIXED_BURST) then      -- AXI4_BURST_FIXED
      tmp_v := addr;
    elsif (axtype = "10" and SUPPORT_WRAP_BURST) then    -- AXI4_BURST_WRAP
      case axlen is
        when X"00" =>  mask_v := X"00000003";
        when X"01" =>  mask_v := X"00000007";
        when X"03" =>  mask_v := X"0000000F";
        when X"07" =>  mask_v := X"0000001F";
        when X"15" =>  mask_v := X"0000003F";
        when others => mask_v := X"0000003F";
      end case;
      if (AXIDATA_W /= 64) then
        tmp_v := (addr and (not(mask_v)))  or  (addu(addr, 4) and mask_v);
      else
        tmp_v := (addr and (not(mask_v)))  or  (addu(addr, 8) and mask_v);
      end if;
    else                                                 -- AXI4_BURST_INCR
      if (AXIDATA_W /= 64) then
        tmp_v := addu(addr, 4);
      else
        tmp_v := addu(addr, 8);
      end if;
    end if;
    return tmp_v;
  end;

  -- - - - - - - - - - - - -
  --  registers / wires
  -- - - - - - - - - - - - -
  signal req_len_q        : slv_07_00;
  signal req_addr_q       : slv_31_00;
  signal req_rd_q         : std_logic;
  signal req_wr_q         : std_logic;
  signal req_id_q         : slv_03_00;
  signal req_axburst_q    : slv_01_00;
  signal req_axlen_q      : slv_07_00;

  signal bvalid_q         : std_logic;
  signal rvalid_q         : std_logic;
  signal rlast_q          : std_logic;
  signal rbuf_valid_q     : std_logic;
  signal rbuf_data_q      : slv_t(AXIDATA_W-1 downto 0);
  signal rbuf_last_q      : std_logic;

  signal resp_pending_w   : std_logic;

  signal write_active     : std_logic;
  signal read_active      : std_logic;
  signal addr_w           : slv_31_00;
  signal wr_w             : std_logic;
  signal rd_w             : std_logic;

  signal axi_wready_o_w   : std_logic;
  signal axi_awready_o_w  : std_logic;
  signal axi_arready_o_w  : std_logic;
  signal axi_rvalid_o_w   : std_logic;
  signal axi_rdata_o_w    : slv_t(AXIDATA_W-1 downto 0);
  signal axi_rlast_o_w    : std_logic;
  signal axi_bvalid_o_w   : std_logic;

begin

  -- - - - - - - - - - - - -
  --  sequential
  -- - - - - - - - - - - - -
  p_axi : process (clk_i)
  begin
    if (clk_i'event and clk_i = '1') then
      if (xrst_i = '0') then
        req_len_q     <= X"00";                         -- 8b
        req_addr_q    <= X"00000000";                   -- 32b
        req_wr_q      <= '0';                           -- 1b
        req_rd_q      <= '0';                           -- 1b
        req_id_q      <= X"0";                          -- 4b
        req_axburst_q <= "00";                          -- 2b
        req_axlen_q   <= X"00";                         -- 8b
        bvalid_q      <= '0';                           -- 1b
        rvalid_q      <= '0';                           -- 1b
        rlast_q       <= '0';                           -- 1b
        rbuf_valid_q  <= '0';                           -- 1b
        rbuf_data_q   <= (others => '0');               -- 32b/64b
        rbuf_last_q   <= '0';                           -- 1b
      else
        rvalid_q <= '0';
        rlast_q  <= '0';

        if (axi_bready_i = '1') then
          bvalid_q <= '0';
        end if;
        --  burst continuation
        if ((req_rd_q = '1' and ram_accept_i = '1'
             and axi_rready_i = '1') or                 -- read accepted
            (req_wr_q = '1' and axi_wvalid_i = '1' and
             axi_wready_o_w = '1')) then                -- write data presented
          rvalid_q <= req_rd_q;

          if (unsigned(req_len_q) = 0) then
            bvalid_q   <= req_wr_q;
            rlast_q    <= req_rd_q;
            req_rd_q   <= '0';
            req_wr_q   <= '0';
          else
            req_addr_q <= calculate_addr_next(req_addr_q, req_axburst_q,
                                              req_axlen_q);
            req_len_q  <= dec1u(req_len_q);
          end if;
        end if;

        --  write command accepted
        if (axi_awvalid_i = '1' and axi_awready_o_w = '1') then
          --  data ready?
          if (axi_wvalid_i = '1' and axi_wready_o_w = '1') then
            req_wr_q      <= not axi_wlast_i;
            req_len_q     <= dec1u(axi_awlen_i);
            req_id_q      <= axi_awid_i;
            req_axburst_q <= axi_awburst_i;
            req_axlen_q   <= axi_awlen_i;

            req_addr_q    <= calculate_addr_next(axi_awaddr_i, axi_awburst_i,
                                                 axi_awlen_i);

            bvalid_q      <= axi_wlast_i;
            --  data not ready
          else
            req_wr_q      <= '1';
            req_len_q     <= axi_awlen_i;
            req_id_q      <= axi_awid_i;
            req_axburst_q <= axi_awburst_i;
            req_axlen_q   <= axi_awlen_i;
            req_addr_q    <= axi_awaddr_i;
          end if;
          --  read command accepted
        elsif (axi_arvalid_i = '1' and axi_arready_o_w = '1') then
          req_rd_q      <= '0';
          if (unsigned(axi_arlen_i) /= 0) then
            req_rd_q    <= '1';
          end if;
          req_rd_q      <= '0';
          if (unsigned(axi_arlen_i) /= 0) then
            req_rd_q    <= '1';
          end if;
          req_len_q     <= dec1u(axi_arlen_i);
          req_addr_q    <= calculate_addr_next(axi_araddr_i, axi_arburst_i,
                                               axi_arlen_i);
          req_id_q      <= axi_arid_i;
          req_axburst_q <= axi_arburst_i;
          req_axlen_q   <= axi_arlen_i;

          rvalid_q      <= '1';
          rlast_q       <= '0';
          if (unsigned(axi_arlen_i) = 0) then
            rlast_q     <= '1';
          end if;
        end if;

        --  response skid buffer
        if (axi_rvalid_o_w = '1' and axi_rready_i = '0') then
          rbuf_valid_q <= '1';
          rbuf_data_q  <= axi_rdata_o_w;
          rbuf_last_q  <= axi_rlast_o_w;
        else
          rbuf_valid_q <= '0';
        end if;
      end if;
    end if;
  end process p_axi;


  -- - - - - - - - - - - - -
  --  assignments
  -- - - - - - - - - - - - -
  axi_bvalid_o_w   <= bvalid_q;
  axi_bvalid_o     <= axi_bvalid_o_w;

  axi_bresp_o      <= "00";
  axi_bid_o        <= req_id_q;

  axi_rvalid_o_w   <= rvalid_q or rbuf_valid_q;
  axi_rvalid_o     <= axi_rvalid_o_w;
  axi_rresp_o      <= "00";
  axi_rdata_o_w    <= rbuf_data_q when (rbuf_valid_q = '1') else ram_rdata_i;

  axi_rdata_o      <= axi_rdata_o_w;

  axi_rid_o        <= req_id_q;
  axi_rlast_o_w    <= rbuf_last_q when (rbuf_valid_q = '1') else rlast_q;
  axi_rlast_o      <= axi_rlast_o_w;

  resp_pending_w   <= (axi_bvalid_o_w and (not axi_bready_i)) or
                      (axi_rvalid_o_w and (not axi_rready_i) );

  --  write takes priority
  write_active     <= (axi_awvalid_i or req_wr_q) and (not req_rd_q);
  read_active      <= (axi_arvalid_i or req_rd_q) and (not write_active);

  axi_awready_o_w  <= write_active and (not req_wr_q) and
                      (not resp_pending_w) and ram_accept_i;
  axi_awready_o    <=  axi_awready_o_w;
  axi_wready_o_w   <= write_active and (not resp_pending_w) and ram_accept_i;
  axi_wready_o     <= axi_wready_o_w;
  axi_arready_o_w  <= read_active  and (not req_rd_q) and ram_accept_i and
                      (not resp_pending_w);
  axi_arready_o    <= axi_arready_o_w;

  addr_w           <= req_addr_q when (req_wr_q = '1' or req_rd_q = '1') else
                      axi_awaddr_i when (write_active = '1') else
                      axi_araddr_i;

  wr_w             <= write_active and axi_wvalid_i;
  rd_w             <= read_active;

  --  RAM if
  ram_addr_o       <= addr_w;
  ram_wdata_o      <= axi_wdata_i;
  ram_rd_o         <= rd_w;
  ram_wr_o         <= axi_wstrb_i when (wr_w = '1') else (others => '0');

end rtl;







-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--                               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 ieee.std_logic_textio.all;
use std.textio.all;
library std_developerskit;
use std_developerskit.std_iopak.all;
-- for rand
use ieee.math_real.all;
-- pragma translate_on


entity axi_sram is
  generic ( AXIDATA_W   : natural range 32 to 64 := 32;  -- 32 / 64
            ram_size_g  : natural := 16*1024;            -- 32bit words
            -- 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')
            --    "-random-"      : mem array has (kinda) random data
            --    "-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
         --  inputs
         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);   -- 64b / 32b
         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;
         --  outputs
         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 entity axi_sram;


architecture rtl of axi_sram is

  -- - - - - - - - - - - - - - - - - - - - - - - -
  --  return size of ram in words
  -- - - - - - - - - - - - - - - - - - - - - - - -
  function define_ram_words (id : string)
    return natural is
  begin
    if (id = "-linear_data-" or id = "-zero_data-" or id = "-one_data-" or
        id =  "-random-"     or id = "-unknown-") then
      return ram_size_g;
    else
      if (AXIDATA_W /= 64) then
        return 16*1024*1024;       -- RISCV BOOT CODE FROM ELF (.mif file)
      else
        return (16/2)*1024*1024;   -- RISCV BOOT CODE FROM ELF (.mif file)
      end if;
    end if;
  end;


  component ram_bridge
    generic ( AXIDATA_W           : natural range 32 to 64 := 32;
              SUPPORT_FIXED_BURST : boolean := false;
              SUPPORT_WRAP_BURST  : boolean := false );
    port ( clk_i          : in  std_logic;
           xrst_i         : in  std_logic;              -- xreset
           --
           ram_accept_i   : in  std_logic;
           ram_rdata_i    : in  slv_t(AXIDATA_W-1 downto 0);
           ram_wr_o       : out slv_t(AXIDATA_W/8-1 downto 0);   -- 64b / 32b
           ram_rd_o       : out std_logic;
           ram_addr_o     : out slv_31_00;
           ram_wdata_o    : out slv_t(AXIDATA_W-1 downto 0);
           --
           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);   -- 64b / 32b
           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_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;

  constant mif_file_name  : string := mif_file_g;

  signal ram_wr_w         : slv_t(AXIDATA_W/8-1 downto 0);   -- 64b / 32b
  signal ram_rd_w         : std_logic;
  signal ram_addr_w       : slv_31_00;
  signal ram_wdata_w      : slv_t(AXIDATA_W-1 downto 0);
  signal ram_rdata_w      : slv_t(AXIDATA_W-1 downto 0);

  -- - - - - - - - - - - - -
  --  RAM
  -- - - - - - - - - - - - -
  signal addr_w          : slv_23_00;                   -- word addr, not byte
  signal ram_read_q      : slv_t(AXIDATA_W-1 downto 0);

  -- pragma translate_off
  signal init_done_w     : std_logic := '0';
  -- pragma translate_on


begin

  u_axi : ram_bridge
    generic map ( AXIDATA_W => AXIDATA_W )
    port map ( clk_i          => clk_i,
               xrst_i         => xrst_i,
               --  inputs
               ram_rdata_i    => ram_rdata_w,
               ram_accept_i   => '1',
               ram_wr_o       => ram_wr_w,
               ram_rd_o       => ram_rd_w,
               ram_addr_o     => ram_addr_w,
               ram_wdata_o    => ram_wdata_w,
               --
               axi_awvalid_i  => axi_awvalid_i,
               axi_awaddr_i   => axi_awaddr_i,
               axi_awid_i     => axi_awid_i,
               axi_awlen_i    => axi_awlen_i,
               axi_awburst_i  => axi_awburst_i,
               axi_wvalid_i   => axi_wvalid_i,
               axi_wdata_i    => axi_wdata_i,
               axi_wstrb_i    => axi_wstrb_i,
               axi_wlast_i    => axi_wlast_i,
               axi_bready_i   => axi_bready_i,
               axi_arvalid_i  => axi_arvalid_i,
               axi_araddr_i   => axi_araddr_i,
               axi_arid_i     => axi_arid_i,
               axi_arlen_i    => axi_arlen_i,
               axi_arburst_i  => axi_arburst_i,
               axi_rready_i   => axi_rready_i,
               --
               axi_awready_o  => axi_awready_o,
               axi_wready_o   => axi_wready_o,
               axi_bvalid_o   => axi_bvalid_o,
               axi_bresp_o    => axi_bresp_o,
               axi_bid_o      => axi_bid_o,
               axi_arready_o  => axi_arready_o,
               axi_rvalid_o   => axi_rvalid_o,
               axi_rdata_o    => axi_rdata_o,
               axi_rresp_o    => axi_rresp_o,
               axi_rid_o      => axi_rid_o,
               axi_rlast_o    => axi_rlast_o );


  addr_w <= ram_addr_w(25 downto 2) when (AXIDATA_W /= 64)   -- drop byte addr
            else ('0' & ram_addr_w(25 downto 3));


  --  RAM write with byte enables
  p_ram : process (clk_i) is
    --
    type ram_t is array(define_ram_words(mif_file_g)-1 downto 0) of
      slv_t(AXIDATA_W-1 downto 0);
    variable ram : ram_t; --  := (others => (others => '0'));
    --
    --
    -- random vec gen
    function randvec ( vec_width : natural ) return slv_t is
      variable seed1, seed2      : positive; -- seed values for random generator
      variable rand_v            : real := 0.0;  -- random real-number value in
      variable rand_num          : integer := 0;
      -- the range of random values created will be 0 to +1000.
      variable range_of_rand : real   := 1000.0;
      -- variable range_of_rand    : real   := 1.0 * (2**vec_width)-1.0;
    begin
      uniform(seed1, seed2, rand_v);              -- generate random number
      rand_num := integer(rand_v*range_of_rand);  -- rescale to 0..1000, convert
      return slv_t(to_unsigned(rand_num, vec_width));
    end randvec;
    --
    --
    -- - - - - - - - - - - - - - - - - - - - - - - - - - - -
    --  for checking .mif file contents (some sanity checks)
    -- - - - - - - - - - - - - - - - - - - - - - - - - - - -
    procedure check_syntax (string_in  : string;
                            string_ref : string;
                            int_in     : integer;
                            int_ref    : integer;
                            err_code   : string;
                            err_line   : integer) is
    begin
      assert ( (string_in = string_ref) and (int_in = int_ref) )
        report "   Mif file format error: " & err_code & " : " & string_in
        & ", line: " & To_String(err_line)
        severity FAILURE;
    end check_syntax;
    --
    --
    -- - - - - - - - - - - - - - - - -
    --  read in .mif file
    -- - - - - - - - - - - - - - - - -
    procedure mif_read ( file_name : in  string;
                         memory    : out ram_t) is
      file mif_file         : text;
      variable status       : File_Open_Status;
      variable ln           : line;
      variable char1        : string (1 to 1);
      variable ok           : boolean;
      --
      variable depth_c      : string (1 to 8);  -- i.e. "DEPTH = "
      variable width_c      : string (1 to 8);  -- i.e. "WIDTH = "
      variable addr_radix_c : string (1 to 20); -- i.e. "ADDRESS_RADIX = dec;"
      variable data_radix_c : string (1 to 17); -- i.e. "DATA_RADIX = bin;"
      variable content_c    : string (1 to 7);
      variable begin_c      : string (1 to 5);
      variable separator_c  : string (1 to 3);  -- i.e. " : " or " = "
      variable semicolon_c  : string (1 to 1);  -- i.e. ";"
      variable end_c        : string (1 to 4);   -- i.e. "END;"
      --
      variable line_cnt_v   : integer := 0;
      variable data_cnt_v   : integer := 0;
      variable tmp_addr_v   : integer;
      variable ram_depth_v  : integer;
      variable ram_word_v   : integer;
      variable tmp_val_v    : slv_t(ram(0)'range);
      variable tmp_val32_v  : slv_31_00;
      --
    begin
      -- Mif file format is like:
      --    DEPTH = 16384;
      --    WIDTH = 16;
      --    ADDRESS_RADIX = dec;
      --    DATA_RADIX = bin;
      --    CONTENT
      --    BEGIN
      --    0 : 0000000000000000;
      --    ...
      --    16383 : 0000000000000000;
      --    END;
      File_Open(status, mif_file, file_name, read_mode);
      assert (status = Open_Ok)
        report "   ERROR : MIF file does not exist."
        severity FAILURE;
      readline(mif_file,ln);            -- DEPTH = x;
      line_cnt_v := line_cnt_v + 1;
      read(ln, depth_c);
      read(ln, tmp_addr_v);
      check_syntax (depth_c, "DEPTH = ", 0, 0, "DEPTH ERROR", line_cnt_v);
      ram_depth_v := tmp_addr_v;
      --
      readline(mif_file,ln);            -- WIDTH = y;
      line_cnt_v := line_cnt_v + 1;
      read(ln, width_c);
      read(ln, tmp_addr_v);
      if (AXIDATA_W /= 64) then
        check_syntax (width_c, "WIDTH = ", tmp_addr_v, ram(0)'length,
                      "WIDTH ERROR", line_cnt_v);
      else
        check_syntax (width_c, "WIDTH = ", tmp_addr_v, 32,  -- 2 words to 1 line
                      "WIDTH ERROR", line_cnt_v);
      end if;
      ram_word_v := tmp_addr_v;
      --
      readline(mif_file,ln);            -- ADDRESS_RADIX = dec;
      line_cnt_v := line_cnt_v + 1;
      read(ln,addr_radix_c);
      check_syntax (addr_radix_c, "ADDRESS_RADIX = dec;", 0, 0,
                    "ADDRESS RADIX ERROR", line_cnt_v);
      --
      readline(mif_file,ln);            -- DATA_RADIX = bin;
      line_cnt_v := line_cnt_v + 1;
      read(ln,data_radix_c);
      check_syntax (data_radix_c, "DATA_RADIX = bin;",0, 0,
                    "DATA RADIX ERROR", line_cnt_v);
      --
      readline(mif_file,ln);            -- CONTENT
      line_cnt_v := line_cnt_v + 1;
      read(ln,content_c);
      check_syntax (content_c, "CONTENT",0, 0, "CONTENT ERROR", line_cnt_v);
      --
      readline(mif_file,ln);            -- BEGIN
      line_cnt_v := line_cnt_v + 1;
      read(ln,begin_c);
      check_syntax (begin_c, "BEGIN",0, 0, "BEGIN ERROR", line_cnt_v);
      --
      while not endfile(mif_file) loop   -- NOTE: Not all words included
        readline(mif_file,ln);
        line_cnt_v := line_cnt_v + 1;
        --
        if (line_cnt_v mod 100000 = 0) then
          report "NOTE: read : " & To_String(line_cnt_v) & " lines. . .";
        end if;
        --
        read(ln, tmp_addr_v, ok);     --
        if ( ok ) then                -- continue data reading
          read(ln, separator_c);
          if (AXIDATA_W /= 64) then
            read(ln, tmp_val_v);      -- NOTE: "use ieee.std_logic_textio.all;"
          else
            read(ln, tmp_val32_v);
          end if;
          read(ln, semicolon_c);      --                    _______
          --
          -- checking only last character is ";"
          check_syntax (semicolon_c, ";",0, 0, "DATA ERROR", line_cnt_v);
          --
          if (AXIDATA_W /= 64) then
            ram(tmp_addr_v) := tmp_val_v;
          else
            if (tmp_addr_v mod 2 = 0) then    -- LSB word
              ram(tmp_addr_v/2)(31 downto 0) := tmp_val32_v;
            else
              ram(tmp_addr_v/2)(63 downto 32) := tmp_val32_v;
            end if;
          end if;
          data_cnt_v      := data_cnt_v + 1;
        else
          read(ln, end_c, ok);        -- reached "END;"
          if ( ok and end_c = "END;" ) then
            report "> > > NOTE: Reached mif file end: " & file_name;
            report "> > > NOTE: Found " & To_String(data_cnt_v) &
              " words (size expected: " & To_String(ram_depth_v) &
              " x " & To_String(ram_word_v) & ")";
          else
            report "ERROR: Bad line (" & To_String(line_cnt_v) & "): " &
              file_name;
          end if;
        end if;
      end loop;
     --
    end procedure mif_read;

  begin
    --
    --
    -- pragma translate_off
    if (init_done_w = '0') then                      -- < < <  MEM INIT
      --    "-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'
      --    "boot_code.mif" : Read mif file
      if ( mif_file_g = "-linear_data-" ) then
        if ( AXIDATA_W /= 64 ) then
          for ii in ram'low to ram'high loop
            ram(ii)   := slv_t(to_unsigned(ii, AXIDATA_W));
          end loop;
        else
          for ii in ram'low to ram'high loop
            ram(ii)   := slv_t(to_unsigned(2*ii+1, AXIDATA_W/2)) &
                         slv_t(to_unsigned(2*ii,   AXIDATA_W/2));
          end loop;
        end if;
      elsif ( mif_file_g =  "-zero_data-" ) then
        ram        := (others => (others => '0'));
      elsif ( mif_file_g =  "-one_data-" ) then
        ram        := (others => (others => '0'));
      elsif ( mif_file_g =  "-random-" ) then
        for ii in ram'range loop
          ram(ii)  := randvec(AXIDATA_W);
        end loop;
      elsif ( mif_file_g =  "-unknown-" ) then
        ram        := (others => (others => 'U'));
      else
        mif_read(mif_file_name, ram);
      end if;
      --
      --
      --
      report "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - ";
      report "- - - BOOTRAM  - MEM INIT : "  &  mif_file_g &
        " -  MEM SIZE : " & To_String(ram'length, "%d");
      report "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - ";
      init_done_w <= '1';
    end if;                                          -- < < <  MEM INIT
    -- pragma translate_on
    --
    --
    if (clk_i'event and clk_i = '1') then
      if (xrst_i = '0') then
        -- init done in init-section above
        -- for ii in 0 to 2047 loop
        --   ram(ii) <= slv_t(to_unsigned(ii, 32));
        -- end loop;
        null;
      else
        --
        --
        ram_read_q <= ram(to_uint(addr_w));
        --
        --
        for ii in 0 to AXIDATA_W/8-1 loop
          if ( ram_wr_w(ii) = '1' ) then    -- and rd = '0') then
            ram(to_uint(addr_w))(ii*8+7 downto ii*8) :=
              ram_wdata_w(ii*8+7 downto ii*8);
          end if;
        end loop;
      end if;
    end if;
  end process p_ram;

  ram_rdata_w <= ram_read_q;

end rtl;
