/* startup.S  —  Minimal reset vector for QEMU "virt" (RV32)
 *
 * What this file does:
 *  1. The linker places _start at 0x80000000 (the DRAM base that QEMU
 *     jumps to after its MROM boot ROM finishes).
 *  2. We set up the stack pointer and zero-initialise the BSS segment.
 *  3. We install a simple trap vector (trap_handler in main.c).
 *  4. We call main().  If main() returns we spin forever.
 *
 * Computer Architecture: Design and Analysis (2026 edition)
 * Krerk Piromsopa, Ph.D. · Chulalongkorn University
 */

    .section .text.boot, "ax"
    .global  _start
    .type    _start, @function

_start:
    /* Disable all interrupts while we set up */
    csrw    mie, zero
    csrw    mstatus, zero

    /* Set stack pointer to top of RAM (defined in linker script) */
    la      sp, _stack_top

    /* Zero-fill .bss */
    la      a0, _bss_start
    la      a1, _bss_end
1:  bgeu    a0, a1, 2f
    sw      zero, 0(a0)
    addi    a0, a0, 4
    j       1b
2:

    /* Copy .data from ROM to RAM (if LMA != VMA) */
    la      a0, _data_lma_start     /* source (load address in flash)  */
    la      a1, _data_vma_start     /* dest   (virtual address in RAM) */
    la      a2, _data_vma_end
3:  bgeu    a1, a2, 4f
    lw      t0, 0(a0)
    sw      t0, 0(a1)
    addi    a0, a0, 4
    addi    a1, a1, 4
    j       3b
4:

    /* Install trap vector (direct mode: mtvec[1:0] = 00) */
    la      t0, trap_entry
    csrw    mtvec, t0

    /* Call main */
    call    main

    /* main() returned — spin */
spin:
    wfi
    j       spin

    .size _start, . - _start


/* ================================================================== */
/*  Trap entry point                                                    */
/*                                                                      */
/*  Saves caller-saved registers, calls trap_handler(mcause, mepc),    */
/*  restores registers, and returns with mret.                          */
/* ================================================================== */

    .section .text.trap, "ax"
    .global  trap_entry
    .align   2                  /* mtvec requires 4-byte alignment     */

trap_entry:
    /* Allocate stack frame: 17 words = 68 bytes */
    addi    sp, sp, -68

    /* Save caller-saved integer registers */
    sw      ra,  0(sp)
    sw      t0,  4(sp)
    sw      t1,  8(sp)
    sw      t2, 12(sp)
    sw      a0, 16(sp)
    sw      a1, 20(sp)
    sw      a2, 24(sp)
    sw      a3, 28(sp)
    sw      a4, 32(sp)
    sw      a5, 36(sp)
    sw      a6, 40(sp)
    sw      a7, 44(sp)
    sw      t3, 48(sp)
    sw      t4, 52(sp)
    sw      t5, 56(sp)
    sw      t6, 60(sp)
    /* Save mepc so trap_handler can inspect/modify it */
    csrr    t0, mepc
    sw      t0, 64(sp)

    /* Call C handler:  void trap_handler(uint32_t mcause, uint32_t mepc) */
    csrr    a0, mcause
    csrr    a1, mepc
    call    trap_handler

    /* Restore mepc (handler may have advanced it to skip faulting insn) */
    lw      t0, 64(sp)
    csrw    mepc, t0

    /* Restore registers */
    lw      ra,  0(sp)
    lw      t0,  4(sp)
    lw      t1,  8(sp)
    lw      t2, 12(sp)
    lw      a0, 16(sp)
    lw      a1, 20(sp)
    lw      a2, 24(sp)
    lw      a3, 28(sp)
    lw      a4, 32(sp)
    lw      a5, 36(sp)
    lw      a6, 40(sp)
    lw      a7, 44(sp)
    lw      t3, 48(sp)
    lw      t4, 52(sp)
    lw      t5, 56(sp)
    lw      t6, 60(sp)

    addi    sp, sp, 68
    mret

    .size trap_entry, . - trap_entry
