
/*
 * crash_handler_asm.S
 *
 * Created: 10/8/2023 10:06:07 PM
 *  Author: david
 */ 

#include "crash_handler_asm.h"


     .text
    .syntax unified
    .arch armv7-m

    /* Called when something pends our special handler 
	   assigned to an unused IRQ that is specifically for handling crashes.

        extern "C" void HardFault_Handler(void);
    */
    .global HardFault_Handler
    .type HardFault_Handler, %function
    .thumb_func
HardFault_Handler:
	// disable IRQs so we don't get any randos messing with our stacks
	cpsid i 
	cpsid f
    /* Push the following onto the stack 
        msp
        psp
        exceptionPSR
        r4
        r5
        r6
        r7
        r8
        r9
        r10
        r11
        exceptionLR */
    mrs     r3, xpsr
    mrs     r2, psp
    mrs     r1, msp
	// change stack to our own stack which probably hasn't been touched yet
    ldr     sp, =(crashdump_stack + 4 * CRASHDUMP_STACK_SIZE)
    push.w  {r1-r11,lr}

    // Call our entry function with this stack as an argument. 
    mov     r0, sp
    bl      crashdump_start

	// If for some reason we make it back here, we can restore old values and return to the calling thread.
    pop.w   {r1-r11,lr}
    mov     sp, r1
    bx      lr

    // Let assembler know that we have hit the end of the HardFault_Handler function.
    .pool
    .size   HardFault_Handler, .-HardFault_Handler


// Copy ALL of the floating point registers to the array given in R0
// Use this if FPU wasn't used before entering interrupt
// Otherwise, you can just copy the higher 16 registers and grab
// the lower ones off the stack.

    .global Copy_All_FPU_Regs
    .type Copy_All_FPU_Regs, %function
    .thumb_func
Copy_All_FPU_Regs:
	// Copy the FPSCR before issuing any more FPU instructions
	// This will preserve its state
	vmrs r1, fpscr

	// Assume we have an array address given in R0
	// Copy each single-precision register to the 
	// pointer in r0, and increment the pointer each
	// time
	vstmia.32 r0!, {S0-S31}
	// Now we can plop the saved FPSCR in the 
	// address pointed to by R0 (after it has been
	// auto-incremented to the end of the array)
	str r1, [r0]

	// back to whoever called us
	bx lr

    .pool
    .size   Copy_All_FPU_Regs, .-Copy_All_FPU_Regs

// Copy just the upper 16 registers
// Use this when the lower 16 and FPSCR have already been 
// automatically stacked upon interrupt entry

    .global Copy_Upper_FPU_Regs
    .type Copy_Upper_FPU_Regs, %function
    .thumb_func
Copy_Upper_FPU_Regs:

	// Assume we have an array address given in R0
	// Copy upper 16 single-precision register to the 
	// pointer in r0, and increment the pointer each
	// time
	vstmia.32 r0!, {S16-S31}

	// back to whoever called us
	bx lr

    .pool
    .size   Copy_Upper_FPU_Regs, .-Copy_Upper_FPU_Regs