1 /* -----------------------------------------------------------------------
2 sysv.S - Copyright (c) 2012, 2013 Xilinx, Inc
4 MicroBlaze Foreign Function Interface
6 Permission is hereby granted, free of charge, to any person obtaining
7 a copy of this software and associated documentation files (the
8 ``Software''), to deal in the Software without restriction, including
9 without limitation the rights to use, copy, modify, merge, publish,
10 distribute, sublicense, and/or sell copies of the Software, and to
11 permit persons to whom the Software is furnished to do so, subject to
12 the following conditions:
14 The above copyright notice and this permission notice shall be included
15 in all copies or substantial portions of the Software.
17 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
18 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 DEALINGS IN THE SOFTWARE.
25 ----------------------------------------------------------------------- */
28 #include <fficonfig.h>
32 * arg[0] (r5) = ffi_prep_args,
33 * arg[1] (r6) = &ecif,
34 * arg[2] (r7) = cif->bytes,
35 * arg[3] (r8) = cif->flags,
36 * arg[4] (r9) = ecif.rvalue,
38 * arg[6] (sp[0]) = cif->rtype->type
39 * arg[7] (sp[4]) = cif->rtype->size
43 .type ffi_call_SYSV, @function
45 /* push callee saves */
47 swi r19, r1, 0 /* Frame Pointer */
48 swi r20, r1, 4 /* PIC register */
49 swi r21, r1, 8 /* PIC register */
50 swi r22, r1, 12 /* save for locals */
51 swi r23, r1, 16 /* save for locals */
53 /* save the r5-r10 registers in the stack */
54 addik r1, r1, -24 /* increment sp to store 6x 32-bit words */
62 /* save function pointer */
63 addik r3, r5, 0 /* copy ffi_prep_args into r3 */
64 addik r22, r1, 0 /* save sp for unallocated args into r22 (callee-saved) */
65 addik r23, r10, 0 /* save function address into r23 (callee-saved) */
67 /* prepare stack with allocation for n (bytes = r7) args */
68 rsub r1, r7, r1 /* subtract bytes from sp */
70 /* prep args for ffi_prep_args call */
71 addik r5, r1, 0 /* store stack pointer into arg[0] */
72 /* r6 still holds ecif for arg[1] */
74 /* Call ffi_prep_args(stack, &ecif). */
76 swi r15, r1, 0 /* store the link register in the frame */
78 nop /* branch has delay slot */
80 addik r1, r1, 4 /* restore the link register from the frame */
81 /* returns calling stack pointer location */
83 /* prepare args for fn call, prep_args populates them onto the stack */
84 lwi r5, r1, 0 /* arg[0] */
85 lwi r6, r1, 4 /* arg[1] */
86 lwi r7, r1, 8 /* arg[2] */
87 lwi r8, r1, 12 /* arg[3] */
88 lwi r9, r1, 16 /* arg[4] */
89 lwi r10, r1, 20 /* arg[5] */
91 /* call (fn) (...). */
93 swi r15, r1, 0 /* store the link register in the frame */
95 nop /* branch has delay slot */
97 addik r1, r1, 4 /* restore the link register from the frame */
99 /* Remove the space we pushed for the args. */
100 addik r1, r22, 0 /* restore old SP */
102 /* restore this functions parameters */
103 lwi r5, r1, 0 /* arg[0] */
104 lwi r6, r1, 4 /* arg[1] */
105 lwi r7, r1, 8 /* arg[2] */
106 lwi r8, r1, 12 /* arg[3] */
107 lwi r9, r1, 16 /* arg[4] */
108 lwi r10, r1, 20 /* arg[5] */
109 addik r1, r1, 24 /* decrement sp to de-allocate 6x 32-bit words */
111 /* If the return value pointer is NULL, assume no return value. */
112 beqi r9, ffi_call_SYSV_end
114 lwi r22, r1, 48 /* get return type (20 for locals + 28 for arg[6]) */
115 lwi r23, r1, 52 /* get return size (20 for locals + 32 for arg[7]) */
117 /* Check if return type is actually a struct, do nothing */
118 rsubi r11, r22, FFI_TYPE_STRUCT
119 beqi r11, ffi_call_SYSV_end
123 beqi r11, ffi_call_SYSV_store8
127 beqi r11, ffi_call_SYSV_store16
131 beqi r11, ffi_call_SYSV_store32
135 beqi r11, ffi_call_SYSV_store64
137 /* Didn't match anything */
138 bri ffi_call_SYSV_end
140 ffi_call_SYSV_store64:
141 swi r3, r9, 0 /* store word r3 into return value */
142 swi r4, r9, 4 /* store word r4 into return value */
143 bri ffi_call_SYSV_end
145 ffi_call_SYSV_store32:
146 swi r3, r9, 0 /* store word r3 into return value */
147 bri ffi_call_SYSV_end
149 ffi_call_SYSV_store16:
150 #ifdef __BIG_ENDIAN__
151 shi r3, r9, 2 /* store half-word r3 into return value */
153 shi r3, r9, 0 /* store half-word r3 into return value */
155 bri ffi_call_SYSV_end
157 ffi_call_SYSV_store8:
158 #ifdef __BIG_ENDIAN__
159 sbi r3, r9, 3 /* store byte r3 into return value */
161 sbi r3, r9, 0 /* store byte r3 into return value */
163 bri ffi_call_SYSV_end
166 /* callee restores */
167 lwi r19, r1, 0 /* frame pointer */
168 lwi r20, r1, 4 /* PIC register */
169 lwi r21, r1, 8 /* PIC register */
174 /* return from sub-routine (with delay slot) */
178 .size ffi_call_SYSV, . - ffi_call_SYSV
180 /* ------------------------------------------------------------------------- */
183 * args passed into this function, are passed down to the callee.
184 * this function is the target of the closure trampoline, as such r12 is
185 * a pointer to the closure object.
188 .globl ffi_closure_SYSV
189 .type ffi_closure_SYSV, @function
191 /* push callee saves */
192 addik r11, r1, 28 /* save stack args start location (excluding regs/link) */
194 swi r19, r1, 0 /* Frame Pointer */
195 swi r20, r1, 4 /* PIC register */
196 swi r21, r1, 8 /* PIC register */
198 /* store register args on stack */
208 addik r5, r1, 0 /* register_args */
209 addik r6, r11, 0 /* stack_args */
210 addik r7, r12, 0 /* closure object */
211 addik r1, r1, -8 /* allocate return value */
212 addik r8, r1, 0 /* void* rvalue */
213 addik r1, r1, -8 /* allocate for return type/size values */
214 addik r9, r1, 0 /* void* rtype */
215 addik r10, r1, 4 /* void* rsize */
217 /* call the wrap_call function */
218 addik r1, r1, -28 /* allocate args + link reg */
219 swi r15, r1, 0 /* store the link register in the frame */
221 nop /* branch has delay slot */
223 addik r1, r1, 28 /* restore the link register from the frame */
225 ffi_closure_SYSV_prepare_return:
226 lwi r9, r1, 0 /* rtype */
227 lwi r10, r1, 4 /* rsize */
228 addik r1, r1, 8 /* de-allocate return info values */
230 /* Check if return type is actually a struct, store 4 bytes */
231 rsubi r11, r9, FFI_TYPE_STRUCT
232 beqi r11, ffi_closure_SYSV_store32
236 beqi r11, ffi_closure_SYSV_store8
240 beqi r11, ffi_closure_SYSV_store16
244 beqi r11, ffi_closure_SYSV_store32
248 beqi r11, ffi_closure_SYSV_store64
250 /* Didn't match anything */
251 bri ffi_closure_SYSV_end
253 ffi_closure_SYSV_store64:
254 lwi r3, r1, 0 /* store word r3 into return value */
255 lwi r4, r1, 4 /* store word r4 into return value */
256 /* 64 bits == 2 words, no sign extend occurs */
257 bri ffi_closure_SYSV_end
259 ffi_closure_SYSV_store32:
260 lwi r3, r1, 0 /* store word r3 into return value */
261 /* 32 bits == 1 word, no sign extend occurs */
262 bri ffi_closure_SYSV_end
264 ffi_closure_SYSV_store16:
265 #ifdef __BIG_ENDIAN__
266 lhui r3, r1, 2 /* store half-word r3 into return value */
268 lhui r3, r1, 0 /* store half-word r3 into return value */
270 rsubi r11, r9, FFI_TYPE_SINT16
271 bnei r11, ffi_closure_SYSV_end
272 sext16 r3, r3 /* fix sign extend of sint8 */
273 bri ffi_closure_SYSV_end
275 ffi_closure_SYSV_store8:
276 #ifdef __BIG_ENDIAN__
277 lbui r3, r1, 3 /* store byte r3 into return value */
279 lbui r3, r1, 0 /* store byte r3 into return value */
281 rsubi r11, r9, FFI_TYPE_SINT8
282 bnei r11, ffi_closure_SYSV_end
283 sext8 r3, r3 /* fix sign extend of sint8 */
284 bri ffi_closure_SYSV_end
286 ffi_closure_SYSV_end:
287 addik r1, r1, 8 /* de-allocate return value */
289 /* de-allocate stored args */
292 /* callee restores */
293 lwi r19, r1, 0 /* frame pointer */
294 lwi r20, r1, 4 /* PIC register */
295 lwi r21, r1, 8 /* PIC register */
298 /* return from sub-routine (with delay slot) */
302 .size ffi_closure_SYSV, . - ffi_closure_SYSV