// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License.  You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this 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.
//
// Author: Michael Schaffner <schaffner@iis.ee.ethz.ch>, ETH Zurich
// Date: 14.11.2018
// Description: Ariane chipset for OpenPiton that includes the bootrom (with DTB),
// debug module, clint and plic.
//
// Note that direct system bus accesses are not yet possible due to a missing
// AXI-lite br_master <-> NOC converter module.
//
// The address bases for the individual peripherals are defined in the
// devices.xml file in OpenPiton, and should be set to
//
// Debug    40'h90_0000_0000 <length 0x1000>
// Boot Rom 40'h90_0001_0000 <length 0x10000>
// CLINT    40'h90_0200_0000 <length 0x1000000>
// PLIC     40'h90_0300_0000 <length 0x1000000>
//

module serpent_peripherals #(
    parameter int unsigned DataWidth      = 64,
    parameter int unsigned NumHarts       =  1,
    parameter int unsigned NumSources     =  1,
    parameter bit          SwapEndianess  =  0
) (
    input                               clk_i,
    input                               rst_ni,
    input                               testmode_i,
    // connections to OpenPiton NoC filters
    // Debug/JTAG
    input  [DataWidth-1:0]              buf_ariane_debug_noc2_data_i,
    input                               buf_ariane_debug_noc2_valid_i,
    output                              ariane_debug_buf_noc2_ready_o,
    output [DataWidth-1:0]              ariane_debug_buf_noc3_data_o,
    output                              ariane_debug_buf_noc3_valid_o,
    input                               buf_ariane_debug_noc3_ready_i,
    // Bootrom
    input  [DataWidth-1:0]              buf_ariane_bootrom_noc2_data_i,
    input                               buf_ariane_bootrom_noc2_valid_i,
    output                              ariane_bootrom_buf_noc2_ready_o,
    output [DataWidth-1:0]              ariane_bootrom_buf_noc3_data_o,
    output                              ariane_bootrom_buf_noc3_valid_o,
    input                               buf_ariane_bootrom_noc3_ready_i,
    // CLINT
    input  [DataWidth-1:0]              buf_ariane_clint_noc2_data_i,
    input                               buf_ariane_clint_noc2_valid_i,
    output                              ariane_clint_buf_noc2_ready_o,
    output [DataWidth-1:0]              ariane_clint_buf_noc3_data_o,
    output                              ariane_clint_buf_noc3_valid_o,
    input                               buf_ariane_clint_noc3_ready_i,
    // PLIC
    input [DataWidth-1:0]               buf_ariane_plic_noc2_data_i,
    input                               buf_ariane_plic_noc2_valid_i,
    output                              ariane_plic_buf_noc2_ready_o,
    output [DataWidth-1:0]              ariane_plic_buf_noc3_data_o,
    output                              ariane_plic_buf_noc3_valid_o,
    input                               buf_ariane_plic_noc3_ready_i,
    // Debug sigs to cores
    output                              ndmreset_o,    // non-debug module reset
    output                              dmactive_o,    // debug module is active
    output [NumHarts-1:0]               debug_req_o,   // async debug request
    input  [NumHarts-1:0]               unavailable_i, // communicate whether the hart is unavailable (e.g.: power down)
    // JTAG
    input                               tck_i,
    input                               tms_i,
    input                               trst_ni,
    input                               td_i,
    output                              td_o,
    output                              tdo_oe_o,
    // CLINT
    input                               rtc_i,        // Real-time clock in (usually 32.768 kHz)
    output [NumHarts-1:0]               timer_irq_o,  // Timer interrupts
    output [NumHarts-1:0]               ipi_o,        // software interrupt (a.k.a inter-process-interrupt)
    // PLIC
    // TODO
    input  [NumSources-1:0]             irq_sources_i,
    output [NumHarts-1:0][1:0]          irq_o         // level sensitive IR lines, mip & sip (async)
);

  localparam int unsigned AxiIdWidth    =  0;
  localparam int unsigned AxiAddrWidth  = 64;
  localparam int unsigned AxiDataWidth  = 64;
  localparam int unsigned AxiUserWidth  =  0;

  /////////////////////////////
  // Debug module and JTAG
  /////////////////////////////

  logic        jtag_req_valid;
  logic        debug_req_ready;
  logic        jtag_resp_ready;
  logic        jtag_resp_valid;

  dm::dmi_req_t  jtag_dmi_req;
  dm::dmi_resp_t debug_resp;

  dmi_jtag i_dmi_jtag (
    .clk_i                               ,
    .rst_ni                              ,
    .testmode_i                          ,
    .dmi_req_o        ( jtag_dmi_req    ),
    .dmi_req_valid_o  ( jtag_req_valid  ),
    .dmi_req_ready_i  ( debug_req_ready ),
    .dmi_resp_i       ( debug_resp      ),
    .dmi_resp_ready_o ( jtag_resp_ready ),
    .dmi_resp_valid_i ( jtag_resp_valid ),
    .dmi_rst_no       (                 ), // not connected
    .tck_i                               ,
    .tms_i                               ,
    .trst_ni                             ,
    .td_i                                ,
    .td_o                                ,
    .tdo_oe_o
  );

  ariane_axi::req_t    dm_axi_m_req,  dm_axi_s_req;
  ariane_axi::resp_t   dm_axi_m_resp, dm_axi_s_resp;

  // debug module
  dm_top #(
    // current implementation only supports 1 hart
    .NrHarts              ( NumHarts             ),
    .AxiIdWidth           ( AxiIdWidth           ),
    .AxiAddrWidth         ( AxiAddrWidth         ),
    .AxiDataWidth         ( AxiDataWidth         ),
    .AxiUserWidth         ( AxiUserWidth         )
  ) i_dm_top (
    .clk_i                                        ,
    .rst_ni                                       , // PoR
    .testmode_i                                   ,
    .ndmreset_o                                   ,
    .dmactive_o                                   , // active debug session
    .debug_req_o                                  ,
    .unavailable_i                                ,
    .axi_s_req_i          ( dm_axi_s_req         ),
    .axi_s_resp_o         ( dm_axi_s_resp        ),
    .axi_m_req_o          ( dm_axi_m_req         ),
    .axi_m_resp_i         ( dm_axi_m_resp        ),
    .dmi_rst_ni           ( rst_ni               ),
    .dmi_req_valid_i      ( jtag_req_valid       ),
    .dmi_req_ready_o      ( debug_req_ready      ),
    .dmi_req_i            ( jtag_dmi_req         ),
    .dmi_resp_valid_o     ( jtag_resp_valid      ),
    .dmi_resp_ready_i     ( jtag_resp_ready      ),
    .dmi_resp_o           ( debug_resp           )
  );

  noc_axilite_bridge #(
    .SLAVE_RESP_BYTEWIDTH   ( 8             ),
    .SWAP_ENDIANESS         ( SwapEndianess )
  ) i_debug_axilite_bridge (
    .clk                    ( clk_i                         ),
    .rst                    ( ~rst_ni                       ),
    // to/from NOC
    .splitter_bridge_val    ( buf_ariane_debug_noc2_valid_i ),
    .splitter_bridge_data   ( buf_ariane_debug_noc2_data_i  ),
    .bridge_splitter_rdy    ( ariane_debug_buf_noc2_ready_o ),
    .bridge_splitter_val    ( ariane_debug_buf_noc3_valid_o ),
    .bridge_splitter_data   ( ariane_debug_buf_noc3_data_o  ),
    .splitter_bridge_rdy    ( buf_ariane_debug_noc3_ready_i ),
    //axi lite signals
    //write address channel
    .m_axi_awaddr           ( dm_axi_s_req.aw.addr          ),
    .m_axi_awvalid          ( dm_axi_s_req.aw_valid         ),
    .m_axi_awready          ( dm_axi_s_resp.aw_ready        ),
    //write data channel
    .m_axi_wdata            ( dm_axi_s_req.w.data           ),
    .m_axi_wstrb            ( dm_axi_s_req.w.strb           ),
    .m_axi_wvalid           ( dm_axi_s_req.w_valid          ),
    .m_axi_wready           ( dm_axi_s_resp.w_ready         ),
    //read address channel
    .m_axi_araddr           ( dm_axi_s_req.ar.addr          ),
    .m_axi_arvalid          ( dm_axi_s_req.ar_valid         ),
    .m_axi_arready          ( dm_axi_s_resp.ar_ready        ),
    //read data channel
    .m_axi_rdata            ( dm_axi_s_resp.r.data          ),
    .m_axi_rresp            ( dm_axi_s_resp.r.resp          ),
    .m_axi_rvalid           ( dm_axi_s_resp.r_valid         ),
    .m_axi_rready           ( dm_axi_s_req.r_ready          ),
    //write response channel
    .m_axi_bresp            ( dm_axi_s_resp.b.resp          ),
    .m_axi_bvalid           ( dm_axi_s_resp.b_valid         ),
    .m_axi_bready           ( dm_axi_s_req.b_ready          )
  );

  // tie off system bus accesses (not supported yet due to
  // missing AXI-lite br_master <-> NOC converter)
  assign dm_axi_m_resp = '0;

  // tie off signals not used by AXI-lite
  assign dm_axi_s_req.aw.id     = '0;
  assign dm_axi_s_req.aw.len    = '0;
  assign dm_axi_s_req.aw.size   = 2'b11;// 8byte
  assign dm_axi_s_req.aw.burst  = '0;
  assign dm_axi_s_req.aw.lock   = '0;
  assign dm_axi_s_req.aw.cache  = '0;
  assign dm_axi_s_req.aw.prot   = '0;
  assign dm_axi_s_req.aw.qos    = '0;
  assign dm_axi_s_req.aw.region = '0;
  assign dm_axi_s_req.aw.atop   = '0;
  assign dm_axi_s_req.w.last    = 1'b1;
  assign dm_axi_s_req.ar.id     = '0;
  assign dm_axi_s_req.ar.len    = '0;
  assign dm_axi_s_req.ar.size   = 2'b11;// 8byte
  assign dm_axi_s_req.ar.burst  = '0;
  assign dm_axi_s_req.ar.lock   = '0;
  assign dm_axi_s_req.ar.cache  = '0;
  assign dm_axi_s_req.ar.prot   = '0;
  assign dm_axi_s_req.ar.qos    = '0;
  assign dm_axi_s_req.ar.region = '0;
  // assign dm_axi_s_resp.r.id     = '0;
  // assign dm_axi_s_resp.r.last   = 1'b1;
  // assign dm_axi_s_resp.b.id     = '0;

  /////////////////////////////
  // Bootrom
  /////////////////////////////

  logic                    rom_req;
  logic [AxiAddrWidth-1:0] rom_addr;
  logic [AxiDataWidth-1:0] rom_rdata;

  AXI_BUS #(
    .AXI_ID_WIDTH   ( AxiIdWidth   ),
    .AXI_ADDR_WIDTH ( AxiAddrWidth ),
    .AXI_DATA_WIDTH ( AxiDataWidth ),
    .AXI_USER_WIDTH ( AxiUserWidth )
  ) br_master();

  axi2mem #(
    .AXI_ID_WIDTH   ( AxiIdWidth    ),
    .AXI_ADDR_WIDTH ( AxiAddrWidth  ),
    .AXI_DATA_WIDTH ( AxiDataWidth  ),
    .AXI_USER_WIDTH ( AxiUserWidth  )
  ) i_axi2rom (
    .clk_i                ,
    .rst_ni               ,
    .slave  ( br_master  ),
    .req_o  ( rom_req    ),
    .we_o   (            ),
    .addr_o ( rom_addr   ),
    .be_o   (            ),
    .data_o (            ),
    .data_i ( rom_rdata  )
  );

  bootrom i_bootrom (
    .clk_i                   ,
    .req_i      ( rom_req   ),
    .addr_i     ( rom_addr  ),
    .rdata_o    ( rom_rdata )
  );

  noc_axilite_bridge #(
    .SLAVE_RESP_BYTEWIDTH   ( 8             ),
    .SWAP_ENDIANESS         ( SwapEndianess )
  ) i_bootrom_axilite_bridge (
    .clk                    ( clk_i                           ),
    .rst                    ( ~rst_ni                         ),
    // to/from NOC
    .splitter_bridge_val    ( buf_ariane_bootrom_noc2_valid_i ),
    .splitter_bridge_data   ( buf_ariane_bootrom_noc2_data_i  ),
    .bridge_splitter_rdy    ( ariane_bootrom_buf_noc2_ready_o ),
    .bridge_splitter_val    ( ariane_bootrom_buf_noc3_valid_o ),
    .bridge_splitter_data   ( ariane_bootrom_buf_noc3_data_o  ),
    .splitter_bridge_rdy    ( buf_ariane_bootrom_noc3_ready_i ),
    //axi lite signals
    //write address channel
    .m_axi_awaddr           ( br_master.aw_addr               ),
    .m_axi_awvalid          ( br_master.aw_valid              ),
    .m_axi_awready          ( br_master.aw_ready              ),
    //write data channel
    .m_axi_wdata            ( br_master.w_data                ),
    .m_axi_wstrb            ( br_master.w_strb                ),
    .m_axi_wvalid           ( br_master.w_valid               ),
    .m_axi_wready           ( br_master.w_ready               ),
    //read address channel
    .m_axi_araddr           ( br_master.ar_addr               ),
    .m_axi_arvalid          ( br_master.ar_valid              ),
    .m_axi_arready          ( br_master.ar_ready              ),
    //read data channel
    .m_axi_rdata            ( br_master.r_data                ),
    .m_axi_rresp            ( br_master.r_resp                ),
    .m_axi_rvalid           ( br_master.r_valid               ),
    .m_axi_rready           ( br_master.r_ready               ),
    //write response channel
    .m_axi_bresp            ( br_master.b_resp                ),
    .m_axi_bvalid           ( br_master.b_valid               ),
    .m_axi_bready           ( br_master.b_ready               )
  );

  // tie off signals not used by AXI-lite
  assign br_master.aw_id     = '0;
  assign br_master.aw_len    = '0;
  assign br_master.aw_size   = 2'b11;// 8byte
  assign br_master.aw_burst  = '0;
  assign br_master.aw_lock   = '0;
  assign br_master.aw_cache  = '0;
  assign br_master.aw_prot   = '0;
  assign br_master.aw_qos    = '0;
  assign br_master.aw_region = '0;
  assign br_master.w_last    = 1'b1;
  assign br_master.ar_id     = '0;
  assign br_master.ar_len    = '0;
  assign br_master.ar_size   = 2'b11;// 8byte
  assign br_master.ar_burst  = '0;
  assign br_master.ar_lock   = '0;
  assign br_master.ar_cache  = '0;
  assign br_master.ar_prot   = '0;
  assign br_master.ar_qos    = '0;
  assign br_master.ar_region = '0;
  // assign br_master.r_id      = '0;
  // assign br_master.r_last    = 1'b1;
  // assign br_master.b_id      = '0;

  /////////////////////////////
  // CLINT
  /////////////////////////////

  ariane_axi::req_t    clint_axi_req;
  ariane_axi::resp_t   clint_axi_resp;

  clint #(
      .AXI_ADDR_WIDTH ( AxiAddrWidth ),
      .AXI_DATA_WIDTH ( AxiDataWidth ),
      .AXI_ID_WIDTH   ( AxiIdWidth   ),
      .NR_CORES       ( NumHarts     )
  ) i_clint (
      .clk_i                         ,
      .rst_ni                        ,
      .testmode_i                    ,
      .axi_req_i   ( clint_axi_req  ),
      .axi_resp_o  ( clint_axi_resp ),
      .rtc_i                         ,
      .timer_irq_o                   ,
      .ipi_o
  );

  noc_axilite_bridge #(
    .SLAVE_RESP_BYTEWIDTH   ( 8             ),
    .SWAP_ENDIANESS         ( SwapEndianess )
  ) i_clint_axilite_bridge (
    .clk                    ( clk_i                         ),
    .rst                    ( ~rst_ni                       ),
    // to/from NOC
    .splitter_bridge_val    ( buf_ariane_clint_noc2_valid_i ),
    .splitter_bridge_data   ( buf_ariane_clint_noc2_data_i  ),
    .bridge_splitter_rdy    ( ariane_clint_buf_noc2_ready_o ),
    .bridge_splitter_val    ( ariane_clint_buf_noc3_valid_o ),
    .bridge_splitter_data   ( ariane_clint_buf_noc3_data_o  ),
    .splitter_bridge_rdy    ( buf_ariane_clint_noc3_ready_i ),
    //axi lite signals
    //write address channel
    .m_axi_awaddr           ( clint_axi_req.aw.addr         ),
    .m_axi_awvalid          ( clint_axi_req.aw_valid        ),
    .m_axi_awready          ( clint_axi_resp.aw_ready       ),
    //write data channel
    .m_axi_wdata            ( clint_axi_req.w.data          ),
    .m_axi_wstrb            ( clint_axi_req.w.strb          ),
    .m_axi_wvalid           ( clint_axi_req.w_valid         ),
    .m_axi_wready           ( clint_axi_resp.w_ready        ),
    //read address channel
    .m_axi_araddr           ( clint_axi_req.ar.addr         ),
    .m_axi_arvalid          ( clint_axi_req.ar_valid        ),
    .m_axi_arready          ( clint_axi_resp.ar_ready       ),
    //read data channel
    .m_axi_rdata            ( clint_axi_resp.r.data         ),
    .m_axi_rresp            ( clint_axi_resp.r.resp         ),
    .m_axi_rvalid           ( clint_axi_resp.r_valid        ),
    .m_axi_rready           ( clint_axi_req.r_ready         ),
    //write response channel
    .m_axi_bresp            ( clint_axi_resp.b.resp         ),
    .m_axi_bvalid           ( clint_axi_resp.b_valid        ),
    .m_axi_bready           ( clint_axi_req.b_ready         )
  );

  // tie off signals not used by AXI-lite
  assign clint_axi_req.aw.id     = '0;
  assign clint_axi_req.aw.len    = '0;
  assign clint_axi_req.aw.size   = 2'b11;// 8byte
  assign clint_axi_req.aw.burst  = '0;
  assign clint_axi_req.aw.lock   = '0;
  assign clint_axi_req.aw.cache  = '0;
  assign clint_axi_req.aw.prot   = '0;
  assign clint_axi_req.aw.qos    = '0;
  assign clint_axi_req.aw.region = '0;
  assign clint_axi_req.aw.atop   = '0;
  assign clint_axi_req.w.last    = 1'b1;
  assign clint_axi_req.ar.id     = '0;
  assign clint_axi_req.ar.len    = '0;
  assign clint_axi_req.ar.size   = 2'b11;// 8byte
  assign clint_axi_req.ar.burst  = '0;
  assign clint_axi_req.ar.lock   = '0;
  assign clint_axi_req.ar.cache  = '0;
  assign clint_axi_req.ar.prot   = '0;
  assign clint_axi_req.ar.qos    = '0;
  assign clint_axi_req.ar.region = '0;


  /////////////////////////////
  // PLIC
  /////////////////////////////

  AXI_BUS #(
    .AXI_ID_WIDTH   ( AxiIdWidth   ),
    .AXI_ADDR_WIDTH ( AxiAddrWidth ),
    .AXI_DATA_WIDTH ( AxiDataWidth ),
    .AXI_USER_WIDTH ( AxiUserWidth )
  ) plic_master();

  noc_axilite_bridge #(
   .SLAVE_RESP_BYTEWIDTH   ( 8             ),
   .SWAP_ENDIANESS         ( SwapEndianess )
  ) i_plic_axilite_bridge (
    .clk                    ( clk_i                        ),
    .rst                    ( ~rst_ni                      ),
    // to/from NOC
    .splitter_bridge_val    ( buf_ariane_plic_noc2_valid_i ),
    .splitter_bridge_data   ( buf_ariane_plic_noc2_data_i  ),
    .bridge_splitter_rdy    ( ariane_plic_buf_noc2_ready_o ),
    .bridge_splitter_val    ( ariane_plic_buf_noc3_valid_o ),
    .bridge_splitter_data   ( ariane_plic_buf_noc3_data_o  ),
    .splitter_bridge_rdy    ( buf_ariane_plic_noc3_ready_i ),
    //axi lite signals
    //write address channel
    //write address channel
    .m_axi_awaddr           ( plic_master.aw_addr               ),
    .m_axi_awvalid          ( plic_master.aw_valid              ),
    .m_axi_awready          ( plic_master.aw_ready              ),
    //write data channel
    .m_axi_wdata            ( plic_master.w_data                ),
    .m_axi_wstrb            ( plic_master.w_strb                ),
    .m_axi_wvalid           ( plic_master.w_valid               ),
    .m_axi_wready           ( plic_master.w_ready               ),
    //read address channel
    .m_axi_araddr           ( plic_master.ar_addr               ),
    .m_axi_arvalid          ( plic_master.ar_valid              ),
    .m_axi_arready          ( plic_master.ar_ready              ),
    //read data channel
    .m_axi_rdata            ( plic_master.r_data                ),
    .m_axi_rresp            ( plic_master.r_resp                ),
    .m_axi_rvalid           ( plic_master.r_valid               ),
    .m_axi_rready           ( plic_master.r_ready               ),
    //write response channel
    .m_axi_bresp            ( plic_master.b_resp                ),
    .m_axi_bvalid           ( plic_master.b_valid               ),
    .m_axi_bready           ( plic_master.b_ready               )
  );

  // tie off signals not used by AXI-lite
  assign plic_master.aw_id     = '0;
  assign plic_master.aw_len    = '0;
  assign plic_master.aw_size   = 2'b11;// 8byte
  assign plic_master.aw_burst  = '0;
  assign plic_master.aw_lock   = '0;
  assign plic_master.aw_cache  = '0;
  assign plic_master.aw_prot   = '0;
  assign plic_master.aw_qos    = '0;
  assign plic_master.aw_region = '0;
  assign plic_master.w_last    = 1'b1;
  assign plic_master.ar_id     = '0;
  assign plic_master.ar_len    = '0;
  assign plic_master.ar_size   = 2'b11;// 8byte
  assign plic_master.ar_burst  = '0;
  assign plic_master.ar_lock   = '0;
  assign plic_master.ar_cache  = '0;
  assign plic_master.ar_prot   = '0;
  assign plic_master.ar_qos    = '0;
  assign plic_master.ar_region = '0;

    REG_BUS #(
        .ADDR_WIDTH ( 32 ),
        .DATA_WIDTH ( 32 )
    ) reg_bus (clk_i);

    logic         plic_penable;
    logic         plic_pwrite;
    logic [31:0]  plic_paddr;
    logic         plic_psel;
    logic [31:0]  plic_pwdata;
    logic [31:0]  plic_prdata;
    logic         plic_pready;
    logic         plic_pslverr;

    axi2apb_64_32 #(
        .AXI4_ADDRESS_WIDTH ( AxiAddrWidth ),
        .AXI4_RDATA_WIDTH   ( AxiDataWidth ),
        .AXI4_WDATA_WIDTH   ( AxiDataWidth ),
        .AXI4_ID_WIDTH      ( AxiIdWidth   ),
        .AXI4_USER_WIDTH    ( AxiUserWidth ),
        .BUFF_DEPTH_SLAVE   ( 2            ),
        .APB_ADDR_WIDTH     ( 32           )
    ) i_axi2apb_64_32_plic (
        .ACLK      ( clk_i                 ),
        .ARESETn   ( rst_ni                ),
        .test_en_i ( testmode_i            ),
        .AWID_i    ( plic_master.aw_id     ),
        .AWADDR_i  ( plic_master.aw_addr   ),
        .AWLEN_i   ( plic_master.aw_len    ),
        .AWSIZE_i  ( plic_master.aw_size   ),
        .AWBURST_i ( plic_master.aw_burst  ),
        .AWLOCK_i  ( plic_master.aw_lock   ),
        .AWCACHE_i ( plic_master.aw_cache  ),
        .AWPROT_i  ( plic_master.aw_prot   ),
        .AWREGION_i( plic_master.aw_region ),
        .AWUSER_i  ( plic_master.aw_user   ),
        .AWQOS_i   ( plic_master.aw_qos    ),
        .AWVALID_i ( plic_master.aw_valid  ),
        .AWREADY_o ( plic_master.aw_ready  ),
        .WDATA_i   ( plic_master.w_data    ),
        .WSTRB_i   ( plic_master.w_strb    ),
        .WLAST_i   ( plic_master.w_last    ),
        .WUSER_i   ( plic_master.w_user    ),
        .WVALID_i  ( plic_master.w_valid   ),
        .WREADY_o  ( plic_master.w_ready   ),
        .BID_o     ( plic_master.b_id      ),
        .BRESP_o   ( plic_master.b_resp    ),
        .BVALID_o  ( plic_master.b_valid   ),
        .BUSER_o   ( plic_master.b_user    ),
        .BREADY_i  ( plic_master.b_ready   ),
        .ARID_i    ( plic_master.ar_id     ),
        .ARADDR_i  ( plic_master.ar_addr   ),
        .ARLEN_i   ( plic_master.ar_len    ),
        .ARSIZE_i  ( plic_master.ar_size   ),
        .ARBURST_i ( plic_master.ar_burst  ),
        .ARLOCK_i  ( plic_master.ar_lock   ),
        .ARCACHE_i ( plic_master.ar_cache  ),
        .ARPROT_i  ( plic_master.ar_prot   ),
        .ARREGION_i( plic_master.ar_region ),
        .ARUSER_i  ( plic_master.ar_user   ),
        .ARQOS_i   ( plic_master.ar_qos    ),
        .ARVALID_i ( plic_master.ar_valid  ),
        .ARREADY_o ( plic_master.ar_ready  ),
        .RID_o     ( plic_master.r_id      ),
        .RDATA_o   ( plic_master.r_data    ),
        .RRESP_o   ( plic_master.r_resp    ),
        .RLAST_o   ( plic_master.r_last    ),
        .RUSER_o   ( plic_master.r_user    ),
        .RVALID_o  ( plic_master.r_valid   ),
        .RREADY_i  ( plic_master.r_ready   ),
        .PENABLE   ( plic_penable   ),
        .PWRITE    ( plic_pwrite    ),
        .PADDR     ( plic_paddr     ),
        .PSEL      ( plic_psel      ),
        .PWDATA    ( plic_pwdata    ),
        .PRDATA    ( plic_prdata    ),
        .PREADY    ( plic_pready    ),
        .PSLVERR   ( plic_pslverr   )
    );

    apb_to_reg i_apb_to_reg (
        .clk_i                     ,
        .rst_ni                    ,
        .penable_i ( plic_penable ),
        .pwrite_i  ( plic_pwrite  ),
        .paddr_i   ( plic_paddr   ),
        .psel_i    ( plic_psel    ),
        .pwdata_i  ( plic_pwdata  ),
        .prdata_o  ( plic_prdata  ),
        .pready_o  ( plic_pready  ),
        .pslverr_o ( plic_pslverr ),
        .reg_o     ( reg_bus      )
    );

    plic #(
        .ADDR_WIDTH         ( 32                     ),
        .DATA_WIDTH         ( 32                     ),
        .ID_BITWIDTH        ( 3                      ), // TODO (zarubaf): Find propper width
        .PARAMETER_BITWIDTH ( 3                      ), // TODO (zarubaf): Find propper width
        .NUM_TARGETS        ( 2*NumHarts             ),
        .NUM_SOURCES        ( NumSources             )
    ) i_plic (
        .clk_i                                        ,
        .rst_ni                                       ,
        .irq_sources_i                                ,
        .eip_targets_o      ( irq_o                  ),
        .external_bus_io    ( reg_bus                )
);



endmodule