#![cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]

use core::arch::global_asm;

global_asm!(
    r#"
    .weak SmallSystemInit, SystemInit
    .global _start
    .global trap_entry
    .global _start_trap

    .altmacro

    .macro copy_words src, src_end, dst, tmp
        j 2f
    1:
        lw \tmp, 0(\src)
        sw \tmp, 0(\dst)
        addi \src, \src, 4
        addi \dst, \dst, 4
    2:
        bltu \src, \src_end, 1b
    .endm

    .macro zero_words dst, dst_end
        j 2f
    1:
        sw zero, 0(\dst)
        addi \dst, \dst, 4
    2:
        bltu \dst, \dst_end, 1b
    .endm

    .macro la_abs reg, address
        .option push
        .option norelax
        lui \reg, %hi(\address)
        addi \reg, \reg, %lo(\address)
        .option pop
    .endm

    .macro call_abs address
        .option push
        .option norelax
        lui ra, %hi(\address)
        jalr ra, %lo(\address)(ra)
        .option pop
    .endm

    .section .startup, "ax"
    .align 2
_start:
    /* Let EEPROM and clocks settle after reset, matching the vendor runtime. */
    li t0, 128000
1:
    addi t0, t0, -1
    bnez t0, 1b

    la_abs sp, __C_STACK_TOP__
    la_abs gp, __global_pointer$

    /* Copy all code that executes from SRAM, including the trap entry. */
    la_abs a1, __RAM_TEXT_IMAGE_START__
    la_abs a2, __RAM_TEXT_IMAGE_END__
    la_abs a3, __RAM_TEXT_START__
    copy_words a1, a2, a3, t0

    /* Initialize thread-local data and establish the single-hart TLS base. */
    la_abs a1, __TDATA_IMAGE_START__
    la_abs a2, __TDATA_IMAGE_END__
    la_abs a3, _tdata_start
    copy_words a1, a2, a3, t0
    la_abs tp, _tls_data

    la_abs a1, _tbss_start
    la_abs a2, _tbss_end
    zero_words a1, a2

    /* .data, .sdata and .srodata form one contiguous load image. */
    la_abs a1, __DATA_IMAGE_START__
    la_abs a2, __DATA_IMAGE_END__
    la_abs a3, __DATA_START__
    copy_words a1, a2, a3, t0

    la_abs a1, __SBSS_START__
    la_abs a2, __BSS_END__
    zero_words a1, a2

    la_abs t0, __TRAP_TEXT_START__
    csrw mtvec, t0

    call_abs SmallSystemInit
    call_abs SystemInit
    call_abs __start_rust

2:
    wfi
    j 2b

    .size _start, . - _start

    /* The reset vector table reserves offset 0xc0 for the trap jump. */
    .section .trap_text, "ax"
    .align 2
trap_entry:
    j _start_trap
    .size trap_entry, . - trap_entry

_start_trap:
    /* One 32-bit slot per x-register; slot x2 records the pre-trap SP. */
    addi sp, sp, -128
    sw x5, 20(sp)
    addi x5, sp, 128
    sw x5, 8(sp)

    .irp index, 1, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
        sw x\index, 4*index(sp)
    .endr

    call_abs trap_handler

    .irp index, 1, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
        lw x\index, 4*index(sp)
    .endr
    lw x5, 20(sp)
    addi sp, sp, 128
    mret

    .size _start_trap, . - _start_trap

    .section .startup, "ax"
SmallSystemInit:
SystemInit:
    ret
"#
);
