| /* ----------------------------------------------------------------------- | |
| sysv.S - Copyright (c) 2004 Simon Posnjak | |
| Copyright (c) 2005 Axis Communications AB | |
| CRIS 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 SIMON POSNJAK 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 <ffi.h> | |
| #define CONCAT(x,y) x ## y | |
| #define XCONCAT(x,y) CONCAT (x, y) | |
| #define L(x) XCONCAT (__USER_LABEL_PREFIX__, x) | |
| .text | |
| ;; OK, when we get called we should have this (according to | |
| ;; AXIS ETRAX 100LX Programmer's Manual chapter 6.3). | |
| ;; | |
| ;; R10: ffi_prep_args (func. pointer) | |
| ;; R11: &ecif | |
| ;; R12: cif->bytes | |
| ;; R13: fig->flags | |
| ;; sp+0: ecif.rvalue | |
| ;; sp+4: fn (function pointer to the function that we need to call) | |
| .globl L(ffi_call_SYSV) | |
| .type L(ffi_call_SYSV),@function | |
| .hidden L(ffi_call_SYSV) | |
| L(ffi_call_SYSV): | |
| ;; Save the regs to the stack. | |
| push $srp | |
| ;; Used for stack pointer saving. | |
| push $r6 | |
| ;; Used for function address pointer. | |
| push $r7 | |
| ;; Used for stack pointer saving. | |
| push $r8 | |
| ;; We save fig->flags to stack we will need them after we | |
| ;; call The Function. | |
| push $r13 | |
| ;; Saving current stack pointer. | |
| move.d $sp,$r8 | |
| move.d $sp,$r6 | |
| ;; Move address of ffi_prep_args to r13. | |
| move.d $r10,$r13 | |
| ;; Make room on the stack for the args of fn. | |
| sub.d $r12,$sp | |
| ;; Function void ffi_prep_args(char *stack, extended_cif *ecif) parameters are: | |
| ;; r10 <-- stack pointer | |
| ;; r11 <-- &ecif (already there) | |
| move.d $sp,$r10 | |
| ;; Call the function. | |
| jsr $r13 | |
| ;; Save the size of the structures which are passed on stack. | |
| move.d $r10,$r7 | |
| ;; Move first four args in to r10..r13. | |
| move.d [$sp+0],$r10 | |
| move.d [$sp+4],$r11 | |
| move.d [$sp+8],$r12 | |
| move.d [$sp+12],$r13 | |
| ;; Adjust the stack and check if any parameters are given on stack. | |
| addq 16,$sp | |
| sub.d $r7,$r6 | |
| cmp.d $sp,$r6 | |
| bpl go_on | |
| nop | |
| go_on_no_params_on_stack: | |
| move.d $r6,$sp | |
| go_on: | |
| ;; Discover if we need to put rval address in to r9. | |
| move.d [$r8+0],$r7 | |
| cmpq FFI_TYPE_STRUCT,$r7 | |
| bne call_now | |
| nop | |
| ;; Move rval address to $r9. | |
| move.d [$r8+20],$r9 | |
| call_now: | |
| ;; Move address of The Function in to r7. | |
| move.d [$r8+24],$r7 | |
| ;; Call The Function. | |
| jsr $r7 | |
| ;; Reset stack. | |
| move.d $r8,$sp | |
| ;; Load rval type (fig->flags) in to r13. | |
| pop $r13 | |
| ;; Detect rval type. | |
| cmpq FFI_TYPE_VOID,$r13 | |
| beq epilogue | |
| cmpq FFI_TYPE_STRUCT,$r13 | |
| beq epilogue | |
| cmpq FFI_TYPE_DOUBLE,$r13 | |
| beq return_double_or_longlong | |
| cmpq FFI_TYPE_UINT64,$r13 | |
| beq return_double_or_longlong | |
| cmpq FFI_TYPE_SINT64,$r13 | |
| beq return_double_or_longlong | |
| nop | |
| ;; Just return the 32 bit value. | |
| ba return | |
| nop | |
| return_double_or_longlong: | |
| ;; Load half of the rval to r10 and the other half to r11. | |
| move.d [$sp+16],$r13 | |
| move.d $r10,[$r13] | |
| addq 4,$r13 | |
| move.d $r11,[$r13] | |
| ba epilogue | |
| nop | |
| return: | |
| ;; Load the rval to r10. | |
| move.d [$sp+16],$r13 | |
| move.d $r10,[$r13] | |
| epilogue: | |
| pop $r8 | |
| pop $r7 | |
| pop $r6 | |
| Jump [$sp+] | |
| .size ffi_call_SYSV,.-ffi_call_SYSV | |
| /* Save R10..R13 into an array, somewhat like varargs. Copy the next | |
| argument too, to simplify handling of any straddling parameter. | |
| Save R9 and SP after those. Jump to function handling the rest. | |
| Since this is a template, copied and the main function filled in by | |
| the user. */ | |
| .globl L(ffi_cris_trampoline_template) | |
| .type L(ffi_cris_trampoline_template),@function | |
| .hidden L(ffi_cris_trampoline_template) | |
| L(ffi_cris_trampoline_template): | |
| 0: | |
| /* The value we get for "PC" is right after the prefix instruction, | |
| two bytes from the beginning, i.e. 0b+2. */ | |
| move.d $r10,[$pc+2f-(0b+2)] | |
| move.d $pc,$r10 | |
| 1: | |
| addq 2f-1b+4,$r10 | |
| move.d $r11,[$r10+] | |
| move.d $r12,[$r10+] | |
| move.d $r13,[$r10+] | |
| move.d [$sp],$r11 | |
| move.d $r11,[$r10+] | |
| move.d $r9,[$r10+] | |
| move.d $sp,[$r10+] | |
| subq FFI_CRIS_TRAMPOLINE_DATA_PART_SIZE,$r10 | |
| move.d 0,$r11 | |
| 3: | |
| jump 0 | |
| 2: | |
| .size ffi_cris_trampoline_template,.-0b | |
| /* This macro create a constant usable as "extern const int \name" in | |
| C from within libffi, when \name has no prefix decoration. */ | |
| .macro const name,value | |
| .globl \name | |
| .type \name,@object | |
| .hidden \name | |
| \name: | |
| .dword \value | |
| .size \name,4 | |
| .endm | |
| /* Constants for offsets within the trampoline. We could do this with | |
| just symbols, avoiding memory contents and memory accesses, but the | |
| C usage code would look a bit stranger. */ | |
| const L(ffi_cris_trampoline_fn_offset),2b-4-0b | |
| const L(ffi_cris_trampoline_closure_offset),3b-4-0b |