/**
 * main.c  —  Bare-metal RISC-V I/O starter skeleton
 *
 * *** Student activity — read the comments and fill in the TODOs ***
 *
 * This file provides:
 *   main()         — entry point; calls the polling or IRQ echo loop
 *   trap_handler() — called by startup.S on any machine-mode trap
 *
 * Computer Architecture: Design and Analysis (2026 edition)
 * Krerk Piromsopa, Ph.D. · Chulalongkorn University
 */

#include "platform.h"
#include "uart.h"

/* ------------------------------------------------------------------ */
/*  Helper: simple unsigned integer printer (no printf / libc)         */
/* ------------------------------------------------------------------ */
static void print_uint(uint32_t n)
{
    char buf[11];
    int  i = 10;
    buf[10] = '\0';
    if (n == 0) { uart_putc('0'); return; }
    while (n && i > 0) {
        buf[--i] = '0' + (n % 10);
        n /= 10;
    }
    uart_puts(&buf[i]);
}

/* ------------------------------------------------------------------ */
/*  Exercise 1 — Polling echo loop                                      */
/*                                                                      */
/*  After uart_init(), simply read characters and echo them back.      */
/*  Aim: understand the polling algorithm and measure CPU utilisation.  */
/* ------------------------------------------------------------------ */
static void polling_echo(void)
{
    uart_init();
    uart_puts("=== Polling echo ready (press keys, Ctrl-A X to exit QEMU) ===\r\n");

    while (1) {
        /* TODO Exercise 1:
         *   char c = uart_getc();   // blocks until a key is pressed
         *   uart_putc(c);           // echo it back
         *
         * Extra: also print the hex value of each character to see the
         *        raw byte the UART received:
         *   uart_puts("  [0x"); print_hex(c); uart_puts("]\r\n");
         */
    }
}

/* ------------------------------------------------------------------ */
/*  Exercise 2 — Interrupt-driven echo loop                            */
/*                                                                      */
/*  The main loop does useful work (Fibonacci) while the ISR enqueues  */
/*  received characters into a ring buffer.                             */
/* ------------------------------------------------------------------ */
static uint32_t fib(uint32_t n)
{
    /* Iterative Fibonacci — keeps the CPU busy between keystrokes */
    if (n < 2) return n;
    uint32_t a = 0, b = 1;
    for (uint32_t i = 2; i <= n; i++) {
        uint32_t t = a + b; a = b; b = t;
    }
    return b;
}

static void irq_echo(void)
{
    uart_init();
    uart_init_irq();   /* Enable RX interrupt, configure PLIC */
    uart_puts("=== Interrupt-driven echo + Fibonacci loop ===\r\n");

    uint32_t n = 0;
    while (1) {
        /* Useful background work: compute Fibonacci(n % 40) */
        uint32_t result = fib(n % 40);
        (void)result;   /* TODO Exercise 2: print result via uart_puts */

        /* TODO Exercise 2:
         *   char c = uart_getc_irq();   // non-blocking dequeue
         *   if (c) uart_putc(c);        // echo if a character arrived
         */

        n++;
    }
}

/* ------------------------------------------------------------------ */
/*  Trap handler  (called from trap_entry in startup.S)                */
/*                                                                      */
/*  mcause bit 31 = 1  →  interrupt                                    */
/*  mcause bit 31 = 0  →  exception                                    */
/* ------------------------------------------------------------------ */
void trap_handler(uint32_t mcause, uint32_t mepc)
{
    if (mcause & MCAUSE_INT_BIT) {
        /* Interrupt */
        uint32_t cause = mcause & ~MCAUSE_INT_BIT;
        if (cause == MCAUSE_M_EXT) {
            /* Machine external interrupt — dispatch to UART ISR */
            uart_rx_isr();
        }
        /* Other interrupt sources (timer, software): ignored for now */
    } else {
        /* Exception — print diagnostic and halt */
        uart_puts("\r\n!!! EXCEPTION mcause=0x");
        /* TODO: print mcause in hex if you have a print_hex helper */
        uart_puts(" mepc=0x");
        print_uint(mepc);
        uart_puts("\r\nHalted.\r\n");
        while (1)
            __asm__ volatile("wfi");
    }
}

/* ------------------------------------------------------------------ */
/*  main                                                                */
/* ------------------------------------------------------------------ */
int main(void)
{
    /*
     * Choose which exercise to run by uncommenting ONE of the calls
     * below and commenting the other.  Rebuild and re-run in QEMU.
     *
     * Exercise 1 — polling echo:
     *   polling_echo();
     *
     * Exercise 2 — interrupt-driven echo:
     *   irq_echo();
     */

    polling_echo();   /* default: start with Exercise 1 */

    /* Should never return */
    while (1)
        __asm__ volatile("wfi");
    return 0;
}
