/*

* Copyright (c) 2013 Miodrag Vallat.  <miod@openbsd.org>
*
* 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.
*/

/*

* m88k Foreign Function Interface
*/

define LIBFFI_ASM

include <fficonfig.h> include <ffi.h>

.text

/*

* ffi_cacheflush_OBSD(unsigned int addr,       %r2
*                     unsigned int size);      %r3
*/
       .align  4
       .globl  ffi_cacheflush_OBSD
       .type   ffi_cacheflush_OBSD,@function

ffi_cacheflush_OBSD:

tb0     0,   %r0, 451
or      %r0, %r0, %r0
jmp     %r1
.size   ffi_cacheflush_OBSD, . - ffi_cacheflush_OBSD

/*

* ffi_call_OBSD(unsigned bytes,                %r2
*               extended_cif *ecif,            %r3
*               unsigned flags,                %r4
*               void *rvalue,                  %r5
*               void (*fn)());                 %r6
*/
       .align  4
       .globl  ffi_call_OBSD
       .type   ffi_call_OBSD,@function

ffi_call_OBSD:

subu    %r31, %r31, 32
st      %r30, %r31, 4
st      %r1,  %r31, 0
addu    %r30, %r31, 32

| Save the few arguments we'll need after ffi_prep_args()
st.d    %r4, %r31, 8
st      %r6, %r31, 16

| Allocate room for the image of r2-r9, and the stack space for
| the args (rounded to a 16-byte boundary)
addu    %r2,  %r2,  (8 * 4) + 15
clr     %r2,  %r2,  4<0>
subu    %r31, %r31, %r2

| Fill register and stack image
or      %r2, %r31, %r0

ifdef PIC

bsr     ffi_prep_args#plt

else

bsr     ffi_prep_args

endif

| Save pointer to return struct address, if any
or      %r12, %r2, %r0

| Get function pointer
subu    %r4,  %r30, 32
ld      %r1,  %r4,  16

| Fetch the register arguments
ld.d    %r2, %r31, (0 * 4)
ld.d    %r4, %r31, (2 * 4)
ld.d    %r6, %r31, (4 * 4)
ld.d    %r8, %r31, (6 * 4)
addu    %r31, %r31, (8 * 4)

| Invoke the function
jsr     %r1

| Restore stack now that we don't need the args anymore
subu    %r31, %r30, 32

| Figure out what to return as the function's return value
ld      %r5, %r31, 12           | rvalue
ld      %r4, %r31, 8            | flags

bcnd    eq0, %r5, 9f

bb0     0, %r4, 1f              | CIF_FLAGS_INT
st      %r2, %r5, 0
br      9f

1:

bb0     1, %r4, 1f              | CIF_FLAGS_DINT
st.d    %r2, %r5, 0
br      9f

1: 9:

ld      %r1,  %r31, 0
ld      %r30, %r31, 4
jmp.n   %r1
 addu   %r31, %r31, 32
.size   ffi_call_OBSD, . - ffi_call_OBSD

/*

* ffi_closure_OBSD(ffi_closure *closure);      %r13
*/
       .align  4
       .globl  ffi_closure_OBSD
       .type   ffi_closure_OBSD, @function

ffi_closure_OBSD:

subu    %r31, %r31, 16
st      %r30, %r31, 4
st      %r1,  %r31, 0
addu    %r30, %r31, 16

| Make room on the stack for saved register arguments and return
| value
subu    %r31, %r31, (8 * 4) + (2 * 4)
st.d    %r2,  %r31, (0 * 4)
st.d    %r4,  %r31, (2 * 4)
st.d    %r6,  %r31, (4 * 4)
st.d    %r8,  %r31, (6 * 4)

| Invoke the closure function
or      %r5,  %r30, 0                   | calling stack
addu    %r4,  %r31, 0                   | saved registers
addu    %r3,  %r31, (8 * 4)             | return value
or      %r2,  %r13, %r0                 | closure

ifdef PIC

bsr     ffi_closure_OBSD_inner#plt

else

bsr     ffi_closure_OBSD_inner

endif

| Figure out what to return as the function's return value
bb0     0, %r2, 1f              | CIF_FLAGS_INT
ld      %r2, %r31, (8 * 4)
br      9f

1:

bb0     1, %r2, 1f              | CIF_FLAGS_DINT
ld.d    %r2, %r31, (8 * 4)
br      9f

1: 9:

subu    %r31, %r30, 16
ld      %r1,  %r31, 0
ld      %r30, %r31, 4
jmp.n   %r1
 addu   %r31, %r31, 16
.size   ffi_closure_OBSD,.-ffi_closure_OBSD

/*

* ffi_closure_struct_OBSD(ffi_closure *closure);       %r13
*/
       .align  4
       .globl  ffi_closure_struct_OBSD
       .type   ffi_closure_struct_OBSD, @function

ffi_closure_struct_OBSD:

subu    %r31, %r31, 16
st      %r30, %r31, 4
st      %r1,  %r31, 0
addu    %r30, %r31, 16

| Make room on the stack for saved register arguments
subu    %r31, %r31, (8 * 4)
st.d    %r2,  %r31, (0 * 4)
st.d    %r4,  %r31, (2 * 4)
st.d    %r6,  %r31, (4 * 4)
st.d    %r8,  %r31, (6 * 4)

| Invoke the closure function
or      %r5,  %r30, 0                   | calling stack
addu    %r4,  %r31, 0                   | saved registers
or      %r3,  %r12, 0                   | return value
or      %r2,  %r13, %r0                 | closure

ifdef PIC

bsr     ffi_closure_OBSD_inner#plt

else

bsr     ffi_closure_OBSD_inner

endif

subu    %r31, %r30, 16
ld      %r1,  %r31, 0
ld      %r30, %r31, 4
jmp.n   %r1
 addu   %r31, %r31, 16
.size   ffi_closure_struct_OBSD,.-ffi_closure_struct_OBSD