vexide-startup 0.6.0-alpha.1

User program startup and runtime support for vexide.
.text
.arm

@ Custom ARM vector table. Pointing the VBAR coprocessor register at this will configure the CPU to
@ jump to these functions on an exception.
.align 5
.global vector_table
vector_table:
    b vexSystemBoot
    b {undefined_instruction}
    b vexide_supervisor_call
    b {prefetch_abort}
    b {data_abort}
    nop @ Placeholder for address exception vector
    b vexide_irq
@ Place the FIQ exception vector directly on the last entry of the vector table to
@ avoid an unnecessary branch.
@
@ See: https://developer.arm.com/documentation/dui0056/d/handling-processor-exceptions/interrupt-handlers?lang=en#:~:text=The%20FIQ%20vector,increasing%20execution%20speed.
.global vexide_fiq
vexide_fiq:
    @ NOTE: In FIQ mode r12 is banked, so saving it to the stack here is unnecessary,
    @       but we still do it anyways to maintain stack alignment.
    stmdb sp!,{{r0-r3,r12,lr}}

    vpush {{d0-d7}}
    vpush {{d16-d31}}
    vmrs r1, FPSCR
    push {{r1}}
    vmrs r1, FPEXC
    push {{r1}}

    bl vexSystemFIQInterrupt

    pop {{r1}}
    vmsr FPEXC, r1
    pop {{r1}}
    vmsr FPSCR, r1
    vpop {{d16-d31}}
    vpop {{d0-d7}}

    ldmia sp!,{{r0-r3,r12,lr}}
    subs pc, lr, #4


.global vexide_supervisor_call
vexide_supervisor_call:
    @ Save state and SPSR so we can restore it later. Saving SPSR matches
    @ the behavior of the ARM sample SVC handler:
    @ https://developer.arm.com/documentation/dui0203/j/handling-processor-exceptions/armv6-and-earlier--armv7-a-and-armv7-r-profiles/svc-handlers?lang=en
    @ This is intended to prevent modification inside vexSystemSWInterrupt from
    @ corrupting the register.

    push {{r0-r3,r12,lr}}
    mrs r0, spsr
    push {{r0,r3}} @ r3 is a random register to maintain alignment

    @ Extract the SVC immediate number from the instruction and place it into r0.
    @ This is intended to match the behavior of Xilinx's embeddedsw SVC handler.
    @
    @ The way we do this depends on whether or not user code was running in ARM
    @ or Thumb mode at the time of this exception, so we check the T-bit in SPSR
    @ to determine this.

    @ T-bit check (spsr was placed into r0 a few lines above)
    tst	r0, #0x20

    @ Thumb mode
    ldrhne r0, [lr,#-2]
    bicne r0, r0, #0xff00

    @ ARM mode
    ldreq r0, [lr,#-4]
    biceq r0, r0, #0xff000000

    @ Call VEXos interrupt handler as fn(svc_comment) -> ()
    bl vexSystemSWInterrupt

    @ Restore spsr, other registers. Then return.
    pop {{r0,r3}}
        @ Only the cxsf groups are restored because writing to the entire thing could cause issues.
        @ These bits restore things like interrupt state, condition flags, etc.
    msr spsr_cxsf, r0
    ldmia sp!, {{r0-r3,r12,pc}}^


.global vexide_irq
vexide_irq:
    stmdb sp!,{{r0-r3,r12,lr}}

    vpush {{d0-d7}}
    vpush {{d16-d31}}
    vmrs r1, FPSCR
    push {{r1}}
    vmrs r1, FPEXC
    push {{r1}}

    bl vexSystemIRQInterrupt

    pop {{r1}}
    vmsr FPEXC, r1
    pop {{r1}}
    vmsr FPSCR, r1
    vpop {{d16-d31}}
    vpop {{d0-d7}}

    ldmia sp!,{{r0-r3,r12,lr}}
    subs pc, lr, #4