| /* ----------------------------------------------------------------------- |
| sysv.S - Copyright (c) 2012, 2013 Xilinx, Inc |
| |
| MicroBlaze Foreign Function Interface |
| |
| Permission is hereby granted, free of charge, to any person obtaining |
| a copy of this software and associated documentation files (the |
| ``Software''), to deal in the Software without restriction, including |
| without limitation the rights to use, copy, modify, merge, publish, |
| distribute, sublicense, and/or sell copies of the Software, and to |
| permit persons to whom the Software is furnished to do so, subject to |
| the following conditions: |
| |
| The above copyright notice and this permission notice shall be included |
| in all copies or substantial portions of the Software. |
| |
| THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, |
| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
| HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| DEALINGS IN THE SOFTWARE. |
| ----------------------------------------------------------------------- */ |
| |
| #define LIBFFI_ASM |
| #include <fficonfig.h> |
| #include <ffi.h> |
| |
| /* |
| * arg[0] (r5) = ffi_prep_args, |
| * arg[1] (r6) = &ecif, |
| * arg[2] (r7) = cif->bytes, |
| * arg[3] (r8) = cif->flags, |
| * arg[4] (r9) = ecif.rvalue, |
| * arg[5] (r10) = fn |
| * arg[6] (sp[0]) = cif->rtype->type |
| * arg[7] (sp[4]) = cif->rtype->size |
| */ |
| .text |
| .globl ffi_call_SYSV |
| .type ffi_call_SYSV, @function |
| ffi_call_SYSV: |
| /* push callee saves */ |
| addik r1, r1, -20 |
| swi r19, r1, 0 /* Frame Pointer */ |
| swi r20, r1, 4 /* PIC register */ |
| swi r21, r1, 8 /* PIC register */ |
| swi r22, r1, 12 /* save for locals */ |
| swi r23, r1, 16 /* save for locals */ |
| |
| /* save the r5-r10 registers in the stack */ |
| addik r1, r1, -24 /* increment sp to store 6x 32-bit words */ |
| swi r5, r1, 0 |
| swi r6, r1, 4 |
| swi r7, r1, 8 |
| swi r8, r1, 12 |
| swi r9, r1, 16 |
| swi r10, r1, 20 |
| |
| /* save function pointer */ |
| addik r3, r5, 0 /* copy ffi_prep_args into r3 */ |
| addik r22, r1, 0 /* save sp for unallocated args into r22 (callee-saved) */ |
| addik r23, r10, 0 /* save function address into r23 (callee-saved) */ |
| |
| /* prepare stack with allocation for n (bytes = r7) args */ |
| rsub r1, r7, r1 /* subtract bytes from sp */ |
| |
| /* prep args for ffi_prep_args call */ |
| addik r5, r1, 0 /* store stack pointer into arg[0] */ |
| /* r6 still holds ecif for arg[1] */ |
| |
| /* Call ffi_prep_args(stack, &ecif). */ |
| addik r1, r1, -4 |
| swi r15, r1, 0 /* store the link register in the frame */ |
| brald r15, r3 |
| nop /* branch has delay slot */ |
| lwi r15, r1, 0 |
| addik r1, r1, 4 /* restore the link register from the frame */ |
| /* returns calling stack pointer location */ |
| |
| /* prepare args for fn call, prep_args populates them onto the stack */ |
| lwi r5, r1, 0 /* arg[0] */ |
| lwi r6, r1, 4 /* arg[1] */ |
| lwi r7, r1, 8 /* arg[2] */ |
| lwi r8, r1, 12 /* arg[3] */ |
| lwi r9, r1, 16 /* arg[4] */ |
| lwi r10, r1, 20 /* arg[5] */ |
| |
| /* call (fn) (...). */ |
| addik r1, r1, -4 |
| swi r15, r1, 0 /* store the link register in the frame */ |
| brald r15, r23 |
| nop /* branch has delay slot */ |
| lwi r15, r1, 0 |
| addik r1, r1, 4 /* restore the link register from the frame */ |
| |
| /* Remove the space we pushed for the args. */ |
| addik r1, r22, 0 /* restore old SP */ |
| |
| /* restore this functions parameters */ |
| lwi r5, r1, 0 /* arg[0] */ |
| lwi r6, r1, 4 /* arg[1] */ |
| lwi r7, r1, 8 /* arg[2] */ |
| lwi r8, r1, 12 /* arg[3] */ |
| lwi r9, r1, 16 /* arg[4] */ |
| lwi r10, r1, 20 /* arg[5] */ |
| addik r1, r1, 24 /* decrement sp to de-allocate 6x 32-bit words */ |
| |
| /* If the return value pointer is NULL, assume no return value. */ |
| beqi r9, ffi_call_SYSV_end |
| |
| lwi r22, r1, 48 /* get return type (20 for locals + 28 for arg[6]) */ |
| lwi r23, r1, 52 /* get return size (20 for locals + 32 for arg[7]) */ |
| |
| /* Check if return type is actually a struct, do nothing */ |
| rsubi r11, r22, FFI_TYPE_STRUCT |
| beqi r11, ffi_call_SYSV_end |
| |
| /* Return 8bit */ |
| rsubi r11, r23, 1 |
| beqi r11, ffi_call_SYSV_store8 |
| |
| /* Return 16bit */ |
| rsubi r11, r23, 2 |
| beqi r11, ffi_call_SYSV_store16 |
| |
| /* Return 32bit */ |
| rsubi r11, r23, 4 |
| beqi r11, ffi_call_SYSV_store32 |
| |
| /* Return 64bit */ |
| rsubi r11, r23, 8 |
| beqi r11, ffi_call_SYSV_store64 |
| |
| /* Didn't match anything */ |
| bri ffi_call_SYSV_end |
| |
| ffi_call_SYSV_store64: |
| swi r3, r9, 0 /* store word r3 into return value */ |
| swi r4, r9, 4 /* store word r4 into return value */ |
| bri ffi_call_SYSV_end |
| |
| ffi_call_SYSV_store32: |
| swi r3, r9, 0 /* store word r3 into return value */ |
| bri ffi_call_SYSV_end |
| |
| ffi_call_SYSV_store16: |
| #ifdef __BIG_ENDIAN__ |
| shi r3, r9, 2 /* store half-word r3 into return value */ |
| #else |
| shi r3, r9, 0 /* store half-word r3 into return value */ |
| #endif |
| bri ffi_call_SYSV_end |
| |
| ffi_call_SYSV_store8: |
| #ifdef __BIG_ENDIAN__ |
| sbi r3, r9, 3 /* store byte r3 into return value */ |
| #else |
| sbi r3, r9, 0 /* store byte r3 into return value */ |
| #endif |
| bri ffi_call_SYSV_end |
| |
| ffi_call_SYSV_end: |
| /* callee restores */ |
| lwi r19, r1, 0 /* frame pointer */ |
| lwi r20, r1, 4 /* PIC register */ |
| lwi r21, r1, 8 /* PIC register */ |
| lwi r22, r1, 12 |
| lwi r23, r1, 16 |
| addik r1, r1, 20 |
| |
| /* return from sub-routine (with delay slot) */ |
| rtsd r15, 8 |
| nop |
| |
| .size ffi_call_SYSV, . - ffi_call_SYSV |
| |
| /* ------------------------------------------------------------------------- */ |
| |
| /* |
| * args passed into this function, are passed down to the callee. |
| * this function is the target of the closure trampoline, as such r12 is |
| * a pointer to the closure object. |
| */ |
| .text |
| .globl ffi_closure_SYSV |
| .type ffi_closure_SYSV, @function |
| ffi_closure_SYSV: |
| /* push callee saves */ |
| addik r11, r1, 28 /* save stack args start location (excluding regs/link) */ |
| addik r1, r1, -12 |
| swi r19, r1, 0 /* Frame Pointer */ |
| swi r20, r1, 4 /* PIC register */ |
| swi r21, r1, 8 /* PIC register */ |
| |
| /* store register args on stack */ |
| addik r1, r1, -24 |
| swi r5, r1, 0 |
| swi r6, r1, 4 |
| swi r7, r1, 8 |
| swi r8, r1, 12 |
| swi r9, r1, 16 |
| swi r10, r1, 20 |
| |
| /* setup args */ |
| addik r5, r1, 0 /* register_args */ |
| addik r6, r11, 0 /* stack_args */ |
| addik r7, r12, 0 /* closure object */ |
| addik r1, r1, -8 /* allocate return value */ |
| addik r8, r1, 0 /* void* rvalue */ |
| addik r1, r1, -8 /* allocate for return type/size values */ |
| addik r9, r1, 0 /* void* rtype */ |
| addik r10, r1, 4 /* void* rsize */ |
| |
| /* call the wrap_call function */ |
| addik r1, r1, -28 /* allocate args + link reg */ |
| swi r15, r1, 0 /* store the link register in the frame */ |
| brald r15, r3 |
| nop /* branch has delay slot */ |
| lwi r15, r1, 0 |
| addik r1, r1, 28 /* restore the link register from the frame */ |
| |
| ffi_closure_SYSV_prepare_return: |
| lwi r9, r1, 0 /* rtype */ |
| lwi r10, r1, 4 /* rsize */ |
| addik r1, r1, 8 /* de-allocate return info values */ |
| |
| /* Check if return type is actually a struct, store 4 bytes */ |
| rsubi r11, r9, FFI_TYPE_STRUCT |
| beqi r11, ffi_closure_SYSV_store32 |
| |
| /* Return 8bit */ |
| rsubi r11, r10, 1 |
| beqi r11, ffi_closure_SYSV_store8 |
| |
| /* Return 16bit */ |
| rsubi r11, r10, 2 |
| beqi r11, ffi_closure_SYSV_store16 |
| |
| /* Return 32bit */ |
| rsubi r11, r10, 4 |
| beqi r11, ffi_closure_SYSV_store32 |
| |
| /* Return 64bit */ |
| rsubi r11, r10, 8 |
| beqi r11, ffi_closure_SYSV_store64 |
| |
| /* Didn't match anything */ |
| bri ffi_closure_SYSV_end |
| |
| ffi_closure_SYSV_store64: |
| lwi r3, r1, 0 /* store word r3 into return value */ |
| lwi r4, r1, 4 /* store word r4 into return value */ |
| /* 64 bits == 2 words, no sign extend occurs */ |
| bri ffi_closure_SYSV_end |
| |
| ffi_closure_SYSV_store32: |
| lwi r3, r1, 0 /* store word r3 into return value */ |
| /* 32 bits == 1 word, no sign extend occurs */ |
| bri ffi_closure_SYSV_end |
| |
| ffi_closure_SYSV_store16: |
| #ifdef __BIG_ENDIAN__ |
| lhui r3, r1, 2 /* store half-word r3 into return value */ |
| #else |
| lhui r3, r1, 0 /* store half-word r3 into return value */ |
| #endif |
| rsubi r11, r9, FFI_TYPE_SINT16 |
| bnei r11, ffi_closure_SYSV_end |
| sext16 r3, r3 /* fix sign extend of sint8 */ |
| bri ffi_closure_SYSV_end |
| |
| ffi_closure_SYSV_store8: |
| #ifdef __BIG_ENDIAN__ |
| lbui r3, r1, 3 /* store byte r3 into return value */ |
| #else |
| lbui r3, r1, 0 /* store byte r3 into return value */ |
| #endif |
| rsubi r11, r9, FFI_TYPE_SINT8 |
| bnei r11, ffi_closure_SYSV_end |
| sext8 r3, r3 /* fix sign extend of sint8 */ |
| bri ffi_closure_SYSV_end |
| |
| ffi_closure_SYSV_end: |
| addik r1, r1, 8 /* de-allocate return value */ |
| |
| /* de-allocate stored args */ |
| addik r1, r1, 24 |
| |
| /* callee restores */ |
| lwi r19, r1, 0 /* frame pointer */ |
| lwi r20, r1, 4 /* PIC register */ |
| lwi r21, r1, 8 /* PIC register */ |
| addik r1, r1, 12 |
| |
| /* return from sub-routine (with delay slot) */ |
| rtsd r15, 8 |
| nop |
| |
| .size ffi_closure_SYSV, . - ffi_closure_SYSV |