/***************************************************************************
 * Copyright (C) 2026 Eclipse ThreadX contributors
 *
 * This program and the accompanying materials are made available under the
 * terms of the MIT License which is available at
 * https://opensource.org/licenses/MIT.
 *
 * AI Disclosure: This file was largely AI-generated by Copilot (Sonnet 4.6).
 * The AI-generated portions may be considered public domain (CC0-1.0)
 * and not subject to the project's licence. The human contributor has
 * reviewed and verified that the code is correct.
 *
 * SPDX-License-Identifier: MIT and CC0-1.0
 **************************************************************************/

#include <stddef.h>
#include <stdint.h>

#include "csr.h"
#include "fll.h"
#include "gpio.h"
#include "irq.h"
#include "properties.h"
#include "system_core_v_mcu.h"
#include "timer_irq.h"
#include "tx_api.h"
#include "uart_driver.h"

extern void _tx_timer_interrupt(void);

volatile uint32_t system_core_clock = DEFAULT_SYSTEM_CLOCK;
volatile uint32_t last_trap_mcause;
void (*isr_table[32])(void);

static uint32_t uart_console_ready;

static void uart_write_hex32(uint32_t value)
{
    static const char hex[] = "0123456789ABCDEF";
    int shift;

    uart_write_str(0U, "0x");
    for (shift = 28; shift >= 0; shift -= 4)
    {
        uart_write_byte(0U, (uint8_t)hex[(value >> (uint32_t)shift) & 0xFU]);
    }
}

void tx_undefined_irq_handler(void)
{
    if (uart_console_ready != 0U)
    {
        uart_write_str(0U, "\r\nUndefined IRQ\r\n");
    }

    /* MISRA deviation: intentional infinite loop used as a fault sink. */
    for (;;)
    {
    }
}

void tx_timer_irq_handler(void)
{
    _tx_timer_interrupt();
}

void system_init(void)
{
    uint32_t i;

    for (i = 0U; i < 32U; ++i)
    {
        isr_table[i] = tx_undefined_irq_handler;
    }

    isr_table[7U] = tx_timer_irq_handler;

    for (i = 0U; i < ARCHI_NB_FLL; ++i)
    {
        pi_fll_init((fll_type_t)i, 0U);
    }

    pulp_irq_init();
    (void)timer_irq_init(ARCHI_SOC_FREQUENCY / (uint32_t)TX_TIMER_TICKS_PER_SECOND);
    /* CV32E40P routes the FC Timer LO to irq_i[7] (MTI, bit 7), which maps
     * to mip[7].  IRQ_MASK in cv32e40p_cs_registers forces mie[10] to zero,
     * so bit 7 is the correct enable bit.  mcause will be 0x80000007. */
    (void)csr_read_set(CSR_MIE, BIT(7));

    gpio_init();
    if (uart_init(0U, 115200U, ARCHI_FPGA_FREQUENCY) == 0)
    {
        uart_console_ready = 1U;
    }
}

void tx_trap_handler(uint32_t mcause, uint32_t mepc, uint32_t mtval)
{
    last_trap_mcause = mcause;

    if ((mcause & 0x80000000UL) != 0UL)
    {
        uint32_t irq_id = mcause & 0x1FUL;

        if (isr_table[irq_id] != NULL)
        {
            isr_table[irq_id]();
        }
        else
        {
            tx_undefined_irq_handler();
        }
    }
    else
    {
        if (uart_console_ready != 0U)
        {
            uart_write_str(0U, "\r\nTrap mcause=");
            uart_write_hex32(mcause);
            uart_write_str(0U, " mepc=");
            uart_write_hex32(mepc);
            uart_write_str(0U, " mtval=");
            uart_write_hex32(mtval);
            uart_write_str(0U, "\r\n");
        }

        /* MISRA deviation: intentional infinite loop used as a fault sink. */
        for (;;)
        {
        }
    }
}
