| /* ----------------------------------------------------------------------- | |
| sysv.S - Copyright (c) 2012 Alexandre K. I. de Mendonca <alexandre.keunecke@gmail.com>, | |
| Paulo Pizarro <paulo.pizarro@gmail.com> | |
| Blackfin 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> | |
| .text | |
| .align 4 | |
| /* | |
| There is a "feature" in the bfin toolchain that it puts a _ before function names | |
| that's why the function here it's called _ffi_call_SYSV and not ffi_call_SYSV | |
| */ | |
| .global _ffi_call_SYSV; | |
| .type _ffi_call_SYSV, STT_FUNC; | |
| .func ffi_call_SYSV | |
| /* | |
| cif->bytes = R0 (fp+8) | |
| &ecif = R1 (fp+12) | |
| ffi_prep_args = R2 (fp+16) | |
| ret_type = stack (fp+20) | |
| ecif.rvalue = stack (fp+24) | |
| fn = stack (fp+28) | |
| got (fp+32) | |
| There is room for improvement here (we can use temporary registers | |
| instead of saving the values in the memory) | |
| REGS: | |
| P5 => Stack pointer (function arguments) | |
| R5 => cif->bytes | |
| R4 => ret->type | |
| FP-20 = P3 | |
| FP-16 = SP (parameters area) | |
| FP-12 = SP (temp) | |
| FP-08 = function return part 1 [R0] | |
| FP-04 = function return part 2 [R1] | |
| */ | |
| _ffi_call_SYSV: | |
| .prologue: | |
| LINK 20; | |
| [FP-20] = P3; | |
| [FP+8] = R0; | |
| [FP+12] = R1; | |
| [FP+16] = R2; | |
| .allocate_stack: | |
| //alocate cif->bytes into the stack | |
| R1 = [FP+8]; | |
| R0 = SP; | |
| R0 = R0 - R1; | |
| R1 = 4; | |
| R0 = R0 - R1; | |
| [FP-12] = SP; | |
| SP = R0; | |
| [FP-16] = SP; | |
| .call_prep_args: | |
| //get the addr of prep_args | |
| P0 = [P3 + _ffi_prep_args@FUNCDESC_GOT17M4]; | |
| P1 = [P0]; | |
| P3 = [P0+4]; | |
| R0 = [FP-16];//SP (parameter area) | |
| R1 = [FP+12];//ecif | |
| call (P1); | |
| .call_user_function: | |
| //ajust SP so as to allow the user function access the parameters on the stack | |
| SP = [FP-16]; //point to function parameters | |
| R0 = [SP]; | |
| R1 = [SP+4]; | |
| R2 = [SP+8]; | |
| //load user function address | |
| P0 = FP; | |
| P0 +=28; | |
| P1 = [P0]; | |
| P1 = [P1]; | |
| P3 = [P0+4]; | |
| /* | |
| For functions returning aggregate values (struct) occupying more than 8 bytes, | |
| the caller allocates the return value object on the stack and the address | |
| of this object is passed to the callee as a hidden argument in register P0. | |
| */ | |
| P0 = [FP+24]; | |
| call (P1); | |
| SP = [FP-12]; | |
| .compute_return: | |
| P2 = [FP-20]; | |
| [FP-8] = R0; | |
| [FP-4] = R1; | |
| R0 = [FP+20]; | |
| R1 = R0 << 2; | |
| R0 = [P2+.rettable@GOT17M4]; | |
| R0 = R1 + R0; | |
| P2 = R0; | |
| R1 = [P2]; | |
| P2 = [FP+-20]; | |
| R0 = [P2+.rettable@GOT17M4]; | |
| R0 = R1 + R0; | |
| P2 = R0; | |
| R0 = [FP-8]; | |
| R1 = [FP-4]; | |
| jump (P2); | |
| /* | |
| #define FFIBFIN_RET_VOID 0 | |
| #define FFIBFIN_RET_BYTE 1 | |
| #define FFIBFIN_RET_HALFWORD 2 | |
| #define FFIBFIN_RET_INT64 3 | |
| #define FFIBFIN_RET_INT32 4 | |
| */ | |
| .align 4 | |
| .align 4 | |
| .rettable: | |
| .dd .epilogue - .rettable | |
| .dd .rbyte - .rettable; | |
| .dd .rhalfword - .rettable; | |
| .dd .rint64 - .rettable; | |
| .dd .rint32 - .rettable; | |
| .rbyte: | |
| P0 = [FP+24]; | |
| R0 = R0.B (Z); | |
| [P0] = R0; | |
| JUMP .epilogue | |
| .rhalfword: | |
| P0 = [FP+24]; | |
| R0 = R0.L; | |
| [P0] = R0; | |
| JUMP .epilogue | |
| .rint64: | |
| P0 = [FP+24];// &rvalue | |
| [P0] = R0; | |
| [P0+4] = R1; | |
| JUMP .epilogue | |
| .rint32: | |
| P0 = [FP+24]; | |
| [P0] = R0; | |
| .epilogue: | |
| R0 = [FP+8]; | |
| R1 = [FP+12]; | |
| R2 = [FP+16]; | |
| P3 = [FP-20]; | |
| UNLINK; | |
| RTS; | |
| .size _ffi_call_SYSV,.-_ffi_call_SYSV; | |
| .endfunc |