// Copyright 2021 ETH Zurich and University of Bologna.
// Solderpad Hardware License, Version 0.51, see LICENSE for details.
// SPDX-License-Identifier: SHL-0.51

`include "axi/assign.svh"
`include "common_cells/registers.svh"

module mempool_system
  import mempool_pkg::*;
#(
  // TCDM
  parameter addr_t       TCDMBaseAddr  = 32'h0000_0000,
  // Boot address
  parameter addr_t       BootAddr      = 32'h0000_0000
) (
  input logic                clk_i,
  input logic                rst_ni,

  input  logic               fetch_en_i,
  output logic               eoc_valid_o,
  output logic               busy_o,

  output axi_system_req_t    mst_req_o,
  input  axi_system_resp_t   mst_resp_i,

  input  axi_system_req_t    slv_req_i,
  output axi_system_resp_t   slv_resp_o
);

  import axi_pkg::xbar_cfg_t;
  import axi_pkg::xbar_rule_32_t;

  /*********
   *  AXI  *
   *********/

  // Overview of AXI buses
  //
  //      mst_demux
  //        / |
  //       /  | soc  +----------+ periph  +---------+
  //      |  0|=====>| soc_xbar |========>| periph  |
  //  mst |   |      +----------+         +---------+
  // ====>|   |
  //      |   | l2   +----------+  mem    +---------+ bank  +--------+
  //      |  1|=====>| axi2mem  |-------->| l2_xbar |------>| l2_mem |
  //       \  |      +----------+         +---------+       +--------+
  //        \_|
  //                  == axi ==>          -- tcdm -->

  localparam NumAXIMasters = NumSystemXbarMasters;
  localparam NumAXISlaves  = 3; // control regs, bootrom and the external mst ports
  localparam NumSoCRules   = NumAXISlaves - 1;

  typedef enum logic [$clog2(NumAXISlaves) - 1:0] {
    Peripherals,
    Bootrom,
    External
  } axi_soc_xbar_slave_target;

  typedef enum logic {
    SoCXBar = 0,
    L2Memory = 1
  } axi_mst_demux_slave_target;

  axi_tile_req_t    [NumAXIMasters-1:0] axi_mst_req;
  axi_tile_resp_t   [NumAXIMasters-1:0] axi_mst_resp;
  axi_tile_req_t    [NumAXIMasters-1:0] axi_l2_req;
  axi_tile_resp_t   [NumAXIMasters-1:0] axi_l2_resp;
  axi_tile_req_t    [NumAXIMasters-1:0] axi_soc_req;
  axi_tile_resp_t   [NumAXIMasters-1:0] axi_soc_resp;
  axi_system_req_t  [NumAXISlaves-1:0]  axi_periph_req;
  axi_system_resp_t [NumAXISlaves-1:0]  axi_periph_resp;
  logic             [NumCores-1:0]      wake_up;
  logic             [DataWidth-1:0]     eoc;
  ro_cache_ctrl_t                       ro_cache_ctrl;

  dma_req_t  dma_req;
  logic      dma_req_valid;
  logic      dma_req_ready;
  dma_meta_t dma_meta;
  logic      [1-1:0] dma_id;

  localparam xbar_cfg_t MstDemuxCfg = '{
    NoSlvPorts         : 1, // Each master has a private demux
    NoMstPorts         : 2, // going to either the xbar or L2
    MaxMstTrans        : 4,
    MaxSlvTrans        : 4,
    FallThrough        : 1'b0,
    LatencyMode        : axi_pkg::NO_LATENCY,
    AxiIdWidthSlvPorts : AxiTileIdWidth,
    AxiIdUsedSlvPorts  : AxiTileIdWidth,
    UniqueIds          : 0,
    AxiAddrWidth       : AddrWidth,
    AxiDataWidth       : AxiDataWidth,
    NoAddrRules        : 1
  };

  localparam xbar_cfg_t SoCXBarCfg = '{
    NoSlvPorts         : NumAXIMasters,
    NoMstPorts         : NumAXISlaves,
    MaxMstTrans        : 4,
    MaxSlvTrans        : 4,
    FallThrough        : 1'b0,
    LatencyMode        : axi_pkg::CUT_MST_PORTS,
    AxiIdWidthSlvPorts : AxiTileIdWidth,
    AxiIdUsedSlvPorts  : AxiTileIdWidth,
    UniqueIds          : 0,
    AxiAddrWidth       : AddrWidth,
    AxiDataWidth       : AxiDataWidth,
    NoAddrRules        : NumSoCRules
  };

  /*********************
   *  MemPool Cluster  *
   ********************/

  mempool_cluster #(
    .TCDMBaseAddr(TCDMBaseAddr),
    .BootAddr    (BootAddr    )
  ) i_mempool_cluster (
    .clk_i          (clk_i                          ),
    .rst_ni         (rst_ni                         ),
    .wake_up_i      (wake_up                        ),
    .testmode_i     (1'b0                           ),
    .scan_enable_i  (1'b0                           ),
    .scan_data_i    (1'b0                           ),
    .scan_data_o    (/* Unused */                   ),
    .ro_cache_ctrl_i(ro_cache_ctrl                  ),
    .dma_req_i      (dma_req                        ),
    .dma_req_valid_i(dma_req_valid                  ),
    .dma_req_ready_o(dma_req_ready                  ),
    .dma_meta_o     (dma_meta                       ),
    .axi_mst_req_o  (axi_mst_req[NumAXIMasters-2:0] ),
    .axi_mst_resp_i (axi_mst_resp[NumAXIMasters-2:0])
  );

  /**********************
   *  AXI Interconnect  *
   **********************/

  localparam addr_t PeripheralsBaseAddr   = 32'h4000_0000;
  localparam addr_t PeripheralsEndAddr    = 32'h4002_0000;
  localparam addr_t L2MemoryBaseAddr      = `ifdef L2_BASE `L2_BASE `else 32'h8000_0000 `endif;
  localparam addr_t L2MemoryEndAddr       = L2MemoryBaseAddr + L2Size;
  localparam addr_t BootromBaseAddr       = 32'hA000_0000;
  localparam addr_t BootromEndAddr        = 32'hA000_FFFF;

  xbar_rule_32_t [            0:0]  mst_demux_rules;
  xbar_rule_32_t [NumSoCRules-1:0] soc_xbar_rules;
  assign mst_demux_rules = '{
    '{idx: L2Memory, start_addr: L2MemoryBaseAddr, end_addr: L2MemoryEndAddr}
  };
  assign soc_xbar_rules = '{
    '{idx: Peripherals, start_addr: PeripheralsBaseAddr, end_addr: PeripheralsEndAddr},
    '{idx: Bootrom, start_addr: BootromBaseAddr, end_addr: BootromEndAddr}
  };

  for (genvar i = 0; i < NumAXIMasters; i++) begin : gen_mst_demux
    axi_xbar #(
      .Cfg          (MstDemuxCfg      ),
      .slv_aw_chan_t(axi_tile_aw_t    ),
      .mst_aw_chan_t(axi_tile_aw_t    ),
      .w_chan_t     (axi_tile_w_t     ),
      .slv_b_chan_t (axi_tile_b_t     ),
      .mst_b_chan_t (axi_tile_b_t     ),
      .slv_ar_chan_t(axi_tile_ar_t    ),
      .mst_ar_chan_t(axi_tile_ar_t    ),
      .slv_r_chan_t (axi_tile_r_t     ),
      .mst_r_chan_t (axi_tile_r_t     ),
      .slv_req_t    (axi_tile_req_t   ),
      .slv_resp_t   (axi_tile_resp_t  ),
      .mst_req_t    (axi_tile_req_t   ),
      .mst_resp_t   (axi_tile_resp_t  ),
      .rule_t       (xbar_rule_32_t   )
    ) i_mst_demux (
      .clk_i                (clk_i                           ),
      .rst_ni               (rst_ni                          ),
      .test_i               (1'b0                            ),
      .slv_ports_req_i      (axi_mst_req[i]                  ),
      .slv_ports_resp_o     (axi_mst_resp[i]                 ),
      .mst_ports_req_o      ({axi_l2_req[i] ,axi_soc_req[i] }),
      .mst_ports_resp_i     ({axi_l2_resp[i],axi_soc_resp[i]}),
      .addr_map_i           (mst_demux_rules                 ),
      .en_default_mst_port_i(1'b1                            ),
      .default_mst_port_i   (SoCXBar                         )
    );
  end

  axi_xbar #(
    .Cfg          (SoCXBarCfg       ),
    .slv_aw_chan_t(axi_tile_aw_t    ),
    .mst_aw_chan_t(axi_system_aw_t  ),
    .w_chan_t     (axi_tile_w_t     ),
    .slv_b_chan_t (axi_tile_b_t     ),
    .mst_b_chan_t (axi_system_b_t   ),
    .slv_ar_chan_t(axi_tile_ar_t    ),
    .mst_ar_chan_t(axi_system_ar_t  ),
    .slv_r_chan_t (axi_tile_r_t     ),
    .mst_r_chan_t (axi_system_r_t   ),
    .slv_req_t    (axi_tile_req_t   ),
    .slv_resp_t   (axi_tile_resp_t  ),
    .mst_req_t    (axi_system_req_t ),
    .mst_resp_t   (axi_system_resp_t),
    .rule_t       (xbar_rule_32_t   )
  ) i_soc_xbar (
    .clk_i                (clk_i                    ),
    .rst_ni               (rst_ni                   ),
    .test_i               (1'b0                     ),
    .slv_ports_req_i      (axi_soc_req              ),
    .slv_ports_resp_o     (axi_soc_resp             ),
    .mst_ports_req_o      (axi_periph_req           ),
    .mst_ports_resp_i     (axi_periph_resp          ),
    .addr_map_i           (soc_xbar_rules           ),
    .en_default_mst_port_i({NumAXIMasters{1'b1}}    ), // default all slave ports to master port External
    .default_mst_port_i   ({NumAXIMasters{External}})
  );

  /********
   *  L2  *
   ********/
  localparam int unsigned NumAXIMastersLog2 = NumAXIMasters == 1 ? 1 : $clog2(NumAXIMasters);
  typedef logic [L2AddrWidth-1:0] l2_mem_addr_t;
  typedef logic [L2BankAddrWidth-1:0] l2_bank_addr_t;
  typedef logic [NumAXIMastersLog2-1:0] bank_ini_t;
  // Axi2Mems to l2_xbar
  logic         [NumAXIMasters-1:0] mem_req;
  logic         [NumAXIMasters-1:0] mem_gnt;
  logic         [NumAXIMasters-1:0] mem_rvalid;
  addr_t        [NumAXIMasters-1:0] mem_addr_full;
  l2_mem_addr_t [NumAXIMasters-1:0] mem_addr;
  axi_data_t    [NumAXIMasters-1:0] mem_wdata;
  axi_strb_t    [NumAXIMasters-1:0] mem_strb;
  logic         [NumAXIMasters-1:0] mem_we;
  axi_data_t    [NumAXIMasters-1:0] mem_rdata;
  // l2_xbar to banks
  logic          [NumL2Banks-1:0] bank_req;
  logic          [NumL2Banks-1:0] bank_gnt;
  logic          [NumL2Banks-1:0] bank_rvalid;
  l2_bank_addr_t [NumL2Banks-1:0] bank_addr;
  bank_ini_t     [NumL2Banks-1:0] bank_ini_d, bank_ini_q;
  axi_data_t     [NumL2Banks-1:0] bank_wdata;
  axi_strb_t     [NumL2Banks-1:0] bank_strb;
  logic          [NumL2Banks-1:0] bank_we;
  axi_data_t     [NumL2Banks-1:0] bank_rdata;

  for (genvar i = 0; i < NumAXIMasters; i++) begin : gen_l2_adapters
    axi2mem #(
      .axi_req_t (axi_tile_req_t ),
      .axi_resp_t(axi_tile_resp_t),
      .AddrWidth (L2AddrWidth    ),
      .DataWidth (AxiDataWidth   ),
      .IdWidth   (AxiTileIdWidth ),
      .NumBanks  (1              ),
      .BufDepth  (3              )
    ) i_axi2mem (
      .clk_i       (clk_i         ),
      .rst_ni      (rst_ni        ),
      .busy_o      (/*unsused*/   ),
      .axi_req_i   (axi_l2_req[i] ),
      .axi_resp_o  (axi_l2_resp[i]),
      .mem_req_o   (mem_req[i]    ),
      .mem_gnt_i   (mem_gnt[i]    ),
      .mem_addr_o  (mem_addr[i]   ),
      .mem_wdata_o (mem_wdata[i]  ),
      .mem_strb_o  (mem_strb[i]   ),
      .mem_atop_o  (/*unused*/    ),
      .mem_we_o    (mem_we[i]     ),
      .mem_rvalid_i(mem_rvalid[i] ),
      .mem_rdata_i (mem_rdata[i]  )
    );
  end

  variable_latency_interconnect #(
    .NumIn            (NumAXIMasters  ),
    .NumOut           (NumL2Banks     ),
    .AddrWidth        (L2AddrWidth    ),
    .DataWidth        (L2BankWidth    ),
    .BeWidth          (L2BankBeWidth  ),
    .AddrMemWidth     (L2BankAddrWidth),
    .AxiVldRdy        (1'b1           ),
    .SpillRegisterReq (64'b1          ),
    .SpillRegisterResp(64'b1          )
  ) i_l2_xbar (
    .clk_i          (clk_i      ),
    .rst_ni         (rst_ni     ),
    // master side
    .req_valid_i    (mem_req    ),
    .req_ready_o    (mem_gnt    ),
    .req_tgt_addr_i (mem_addr   ),
    .req_wen_i      (mem_we     ),
    .req_wdata_i    (mem_wdata  ),
    .req_be_i       (mem_strb   ),
    .resp_valid_o   (mem_rvalid ),
    .resp_ready_i   ('1         ),
    .resp_rdata_o   (mem_rdata  ),
    // slave side
    .req_valid_o    (bank_req   ),
    .req_ready_i    ('1         ),
    .req_ini_addr_o (bank_ini_d ),
    .req_tgt_addr_o (bank_addr  ),
    .req_wen_o      (bank_we    ),
    .req_wdata_o    (bank_wdata ),
    .req_be_o       (bank_strb  ),
    .resp_valid_i   (bank_rvalid),
    .resp_ready_o   (/*unused*/ ), // This only works because resp_ready_i = 1
    .resp_ini_addr_i(bank_ini_q ),
    .resp_rdata_i   (bank_rdata )
  );

  `FF(bank_rvalid, bank_req, 1'b0, clk_i, rst_ni)
  `FF(bank_ini_q, bank_ini_d, 1'b0, clk_i, rst_ni)

  for (genvar i = 0; i < NumL2Banks; i++) begin : gen_l2_banks
    tc_sram #(
      .DataWidth(L2BankWidth   ),
      .NumWords (L2BankNumWords),
      .NumPorts (1             )
    ) l2_mem (
      .clk_i  (clk_i        ),
      .rst_ni (rst_ni       ),
      .req_i  (bank_req[i]  ),
      .we_i   (bank_we[i]   ),
      .addr_i (bank_addr[i] ),
      .wdata_i(bank_wdata[i]),
      .be_i   (bank_strb[i] ),
      .rdata_o(bank_rdata[i])
    );
  end

  /*************
   *  Bootrom  *
   *************/

  // Memory
  logic      bootrom_req;
  logic      bootrom_rvalid;
  addr_t     bootrom_addr;
  axi_data_t bootrom_rdata;

  axi2mem #(
    .axi_req_t  (axi_system_req_t ),
    .axi_resp_t (axi_system_resp_t),
    .AddrWidth  (AddrWidth        ),
    .DataWidth  (AxiDataWidth     ),
    .IdWidth    (AxiSystemIdWidth ),
    .NumBanks   (1                ),
    .BufDepth   (2                )
  ) i_axi2mem_bootrom (
    .clk_i        (clk_i                   ),
    .rst_ni       (rst_ni                  ),

    .busy_o       (/*unsused*/             ),

    .axi_req_i    (axi_periph_req[Bootrom] ),
    .axi_resp_o   (axi_periph_resp[Bootrom]),

    .mem_req_o    (bootrom_req             ),
    .mem_gnt_i    (bootrom_req             ),
    .mem_addr_o   (bootrom_addr            ),
    .mem_wdata_o  (/*unused*/              ),
    .mem_strb_o   (/*unused*/              ),
    .mem_atop_o   (/*unused*/              ),
    .mem_we_o     (/*unused*/              ),
    .mem_rvalid_i (bootrom_rvalid          ),
    .mem_rdata_i  (bootrom_rdata           )
  );

  `FF(bootrom_rvalid, bootrom_req, 1'b0, clk_i, rst_ni)

  bootrom i_bootrom (
    .clk_i  (clk_i        ),
    .req_i  (bootrom_req  ),
    .addr_i (bootrom_addr ),
    .rdata_o(bootrom_rdata)
  );

  /***********************
   *  Control Registers  *
   ***********************/

  localparam NumPeriphs = 2; // Control registers + DMA

  typedef enum logic [$clog2(NumPeriphs) - 1:0] {
    CtrlRegisters,
    DMA
  } axi_lite_xbar_slave_target;

  axi_periph_req_t                     axi_periph_narrow_req;
  axi_periph_resp_t                    axi_periph_narrow_resp;
  axi_lite_slv_req_t                   axi_lite_mst_req;
  axi_lite_slv_resp_t                  axi_lite_mst_resp;
  axi_lite_slv_req_t  [NumPeriphs-1:0] axi_lite_slv_req;
  axi_lite_slv_resp_t [NumPeriphs-1:0] axi_lite_slv_resp;

  localparam xbar_cfg_t AXILiteXBarCfg = '{
    NoSlvPorts         : 1,
    NoMstPorts         : NumPeriphs,
    MaxMstTrans        : 1,
    MaxSlvTrans        : 1,
    FallThrough        : 1'b0,
    LatencyMode        : axi_pkg::NO_LATENCY,
    AxiIdWidthSlvPorts : 0, /* Not used for AXI lite */
    AxiIdUsedSlvPorts  : 0, /* Not used for AXI lite */
    UniqueIds          : 0, /* Not used for AXI lite */
    AxiAddrWidth       : AddrWidth,
    AxiDataWidth       : AxiLiteDataWidth,
    NoAddrRules        : NumPeriphs
  };

  localparam addr_t CtrlRegistersBaseAddr = 32'h4000_0000;
  localparam addr_t CtrlRegistersEndAddr  = 32'h4001_0000;
  localparam addr_t DMABaseAddr           = 32'h4001_0000;
  localparam addr_t DMAEndAddr            = 32'h4002_0000;

  xbar_rule_32_t [NumPeriphs-1:0] axi_lite_xbar_rules;
  assign axi_lite_xbar_rules = '{
    '{idx: CtrlRegisters, start_addr: CtrlRegistersBaseAddr, end_addr: CtrlRegistersEndAddr},
    '{idx: DMA, start_addr: DMABaseAddr, end_addr: DMAEndAddr}
  };

  axi_dw_converter #(
    .AxiMaxReads         (1                ), // Number of outstanding reads
    .AxiSlvPortDataWidth (AxiDataWidth     ), // Data width of the slv port
    .AxiMstPortDataWidth (AxiLiteDataWidth ), // Data width of the mst port
    .AxiAddrWidth        (AddrWidth        ), // Address width
    .AxiIdWidth          (AxiSystemIdWidth ), // ID width
    .aw_chan_t           (axi_system_aw_t  ), // AW Channel Type
    .mst_w_chan_t        (axi_periph_w_t   ), //  W Channel Type for the mst port
    .slv_w_chan_t        (axi_system_w_t   ), //  W Channel Type for the slv port
    .b_chan_t            (axi_system_b_t   ), //  B Channel Type
    .ar_chan_t           (axi_system_ar_t  ), // AR Channel Type
    .mst_r_chan_t        (axi_periph_r_t   ), //  R Channel Type for the mst port
    .slv_r_chan_t        (axi_system_r_t   ), //  R Channel Type for the slv port
    .axi_mst_req_t       (axi_periph_req_t ), // AXI Request Type for mst ports
    .axi_mst_resp_t      (axi_periph_resp_t), // AXI Response Type for mst ports
    .axi_slv_req_t       (axi_system_req_t ), // AXI Request Type for slv ports
    .axi_slv_resp_t      (axi_system_resp_t)  // AXI Response Type for slv ports
  ) i_axi_dw_converter_ctrl (
    .clk_i      (clk_i                       ),
    .rst_ni     (rst_ni                      ),
    // Slave interface
    .slv_req_i  (axi_periph_req[Peripherals] ),
    .slv_resp_o (axi_periph_resp[Peripherals]),
    // Master interface
    .mst_req_o  (axi_periph_narrow_req       ),
    .mst_resp_i (axi_periph_narrow_resp      )
  );

  axi_to_axi_lite #(
    .AxiAddrWidth   (AddrWidth          ),
    .AxiDataWidth   (AxiLiteDataWidth   ),
    .AxiIdWidth     (AxiSystemIdWidth   ),
    .AxiUserWidth   (1                  ),
    .AxiMaxReadTxns (1                  ),
    .AxiMaxWriteTxns(1                  ),
    .FallThrough    (1'b0               ),
    .full_req_t     (axi_periph_req_t   ),
    .full_resp_t    (axi_periph_resp_t  ),
    .lite_req_t     (axi_lite_slv_req_t ),
    .lite_resp_t    (axi_lite_slv_resp_t)
  ) i_axi_to_axi_lite (
    .clk_i     (clk_i                 ),
    .rst_ni    (rst_ni                ),
    .test_i    (1'b0                  ),
    .slv_req_i (axi_periph_narrow_req ),
    .slv_resp_o(axi_periph_narrow_resp),
    .mst_req_o (axi_lite_mst_req      ),
    .mst_resp_i(axi_lite_mst_resp     )
  );

  axi_lite_xbar #(
    .Cfg       (AXILiteXBarCfg     ),
    .aw_chan_t (axi_lite_slv_aw_t  ),
    .w_chan_t  (axi_lite_slv_w_t   ),
    .b_chan_t  (axi_lite_slv_b_t   ),
    .ar_chan_t (axi_lite_slv_ar_t  ),
    .r_chan_t  (axi_lite_slv_r_t   ),
    .axi_req_t (axi_lite_slv_req_t ),
    .axi_resp_t(axi_lite_slv_resp_t),
    .rule_t    (xbar_rule_32_t     )
  ) i_axi_lite_xbar (
    .clk_i                (clk_i              ),
    .rst_ni               (rst_ni             ),
    .test_i               (1'b0               ),
    .slv_ports_req_i      (axi_lite_mst_req   ),
    .slv_ports_resp_o     (axi_lite_mst_resp  ),
    .mst_ports_req_o      (axi_lite_slv_req   ),
    .mst_ports_resp_i     (axi_lite_slv_resp  ),
    .addr_map_i           (axi_lite_xbar_rules),
    .en_default_mst_port_i('1                 ),
    .default_mst_port_i   (CtrlRegisters      )
  );

  ctrl_registers #(
    .NumRegs          (16 + 8             ),
    .TCDMBaseAddr     (TCDMBaseAddr       ),
    .TCDMSize         (TCDMSize           ),
    .NumCores         (NumCores           ),
    .axi_lite_req_t (axi_lite_slv_req_t ),
    .axi_lite_resp_t(axi_lite_slv_resp_t)
  ) i_ctrl_registers (
    .clk_i                (clk_i                           ),
    .rst_ni               (rst_ni                          ),
    .axi_lite_slave_req_i (axi_lite_slv_req[CtrlRegisters] ),
    .axi_lite_slave_resp_o(axi_lite_slv_resp[CtrlRegisters]),
    .ro_cache_ctrl_o      (ro_cache_ctrl                   ),
    .tcdm_start_address_o (/* Unused */                    ),
    .tcdm_end_address_o   (/* Unused */                    ),
    .num_cores_o          (/* Unused */                    ),
    .wake_up_o            (wake_up                         ),
    .eoc_o                (/* Unused */                    ),
    .eoc_valid_o          (eoc_valid_o                     )
  );

  mempool_dma #(
    .axi_lite_req_t(axi_lite_slv_req_t       ),
    .axi_lite_rsp_t(axi_lite_slv_resp_t      ),
    .burst_req_t   (dma_req_t                ),
    .NumBackends   (NumGroups                ),
    .DmaIdWidth    (1                        )
  ) i_mempool_dma (
    .clk_i           (clk_i                 ),
    .rst_ni          (rst_ni                ),
    .config_req_i    (axi_lite_slv_req[DMA] ),
    .config_res_o    (axi_lite_slv_resp[DMA]),
    .burst_req_o     (dma_req               ),
    .valid_o         (dma_req_valid         ),
    .ready_i         (dma_req_ready         ),
    .backend_idle_i  (dma_meta.backend_idle),
    .trans_complete_i(dma_meta.trans_complete),
    .dma_id_o        (dma_id                )
  );

  assign busy_o = 1'b0;

  // From MemPool to the Host
  assign mst_req_o                 = axi_periph_req[External];
  assign axi_periph_resp[External] = mst_resp_i;
  // From the Host to MemPool
  axi_id_remap #(
    .AxiSlvPortIdWidth   (AxiSystemIdWidth ),
    .AxiSlvPortMaxUniqIds(1                ),
    .AxiMaxTxnsPerId     (1                ),
    .AxiMstPortIdWidth   (AxiTileIdWidth   ),
    .slv_req_t           (axi_system_req_t ),
    .slv_resp_t          (axi_system_resp_t),
    .mst_req_t           (axi_tile_req_t   ),
    .mst_resp_t          (axi_tile_resp_t  )
  ) i_axi_id_remap (
    .clk_i     (clk_i                        ),
    .rst_ni    (rst_ni                       ),
    .slv_req_i (slv_req_i                    ),
    .slv_resp_o(slv_resp_o                   ),
    .mst_req_o (axi_mst_req[NumAXIMasters-1] ),
    .mst_resp_i(axi_mst_resp[NumAXIMasters-1])
  );

endmodule : mempool_system