-- #################################################################################################
-- # << The NEORV32 RISC-V Processor - Top Entity >>                                               #
-- # ********************************************************************************************* #
-- # Check out the processor's online documentation for more information:                          #
-- #  HQ:         https://github.com/stnolting/neorv32                                             #
-- #  Data Sheet: https://stnolting.github.io/neorv32                                              #
-- #  User Guide: https://stnolting.github.io/neorv32/ug                                           #
-- # ********************************************************************************************* #
-- # BSD 3-Clause License                                                                          #
-- #                                                                                               #
-- # The NEORV32 RISC-V Processor, https://github.com/stnolting/neorv32                            #
-- # Copyright (c) 2024, Stephan Nolting. All rights reserved.                                     #
-- #                                                                                               #
-- # Redistribution and use in source and binary forms, with or without modification, are          #
-- # permitted provided that the following conditions are met:                                     #
-- #                                                                                               #
-- # 1. Redistributions of source code must retain the above copyright notice, this list of        #
-- #    conditions and the following disclaimer.                                                   #
-- #                                                                                               #
-- # 2. Redistributions in binary form must reproduce the above copyright notice, this list of     #
-- #    conditions and the following disclaimer in the documentation and/or other materials        #
-- #    provided with the distribution.                                                            #
-- #                                                                                               #
-- # 3. Neither the name of the copyright holder nor the names of its contributors may be used to  #
-- #    endorse or promote products derived from this software without specific prior written      #
-- #    permission.                                                                                #
-- #                                                                                               #
-- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS   #
-- # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF               #
-- # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE    #
-- # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,     #
-- # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE #
-- # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED    #
-- # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING     #
-- # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED  #
-- # OF THE POSSIBILITY OF SUCH DAMAGE.                                                            #
-- #################################################################################################

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

library neorv32;
use neorv32.neorv32_package.all;

entity neorv32_top is
  generic (
    -- General --
    CLOCK_FREQUENCY            : natural;                                       -- clock frequency of clk_i in Hz
    CLOCK_GATING_EN            : boolean                        := false;       -- enable clock gating when in sleep mode
    HART_ID                    : std_ulogic_vector(31 downto 0) := x"00000000"; -- hardware thread ID
    VENDOR_ID                  : std_ulogic_vector(31 downto 0) := x"00000000"; -- vendor's JEDEC ID
    INT_BOOTLOADER_EN          : boolean                        := false;       -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM

    -- On-Chip Debugger (OCD) --
    ON_CHIP_DEBUGGER_EN        : boolean                        := false;       -- implement on-chip debugger
    DM_LEGACY_MODE             : boolean                        := false;       -- debug module spec version: false = v1.0, true = v0.13

    -- RISC-V CPU Extensions --
    CPU_EXTENSION_RISCV_A      : boolean                        := false;       -- implement atomic memory operations extension?
    CPU_EXTENSION_RISCV_B      : boolean                        := false;       -- implement bit-manipulation extension?
    CPU_EXTENSION_RISCV_C      : boolean                        := false;       -- implement compressed extension?
    CPU_EXTENSION_RISCV_E      : boolean                        := false;       -- implement embedded RF extension?
    CPU_EXTENSION_RISCV_M      : boolean                        := false;       -- implement mul/div extension?
    CPU_EXTENSION_RISCV_U      : boolean                        := false;       -- implement user mode extension?
    CPU_EXTENSION_RISCV_Zfinx  : boolean                        := false;       -- implement 32-bit floating-point extension (using INT regs!)
    CPU_EXTENSION_RISCV_Zicntr : boolean                        := true;        -- implement base counters?
    CPU_EXTENSION_RISCV_Zicond : boolean                        := false;       -- implement integer conditional operations?
    CPU_EXTENSION_RISCV_Zihpm  : boolean                        := false;       -- implement hardware performance monitors?
    CPU_EXTENSION_RISCV_Zmmul  : boolean                        := false;       -- implement multiply-only M sub-extension?
    CPU_EXTENSION_RISCV_Zxcfu  : boolean                        := false;       -- implement custom (instr.) functions unit?

    -- Tuning Options --
    FAST_MUL_EN                : boolean                        := false;       -- use DSPs for M extension's multiplier
    FAST_SHIFT_EN              : boolean                        := false;       -- use barrel shifter for shift operations
    REGFILE_HW_RST             : boolean                        := false;       -- implement full hardware reset for register file

    -- Physical Memory Protection (PMP) --
    PMP_NUM_REGIONS            : natural range 0 to 16          := 0;           -- number of regions (0..16)
    PMP_MIN_GRANULARITY        : natural                        := 4;           -- minimal region granularity in bytes, has to be a power of 2, min 4 bytes
    PMP_TOR_MODE_EN            : boolean                        := true;        -- implement TOR mode
    PMP_NAP_MODE_EN            : boolean                        := true;        -- implement NAPOT/NA4 modes

    -- Hardware Performance Monitors (HPM) --
    HPM_NUM_CNTS               : natural range 0 to 13          := 0;           -- number of implemented HPM counters (0..13)
    HPM_CNT_WIDTH              : natural range 0 to 64          := 40;          -- total size of HPM counters (0..64)

    -- Atomic Memory Access - Reservation Set Granularity --
    AMO_RVS_GRANULARITY        : natural                        := 4;           -- size in bytes, has to be a power of 2, min 4

    -- Internal Instruction memory (IMEM) --
    MEM_INT_IMEM_EN            : boolean                        := false;       -- implement processor-internal instruction memory
    MEM_INT_IMEM_SIZE          : natural                        := 16*1024;     -- size of processor-internal instruction memory in bytes (use a power of 2)

    -- Internal Data memory (DMEM) --
    MEM_INT_DMEM_EN            : boolean                        := false;       -- implement processor-internal data memory
    MEM_INT_DMEM_SIZE          : natural                        := 8*1024;      -- size of processor-internal data memory in bytes (use a power of 2)

    -- Internal Instruction Cache (iCACHE) --
    ICACHE_EN                  : boolean                        := false;       -- implement instruction cache
    ICACHE_NUM_BLOCKS          : natural range 1 to 256         := 4;           -- i-cache: number of blocks (min 1), has to be a power of 2
    ICACHE_BLOCK_SIZE          : natural range 4 to 2**16       := 64;          -- i-cache: block size in bytes (min 4), has to be a power of 2
    ICACHE_ASSOCIATIVITY       : natural range 1 to 2           := 1;           -- i-cache: associativity / number of sets (1=direct_mapped), has to be a power of 2

    -- Internal Data Cache (dCACHE) --
    DCACHE_EN                  : boolean                        := false;       -- implement data cache
    DCACHE_NUM_BLOCKS          : natural range 1 to 256         := 4;           -- d-cache: number of blocks (min 1), has to be a power of 2
    DCACHE_BLOCK_SIZE          : natural range 4 to 2**16       := 64;          -- d-cache: block size in bytes (min 4), has to be a power of 2

    -- External memory interface (WISHBONE) --
    MEM_EXT_EN                 : boolean                        := false;       -- implement external memory bus interface?
    MEM_EXT_TIMEOUT            : natural                        := 255;         -- cycles after a pending bus access auto-terminates (0 = disabled)
    MEM_EXT_PIPE_MODE          : boolean                        := false;       -- protocol: false=classic/standard wishbone mode, true=pipelined wishbone mode
    MEM_EXT_BIG_ENDIAN         : boolean                        := false;       -- byte order: true=big-endian, false=little-endian
    MEM_EXT_ASYNC_RX           : boolean                        := false;       -- use register buffer for RX data when false
    MEM_EXT_ASYNC_TX           : boolean                        := false;       -- use register buffer for TX data when false

    -- Execute in-place module (XIP) --
    XIP_EN                     : boolean                        := false;       -- implement execute in place module (XIP)?
    XIP_CACHE_EN               : boolean                        := false;       -- implement XIP cache?
    XIP_CACHE_NUM_BLOCKS       : natural range 1 to 256         := 8;           -- number of blocks (min 1), has to be a power of 2
    XIP_CACHE_BLOCK_SIZE       : natural range 1 to 2**16       := 256;         -- block size in bytes (min 4), has to be a power of 2

    -- External Interrupts Controller (XIRQ) --
    XIRQ_NUM_CH                : natural range 0 to 32          := 0;           -- number of external IRQ channels (0..32)
    XIRQ_TRIGGER_TYPE          : std_ulogic_vector(31 downto 0) := x"ffffffff"; -- trigger type: 0=level, 1=edge
    XIRQ_TRIGGER_POLARITY      : std_ulogic_vector(31 downto 0) := x"ffffffff"; -- trigger polarity: 0=low-level/falling-edge, 1=high-level/rising-edge

    -- Processor peripherals --
    IO_GPIO_NUM                : natural range 0 to 64          := 0;           -- number of GPIO input/output pairs (0..64)
    IO_MTIME_EN                : boolean                        := false;       -- implement machine system timer (MTIME)?
    IO_UART0_EN                : boolean                        := false;       -- implement primary universal asynchronous receiver/transmitter (UART0)?
    IO_UART0_RX_FIFO           : natural range 1 to 2**15       := 1;           -- RX fifo depth, has to be a power of two, min 1
    IO_UART0_TX_FIFO           : natural range 1 to 2**15       := 1;           -- TX fifo depth, has to be a power of two, min 1
    IO_UART1_EN                : boolean                        := false;       -- implement secondary universal asynchronous receiver/transmitter (UART1)?
    IO_UART1_RX_FIFO           : natural range 1 to 2**15       := 1;           -- RX fifo depth, has to be a power of two, min 1
    IO_UART1_TX_FIFO           : natural range 1 to 2**15       := 1;           -- TX fifo depth, has to be a power of two, min 1
    IO_SPI_EN                  : boolean                        := false;       -- implement serial peripheral interface (SPI)?
    IO_SPI_FIFO                : natural range 1 to 2**15       := 1;           -- RTX fifo depth, has to be a power of two, min 1
    IO_SDI_EN                  : boolean                        := false;       -- implement serial data interface (SDI)?
    IO_SDI_FIFO                : natural range 1 to 2**15       := 1;           -- RTX fifo depth, has to be zero or a power of two, min 1
    IO_TWI_EN                  : boolean                        := false;       -- implement two-wire interface (TWI)?
    IO_PWM_NUM_CH              : natural range 0 to 12          := 0;           -- number of PWM channels to implement (0..12); 0 = disabled
    IO_WDT_EN                  : boolean                        := false;       -- implement watch dog timer (WDT)?
    IO_TRNG_EN                 : boolean                        := false;       -- implement true random number generator (TRNG)?
    IO_TRNG_FIFO               : natural range 1 to 2**15       := 1;           -- data fifo depth, has to be a power of two, min 1
    IO_CFS_EN                  : boolean                        := false;       -- implement custom functions subsystem (CFS)?
    IO_CFS_CONFIG              : std_ulogic_vector(31 downto 0) := x"00000000"; -- custom CFS configuration generic
    IO_CFS_IN_SIZE             : natural                        := 32;          -- size of CFS input conduit in bits
    IO_CFS_OUT_SIZE            : natural                        := 32;          -- size of CFS output conduit in bits
    IO_NEOLED_EN               : boolean                        := false;       -- implement NeoPixel-compatible smart LED interface (NEOLED)?
    IO_NEOLED_TX_FIFO          : natural range 1 to 2**15       := 1;           -- NEOLED FIFO depth, has to be a power of two, min 1
    IO_GPTMR_EN                : boolean                        := false;       -- implement general purpose timer (GPTMR)?
    IO_ONEWIRE_EN              : boolean                        := false;       -- implement 1-wire interface (ONEWIRE)?
    IO_DMA_EN                  : boolean                        := false;       -- implement direct memory access controller (DMA)?
    IO_SLINK_EN                : boolean                        := false;       -- implement stream link interface (SLINK)?
    IO_SLINK_RX_FIFO           : natural range 1 to 2**15       := 1;           -- RX fifo depth, has to be a power of two, min 1
    IO_SLINK_TX_FIFO           : natural range 1 to 2**15       := 1;           -- TX fifo depth, has to be a power of two, min 1
    IO_CRC_EN                  : boolean                        := false        -- implement cyclic redundancy check unit (CRC)?
  );
  port (
    -- Global control --
    clk_i          : in  std_ulogic; -- global clock, rising edge
    rstn_i         : in  std_ulogic; -- global reset, low-active, async

    -- JTAG on-chip debugger interface (available if ON_CHIP_DEBUGGER_EN = true) --
    jtag_trst_i    : in  std_ulogic := 'H'; -- low-active TAP reset (optional)
    jtag_tck_i     : in  std_ulogic := 'L'; -- serial clock
    jtag_tdi_i     : in  std_ulogic := 'L'; -- serial data input
    jtag_tdo_o     : out std_ulogic; -- serial data output
    jtag_tms_i     : in  std_ulogic := 'L'; -- mode select

    -- Wishbone bus interface (available if MEM_EXT_EN = true) --
    wb_tag_o       : out std_ulogic_vector(02 downto 0); -- request tag
    wb_adr_o       : out std_ulogic_vector(31 downto 0); -- address
    wb_dat_i       : in  std_ulogic_vector(31 downto 0) := (others => 'L'); -- read data
    wb_dat_o       : out std_ulogic_vector(31 downto 0); -- write data
    wb_we_o        : out std_ulogic; -- read/write
    wb_sel_o       : out std_ulogic_vector(03 downto 0); -- byte enable
    wb_stb_o       : out std_ulogic; -- strobe
    wb_cyc_o       : out std_ulogic; -- valid cycle
    wb_ack_i       : in  std_ulogic := 'L'; -- transfer acknowledge
    wb_err_i       : in  std_ulogic := 'L'; -- transfer error

    -- Stream Link Interface (available if IO_SLINK_EN = true) --
    slink_rx_dat_i : in  std_ulogic_vector(31 downto 0) := (others => 'L'); -- RX input data
    slink_rx_val_i : in  std_ulogic := 'L'; -- RX valid input
    slink_rx_lst_i : in  std_ulogic := 'L'; -- last element of stream
    slink_rx_rdy_o : out std_ulogic; -- RX ready to receive
    slink_tx_dat_o : out std_ulogic_vector(31 downto 0); -- TX output data
    slink_tx_val_o : out std_ulogic; -- TX valid output
    slink_tx_lst_o : out std_ulogic; -- last element of stream
    slink_tx_rdy_i : in  std_ulogic := 'L'; -- TX ready to send

    -- XIP (execute in place via SPI) signals (available if XIP_EN = true) --
    xip_csn_o      : out std_ulogic; -- chip-select, low-active
    xip_clk_o      : out std_ulogic; -- serial clock
    xip_dat_i      : in  std_ulogic := 'L'; -- device data input
    xip_dat_o      : out std_ulogic; -- controller data output

    -- GPIO (available if IO_GPIO_NUM > 0) --
    gpio_o         : out std_ulogic_vector(63 downto 0); -- parallel output
    gpio_i         : in  std_ulogic_vector(63 downto 0) := (others => 'L'); -- parallel input

    -- primary UART0 (available if IO_UART0_EN = true) --
    uart0_txd_o    : out std_ulogic; -- UART0 send data
    uart0_rxd_i    : in  std_ulogic := 'L'; -- UART0 receive data
    uart0_rts_o    : out std_ulogic; -- HW flow control: UART0.RX ready to receive ("RTR"), low-active, optional
    uart0_cts_i    : in  std_ulogic := 'L'; -- HW flow control: UART0.TX allowed to transmit, low-active, optional

    -- secondary UART1 (available if IO_UART1_EN = true) --
    uart1_txd_o    : out std_ulogic; -- UART1 send data
    uart1_rxd_i    : in  std_ulogic := 'L'; -- UART1 receive data
    uart1_rts_o    : out std_ulogic; -- HW flow control: UART1.RX ready to receive ("RTR"), low-active, optional
    uart1_cts_i    : in  std_ulogic := 'L'; -- HW flow control: UART1.TX allowed to transmit, low-active, optional

    -- SPI (available if IO_SPI_EN = true) --
    spi_clk_o      : out std_ulogic; -- SPI serial clock
    spi_dat_o      : out std_ulogic; -- controller data out, peripheral data in
    spi_dat_i      : in  std_ulogic := 'L'; -- controller data in, peripheral data out
    spi_csn_o      : out std_ulogic_vector(07 downto 0); -- chip-select

    -- SDI (available if IO_SDI_EN = true) --
    sdi_clk_i      : in  std_ulogic := 'L'; -- SDI serial clock
    sdi_dat_o      : out std_ulogic; -- controller data out, peripheral data in
    sdi_dat_i      : in  std_ulogic := 'L'; -- controller data in, peripheral data out
    sdi_csn_i      : in  std_ulogic := 'H'; -- chip-select

    -- TWI (available if IO_TWI_EN = true) --
    twi_sda_i      : in  std_ulogic := 'H'; -- serial data line sense input
    twi_sda_o      : out std_ulogic; -- serial data line output (pull low only)
    twi_scl_i      : in  std_ulogic := 'H'; -- serial clock line sense input
    twi_scl_o      : out std_ulogic; -- serial clock line output (pull low only)

    -- 1-Wire Interface (available if IO_ONEWIRE_EN = true) --
    onewire_i      : in  std_ulogic := 'H'; -- 1-wire bus sense input
    onewire_o      : out std_ulogic; -- 1-wire bus output (pull low only)

    -- PWM (available if IO_PWM_NUM_CH > 0) --
    pwm_o          : out std_ulogic_vector(11 downto 0); -- pwm channels

    -- Custom Functions Subsystem IO (available if IO_CFS_EN = true) --
    cfs_in_i       : in  std_ulogic_vector(IO_CFS_IN_SIZE-1 downto 0) := (others => 'L'); -- custom CFS inputs conduit
    cfs_out_o      : out std_ulogic_vector(IO_CFS_OUT_SIZE-1 downto 0); -- custom CFS outputs conduit

    -- NeoPixel-compatible smart LED interface (available if IO_NEOLED_EN = true) --
    neoled_o       : out std_ulogic; -- async serial data line

    -- Machine timer system time (available if IO_MTIME_EN = true) --
    mtime_time_o   : out std_ulogic_vector(63 downto 0); -- current system time

    -- GPTMR timer capture (available if IO_GPTMR_EN = true) --
    gptmr_trig_i   : in  std_ulogic := 'L'; -- capture trigger

    -- External platform interrupts (available if XIRQ_NUM_CH > 0) --
    xirq_i         : in  std_ulogic_vector(31 downto 0) := (others => 'L'); -- IRQ channels

    -- CPU interrupts --
    mtime_irq_i    : in  std_ulogic := 'L'; -- machine timer interrupt, available if IO_MTIME_EN = false
    msw_irq_i      : in  std_ulogic := 'L'; -- machine software interrupt
    mext_irq_i     : in  std_ulogic := 'L'  -- machine external interrupt
  );
end neorv32_top;

architecture neorv32_top_rtl of neorv32_top is

  -- auto-configuration --
  constant cpu_boot_addr_c : std_ulogic_vector(31 downto 0) := cond_sel_suv_f(INT_BOOTLOADER_EN, mem_boot_base_c, mem_imem_base_c);
  constant imem_as_rom_c   : boolean := not INT_BOOTLOADER_EN;
  constant io_gpio_en_c    : boolean := boolean(IO_GPIO_NUM > 0);
  constant io_xirq_en_c    : boolean := boolean(XIRQ_NUM_CH > 0);
  constant io_pwm_en_c     : boolean := boolean(IO_PWM_NUM_CH > 0);

  -- make sure physical memory sizes are a power of two --
  constant imem_size_valid_c : boolean := is_power_of_two_f(MEM_INT_IMEM_SIZE);
  constant imem_size_pow2_c  : natural := 2**index_size_f(MEM_INT_IMEM_SIZE);
  constant imem_size_c       : natural := cond_sel_natural_f(imem_size_valid_c, MEM_INT_IMEM_SIZE, imem_size_pow2_c);
  --
  constant dmem_size_valid_c : boolean := is_power_of_two_f(MEM_INT_DMEM_SIZE);
  constant dmem_size_pow2_c  : natural := 2**index_size_f(MEM_INT_DMEM_SIZE);
  constant dmem_size_c       : natural := cond_sel_natural_f(dmem_size_valid_c, MEM_INT_DMEM_SIZE, dmem_size_pow2_c);

  -- reset generator --
  signal rstn_wdt                     : std_ulogic;
  signal rstn_sys_sreg, rstn_ext_sreg : std_ulogic_vector(3 downto 0);
  signal rstn_sys, rstn_ext           : std_ulogic;
  signal rst_cause                    : std_ulogic_vector(1 downto 0);

  -- clock generator --
  signal clk_cpu                   : std_ulogic; -- CPU core clock, can be switched off
  signal clk_div, clk_div_ff       : std_ulogic_vector(11 downto 0);
  signal clk_gen                   : std_ulogic_vector(07 downto 0);
  signal clk_gen_en, clk_gen_en_ff : std_ulogic;
  --
  type cg_en_t is record
    wdt, uart0, uart1, spi, twi, pwm, cfs, neoled, gptmr, xip, onewire : std_ulogic;
  end record;
  signal cg_en : cg_en_t;

  -- CPU status --
  signal cpu_debug, cpu_sleep : std_ulogic; -- cpu is in debug/sleep mode

  -- debug module interface (DMI) --
  signal dmi_req : dmi_req_t;
  signal dmi_rsp : dmi_rsp_t;

  -- debug core interface (DCI) --
  signal dci_ndmrstn, dci_halt_req : std_ulogic;

  -- bus: core complex --
  signal cpu_i_req,  cpu_d_req  : bus_req_t; -- CPU core
  signal cpu_i_rsp,  cpu_d_rsp  : bus_rsp_t; -- CPU core
  signal icache_req, dcache_req : bus_req_t; -- CPU caches
  signal icache_rsp, dcache_rsp : bus_rsp_t; -- CPU caches
  signal core_req               : bus_req_t; -- core complex (CPU + caches)
  signal core_rsp               : bus_rsp_t; -- core complex (CPU + caches)

  -- bus: core complex + DMA --
  signal main_req, main2_req, dma_req : bus_req_t; -- core complex (CPU + caches + DMA)
  signal main_rsp, main2_rsp, dma_rsp : bus_rsp_t; -- core complex (CPU + caches + DMA)

  -- bus: main sections --
  signal imem_req, dmem_req, xip_req, boot_req, io_req, xbus_req : bus_req_t;
  signal imem_rsp, dmem_rsp, xip_rsp, boot_rsp, io_rsp, xbus_rsp : bus_rsp_t;

  -- bus: IO devices --
  type io_devices_t is (
    IODEV_OCD, IODEV_SYSINFO, IODEV_NEOLED, IODEV_GPIO, IODEV_WDT, IODEV_TRNG, IODEV_TWI,
    IODEV_SPI, IODEV_SDI, IODEV_UART1, IODEV_UART0, IODEV_MTIME, IODEV_XIRQ, IODEV_ONEWIRE,
    IODEV_GPTMR, IODEV_PWM, IODEV_XIP, IODEV_CRC, IODEV_DMA, IODEV_SLINK, IODEV_CFS
  );
  type iodev_req_t is array (io_devices_t) of bus_req_t;
  type iodev_rsp_t is array (io_devices_t) of bus_rsp_t;
  signal iodev_req : iodev_req_t;
  signal iodev_rsp : iodev_rsp_t;

  -- IRQs --
  signal cpu_firq : std_ulogic_vector(15 downto 0);
  type irq_t is record
    wdt, uart0_rx, uart0_tx, uart1_rx, uart1_tx, spi, sdi, twi, cfs, neoled, xirq, gptmr, onewire, dma, trng, slink : std_ulogic;
  end record;
  signal firq      : irq_t;
  signal mtime_irq : std_ulogic;

  -- misc --
  signal mtime_time : std_ulogic_vector(63 downto 0);

begin

  -- **************************************************************************************************************************
  -- Sanity Checks
  -- **************************************************************************************************************************
  sanity_checks:
  if (true) generate

    -- say hello --
    assert false report
      "[NEORV32] The NEORV32 RISC-V Processor " &
      "(version 0x" & to_hstring32_f(hw_version_c) & "), " &
      "github.com/stnolting/neorv32" severity note;

    -- show main SoC configuration --
    assert false report
      "[NEORV32] Processor Configuration: " &
      cond_sel_string_f(MEM_INT_IMEM_EN,     "IMEM ",     "") &
      cond_sel_string_f(MEM_INT_DMEM_EN,     "DMEM ",     "") &
      cond_sel_string_f(INT_BOOTLOADER_EN,   "BOOTROM ",  "") &
      cond_sel_string_f(ICACHE_EN,           "I-CACHE ",  "") &
      cond_sel_string_f(DCACHE_EN,           "D-CACHE ",  "") &
      cond_sel_string_f(MEM_EXT_EN,          "WISHBONE ", "") &
      cond_sel_string_f(io_gpio_en_c,        "GPIO ",     "") &
      cond_sel_string_f(IO_MTIME_EN,         "MTIME ",    "") &
      cond_sel_string_f(IO_UART0_EN,         "UART0 ",    "") &
      cond_sel_string_f(IO_UART1_EN,         "UART1 ",    "") &
      cond_sel_string_f(IO_SPI_EN,           "SPI ",      "") &
      cond_sel_string_f(IO_SDI_EN,           "SDI ",      "") &
      cond_sel_string_f(IO_TWI_EN,           "TWI ",      "") &
      cond_sel_string_f(io_pwm_en_c,         "PWM ",      "") &
      cond_sel_string_f(IO_WDT_EN,           "WDT ",      "") &
      cond_sel_string_f(IO_TRNG_EN,          "TRNG ",     "") &
      cond_sel_string_f(IO_CFS_EN,           "CFS ",      "") &
      cond_sel_string_f(IO_NEOLED_EN,        "NEOLED ",   "") &
      cond_sel_string_f(io_xirq_en_c,        "XIRQ ",     "") &
      cond_sel_string_f(IO_GPTMR_EN,         "GPTMR ",    "") &
      cond_sel_string_f(XIP_EN,              "XIP ",      "") &
      cond_sel_string_f(IO_ONEWIRE_EN,       "ONEWIRE ",  "") &
      cond_sel_string_f(IO_DMA_EN,           "DMA ",      "") &
      cond_sel_string_f(IO_SLINK_EN,         "SLINK ",    "") &
      cond_sel_string_f(IO_CRC_EN,           "CRC ",      "") &
      cond_sel_string_f(true,                "SYSINFO ",  "") & -- always enabled
      cond_sel_string_f(ON_CHIP_DEBUGGER_EN, "OCD ",      "") &
      ""
      severity note;

    -- IMEM size --
    assert not ((imem_size_valid_c = false) and (MEM_INT_IMEM_EN = true)) report
      "[NEORV32] Auto-adjusting invalid IMEM size configuration." severity warning;

    -- DMEM size --
    assert not ((dmem_size_valid_c = false) and (MEM_INT_DMEM_EN = true)) report
      "[NEORV32] Auto-adjusting invalid DMEM size configuration." severity warning;

  end generate; -- /sanity_checks


  -- **************************************************************************************************************************
  -- Clock and Reset Generators
  -- **************************************************************************************************************************
  generators:
  if (true) generate

    -- Reset Generator ------------------------------------------------------------------------
    -- -------------------------------------------------------------------------------------------
    reset_generator: process(rstn_i, clk_i)
    begin
      if (rstn_i = '0') then
        rstn_ext_sreg <= (others => '0');
        rstn_ext      <= '0';
        rstn_sys_sreg <= (others => '0');
        rstn_sys      <= '0';
      elsif falling_edge(clk_i) then -- inverted clock to release reset _before_ all FFs trigger (rising edge)
        -- external reset --
        rstn_ext_sreg <= rstn_ext_sreg(rstn_ext_sreg'left-1 downto 0) & '1'; -- active for at least <rstn_ext_sreg'size> clock cycles
        rstn_ext      <= and_reduce_f(rstn_ext_sreg);
        -- internal reset --
        if (rstn_wdt = '0') or (dci_ndmrstn = '0') then -- sync reset sources
          rstn_sys_sreg <= (others => '0');
        else
          rstn_sys_sreg <= rstn_sys_sreg(rstn_sys_sreg'left-1 downto 0) & '1'; -- active for at least <rstn_sys_sreg'size> clock cycles
        end if;
        rstn_sys <= and_reduce_f(rstn_sys_sreg);
      end if;
    end process reset_generator;


    -- Reset Cause ----------------------------------------------------------------------------
    -- -------------------------------------------------------------------------------------------
    reset_cause: process(rstn_ext, clk_i)
    begin
      if (rstn_ext = '0') then
        rst_cause <= "00"; -- reset from external pin
      elsif falling_edge(clk_i) then
        if (dci_ndmrstn = '0') then
          rst_cause <= "01"; -- reset from on-chip debugger
        elsif (rstn_wdt = '0') then
          rst_cause <= "10"; -- reset from watchdog timer
        end if;
      end if;
    end process reset_cause;


    -- Clock Generator ------------------------------------------------------------------------
    -- -------------------------------------------------------------------------------------------
    clock_generator: process(rstn_sys, clk_i)
    begin
      if (rstn_sys = '0') then
        clk_gen_en_ff <= '0';
        clk_div       <= (others => '0');
        clk_div_ff    <= (others => '0');
      elsif rising_edge(clk_i) then
        clk_gen_en_ff <= clk_gen_en;
        if (clk_gen_en_ff = '1') then
          clk_div <= std_ulogic_vector(unsigned(clk_div) + 1);
        else -- reset if disabled
          clk_div <= (others => '0');
        end if;
        clk_div_ff <= clk_div;
      end if;
    end process clock_generator;

    -- clock enables: rising edge detectors --
    clk_gen(clk_div2_c)    <= clk_div(0)  and (not clk_div_ff(0));  -- clk/2
    clk_gen(clk_div4_c)    <= clk_div(1)  and (not clk_div_ff(1));  -- clk/4
    clk_gen(clk_div8_c)    <= clk_div(2)  and (not clk_div_ff(2));  -- clk/8
    clk_gen(clk_div64_c)   <= clk_div(5)  and (not clk_div_ff(5));  -- clk/64
    clk_gen(clk_div128_c)  <= clk_div(6)  and (not clk_div_ff(6));  -- clk/128
    clk_gen(clk_div1024_c) <= clk_div(9)  and (not clk_div_ff(9));  -- clk/1024
    clk_gen(clk_div2048_c) <= clk_div(10) and (not clk_div_ff(10)); -- clk/2048
    clk_gen(clk_div4096_c) <= clk_div(11) and (not clk_div_ff(11)); -- clk/4096

    -- fresh clocks anyone? --
    clk_gen_en <= cg_en.wdt or cg_en.uart0  or cg_en.uart1 or cg_en.spi or cg_en.twi or cg_en.pwm or
                  cg_en.cfs or cg_en.neoled or cg_en.gptmr or cg_en.xip or cg_en.onewire;


    -- Clock Gating ---------------------------------------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_clockgate_inst_true:
    if CLOCK_GATING_EN generate
      neorv32_clockgate_inst: entity neorv32.neorv32_clockgate
      port map (
        clk_i  => clk_i,
        rstn_i => rstn_sys,
        halt_i => cpu_sleep,
        clk_o  => clk_cpu
      );
    end generate;

    neorv32_clockgate_inst_false:
    if not CLOCK_GATING_EN generate
      clk_cpu <= clk_i;
    end generate;

  end generate; -- /generators


  -- **************************************************************************************************************************
  -- Core Complex
  -- **************************************************************************************************************************
  core_complex:
  if (true) generate

    -- CPU Core -------------------------------------------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_cpu_inst: entity neorv32.neorv32_cpu
    generic map (
      -- General --
      HART_ID                    => HART_ID,
      VENDOR_ID                  => VENDOR_ID,
      CPU_BOOT_ADDR              => cpu_boot_addr_c,
      CPU_DEBUG_PARK_ADDR        => dm_park_entry_c,
      CPU_DEBUG_EXC_ADDR         => dm_exc_entry_c,
      -- RISC-V CPU Extensions --
      CPU_EXTENSION_RISCV_A      => CPU_EXTENSION_RISCV_A,
      CPU_EXTENSION_RISCV_B      => CPU_EXTENSION_RISCV_B,
      CPU_EXTENSION_RISCV_C      => CPU_EXTENSION_RISCV_C,
      CPU_EXTENSION_RISCV_E      => CPU_EXTENSION_RISCV_E,
      CPU_EXTENSION_RISCV_M      => CPU_EXTENSION_RISCV_M,
      CPU_EXTENSION_RISCV_U      => CPU_EXTENSION_RISCV_U,
      CPU_EXTENSION_RISCV_Zfinx  => CPU_EXTENSION_RISCV_Zfinx,
      CPU_EXTENSION_RISCV_Zicntr => CPU_EXTENSION_RISCV_Zicntr,
      CPU_EXTENSION_RISCV_Zicond => CPU_EXTENSION_RISCV_Zicond,
      CPU_EXTENSION_RISCV_Zihpm  => CPU_EXTENSION_RISCV_Zihpm,
      CPU_EXTENSION_RISCV_Zmmul  => CPU_EXTENSION_RISCV_Zmmul,
      CPU_EXTENSION_RISCV_Zxcfu  => CPU_EXTENSION_RISCV_Zxcfu,
      CPU_EXTENSION_RISCV_Sdext  => ON_CHIP_DEBUGGER_EN,
      CPU_EXTENSION_RISCV_Sdtrig => ON_CHIP_DEBUGGER_EN,
      -- Tuning Options --
      FAST_MUL_EN                => FAST_MUL_EN,
      FAST_SHIFT_EN              => FAST_SHIFT_EN,
      REGFILE_HW_RST             => REGFILE_HW_RST,
      -- Physical Memory Protection (PMP) --
      PMP_NUM_REGIONS            => PMP_NUM_REGIONS,
      PMP_MIN_GRANULARITY        => PMP_MIN_GRANULARITY,
      PMP_TOR_MODE_EN            => PMP_TOR_MODE_EN,
      PMP_NAP_MODE_EN            => PMP_NAP_MODE_EN,
      -- Hardware Performance Monitors (HPM) --
      HPM_NUM_CNTS               => HPM_NUM_CNTS,
      HPM_CNT_WIDTH              => HPM_CNT_WIDTH
    )
    port map (
      -- global control --
      clk_i      => clk_cpu,
      clk_aux_i  => clk_i,
      rstn_i     => rstn_sys,
      sleep_o    => cpu_sleep,
      debug_o    => cpu_debug,
      -- interrupts --
      msi_i      => msw_irq_i,
      mei_i      => mext_irq_i,
      mti_i      => mtime_irq,
      firq_i     => cpu_firq,
      dbi_i      => dci_halt_req,
      -- instruction bus interface --
      ibus_req_o => cpu_i_req,
      ibus_rsp_i => cpu_i_rsp,
      -- data bus interface --
      dbus_req_o => cpu_d_req,
      dbus_rsp_i => cpu_d_rsp
    );

    -- fast interrupt requests (FIRQs) --
    cpu_firq(00) <= firq.wdt; -- highest priority
    cpu_firq(01) <= firq.cfs;
    cpu_firq(02) <= firq.uart0_rx;
    cpu_firq(03) <= firq.uart0_tx;
    cpu_firq(04) <= firq.uart1_rx;
    cpu_firq(05) <= firq.uart1_tx;
    cpu_firq(06) <= firq.spi;
    cpu_firq(07) <= firq.twi;
    cpu_firq(08) <= firq.xirq;
    cpu_firq(09) <= firq.neoled;
    cpu_firq(10) <= firq.dma;
    cpu_firq(11) <= firq.sdi;
    cpu_firq(12) <= firq.gptmr;
    cpu_firq(13) <= firq.onewire;
    cpu_firq(14) <= firq.slink;
    cpu_firq(15) <= firq.trng; -- lowest priority


    -- CPU Instruction Cache ------------------------------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_icache_inst_true:
    if ICACHE_EN generate
      neorv32_icache_inst: entity neorv32.neorv32_icache
      generic map (
        ICACHE_NUM_BLOCKS => ICACHE_NUM_BLOCKS,
        ICACHE_BLOCK_SIZE => ICACHE_BLOCK_SIZE,
        ICACHE_NUM_SETS   => ICACHE_ASSOCIATIVITY,
        ICACHE_UC_PBEGIN  => uncached_begin_c(31 downto 28)
      )
      port map (
        clk_i     => clk_cpu,
        rstn_i    => rstn_sys,
        cpu_req_i => cpu_i_req,
        cpu_rsp_o => cpu_i_rsp,
        bus_req_o => icache_req,
        bus_rsp_i => icache_rsp
      );
    end generate;

    neorv32_icache_inst_false:
    if not ICACHE_EN generate
      icache_req <= cpu_i_req;
      cpu_i_rsp  <= icache_rsp;
    end generate;


    -- CPU Data Cache -------------------------------------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_dcache_inst_true:
    if DCACHE_EN generate
      neorv32_dcache_inst: entity neorv32.neorv32_dcache
      generic map (
        DCACHE_NUM_BLOCKS => DCACHE_NUM_BLOCKS,
        DCACHE_BLOCK_SIZE => DCACHE_BLOCK_SIZE,
        DCACHE_UC_PBEGIN  => uncached_begin_c(31 downto 28)
      )
      port map (
        clk_i     => clk_cpu,
        rstn_i    => rstn_sys,
        cpu_req_i => cpu_d_req,
        cpu_rsp_o => cpu_d_rsp,
        bus_req_o => dcache_req,
        bus_rsp_i => dcache_rsp
      );
    end generate;

    neorv32_dcache_inst_false:
    if not DCACHE_EN generate
      dcache_req <= cpu_d_req;
      cpu_d_rsp  <= dcache_rsp;
    end generate;


    -- Core Complex Bus Switch ----------------------------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_core_bus_switch_inst: entity neorv32.neorv32_bus_switch
    generic map (
      PORT_A_READ_ONLY => false,
      PORT_B_READ_ONLY => true -- i-fetch is read-only
    )
    port map (
      clk_i   => clk_cpu,
      rstn_i  => rstn_sys,
      a_req_i => dcache_req, -- prioritized
      a_rsp_o => dcache_rsp,
      b_req_i => icache_req,
      b_rsp_o => icache_rsp,
      x_req_o => core_req,
      x_rsp_i => core_rsp
    );

  end generate; -- /core_complex


  -- **************************************************************************************************************************
  -- Direct Memory Access Controller (DMA) Complex
  -- **************************************************************************************************************************
  neorv32_dma_complex_true:
  if IO_DMA_EN generate

    -- DMA Controller -------------------------------------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_dma_inst: entity neorv32.neorv32_dma
    port map (
      clk_i     => clk_i,
      rstn_i    => rstn_sys,
      bus_req_i => iodev_req(IODEV_DMA),
      bus_rsp_o => iodev_rsp(IODEV_DMA),
      dma_req_o => dma_req,
      dma_rsp_i => dma_rsp,
      firq_i    => cpu_firq,
      irq_o     => firq.dma
    );


    -- DMA Bus Switch -------------------------------------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_dma_bus_switch_inst: entity neorv32.neorv32_bus_switch
    generic map (
      PORT_A_READ_ONLY => false,
      PORT_B_READ_ONLY => false
    )
    port map (
      clk_i   => clk_i,
      rstn_i  => rstn_sys,
      a_req_i => core_req, -- prioritized
      a_rsp_o => core_rsp,
      b_req_i => dma_req,
      b_rsp_o => dma_rsp,
      x_req_o => main_req,
      x_rsp_i => main_rsp
    );

  end generate; -- /neorv32_dma_complex_true

  neorv32_dma_complex_false:
  if not IO_DMA_EN generate
    iodev_rsp(IODEV_DMA) <= rsp_terminate_c;
    main_req             <= core_req;
    core_rsp             <= main_rsp;
    firq.dma             <= '0';
  end generate;


  -- **************************************************************************************************************************
  -- Reservation Set Controller (for atomic LR/SC memory accesses)
  -- **************************************************************************************************************************
  neorv32_bus_reservation_set_true:
  if CPU_EXTENSION_RISCV_A generate
    neorv32_bus_reservation_set_inst: entity neorv32.neorv32_bus_reservation_set
    generic map (
      GRANULARITY => AMO_RVS_GRANULARITY
    )
    port map (
      clk_i       => clk_i,
      rstn_i      => rstn_sys,
      rvs_addr_o  => open, -- yet unused
      rvs_valid_o => open, -- yet unused
      rvs_clear_i => '0',  -- yet unused
      core_req_i  => main_req,
      core_rsp_o  => main_rsp,
      sys_req_o   => main2_req,
      sys_rsp_i   => main2_rsp
    );
  end generate;

  neorv32_bus_reservation_set_false:
  if not CPU_EXTENSION_RISCV_A generate
    main2_req <= main_req;
    main_rsp  <= main2_rsp;
  end generate;


  -- **************************************************************************************************************************
  -- Address Region Gateway
  -- **************************************************************************************************************************
  neorv32_bus_gateway_inst: entity neorv32.neorv32_bus_gateway
  generic map (
    TIMEOUT     => bus_timeout_c,
    -- IMEM port --
    IMEM_ENABLE => MEM_INT_IMEM_EN,
    IMEM_BASE   => mem_imem_base_c,
    IMEM_SIZE   => imem_size_c,
    -- DMEM port --
    DMEM_ENABLE => MEM_INT_DMEM_EN,
    DMEM_BASE   => mem_dmem_base_c,
    DMEM_SIZE   => dmem_size_c,
    -- XIP port --
    XIP_ENABLE  => XIP_EN,
    XIP_BASE    => mem_xip_base_c,
    XIP_SIZE    => mem_xip_size_c,
    -- BOOT ROM port --
    BOOT_ENABLE => INT_BOOTLOADER_EN,
    BOOT_BASE   => mem_boot_base_c,
    BOOT_SIZE   => mem_boot_size_c,
    -- IO port --
    IO_ENABLE   => true, -- always enabled (mandatory core module)
    IO_BASE     => mem_io_base_c,
    IO_SIZE     => mem_io_size_c,
    -- EXT port --
    EXT_ENABLE  => MEM_EXT_EN
  )
  port map (
    -- global control --
    clk_i      => clk_i,
    rstn_i     => rstn_sys,
    -- host port --
    main_req_i => main2_req,
    main_rsp_o => main2_rsp,
    -- section ports --
    imem_req_o => imem_req,
    imem_rsp_i => imem_rsp,
    dmem_req_o => dmem_req,
    dmem_rsp_i => dmem_rsp,
    xip_req_o  => xip_req,
    xip_rsp_i  => xip_rsp,
    boot_req_o => boot_req,
    boot_rsp_i => boot_rsp,
    io_req_o   => io_req,
    io_rsp_i   => io_rsp,
    ext_req_o  => xbus_req,
    ext_rsp_i  => xbus_rsp
  );


  -- **************************************************************************************************************************
  -- Memory System
  -- **************************************************************************************************************************
  memory_system:
  if (true) generate

    -- Processor-Internal Instruction Memory (IMEM) -------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_int_imem_inst_true:
    if MEM_INT_IMEM_EN generate
      neorv32_int_imem_inst: entity neorv32.neorv32_imem
      generic map (
        IMEM_SIZE    => imem_size_c,
        IMEM_AS_IROM => imem_as_rom_c
      )
      port map (
        clk_i     => clk_i,
        rstn_i    => rstn_sys,
        bus_req_i => imem_req,
        bus_rsp_o => imem_rsp
      );
    end generate;

    neorv32_int_imem_inst_false:
    if not MEM_INT_IMEM_EN generate
      imem_rsp <= rsp_terminate_c;
    end generate;


    -- Processor-Internal Data Memory (DMEM) --------------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_int_dmem_inst_true:
    if MEM_INT_DMEM_EN generate
      neorv32_int_dmem_inst: entity neorv32.neorv32_dmem
      generic map (
        DMEM_SIZE => dmem_size_c
      )
      port map (
        clk_i     => clk_i,
        rstn_i    => rstn_sys,
        bus_req_i => dmem_req,
        bus_rsp_o => dmem_rsp
      );
    end generate;

    neorv32_int_dmem_inst_false:
    if not MEM_INT_DMEM_EN generate
      dmem_rsp <= rsp_terminate_c;
    end generate;


    -- Processor-Internal Bootloader ROM (BOOTROM) --------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_boot_rom_inst_true:
    if INT_BOOTLOADER_EN generate
      neorv32_boot_rom_inst: entity neorv32.neorv32_boot_rom
      port map (
        clk_i     => clk_i,
        rstn_i    => rstn_sys,
        bus_req_i => boot_req,
        bus_rsp_o => boot_rsp
      );
    end generate;

    neorv32_boot_rom_inst_false:
    if not INT_BOOTLOADER_EN generate
      boot_rsp <= rsp_terminate_c;
    end generate;


    -- Execute In Place Module (XIP) ----------------------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_xip_inst_true:
    if XIP_EN generate
      neorv32_xip_inst: entity neorv32.neorv32_xip
      generic map (
        XIP_CACHE_EN         => XIP_CACHE_EN,
        XIP_CACHE_NUM_BLOCKS => XIP_CACHE_NUM_BLOCKS,
        XIP_CACHE_BLOCK_SIZE => XIP_CACHE_BLOCK_SIZE
      )
      port map (
        -- global control --
        clk_i       => clk_i,
        rstn_i      => rstn_sys,
        bus_req_i   => iodev_req(IODEV_XIP),
        bus_rsp_o   => iodev_rsp(IODEV_XIP),
        xip_req_i   => xip_req,
        xip_rsp_o   => xip_rsp,
        clkgen_en_o => cg_en.xip,
        clkgen_i    => clk_gen,
        spi_csn_o   => xip_csn_o,
        spi_clk_o   => xip_clk_o,
        spi_dat_i   => xip_dat_i,
        spi_dat_o   => xip_dat_o
      );
    end generate;

    neorv32_xip_inst_false:
    if not XIP_EN generate
      iodev_rsp(IODEV_XIP) <= rsp_terminate_c;
      xip_rsp              <= rsp_terminate_c;
      cg_en.xip            <= '0';
      xip_csn_o            <= '1';
      xip_clk_o            <= '0';
      xip_dat_o            <= '0';
    end generate;


    -- External Wishbone Gateway (WISHBONE) ---------------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_wishbone_inst_true:
    if MEM_EXT_EN generate
      neorv32_wishbone_inst: entity neorv32.neorv32_wishbone
      generic map (
        BUS_TIMEOUT => MEM_EXT_TIMEOUT,
        PIPE_MODE   => MEM_EXT_PIPE_MODE,
        BIG_ENDIAN  => MEM_EXT_BIG_ENDIAN,
        ASYNC_RX    => MEM_EXT_ASYNC_RX,
        ASYNC_TX    => MEM_EXT_ASYNC_TX
      )
      port map (
        clk_i     => clk_i,
        rstn_i    => rstn_sys,
        bus_req_i => xbus_req,
        bus_rsp_o => xbus_rsp,
        --
        wb_tag_o  => wb_tag_o,
        wb_adr_o  => wb_adr_o,
        wb_dat_i  => wb_dat_i,
        wb_dat_o  => wb_dat_o,
        wb_we_o   => wb_we_o,
        wb_sel_o  => wb_sel_o,
        wb_stb_o  => wb_stb_o,
        wb_cyc_o  => wb_cyc_o,
        wb_ack_i  => wb_ack_i,
        wb_err_i  => wb_err_i
      );
    end generate;

    neorv32_wishbone_inst_false:
    if not MEM_EXT_EN generate
      xbus_rsp <= rsp_terminate_c;
      wb_adr_o <= (others => '0');
      wb_dat_o <= (others => '0');
      wb_we_o  <= '0';
      wb_sel_o <= (others => '0');
      wb_stb_o <= '0';
      wb_cyc_o <= '0';
      wb_tag_o <= (others => '0');
    end generate;

  end generate; -- /memory_system


  -- **************************************************************************************************************************
  -- IO/Peripheral Modules
  -- **************************************************************************************************************************
  io_system:
  if (true) generate

    -- IO Switch ------------------------------------------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_bus_io_switch_inst: entity neorv32.neorv32_bus_io_switch
    generic map (
      DEV_SIZE  => iodev_size_c, -- size of a single IO device
      -- device port enable and base address --
      DEV_00_EN => ON_CHIP_DEBUGGER_EN, DEV_00_BASE => base_io_dm_c,
      DEV_01_EN => true,                DEV_01_BASE => base_io_sysinfo_c, -- always enabled (mandatory core module)
      DEV_02_EN => IO_NEOLED_EN,        DEV_02_BASE => base_io_neoled_c,
      DEV_03_EN => io_gpio_en_c,        DEV_03_BASE => base_io_gpio_c,
      DEV_04_EN => IO_WDT_EN,           DEV_04_BASE => base_io_wdt_c,
      DEV_05_EN => IO_TRNG_EN,          DEV_05_BASE => base_io_trng_c,
      DEV_06_EN => IO_TWI_EN,           DEV_06_BASE => base_io_twi_c,
      DEV_07_EN => IO_SPI_EN,           DEV_07_BASE => base_io_spi_c,
      DEV_08_EN => IO_SDI_EN,           DEV_08_BASE => base_io_sdi_c,
      DEV_09_EN => IO_UART1_EN,         DEV_09_BASE => base_io_uart1_c,
      DEV_10_EN => IO_UART0_EN,         DEV_10_BASE => base_io_uart0_c,
      DEV_11_EN => IO_MTIME_EN,         DEV_11_BASE => base_io_mtime_c,
      DEV_12_EN => io_xirq_en_c,        DEV_12_BASE => base_io_xirq_c,
      DEV_13_EN => IO_ONEWIRE_EN,       DEV_13_BASE => base_io_onewire_c,
      DEV_14_EN => IO_GPTMR_EN,         DEV_14_BASE => base_io_gptmr_c,
      DEV_15_EN => io_pwm_en_c,         DEV_15_BASE => base_io_pwm_c,
      DEV_16_EN => XIP_EN,              DEV_16_BASE => base_io_xip_c,
      DEV_17_EN => IO_CRC_EN,           DEV_17_BASE => base_io_crc_c,
      DEV_18_EN => IO_DMA_EN,           DEV_18_BASE => base_io_dma_c,
      DEV_19_EN => IO_SLINK_EN,         DEV_19_BASE => base_io_slink_c,
      DEV_20_EN => IO_CFS_EN,           DEV_20_BASE => base_io_cfs_c
    )
    port map (
      -- host port --
      main_req_i   => io_req,
      main_rsp_o   => io_rsp,
      -- device ports --
      dev_00_req_o => iodev_req(IODEV_OCD),     dev_00_rsp_i => iodev_rsp(IODEV_OCD),
      dev_01_req_o => iodev_req(IODEV_SYSINFO), dev_01_rsp_i => iodev_rsp(IODEV_SYSINFO),
      dev_02_req_o => iodev_req(IODEV_NEOLED),  dev_02_rsp_i => iodev_rsp(IODEV_NEOLED),
      dev_03_req_o => iodev_req(IODEV_GPIO),    dev_03_rsp_i => iodev_rsp(IODEV_GPIO),
      dev_04_req_o => iodev_req(IODEV_WDT),     dev_04_rsp_i => iodev_rsp(IODEV_WDT),
      dev_05_req_o => iodev_req(IODEV_TRNG),    dev_05_rsp_i => iodev_rsp(IODEV_TRNG),
      dev_06_req_o => iodev_req(IODEV_TWI),     dev_06_rsp_i => iodev_rsp(IODEV_TWI),
      dev_07_req_o => iodev_req(IODEV_SPI),     dev_07_rsp_i => iodev_rsp(IODEV_SPI),
      dev_08_req_o => iodev_req(IODEV_SDI),     dev_08_rsp_i => iodev_rsp(IODEV_SDI),
      dev_09_req_o => iodev_req(IODEV_UART1),   dev_09_rsp_i => iodev_rsp(IODEV_UART1),
      dev_10_req_o => iodev_req(IODEV_UART0),   dev_10_rsp_i => iodev_rsp(IODEV_UART0),
      dev_11_req_o => iodev_req(IODEV_MTIME),   dev_11_rsp_i => iodev_rsp(IODEV_MTIME),
      dev_12_req_o => iodev_req(IODEV_XIRQ),    dev_12_rsp_i => iodev_rsp(IODEV_XIRQ),
      dev_13_req_o => iodev_req(IODEV_ONEWIRE), dev_13_rsp_i => iodev_rsp(IODEV_ONEWIRE),
      dev_14_req_o => iodev_req(IODEV_GPTMR),   dev_14_rsp_i => iodev_rsp(IODEV_GPTMR),
      dev_15_req_o => iodev_req(IODEV_PWM),     dev_15_rsp_i => iodev_rsp(IODEV_PWM),
      dev_16_req_o => iodev_req(IODEV_XIP),     dev_16_rsp_i => iodev_rsp(IODEV_XIP),
      dev_17_req_o => iodev_req(IODEV_CRC),     dev_17_rsp_i => iodev_rsp(IODEV_CRC),
      dev_18_req_o => iodev_req(IODEV_DMA),     dev_18_rsp_i => iodev_rsp(IODEV_DMA),
      dev_19_req_o => iodev_req(IODEV_SLINK),   dev_19_rsp_i => iodev_rsp(IODEV_SLINK),
      dev_20_req_o => iodev_req(IODEV_CFS),     dev_20_rsp_i => iodev_rsp(IODEV_CFS)
    );


    -- Custom Functions Subsystem (CFS) -------------------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_cfs_inst_true:
    if IO_CFS_EN generate
      neorv32_cfs_inst: entity neorv32.neorv32_cfs
      generic map (
        CFS_CONFIG   => IO_CFS_CONFIG,
        CFS_IN_SIZE  => IO_CFS_IN_SIZE,
        CFS_OUT_SIZE => IO_CFS_OUT_SIZE
      )
      port map (
        clk_i       => clk_i,
        rstn_i      => rstn_sys,
        bus_req_i   => iodev_req(IODEV_CFS),
        bus_rsp_o   => iodev_rsp(IODEV_CFS),
        clkgen_en_o => cg_en.cfs,
        clkgen_i    => clk_gen,
        irq_o       => firq.cfs,
        cfs_in_i    => cfs_in_i,
        cfs_out_o   => cfs_out_o
      );
    end generate;

    neorv32_cfs_inst_false:
    if not IO_CFS_EN generate
      iodev_rsp(IODEV_CFS) <= rsp_terminate_c;
      cg_en.cfs            <= '0';
      firq.cfs             <= '0';
      cfs_out_o            <= (others => '0');
    end generate;


    -- Serial Data Interface (SDI) ------------------------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_sdi_inst_true:
    if IO_SDI_EN generate
      neorv32_sdi_inst: entity neorv32.neorv32_sdi
      generic map (
        RTX_FIFO => IO_SDI_FIFO
      )
      port map (
        clk_i     => clk_i,
        rstn_i    => rstn_sys,
        bus_req_i => iodev_req(IODEV_SDI),
        bus_rsp_o => iodev_rsp(IODEV_SDI),
        sdi_csn_i => sdi_csn_i,
        sdi_clk_i => sdi_clk_i,
        sdi_dat_i => sdi_dat_i,
        sdi_dat_o => sdi_dat_o,
        irq_o     => firq.sdi
      );
    end generate;

    neorv32_sdi_inst_false:
    if not IO_SDI_EN generate
      iodev_rsp(IODEV_SDI) <= rsp_terminate_c;
      sdi_dat_o            <= '0';
      firq.sdi             <= '0';
    end generate;


    -- General Purpose Input/Output Port (GPIO) -----------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_gpio_inst_true:
    if io_gpio_en_c generate
      neorv32_gpio_inst: entity neorv32.neorv32_gpio
      generic map (
        GPIO_NUM => IO_GPIO_NUM
      )
      port map (
        clk_i     => clk_i,
        rstn_i    => rstn_sys,
        bus_req_i => iodev_req(IODEV_GPIO),
        bus_rsp_o => iodev_rsp(IODEV_GPIO),
        gpio_o    => gpio_o,
        gpio_i    => gpio_i
      );
    end generate;

    neorv32_gpio_inst_false:
    if not io_gpio_en_c generate
      iodev_rsp(IODEV_GPIO) <= rsp_terminate_c;
      gpio_o                <= (others => '0');
    end generate;


    -- Watch Dog Timer (WDT) ------------------------------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_wdt_inst_true:
    if IO_WDT_EN generate
      neorv32_wdt_inst: entity neorv32.neorv32_wdt
      port map (
        clk_i       => clk_i,
        rstn_i      => rstn_sys,
        rst_cause_i => rst_cause,
        bus_req_i   => iodev_req(IODEV_WDT),
        bus_rsp_o   => iodev_rsp(IODEV_WDT),
        cpu_debug_i => cpu_debug,
        cpu_sleep_i => cpu_sleep,
        clkgen_en_o => cg_en.wdt,
        clkgen_i    => clk_gen,
        irq_o       => firq.wdt,
        rstn_o      => rstn_wdt
      );
    end generate;

    neorv32_wdt_inst_false:
    if not IO_WDT_EN generate
      iodev_rsp(IODEV_WDT) <= rsp_terminate_c;
      firq.wdt             <= '0';
      rstn_wdt             <= '1';
      cg_en.wdt            <= '0';
    end generate;


    -- Machine System Timer (MTIME) -----------------------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_mtime_inst_true:
    if IO_MTIME_EN generate
      neorv32_mtime_inst: entity neorv32.neorv32_mtime
      port map (
        clk_i     => clk_i,
        rstn_i    => rstn_sys,
        bus_req_i => iodev_req(IODEV_MTIME),
        bus_rsp_o => iodev_rsp(IODEV_MTIME),
        time_o    => mtime_time,
        irq_o     => mtime_irq
      );

      -- synchronize system time output LO --
      mtime_sync: process(rstn_sys, clk_i)
      begin
        if (rstn_sys = '0') then
          mtime_time_o(31 downto 0) <= (others => '0');
        elsif rising_edge(clk_i) then
          mtime_time_o(31 downto 0) <= mtime_time(31 downto 0);
        end if;
      end process mtime_sync;

      -- system time output HI --
      mtime_time_o(63 downto 32) <= mtime_time(63 downto 32);

    end generate;

    neorv32_mtime_inst_false:
    if not IO_MTIME_EN generate
      iodev_rsp(IODEV_MTIME) <= rsp_terminate_c;
      mtime_irq              <= mtime_irq_i;
      mtime_time_o           <= (others => '0');
    end generate;


    -- Primary Universal Asynchronous Receiver/Transmitter (UART0) ----------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_uart0_inst_true:
    if IO_UART0_EN generate
      neorv32_uart0_inst: entity neorv32.neorv32_uart
      generic map (
        SIM_LOG_FILE => "neorv32.uart0.sim_mode.text.out",
        UART_RX_FIFO => IO_UART0_RX_FIFO,
        UART_TX_FIFO => IO_UART0_TX_FIFO
      )
      port map (
        clk_i       => clk_i,
        rstn_i      => rstn_sys,
        bus_req_i   => iodev_req(IODEV_UART0),
        bus_rsp_o   => iodev_rsp(IODEV_UART0),
        clkgen_en_o => cg_en.uart0,
        clkgen_i    => clk_gen,
        uart_txd_o  => uart0_txd_o,
        uart_rxd_i  => uart0_rxd_i,
        uart_rts_o  => uart0_rts_o,
        uart_cts_i  => uart0_cts_i,
        irq_rx_o    => firq.uart0_rx,
        irq_tx_o    => firq.uart0_tx
      );
    end generate;

    neorv32_uart0_inst_false:
    if not IO_UART0_EN generate
      iodev_rsp(IODEV_UART0) <= rsp_terminate_c;
      uart0_txd_o            <= '0';
      uart0_rts_o            <= '1';
      cg_en.uart0            <= '0';
      firq.uart0_rx          <= '0';
      firq.uart0_tx          <= '0';
    end generate;


    -- Secondary Universal Asynchronous Receiver/Transmitter (UART1) --------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_uart1_inst_true:
    if IO_UART1_EN generate
      neorv32_uart1_inst: entity neorv32.neorv32_uart
      generic map (
        SIM_LOG_FILE => "neorv32.uart1.sim_mode.text.out",
        UART_RX_FIFO => IO_UART1_RX_FIFO,
        UART_TX_FIFO => IO_UART1_TX_FIFO
      )
      port map (
        clk_i       => clk_i,
        rstn_i      => rstn_sys,
        bus_req_i   => iodev_req(IODEV_UART1),
        bus_rsp_o   => iodev_rsp(IODEV_UART1),
        clkgen_en_o => cg_en.uart1,
        clkgen_i    => clk_gen,
        uart_txd_o  => uart1_txd_o,
        uart_rxd_i  => uart1_rxd_i,
        uart_rts_o  => uart1_rts_o,
        uart_cts_i  => uart1_cts_i,
        irq_rx_o    => firq.uart1_rx,
        irq_tx_o    => firq.uart1_tx
      );
    end generate;

    neorv32_uart1_inst_false:
    if not IO_UART1_EN generate
      iodev_rsp(IODEV_UART1) <= rsp_terminate_c;
      uart1_txd_o            <= '0';
      uart1_rts_o            <= '1';
      cg_en.uart1            <= '0';
      firq.uart1_rx          <= '0';
      firq.uart1_tx          <= '0';
    end generate;


    -- Serial Peripheral Interface (SPI) ------------------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_spi_inst_true:
    if IO_SPI_EN generate
      neorv32_spi_inst: entity neorv32.neorv32_spi
      generic map (
        IO_SPI_FIFO => IO_SPI_FIFO
      )
      port map (
        clk_i       => clk_i,
        rstn_i      => rstn_sys,
        bus_req_i   => iodev_req(IODEV_SPI),
        bus_rsp_o   => iodev_rsp(IODEV_SPI),
        clkgen_en_o => cg_en.spi,
        clkgen_i    => clk_gen,
        spi_clk_o   => spi_clk_o,
        spi_dat_o   => spi_dat_o,
        spi_dat_i   => spi_dat_i,
        spi_csn_o   => spi_csn_o,
        irq_o       => firq.spi
      );
    end generate;

    neorv32_spi_inst_false:
    if not IO_SPI_EN generate
      iodev_rsp(IODEV_SPI) <= rsp_terminate_c;
      spi_clk_o            <= '0';
      spi_dat_o            <= '0';
      spi_csn_o            <= (others => '1');
      cg_en.spi            <= '0';
      firq.spi             <= '0';
    end generate;


    -- Two-Wire Interface (TWI) ---------------------------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_twi_inst_true:
    if IO_TWI_EN generate
      neorv32_twi_inst: entity neorv32.neorv32_twi
      port map (
        clk_i       => clk_i,
        rstn_i      => rstn_sys,
        bus_req_i   => iodev_req(IODEV_TWI),
        bus_rsp_o   => iodev_rsp(IODEV_TWI),
        clkgen_en_o => cg_en.twi,
        clkgen_i    => clk_gen,
        twi_sda_i   => twi_sda_i,
        twi_sda_o   => twi_sda_o,
        twi_scl_i   => twi_scl_i,
        twi_scl_o   => twi_scl_o,
        irq_o       => firq.twi
      );
    end generate;

    neorv32_twi_inst_false:
    if not IO_TWI_EN generate
      iodev_rsp(IODEV_TWI) <= rsp_terminate_c;
      twi_sda_o            <= '1';
      twi_scl_o            <= '1';
      cg_en.twi            <= '0';
      firq.twi             <= '0';
    end generate;


    -- Pulse-Width Modulation Controller (PWM) ------------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_pwm_inst_true:
    if io_pwm_en_c generate
      neorv32_pwm_inst: entity neorv32.neorv32_pwm
      generic map (
        NUM_CHANNELS => IO_PWM_NUM_CH
      )
      port map (
        clk_i       => clk_i,
        rstn_i      => rstn_sys,
        bus_req_i   => iodev_req(IODEV_PWM),
        bus_rsp_o   => iodev_rsp(IODEV_PWM),
        clkgen_en_o => cg_en.pwm,
        clkgen_i    => clk_gen,
        pwm_o       => pwm_o
      );
    end generate;

    neorv32_pwm_inst_false:
    if not io_pwm_en_c generate
      iodev_rsp(IODEV_PWM) <= rsp_terminate_c;
      cg_en.pwm            <= '0';
      pwm_o                <= (others => '0');
    end generate;


    -- True Random Number Generator (TRNG) ----------------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_trng_inst_true:
    if IO_TRNG_EN generate
      neorv32_trng_inst: entity neorv32.neorv32_trng
      generic map (
        IO_TRNG_FIFO => IO_TRNG_FIFO
      )
      port map (
        clk_i     => clk_i,
        rstn_i    => rstn_sys,
        bus_req_i => iodev_req(IODEV_TRNG),
        bus_rsp_o => iodev_rsp(IODEV_TRNG),
        irq_o     => firq.trng
      );
    end generate;

    neorv32_trng_inst_false:
    if not IO_TRNG_EN generate
      iodev_rsp(IODEV_TRNG) <= rsp_terminate_c;
      firq.trng             <= '0';
    end generate;


    -- Smart LED (WS2811/WS2812) Interface (NEOLED) -------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_neoled_inst_true:
    if IO_NEOLED_EN generate
      neorv32_neoled_inst: entity neorv32.neorv32_neoled
      generic map (
        FIFO_DEPTH => IO_NEOLED_TX_FIFO
      )
      port map (
        clk_i       => clk_i,
        rstn_i      => rstn_sys,
        bus_req_i   => iodev_req(IODEV_NEOLED),
        bus_rsp_o   => iodev_rsp(IODEV_NEOLED),
        clkgen_en_o => cg_en.neoled,
        clkgen_i    => clk_gen,
        irq_o       => firq.neoled,
        neoled_o    => neoled_o
      );
    end generate;

    neorv32_neoled_inst_false:
    if not IO_NEOLED_EN generate
      iodev_rsp(IODEV_NEOLED) <= rsp_terminate_c;
      cg_en.neoled            <= '0';
      firq.neoled             <= '0';
      neoled_o                <= '0';
    end generate;


    -- External Interrupt Controller (XIRQ) ---------------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_xirq_inst_true:
    if io_xirq_en_c generate
      neorv32_xirq_inst: entity neorv32.neorv32_xirq
      generic map (
        XIRQ_NUM_CH           => XIRQ_NUM_CH,
        XIRQ_TRIGGER_TYPE     => XIRQ_TRIGGER_TYPE,
        XIRQ_TRIGGER_POLARITY => XIRQ_TRIGGER_POLARITY
      )
      port map (
        -- host access --
        clk_i     => clk_i,
        rstn_i    => rstn_sys,
        bus_req_i => iodev_req(IODEV_XIRQ),
        bus_rsp_o => iodev_rsp(IODEV_XIRQ),
        xirq_i    => xirq_i,
        cpu_irq_o => firq.xirq
      );
    end generate;

    neorv32_xirq_inst_false:
    if not io_xirq_en_c generate
      iodev_rsp(IODEV_XIRQ) <= rsp_terminate_c;
      firq.xirq             <= '0';
    end generate;


    -- General Purpose Timer (GPTMR) ----------------------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_gptmr_inst_true:
    if IO_GPTMR_EN generate
      neorv32_gptmr_inst: entity neorv32.neorv32_gptmr
      port map (
        clk_i       => clk_i,
        rstn_i      => rstn_sys,
        bus_req_i   => iodev_req(IODEV_GPTMR),
        bus_rsp_o   => iodev_rsp(IODEV_GPTMR),
        clkgen_en_o => cg_en.gptmr,
        clkgen_i    => clk_gen,
        irq_o       => firq.gptmr,
        capture_i   => gptmr_trig_i
      );
    end generate;

    neorv32_gptmr_inst_false:
    if not IO_GPTMR_EN generate
      iodev_rsp(IODEV_GPTMR) <= rsp_terminate_c;
      cg_en.gptmr            <= '0';
      firq.gptmr             <= '0';
    end generate;


    -- 1-Wire Interface Controller (ONEWIRE) --------------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_onewire_inst_true:
    if IO_ONEWIRE_EN generate
      neorv32_onewire_inst: entity neorv32.neorv32_onewire
      port map (
        clk_i       => clk_i,
        rstn_i      => rstn_sys,
        bus_req_i   => iodev_req(IODEV_ONEWIRE),
        bus_rsp_o   => iodev_rsp(IODEV_ONEWIRE),
        clkgen_en_o => cg_en.onewire,
        clkgen_i    => clk_gen,
        onewire_i   => onewire_i,
        onewire_o   => onewire_o,
        irq_o       => firq.onewire
      );
    end generate;

    neorv32_onewire_inst_false:
    if not IO_ONEWIRE_EN generate
      iodev_rsp(IODEV_ONEWIRE) <= rsp_terminate_c;
      onewire_o                <= '1';
      cg_en.onewire            <= '0';
      firq.onewire             <= '0';
    end generate;


    -- Stream Link Interface (SLINK) ----------------------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_slink_inst_true:
    if IO_SLINK_EN generate
      neorv32_slink_inst: entity neorv32.neorv32_slink
      generic map (
        SLINK_RX_FIFO => IO_SLINK_RX_FIFO,
        SLINK_TX_FIFO => IO_SLINK_TX_FIFO
      )
      port map (
        -- Host access --
        clk_i            => clk_i,
        rstn_i           => rstn_sys,
        bus_req_i        => iodev_req(IODEV_SLINK),
        bus_rsp_o        => iodev_rsp(IODEV_SLINK),
        irq_o            => firq.slink,
        -- RX stream interface --
        slink_rx_data_i  => slink_rx_dat_i,
        slink_rx_valid_i => slink_rx_val_i,
        slink_rx_last_i  => slink_rx_lst_i,
        slink_rx_ready_o => slink_rx_rdy_o,
        -- TX stream interface --
        slink_tx_data_o  => slink_tx_dat_o,
        slink_tx_valid_o => slink_tx_val_o,
        slink_tx_last_o  => slink_tx_lst_o,
        slink_tx_ready_i => slink_tx_rdy_i
      );
    end generate;

    neorv32_slink_inst_false:
    if not IO_SLINK_EN generate
      iodev_rsp(IODEV_SLINK) <= rsp_terminate_c;
      firq.slink             <= '0';
      slink_rx_rdy_o         <= '0';
      slink_tx_dat_o         <= (others => '0');
      slink_tx_val_o         <= '0';
      slink_tx_lst_o         <= '0';
    end generate;


    -- Cyclic Redundancy Check Unit (CRC) -----------------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_crc_inst_true:
    if IO_CRC_EN generate
      neorv32_crc_inst: entity neorv32.neorv32_crc
        port map (
        clk_i     => clk_i,
        rstn_i    => rstn_sys,
        bus_req_i => iodev_req(IODEV_CRC),
        bus_rsp_o => iodev_rsp(IODEV_CRC)
      );
    end generate;

    neorv32_crc_inst_false:
    if not IO_CRC_EN generate
      iodev_rsp(IODEV_CRC) <= rsp_terminate_c;
    end generate;


    -- System Configuration Information Memory (SYSINFO) --------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_sysinfo_inst: entity neorv32.neorv32_sysinfo
    generic map (
      -- General --
      CLOCK_FREQUENCY      => CLOCK_FREQUENCY,
      CLOCK_GATING_EN      => CLOCK_GATING_EN,
      INT_BOOTLOADER_EN    => INT_BOOTLOADER_EN,
      -- Internal Instruction memory --
      MEM_INT_IMEM_EN      => MEM_INT_IMEM_EN,
      MEM_INT_IMEM_SIZE    => imem_size_c,
      -- Internal Data memory --
      MEM_INT_DMEM_EN      => MEM_INT_DMEM_EN,
      MEM_INT_DMEM_SIZE    => dmem_size_c,
      -- Reservation Set Granularity --
      AMO_RVS_GRANULARITY  => AMO_RVS_GRANULARITY,
      -- Instruction cache --
      ICACHE_EN            => ICACHE_EN,
      ICACHE_NUM_BLOCKS    => ICACHE_NUM_BLOCKS,
      ICACHE_BLOCK_SIZE    => ICACHE_BLOCK_SIZE,
      ICACHE_ASSOCIATIVITY => ICACHE_ASSOCIATIVITY,
      -- Data cache --
      DCACHE_EN            => DCACHE_EN,
      DCACHE_NUM_BLOCKS    => DCACHE_NUM_BLOCKS,
      DCACHE_BLOCK_SIZE    => DCACHE_BLOCK_SIZE,
      -- External memory interface --
      MEM_EXT_EN           => MEM_EXT_EN,
      MEM_EXT_BIG_ENDIAN   => MEM_EXT_BIG_ENDIAN,
      -- On-Chip Debugger --
      ON_CHIP_DEBUGGER_EN  => ON_CHIP_DEBUGGER_EN,
      -- Processor peripherals --
      IO_GPIO_EN           => io_gpio_en_c,
      IO_MTIME_EN          => IO_MTIME_EN,
      IO_UART0_EN          => IO_UART0_EN,
      IO_UART1_EN          => IO_UART1_EN,
      IO_SPI_EN            => IO_SPI_EN,
      IO_SDI_EN            => IO_SDI_EN,
      IO_TWI_EN            => IO_TWI_EN,
      IO_PWM_EN            => io_pwm_en_c,
      IO_WDT_EN            => IO_WDT_EN,
      IO_TRNG_EN           => IO_TRNG_EN,
      IO_CFS_EN            => IO_CFS_EN,
      IO_NEOLED_EN         => IO_NEOLED_EN,
      IO_XIRQ_EN           => io_xirq_en_c,
      IO_GPTMR_EN          => IO_GPTMR_EN,
      XIP_EN               => XIP_EN,
      IO_ONEWIRE_EN        => IO_ONEWIRE_EN,
      IO_DMA_EN            => IO_DMA_EN,
      IO_SLINK_EN          => IO_SLINK_EN,
      IO_CRC_EN            => IO_CRC_EN
    )
    port map (
      clk_i     => clk_i,
      rstn_i    => rstn_sys,
      bus_req_i => iodev_req(IODEV_SYSINFO),
      bus_rsp_o => iodev_rsp(IODEV_SYSINFO)
    );

  end generate; -- /io_system


  -- **************************************************************************************************************************
  -- On-Chip Debugger Complex
  -- **************************************************************************************************************************
  neorv32_neorv32_ocd_inst_true:
  if ON_CHIP_DEBUGGER_EN generate

    -- On-Chip Debugger - Debug Transport Module (DTM) ----------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_debug_dtm_inst: entity neorv32.neorv32_debug_dtm
    generic map (
      IDCODE_VERSION => (others => '0'),
      IDCODE_PARTID  => (others => '0'),
      IDCODE_MANID   => (others => '0')
    )
    port map (
      -- global control --
      clk_i        => clk_i,
      rstn_i       => rstn_ext,
      -- jtag connection --
      jtag_trst_i  => jtag_trst_i,
      jtag_tck_i   => jtag_tck_i,
      jtag_tdi_i   => jtag_tdi_i,
      jtag_tdo_o   => jtag_tdo_o,
      jtag_tms_i   => jtag_tms_i,
      -- debug module interface (DMI) --
      dmi_req_o    => dmi_req,
      dmi_rsp_i    => dmi_rsp
    );

    -- On-Chip Debugger - Debug Module (DM) ---------------------------------------------------
    -- -------------------------------------------------------------------------------------------
    neorv32_debug_dm_inst: entity neorv32.neorv32_debug_dm
    generic map (
      CPU_BASE_ADDR => base_io_dm_c,
      LEGACY_MODE   => DM_LEGACY_MODE
    )
    port map (
      -- global control --
      clk_i          => clk_i,
      rstn_i         => rstn_ext,
      cpu_debug_i    => cpu_debug,
      -- debug module interface (DMI) --
      dmi_req_i      => dmi_req,
      dmi_rsp_o      => dmi_rsp,
      -- CPU bus access --
      bus_req_i      => iodev_req(IODEV_OCD),
      bus_rsp_o      => iodev_rsp(IODEV_OCD),
      -- CPU control --
      cpu_ndmrstn_o  => dci_ndmrstn,
      cpu_halt_req_o => dci_halt_req
    );

  end generate;

  neorv32_debug_ocd_inst_false:
  if not ON_CHIP_DEBUGGER_EN generate
    iodev_rsp(IODEV_OCD) <= rsp_terminate_c;
    jtag_tdo_o           <= jtag_tdi_i; -- JTAG feed-through
    dci_ndmrstn          <= '1';
    dci_halt_req         <= '0';
  end generate;


end neorv32_top_rtl;
