-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--
-- 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 rv_core is
  generic ( AXIDATA_W      : natural range 32 to 64 := 64;  -- 32/64 bit allowed
            BOOT_ADDR      : slv_31_00 := X"80000000";
            CPU_ID         : slv_31_00 := X"00000000";
            AXI_ID         : slv_03_00 := X"4";
            CACHE_ADDR_L   : slv_31_00 := X"80000000";
            CACHE_ADDR_H   : slv_31_00 := X"8FFFFFFF" );
  port ( clk_i            : in  std_logic;
         xrst_i           : in  std_logic;                  -- syncr reset
         xrst_core_i      : in  std_logic;                  -- cpu/cache xreset
         xrst_cpu_i       : in  std_logic;                  -- cpu xreset only
         --  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_i      : in  std_logic;
         imbist_rd_i      : in  slv_03_00;                  -- t1,d1,t0,d0
         imbist_wr_i      : in  slv_03_00;                  -- t1,d1,t0,d0
         dmbist_rd_i      : in  slv_03_00;                  -- t1,d1,t0,d0
         dmbist_wr_i      : in  slv_03_00;                  -- t1,d1,t0,d0
         mbist_addr_i     : in  slv_12_00;
         mbist_data_i     : in  slv_t(AXIDATA_W-1 downto 0);
         mbist_data_o     : out slv_t(AXIDATA_W-1 downto 0);
         -- axi bus
         axi_awready_i    : in  std_logic;
         axi_wready_i     : in  std_logic;
         axi_bvalid_i     : in  std_logic;
         axi_bresp_i      : in  slv_01_00;
         axi_bid_i        : in  slv_03_00;
         axi_arready_i    : in  std_logic;
         axi_rvalid_i     : in  std_logic;
         axi_rdata_i      : in  slv_t(AXIDATA_W-1 downto 0);
         axi_rresp_i      : in  slv_01_00;
         axi_rid_i        : in  slv_03_00;
         axi_rlast_i      : in  std_logic;
         axi_awvalid_o    : out std_logic;
         axi_awaddr_o     : out slv_31_00;
         axi_awid_o       : out slv_03_00;
         axi_awlen_o      : out slv_07_00;
         axi_awburst_o    : out slv_01_00;
         axi_wvalid_o     : out std_logic;
         axi_wdata_o      : out slv_t(AXIDATA_W-1 downto 0);
         axi_wstrb_o      : out slv_t(AXIDATA_W/8-1 downto 0);
         axi_wlast_o      : out std_logic;
         axi_bready_o     : out std_logic;
         axi_arvalid_o    : out std_logic;
         axi_araddr_o     : out slv_31_00;
         axi_arid_o       : out slv_03_00;
         axi_arlen_o      : out slv_07_00;
         axi_arburst_o    : out slv_01_00;
         axi_rready_o     : out std_logic;
         --  VSBUS
         pp_irq_i         : in  std_logic;  -- perip interrupt
         pp_addr_o        : out slv_31_00;
         pp_rd_o          : out std_logic;
         pp_rd_data_i     : in  slv_31_00;
         pp_wr_o          : out slv_03_00;
         pp_wr_data_o     : out slv_31_00;
         -- dma1
         dma_rd_i         : in  std_logic;
         dma_wr_i         : in  std_logic;
         dma_addr_i       : in  slv_31_02;
         dma_wr_data_i    : in  slv_31_00;
         dma_rd_data_o    : out slv_31_00;
         dma_intr_o       : out std_logic   -- dma interrupt
         );
end entity rv_core;


architecture rtl of rv_core is

  component rv_cpu
    generic (
      BOOT_ADDR       : slv_31_00 := X"80000000";
      CPU_ID          : slv_31_00 := X"00000000";
      CACHE_ADDR_L    : slv_31_00 := X"80000000";
      CACHE_ADDR_H    : slv_31_00 := X"8FFFFFFF";
      --
      RISCV_M         : std_logic := '1';   -- RV mul / div extension
      RISCV_E         : std_logic := '0';   -- RV rf embedded extension
      RISCV_S_U       : std_logic := '1';   -- supervisor/user privilege levels
  --  RISCV_I         : std_logic := '1';   -- always enabled when no RISCV_E !
  --  RISCV_Zicsr     : std_logic := '1';   -- always enabled !
  --  RISCV_Zifencei  : std_logic := '1';   -- always enabled !
      RISCV_A         : std_logic := '1';  -- amo extension
      RISCV_Zba       : std_logic := '1';  -- address generation (shXadd)
      RISCV_ZB        : std_logic := '1';  -- ZB-extension + Zicond
      --
      SUPPORT_MMU         : std_logic := '1';
      BYPASS_LOAD         : std_logic := '1';     -- support data load bypass
      BYPASS_MULT         : std_logic := '1';     -- support multiplier bypass
      EXTRA_DECODE_STAGE  : std_logic := '1' );
    port ( clk_i              : in  std_logic;
           xrst_i             : in  std_logic;    -- syncr reset
           --   interrupt request from irq ctrl
           irq_i              : in  std_logic;    -- external inter
           tmrirq_i           : in  std_logic;    -- riscv timer inter
           --  icache inputs
           imem_accept_i      : in  std_logic;
           imem_valid_i       : in  std_logic;
           imem_error_i       : in  std_logic;
           imem_rdata_i       : in  slv_31_00;
           --  icache outputs
           imem_rd_o          : out std_logic;
           imem_pc_o          : out slv_31_00;
           imem_flush_o       : out std_logic;
           imem_invalidate_o  : out std_logic;
           --  dcache/peripheral inputs
           dmem_rdata_i       : in  slv_31_00;
           dmem_accept_i      : in  std_logic;
           dmem_ack_i         : in  std_logic;
           dmem_error_i       : in  std_logic;
           dmem_resp_tag_i    : in  slv_10_00;
           --  dcache/peripheral outputs
           dmem_rd_o          : out std_logic;
           dmem_wr_o          : out slv_03_00;
           dmem_addr_o        : out slv_31_00;
           dmem_wdata_o       : out slv_31_00;
           dmem_cacheable_o   : out std_logic;
           dmem_req_tag_o     : out slv_10_00;
           dmem_invalidate_o  : out std_logic;
           dmem_wb_o          : out std_logic;
           dmem_flush_o       : out std_logic );
  end component;


  component icachew
    generic ( AXIDATA_W   : natural range 32 to 64 := 32;   -- Data width
              WAYS        : natural range 1  to 8  := 2;    -- Nro ways 1,2,4,8
              LINE_ADDR_W : natural range 6  to 12 := 8;    -- Line address
              LINE_SIZE_W : natural range 2  to 8  := 5 );  -- Line size (bytes)
    port ( clk_i            : in  std_logic;
           xrst_i           : in  std_logic;                -- syncr reset
           --  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
           --  NOTE: mbist uses pmem_rdata_i as its input data also
           mbist_ena_i      : in  std_logic;
           mbist_rd_i       : in  slv_t(2*WAYS-1 downto 0); -- 1-hot t1,d1,t0,d0
           mbist_wr_i       : in  slv_t(2*WAYS-1 downto 0); -- 1-hot t1,d1,t0,d0
           mbist_addr_i     : in  slv_t(LINE_ADDR_W+LINE_SIZE_W-2-1 downto 0);
           mbist_data_o     : out slv_t(AXIDATA_W-1 downto 0);
           -- mem inputs (from cpu)
           cpu_rd_i         : in  std_logic;
           cpu_flush_i      : in  std_logic;
           cpu_invalidate_i : in  std_logic;
           cpu_pc_i         : in  slv_31_00;
           -- mem outputs (to cpu)
           cpu_accept_o     : out std_logic;
           cpu_valid_o      : out std_logic;
           cpu_error_o      : out std_logic;
           cpu_inst_o       : out slv_31_00;
           --
           xmem_accept_i    : in  std_logic;
           xmem_ack_i       : in  std_logic;
           xmem_error_i     : in  std_logic;
           xmem_rdata_i     : in  slv_t(AXIDATA_W-1 downto 0);
           xmem_rd_o        : buffer std_logic;
           xmem_wr_o        : out slv_t(AXIDATA_W/8-1 downto 0); -- no w-channel
           xmem_len_o       : out slv_07_00;                     -- burst len
           xmem_addr_o      : buffer slv_31_00;
           xmem_wdata_o     : out slv_t(AXIDATA_W-1 downto 0) ); -- no w-channel
  end component;


  component dcachew is
    generic (AXIDATA_W   : natural range 32 to 64 := 32;  -- Data width
             WAYS        : natural range 1 to 8   := 2;   -- Nro of ways 1,2,4,8
             LINE_ADDR_W : natural range 6 to 12  := 8;   -- Line address
             LINE_SIZE_W : natural range 2 to 8   := 5 ); -- Line size (bytes)
    port ( clk_i             : in  std_logic;
           xrst_i            : in  std_logic;             -- syncr reset
           --  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_i       : in  std_logic;
           mbist_rd_i        : in  slv_t(2*WAYS-1 downto 0);
           mbist_wr_i        : in  slv_t(2*WAYS-1 downto 0);
           mbist_addr_i      : in  slv_t(LINE_ADDR_W+LINE_SIZE_W-2-1 downto 0);
           -- ! ! NOTE: mbist_data_i is outport_read_data_i ! !
           mbist_data_o      : out slv_t(AXIDATA_W-1 downto 0);
           --
           -- CPU
           cpu_rd_i          : in  std_logic;
           cpu_wr_i          : in  slv_03_00;
           cpu_addr_i        : in  slv_31_00;                   -- WORD address
           cpu_wdata_i       : in  slv_31_00;
           cpu_req_tag_i     : in  slv_10_00;
           cpu_invalidate_i  : in  std_logic;
           cpu_wb_i          : in  std_logic;
           cpu_flush_i       : in  std_logic;
           cpu_rdata_o       : out slv_31_00;
           cpu_accept_o      : out std_logic;
           cpu_ack_o         : out std_logic;
           cpu_error_o       : out std_logic;
           cpu_resp_tag_o    : out slv_10_00;
           -- MEM
           xmem_accept_i     : in  std_logic;
           xmem_ack_i        : in  std_logic;
           xmem_error_i      : in  std_logic;
           xmem_rdata_i      : in  slv_t(AXIDATA_W-1 downto 0);
           xmem_rd_o         : out std_logic;
           xmem_wr_o         : out slv_t(AXIDATA_W/8-1 downto 0);
           xmem_len_o        : out slv_07_00;
           xmem_addr_o       : out slv_31_00;
           xmem_wdata_o      : out slv_t(AXIDATA_W-1 downto 0) );
  end component;


  component dma is
    generic ( AXIDATA_W   : natural range 32 to 64 := 32 );
    port ( clk_i            : in std_logic;
           xrst_i           : in std_logic;
           -- from perips
           dma_rd_i         : in  std_logic;
           dma_wr_i         : in  std_logic;
           dma_addr_i       : in  slv_04_00;
           dma_wr_data_i    : in  slv_31_00;
           dma_rd_data_o    : out slv_31_00;
           dma_intr_o       : out std_logic;                     -- from dma ack
           -- to/from axi
           resp_rdata_i     : in  slv_t(AXIDATA_W-1 downto 0);
           dma1_rd_o        : out std_logic;
           dma1_wr_o        : out std_logic;
           dma1_len_o       : out slv_07_00;                    -- burst len
           dma1_addr_o      : out slv_31_00;                    -- [1:0] NC
           dma1_wdata_o     : out slv_t(AXIDATA_W-1 downto 0);
           dma1_accept_i    : in  std_logic;
           dma1_ack_i       : in  std_logic;
           dma1_error_i     : in  std_logic );
  end component;


  component axi_wrapper
    generic ( AXI_ID    : slv_03_00 := X"0";
              AXIDATA_W : natural range 32 to 64 := 32; -- Data width 32/64 only
              ROM_BASE  : slv_31_28 := X"7" );
    port ( clk_i          : in  std_logic;
           xrst_i         : in  std_logic;
           --
           --  channel 1  (dcache)
           dmem_rd_i      : in     std_logic; -- HIGH until request accepted
           dmem_wr_i      : in     std_logic; -- HIGH during whole burst time
           dmem_len_i     : in     slv_07_00;
           dmem_addr_i    : in     slv_31_00; -- [1:0] NC
           dmem_wdata_i   : in     slv_t(AXIDATA_W-1 downto 0);
           dmem_accept_o  : buffer std_logic;
           dmem_ack_o     : buffer std_logic; -- HIGH when rdata valid / WR done
           dmem_error_o   : out    std_logic;
           --
           --  channel 2  (icache)
           imem_rd_i      : in     std_logic;
           imem_wr_i      : in     std_logic;
           imem_len_i     : in     slv_07_00;
           imem_addr_i    : in     slv_31_00; -- [1:0] NC
           imem_wdata_i   : in     slv_t(AXIDATA_W-1 downto 0);
           imem_accept_o  : buffer std_logic;
           imem_ack_o     : buffer std_logic;
           imem_error_o   : out    std_logic;
           --
           --  channel 3  (dma / dbg_uart)
           dma1_rd_i      : in     std_logic;
           dma1_wr_i      : in     std_logic;
           dma1_len_i     : in     slv_07_00;
           dma1_addr_i    : in     slv_31_00; -- [1:0] NC
           dma1_wdata_i   : in     slv_t(AXIDATA_W-1 downto 0);
           dma1_accept_o  : buffer std_logic;
           dma1_ack_o     : buffer std_logic;
           dma1_error_o   : out    std_logic;
           --
           --  channel 4  (dbg_uart / NC)
           dma2_rd_i      : in     std_logic;
           dma2_wr_i      : in     std_logic;
           dma2_len_i     : in     slv_07_00;
           dma2_addr_i    : in     slv_31_00; -- [1:0] NC
           dma2_wdata_i   : in     slv_t(AXIDATA_W-1 downto 0);
           dma2_accept_o  : buffer std_logic;
           dma2_ack_o     : buffer std_logic;
           dma2_error_o   : out    std_logic;
           --
           --  channel 5  (dma / dbg_uart)
           dma3_rd_i      : in     std_logic;
           dma3_wr_i      : in     std_logic;
           dma3_len_i     : in     slv_07_00;
           dma3_addr_i    : in     slv_31_00;
           dma3_wdata_i   : in     slv_t(AXIDATA_W-1 downto 0);
           dma3_accept_o  : buffer std_logic;
           dma3_ack_o     : buffer std_logic;
           dma3_error_o   : out    std_logic;
           --
           --  common ports for all channels requests
           resp_rdata_o   : out    slv_t(AXIDATA_W-1 downto 0);
           --
           -- AXI4 ports
           axi_arvalid_o  : out    std_logic; -- AXI4 read req
           axi_araddr_o   : out    slv_31_00;
           axi_arid_o     : out    slv_03_00;
           axi_arlen_o    : out    slv_07_00;
           axi_arburst_o  : out    slv_01_00;
           axi_rready_o   : out    std_logic;
           axi_arready_i  : in     std_logic; -- AXI4 read resp
           axi_rvalid_i   : in     std_logic;
           axi_rdata_i    : in     slv_t(AXIDATA_W-1 downto 0);
           axi_rresp_i    : in     slv_01_00;
           axi_rid_i      : in     slv_03_00;
           axi_rlast_i    : in     std_logic;
           axi_awready_i  : in     std_logic; -- AXI4 write req
           axi_wready_i   : in     std_logic;
           axi_bvalid_i   : in     std_logic;
           axi_bresp_i    : in     slv_01_00;
           axi_bid_i      : in     slv_03_00;
           axi_awvalid_o  : buffer std_logic; -- AXI4 write resp
           axi_awaddr_o   : out    slv_31_00;
           axi_awid_o     : out    slv_03_00;
           axi_awlen_o    : out    slv_07_00;
           axi_awburst_o  : out    slv_01_00;
           axi_wvalid_o   : buffer std_logic;
           axi_wdata_o    : out    slv_t(AXIDATA_W-1 downto 0);
           axi_wstrb_o    : out    slv_t(AXIDATA_W/8-1 downto 0);
           axi_wlast_o    : buffer std_logic;
           axi_bready_o   : buffer std_logic );
  end component;

  --                               default (32kB)    (128kB)   (128kB)
  constant IWAYS         : natural :=  2;             -- 2;     -- 2;
  constant ILINE_ADDR_W  : natural :=  8;             -- 9;     -- 10;
  constant ILINE_SIZE_W  : natural :=  5;             -- 6;     -- 5;
  --                                                                        
  constant DWAYS         : natural :=  2;             -- 2;     -- 2;
  constant DLINE_ADDR_W  : natural :=  8;             -- 9;     -- 10;
  constant DLINE_SIZE_W  : natural :=  5;             -- 6;     -- 5;

  signal icache_rd_w          : std_logic;
  signal icache_pc_w          : slv_31_00;
  signal icache_iword_x01_w   : slv_31_00;
  signal icache_iword_w       : slv_31_00;
  signal icache_accept_w      : std_logic;
  signal icache_valid_w       : std_logic;
  signal icache_flush_w       : std_logic;
  signal icache_error_w       : std_logic;
  signal icache_invalidate_w  : std_logic;

  signal i_len_w              : slv_07_00;            -- burst len
  signal i_addr_w             : slv_31_00;
  signal i_ack_w              : std_logic;
  signal i_wdata_w            : slv_t(AXIDATA_W-1 downto 0);
  signal i_rd_w               : std_logic;
  --  (no write channel)
  signal i_wr_w               : slv_t(AXIDATA_W/8-1 downto 0);
  signal i_accept_w           : std_logic;
  signal i_error_w            : std_logic;

  signal core_d_cacheable_w   : std_logic;
  signal core_d_accept_w      : std_logic;
  signal core_d_ack_w         : std_logic;            -- core_d rd/wr ack
  signal core_d_rd_w          : std_logic;            -- core_d rd ena
  signal core_d_wr_w          : slv_03_00;            -- core_d wr ena
  signal core_d_addr_w        : slv_31_00;
  signal core_d_data_rd_w     : slv_31_00;
  signal core_d_data_wr_w     : slv_31_00;
  signal core_d_resp_tag_w    : slv_10_00;
  signal core_d_req_tag_w     : slv_10_00;
  signal core_d_wb_w          : std_logic;
  signal core_d_error_w       : std_logic;
  signal core_d_flush_w       : std_logic;
  signal core_d_invalidate_w  : std_logic;

  signal dcache_accept_w      : std_logic;
  signal dcache_ack_w         : std_logic;
  signal dcache_cached_rd_w   : std_logic;            -- dcache rd ena
  signal dcache_cached_wr_w   : slv_03_00;            -- dcache wr ena
  signal dcache_data_rd_w     : slv_31_00;
  signal dcache_resp_tag_w    : slv_10_00;
  signal dcache_error_w       : std_logic;

  signal d_len_w              : slv_07_00;
  signal d_addr_w             : slv_31_00;
  signal d_ack_w              : std_logic;
  signal d_wdata_w            : slv_t(AXIDATA_W-1 downto 0);
  signal d_rd_w               : std_logic;
  signal d_wr_w               : slv_t(AXIDATA_W/8-1 downto 0);
  signal d_accept_w           : std_logic;
  signal d_error_w            : std_logic;

  signal pmem_rdata_w         : slv_t(AXIDATA_W-1 downto 0);

  signal axi_awvalid_o_w      : std_logic;
  signal axi_wvalid_o_w       : std_logic;
  signal axi_wstrb_o_w        : slv_t(AXIDATA_W/8-1 downto 0);
  signal axi_wlast_o_w        : std_logic;
  signal axi_bready_o_w       : std_logic;

  --  perip control
  signal core_rd_q            : std_logic;
  signal core_wr_q            : slv_03_00;
  signal core_addr_q          : slv_31_00;
  signal core_wr_data_q       : slv_31_00;
  signal core_d_cacheable_q   : std_logic;

  signal pp_access_w          : std_logic;
  signal pp_ack_w             : std_logic;

  signal imbist_ena_i_w       : std_logic;
  signal imbist_rd_i_w        : slv_03_00;                        -- t1,d1,t0,d0
  signal imbist_rd_q          : std_logic;
  signal imbist_wr_i_w        : slv_03_00;                        -- t1,d1,t0,d0
  signal imbist_addr_i_w      : slv_t(DLINE_ADDR_W+DLINE_SIZE_W-2-1 downto 0);
  --  ! ! NOTE: mbist_data_i is shared axi rdata  ! !
  signal pmem_mbist_i_w       : slv_t(AXIDATA_W-1 downto 0);
  signal imbist_data_o_w      : slv_t(AXIDATA_W-1 downto 0);

  signal dmbist_ena_i_w       : std_logic;
  signal dmbist_rd_i_w        : slv_03_00;                        -- t1,d1,t0,d0
  signal dmbist_wr_i_w        : slv_03_00;                        -- t1,d1,t0,d0
  signal dmbist_addr_i_w      : slv_t(ILINE_ADDR_W+ILINE_SIZE_W-2-1 downto 0);
  --  ! ! NOTE: mbist_data_i is shared axi rdata  ! !
  signal dmbist_data_o_w      : slv_t(AXIDATA_W-1 downto 0);

  signal pmem_mbist_d_w       : slv_t(AXIDATA_W-1 downto 0);

  signal xrst_cache_w         : std_logic;

  signal dma1_rd_w            : std_logic;
  signal dma1_wr_w            : std_logic;
  signal dma1_len_w           : slv_07_00;                        -- burst len
  signal dma1_addr_w          : slv_31_00;                        -- [1:0] NC
  signal dma1_wdata_w         : slv_t(AXIDATA_W-1 downto 0);
  signal dma1_accept_w        : std_logic;
  signal dma1_ack_w           : std_logic;
  signal dma1_error_w         : std_logic;

  signal sd_error_w           : std_logic;
 
begin


  imbist_ena_i_w        <= mbist_ena_i;
  imbist_rd_i_w         <= imbist_rd_i;                           -- t1,d1,t0,d0
  imbist_wr_i_w         <= imbist_wr_i;                           -- t1,d1,t0,d0
  imbist_addr_i_w       <= mbist_addr_i(imbist_addr_i_w'range);   -- 11:0 (8k)

  pmem_mbist_i_w        <= mbist_data_i when (mbist_ena_i = '1')  -- 31:0
                           else  pmem_rdata_w;                    -- 31:0

  dmbist_ena_i_w        <= mbist_ena_i;
  dmbist_rd_i_w         <= dmbist_rd_i;                           -- t1,d1,t0,d0
  dmbist_wr_i_w         <= dmbist_wr_i;                           -- t1,d1,t0,d0
  dmbist_addr_i_w       <= mbist_addr_i(dmbist_addr_i_w'range);   -- 11:0 (8k)

  pmem_mbist_d_w        <= mbist_data_i when (mbist_ena_i = '1')  -- 31:0
                           else  pmem_rdata_w;                    -- 31:0

  mbist_data_o <= imbist_data_o_w when (imbist_rd_q /= '0')
                  else dmbist_data_o_w;


  p_mbist_sel : process (clk_i)
  begin
    if (clk_i'event and clk_i = '1') then
      if (xrst_i = '0') then
        imbist_rd_q   <= '0';
      else
        imbist_rd_q   <= '0';
        if ( not_zero(imbist_rd_i_w) ) then
          imbist_rd_q <= '1';
        end if;
      end if;
    end if;
  end process p_mbist_sel;



  p_pp_retime : process (clk_i)
  begin
    if (clk_i'event and clk_i = '1') then
      if (xrst_i = '0') then
        core_rd_q            <= '0';
        core_wr_q            <= X"0";                   -- 3:0   --! 3:1 NC
        core_addr_q          <= X"00000000";            -- 31:0
        core_wr_data_q       <= X"00000000";            -- 31:0
        core_d_cacheable_q   <= '0';
      else
        if (core_d_accept_w = '1') then
          core_rd_q          <= core_d_rd_w;
          core_wr_q          <= core_d_wr_w;            -- 3:0   --! 3:1 NC
          core_addr_q        <= core_d_addr_w;          -- 31:0
          core_wr_data_q     <= core_d_data_wr_w;       -- 31:0
          core_d_cacheable_q <= core_d_cacheable_w;
        end if;
      end if;
    end if;
  end process p_pp_retime;


  --
  -- NOTE: peripheral bus has a one clock cycle delay in all operations
  --
  pp_access_w  <= not core_d_cacheable_q;
  pp_addr_o    <= core_addr_q;
  pp_rd_o      <= core_rd_q and pp_access_w;
  pp_wr_o      <= core_wr_q and (pp_access_w & pp_access_w &
                                 pp_access_w & pp_access_w);
  pp_wr_data_o <= core_wr_data_q;
  -- always ack after one clock
  pp_ack_w     <= ( not core_d_cacheable_q ) and
                  ( core_rd_q or not_zero(core_wr_q) );



  -- dcache read/write enebles
  dcache_cached_rd_w <= core_d_rd_w and core_d_cacheable_w;
  dcache_cached_wr_w <= core_d_wr_w and ( core_d_cacheable_w &
                                          core_d_cacheable_w &
                                          core_d_cacheable_w &
                                          core_d_cacheable_w );



  --
  -- MUXED dcache/perip inputs to core
  --
  core_d_data_rd_w <= dcache_data_rd_w when (core_d_cacheable_q = '1') else
                      pp_rd_data_i;

  core_d_ack_w     <= pp_ack_w when (core_d_cacheable_q = '0') else
                      dcache_ack_w;

  core_d_resp_tag_w <= dcache_resp_tag_w;


  core_d_accept_w <= dcache_accept_w  and  '1';    -- perips always ready
  core_d_error_w  <= dcache_error_w   or   '0';    -- perips never error



  u_cpu : rv_cpu
    generic map ( BOOT_ADDR       => BOOT_ADDR,
                  CPU_ID          => CPU_ID,
                  CACHE_ADDR_L    => CACHE_ADDR_L,
                  CACHE_ADDR_H    => CACHE_ADDR_H,
                  --
                  RISCV_M         => '1',   -- RV mul / div extension
                  RISCV_E         => '0',   -- RV rf embedded extension
                  RISCV_S_U       => '1',   -- supervisor/user privilege levels
               -- RISCV_I         => '1',   -- always enabled when no RISCV_E !
               -- RISCV_Zicsr     => '1',   -- always enabled !
               -- RISCV_Zifencei  => '1',   -- always enabled !
                  RISCV_A         => '1',   -- amo extension
                  RISCV_Zba       => '1',   -- address generation (shXadd)
                  RISCV_ZB        => '1',   -- ZB-extension + Zicond
                  --
                  SUPPORT_MMU         => '1',
                  BYPASS_LOAD         => '1',
                  BYPASS_MULT         => '1',
                  EXTRA_DECODE_STAGE  => '1' )
    port map ( clk_i              => clk_i,
               xrst_i             => xrst_cpu_i,
               --  interrupt request from irq ctrl
               irq_i              => pp_irq_i,   -- external irq from irq_ctrl
               tmrirq_i           => '0',        -- riscv timer inter
               -- icache inputs
               imem_accept_i      => icache_accept_w,
               imem_valid_i       => icache_valid_w,
               imem_error_i       => icache_error_w,
               imem_rdata_i       => icache_iword_w,
               --  icache outputs
               imem_rd_o          => icache_rd_w,
               imem_pc_o          => icache_pc_w,
               imem_flush_o       => icache_flush_w,
               imem_invalidate_o  => icache_invalidate_w,
               --  dcache/peripheral inputs
               dmem_rdata_i       => core_d_data_rd_w,  -- MUXED dcache/perip
               dmem_accept_i      => core_d_accept_w,
               dmem_ack_i         => core_d_ack_w,      -- MUXED dcache/perip
               dmem_error_i       => core_d_error_w,
               dmem_resp_tag_i    => core_d_resp_tag_w,
               --  dcache/peripheral outputs
               dmem_rd_o          => core_d_rd_w,       -- dcache/perip rd ena
               dmem_wr_o          => core_d_wr_w,       -- dcache/perip wr ena
               dmem_addr_o        => core_d_addr_w,
               dmem_wdata_o       => core_d_data_wr_w,
               dmem_cacheable_o   => core_d_cacheable_w,
               dmem_req_tag_o     => core_d_req_tag_w,
               dmem_invalidate_o  => core_d_invalidate_w,
               dmem_wb_o          => core_d_wb_w,
               dmem_flush_o       => core_d_flush_w );


  -- Get rid of simulations warnings:
  --   "Warning: NUMERIC_STD."<": metavalue detected"
  icache_iword_w <=
    -- pragma translate_off
    to_stdlogicvector(to_bitvector(
      -- pragma translate_on
      icache_iword_x01_w
      -- pragma translate_off
      ))
    -- pragma translate_on
    ;



  xrst_cache_w <= mbist_ena_i or xrst_core_i; -- mbist enables (after pwr up)



  u_icache: icachew
    generic  map (
      -- default   WAYS         => 2,              -- Number of ways 1,2,4,8
      --           LINE_ADDR_W  => 8,              -- Line address
      --           LINE_SIZE_W  => 5 )             -- Line size (bytes !)
                   AXIDATA_W    => AXIDATA_W,      -- Data width
                   WAYS         => IWAYS,          -- Number of ways  (1,2,4,8)
                   LINE_ADDR_W  => ILINE_ADDR_W,   -- Line address
                   LINE_SIZE_W  => ILINE_SIZE_W )  -- Line size (bytes !)
    port map ( clk_i            => clk_i,
               xrst_i           => xrst_cache_w,
               --  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
               --  NOTE: mbist uses pmem_rdata_i as its input data also
               mbist_ena_i       => imbist_ena_i_w,
               mbist_rd_i        => imbist_rd_i_w, -- 1-hot, 2-WAY: t1,d1,t0,d0
               mbist_wr_i        => imbist_wr_i_w, -- 1-hot, 2-WAY: t1,d1,t0,d0
               mbist_addr_i      => imbist_addr_i_w,
               -- ! ! NOTE: mbist_data_i is pmem_rdata_i  ! !
               mbist_data_o      => imbist_data_o_w,
               -- mem inputs (from cpu)
               cpu_rd_i          => icache_rd_w,
               cpu_flush_i       => icache_flush_w,
               cpu_invalidate_i  => icache_invalidate_w,
               cpu_pc_i          => icache_pc_w,
               cpu_accept_o      => icache_accept_w,
               cpu_valid_o       => icache_valid_w,
               cpu_error_o       => icache_error_w,
               cpu_inst_o        => icache_iword_x01_w,
               --
               xmem_accept_i     => i_accept_w,
               xmem_ack_i        => i_ack_w,
               xmem_error_i      => i_error_w,
               xmem_rdata_i      => pmem_mbist_i_w,
               xmem_rd_o         => i_rd_w,
               xmem_len_o        => i_len_w,       -- burst len
               xmem_addr_o       => i_addr_w,
               xmem_wr_o         => i_wr_w,        -- ZERO  (no write channel)
               xmem_wdata_o      => i_wdata_w );   -- ZERO, (no write channel)



  u_dcache : dcachew
    generic  map (
      -- default   WAYS         => 2,              -- Number of ways 1,2,4,8
      --           LINE_ADDR_W  => 8,              -- Line address
      --           LINE_SIZE_W  => 5 )             -- Line size (bytes !)
      AXIDATA_W    => AXIDATA_W,                   -- Data width
      WAYS         => DWAYS,                       -- Number of ways  (1,2,4,8)
      LINE_ADDR_W  => DLINE_ADDR_W,                -- Line address
      LINE_SIZE_W  => DLINE_SIZE_W )               -- Line size (bytes !)
    port map ( clk_i             => clk_i,
               xrst_i            => xrst_cache_w,
               --  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_i       => dmbist_ena_i_w,
               mbist_rd_i        => dmbist_rd_i_w,      -- 1-hot, t1,d1,t0,d0
               mbist_wr_i        => dmbist_wr_i_w,      -- 1-hot, t1,d1,t0,d0
               mbist_addr_i      => dmbist_addr_i_w,
               mbist_data_o      => dmbist_data_o_w,
               --
               cpu_rd_i          => dcache_cached_rd_w,
               cpu_wr_i          => dcache_cached_wr_w,
               cpu_addr_i        => core_d_addr_w,      -- BYTE addr, [1:0] NC
               cpu_wdata_i       => core_d_data_wr_w,
               cpu_req_tag_i     => core_d_req_tag_w,
               cpu_invalidate_i  => core_d_invalidate_w,
               cpu_wb_i          => core_d_wb_w,
               cpu_flush_i       => core_d_flush_w,
               cpu_rdata_o       => dcache_data_rd_w,
               cpu_accept_o      => dcache_accept_w,
               cpu_ack_o         => dcache_ack_w,
               cpu_error_o       => dcache_error_w,
               cpu_resp_tag_o    => dcache_resp_tag_w,  -- mem resp tag
               --
               xmem_accept_i     => d_accept_w,
               xmem_ack_i        => d_ack_w,
               xmem_error_i      => d_error_w,
               xmem_rdata_i      => pmem_mbist_d_w,     -- ! !
               xmem_rd_o         => d_rd_w,
               xmem_wr_o         => d_wr_w,
               xmem_len_o        => d_len_w,
               xmem_addr_o       => d_addr_w,
               xmem_wdata_o      => d_wdata_w );


  u_dma : dma
    generic map ( AXIDATA_W => AXIDATA_W )
    port map ( clk_i          => clk_i,
               xrst_i         => xrst_cache_w,
               --
               dma_rd_i       => dma_rd_i,
               dma_wr_i       => dma_wr_i,
               dma_addr_i     => dma_addr_i(6 downto 2),
               dma_wr_data_i  => dma_wr_data_i,
               dma_rd_data_o  => dma_rd_data_o,
               dma_intr_o     => dma_intr_o,
               -- to/from axi
               resp_rdata_i   => pmem_rdata_w,
               dma1_rd_o      => dma1_rd_w,
               dma1_wr_o      => dma1_wr_w,
               dma1_len_o     => dma1_len_w,
               dma1_addr_o    => dma1_addr_w,
               dma1_wdata_o   => dma1_wdata_w,
               dma1_accept_i  => dma1_accept_w,
               dma1_ack_i     => dma1_ack_w,
               dma1_error_i   => dma1_error_w );


  u_axi : axi_wrapper
    generic map ( AXI_ID    => AXI_ID,
                  AXIDATA_W => AXIDATA_W,               -- Data width 32/64 only
                  ROM_BASE  => X"7" )
    port map ( clk_i          => clk_i,
               xrst_i         => xrst_cache_w,
               --
               --  channel 1
               dmem_rd_i      => d_rd_w,
               dmem_wr_i      => d_wr_w(0),             -- [3:1] NC
               dmem_len_i     => d_len_w,
               dmem_addr_i    => d_addr_w,              -- BYTE, [1:0] NC
               dmem_wdata_i   => d_wdata_w,
               dmem_accept_o  => d_accept_w,
               dmem_ack_o     => d_ack_w,
               dmem_error_o   => d_error_w,
               --  channel 2
               imem_rd_i      => i_rd_w,
               imem_wr_i      => i_wr_w(0),             -- NC in icache
               imem_len_i     => i_len_w,
               imem_addr_i    => i_addr_w,              -- BYTE, [1:0] NC
               imem_wdata_i   => i_wdata_w,             -- NC in icache
               imem_accept_o  => i_accept_w,
               imem_ack_o     => i_ack_w,
               imem_error_o   => i_error_w,
               --
               --  channel 3  (dma / dbg_uart)
               dma1_rd_i      => dma1_rd_w,
               dma1_wr_i      => dma1_wr_w,
               dma1_len_i     => dma1_len_w,
               dma1_addr_i    => dma1_addr_w,           -- [1:0] NC
               dma1_wdata_i   => dma1_wdata_w,
               dma1_accept_o  => dma1_accept_w,
               dma1_ack_o     => dma1_ack_w,
               dma1_error_o   => dma1_error_w,
               --
               dma2_rd_i      => '0',
               dma2_wr_i      => '0',
               dma2_len_i     => (others => '0'),
               dma2_addr_i    => (others => '0'),       -- [1:0] NC
               dma2_wdata_i   => (others => '0'),
               dma2_accept_o  => OPEN,
               dma2_ack_o     => OPEN,
               dma2_error_o   => OPEN,
               --
               dma3_rd_i      => '0',
               dma3_wr_i      => '0',
               dma3_len_i     => (others => '0'),
               dma3_addr_i    => (others => '0'),       -- [1:0] NC
               dma3_wdata_i   => (others => '0'),
               dma3_accept_o  => OPEN,
               dma3_ack_o     => OPEN,
               dma3_error_o   => OPEN,
               --
                --  common ports for all channels
               resp_rdata_o   => pmem_rdata_w,
               --  read req
               axi_arvalid_o  => axi_arvalid_o,
               axi_araddr_o   => axi_araddr_o,
               axi_arid_o     => axi_arid_o,
               axi_arlen_o    => axi_arlen_o,
               axi_arburst_o  => axi_arburst_o,
               axi_rready_o   => axi_rready_o,
               --  read resp
               axi_arready_i  => axi_arready_i,
               axi_rvalid_i   => axi_rvalid_i,
               axi_rdata_i    => axi_rdata_i,
               axi_rresp_i    => axi_rresp_i,
               axi_rid_i      => axi_rid_i,
               axi_rlast_i    => axi_rlast_i,
               --  write req
               axi_awready_i  => axi_awready_i,
               axi_wready_i   => axi_wready_i,
               axi_bvalid_i   => axi_bvalid_i,
               axi_bresp_i    => axi_bresp_i,
               axi_bid_i      => axi_bid_i,
               --  write resp
               axi_awvalid_o  => axi_awvalid_o_w,
               axi_awaddr_o   => axi_awaddr_o,
               axi_awid_o     => axi_awid_o,
               axi_awlen_o    => axi_awlen_o,
               axi_awburst_o  => axi_awburst_o,
               axi_wvalid_o   => axi_wvalid_o_w,
               axi_wdata_o    => axi_wdata_o,
               axi_wstrb_o    => axi_wstrb_o_w,       -- [31:4] NC
               axi_wlast_o    => axi_wlast_o_w,
               axi_bready_o   => axi_bready_o_w  );

  axi_awvalid_o <= axi_awvalid_o_w;
  axi_wvalid_o  <= axi_wvalid_o_w;
  axi_wstrb_o   <= axi_wstrb_o_w;
  axi_wlast_o   <= axi_wlast_o_w;
  axi_bready_o  <= axi_bready_o_w;

end rtl;
