| /* ----------------------------------------------------------------------- |
| 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 |