OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [libffi/] [src/] [pa/] [ffi.c] - Blame information for rev 14

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 jlechner
/* -----------------------------------------------------------------------
2
   ffi.c - (c) 2003-2004 Randolph Chung <tausq@debian.org>
3
 
4
   HPPA Foreign Function Interface
5
 
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:
13
 
14
   The above copyright notice and this permission notice shall be included
15
   in all copies or substantial portions of the Software.
16
 
17
   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
18
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20
   IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21
   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22
   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
   OTHER DEALINGS IN THE SOFTWARE.
24
   ----------------------------------------------------------------------- */
25
 
26
#include <ffi.h>
27
#include <ffi_common.h>
28
 
29
#include <stdlib.h>
30
#include <stdio.h>
31
 
32
#define ROUND_UP(v, a)  (((size_t)(v) + (a) - 1) & ~((a) - 1))
33
#define ROUND_DOWN(v, a)  (((size_t)(v) - (a) + 1) & ~((a) - 1))
34
#define MIN_STACK_SIZE  64
35
#define FIRST_ARG_SLOT  9
36
#define DEBUG_LEVEL   0
37
 
38
#define fldw(addr, fpreg) asm volatile ("fldw 0(%0), %%" #fpreg "L" : : "r"(addr) : #fpreg)
39
#define fstw(fpreg, addr) asm volatile ("fstw %%" #fpreg "L, 0(%0)" : : "r"(addr))
40
#define fldd(addr, fpreg) asm volatile ("fldd 0(%0), %%" #fpreg : : "r"(addr) : #fpreg)
41
#define fstd(fpreg, addr) asm volatile ("fstd %%" #fpreg "L, 0(%0)" : : "r"(addr))
42
 
43
#define debug(lvl, x...) do { if (lvl <= DEBUG_LEVEL) { printf(x); } } while (0)
44
 
45
static inline int ffi_struct_type(ffi_type *t)
46
{
47
  size_t sz = t->size;
48
 
49
  /* Small structure results are passed in registers,
50
     larger ones are passed by pointer.  */
51
 
52
  if (sz <= 1)
53
    return FFI_TYPE_UINT8;
54
  else if (sz == 2)
55
    return FFI_TYPE_UINT16;
56
  else if (sz == 3)
57
    return FFI_TYPE_SMALL_STRUCT3;
58
  else if (sz == 4)
59
    return FFI_TYPE_UINT32;
60
  else if (sz == 5)
61
    return FFI_TYPE_SMALL_STRUCT5;
62
  else if (sz == 6)
63
    return FFI_TYPE_SMALL_STRUCT6;
64
  else if (sz == 7)
65
    return FFI_TYPE_SMALL_STRUCT7;
66
  else if (sz <= 8)
67
    return FFI_TYPE_UINT64;
68
  else
69
    return FFI_TYPE_STRUCT; /* else, we pass it by pointer.  */
70
}
71
 
72
/* PA has a downward growing stack, which looks like this:
73
 
74
   Offset
75
        [ Variable args ]
76
   SP = (4*(n+9))       arg word N
77
   ...
78
   SP-52                arg word 4
79
        [ Fixed args ]
80
   SP-48                arg word 3
81
   SP-44                arg word 2
82
   SP-40                arg word 1
83
   SP-36                arg word 0
84
        [ Frame marker ]
85
   ...
86
   SP-20                RP
87
   SP-4                 previous SP
88
 
89
   First 4 non-FP 32-bit args are passed in gr26, gr25, gr24 and gr23
90
   First 2 non-FP 64-bit args are passed in register pairs, starting
91
     on an even numbered register (i.e. r26/r25 and r24+r23)
92
   First 4 FP 32-bit arguments are passed in fr4L, fr5L, fr6L and fr7L
93
   First 2 FP 64-bit arguments are passed in fr5 and fr7
94
   The rest are passed on the stack starting at SP-52, but 64-bit
95
     arguments need to be aligned to an 8-byte boundary
96
 
97
   This means we can have holes either in the register allocation,
98
   or in the stack.  */
99
 
100
/* ffi_prep_args is called by the assembly routine once stack space
101
   has been allocated for the function's arguments
102
 
103
   The following code will put everything into the stack frame
104
   (which was allocated by the asm routine), and on return
105
   the asm routine will load the arguments that should be
106
   passed by register into the appropriate registers
107
 
108
   NOTE: We load floating point args in this function... that means we
109
   assume gcc will not mess with fp regs in here.  */
110
 
111
/*@-exportheader@*/
112
void ffi_prep_args_LINUX(UINT32 *stack, extended_cif *ecif, unsigned bytes)
113
/*@=exportheader@*/
114
{
115
  register unsigned int i;
116
  register ffi_type **p_arg;
117
  register void **p_argv;
118
  unsigned int slot = FIRST_ARG_SLOT - 1;
119
  char *dest_cpy;
120
 
121
  debug(1, "%s: stack = %p, ecif = %p, bytes = %u\n", __FUNCTION__, stack, ecif, bytes);
122
 
123
  p_arg = ecif->cif->arg_types;
124
  p_argv = ecif->avalue;
125
 
126
  for (i = 0; i < ecif->cif->nargs; i++)
127
    {
128
      int type = (*p_arg)->type;
129
 
130
      switch (type)
131
        {
132
        case FFI_TYPE_SINT8:
133
          slot++;
134
          *(SINT32 *)(stack - slot) = *(SINT8 *)(*p_argv);
135
          break;
136
 
137
        case FFI_TYPE_UINT8:
138
          slot++;
139
          *(UINT32 *)(stack - slot) = *(UINT8 *)(*p_argv);
140
          break;
141
 
142
        case FFI_TYPE_SINT16:
143
          slot++;
144
          *(SINT32 *)(stack - slot) = *(SINT16 *)(*p_argv);
145
          break;
146
 
147
        case FFI_TYPE_UINT16:
148
          slot++;
149
          *(UINT32 *)(stack - slot) = *(UINT16 *)(*p_argv);
150
          break;
151
 
152
        case FFI_TYPE_UINT32:
153
        case FFI_TYPE_SINT32:
154
        case FFI_TYPE_POINTER:
155
          slot++;
156
          debug(3, "Storing UINT32 %u in slot %u\n", *(UINT32 *)(*p_argv), slot);
157
          *(UINT32 *)(stack - slot) = *(UINT32 *)(*p_argv);
158
          break;
159
 
160
        case FFI_TYPE_UINT64:
161
        case FFI_TYPE_SINT64:
162
          slot += 2;
163
          if (slot & 1)
164
            slot++;
165
 
166
          *(UINT32 *)(stack - slot) = (*(UINT64 *)(*p_argv)) >> 32;
167
          *(UINT32 *)(stack - slot + 1) = (*(UINT64 *)(*p_argv)) & 0xffffffffUL;
168
          break;
169
 
170
        case FFI_TYPE_FLOAT:
171
          /* First 4 args go in fr4L - fr7L */
172
          slot++;
173
          switch (slot - FIRST_ARG_SLOT)
174
            {
175
            case 0: fldw(*p_argv, fr4); break;
176
            case 1: fldw(*p_argv, fr5); break;
177
            case 2: fldw(*p_argv, fr6); break;
178
            case 3: fldw(*p_argv, fr7); break;
179
            default:
180
              /* Other ones are just passed on the stack.  */
181
              debug(3, "Storing UINT32(float) in slot %u\n", slot);
182
              *(UINT32 *)(stack - slot) = *(UINT32 *)(*p_argv);
183
              break;
184
            }
185
            break;
186
 
187
        case FFI_TYPE_DOUBLE:
188
          slot += 2;
189
          if (slot & 1)
190
            slot++;
191
          switch (slot - FIRST_ARG_SLOT + 1)
192
            {
193
              /* First 2 args go in fr5, fr7 */
194
              case 2: fldd(*p_argv, fr5); break;
195
              case 4: fldd(*p_argv, fr7); break;
196
              default:
197
                debug(3, "Storing UINT64(double) at slot %u\n", slot);
198
                *(UINT64 *)(stack - slot) = *(UINT64 *)(*p_argv);
199
                break;
200
            }
201
          break;
202
 
203
        case FFI_TYPE_STRUCT:
204
 
205
          /* Structs smaller or equal than 4 bytes are passed in one
206
             register. Structs smaller or equal 8 bytes are passed in two
207
             registers. Larger structures are passed by pointer.  */
208
 
209
          if((*p_arg)->size <= 4)
210
            {
211
              slot++;
212
              dest_cpy = (char *)(stack - slot);
213
              dest_cpy += 4 - (*p_arg)->size;
214
              memcpy((char *)dest_cpy, (char *)*p_argv, (*p_arg)->size);
215
            }
216
          else if ((*p_arg)->size <= 8)
217
            {
218
              slot += 2;
219
              if (slot & 1)
220
                slot++;
221
              dest_cpy = (char *)(stack - slot);
222
              dest_cpy += 8 - (*p_arg)->size;
223
              memcpy((char *)dest_cpy, (char *)*p_argv, (*p_arg)->size);
224
            }
225
          else
226
            {
227
              slot++;
228
              *(UINT32 *)(stack - slot) = (UINT32)(*p_argv);
229
            }
230
          break;
231
 
232
        default:
233
          FFI_ASSERT(0);
234
        }
235
 
236
      p_arg++;
237
      p_argv++;
238
    }
239
 
240
  /* Make sure we didn't mess up and scribble on the stack.  */
241
  {
242
    int n;
243
 
244
    debug(5, "Stack setup:\n");
245
    for (n = 0; n < (bytes + 3) / 4; n++)
246
      {
247
        if ((n%4) == 0) { debug(5, "\n%08x: ", (unsigned int)(stack - n)); }
248
        debug(5, "%08x ", *(stack - n));
249
      }
250
    debug(5, "\n");
251
  }
252
 
253
  FFI_ASSERT(slot * 4 <= bytes);
254
 
255
  return;
256
}
257
 
258
static void ffi_size_stack_LINUX(ffi_cif *cif)
259
{
260
  ffi_type **ptr;
261
  int i;
262
  int z = 0; /* # stack slots */
263
 
264
  for (ptr = cif->arg_types, i = 0; i < cif->nargs; ptr++, i++)
265
    {
266
      int type = (*ptr)->type;
267
 
268
      switch (type)
269
        {
270
        case FFI_TYPE_DOUBLE:
271
        case FFI_TYPE_UINT64:
272
        case FFI_TYPE_SINT64:
273
          z += 2 + (z & 1); /* must start on even regs, so we may waste one */
274
          break;
275
 
276
        case FFI_TYPE_STRUCT:
277
          z += 1; /* pass by ptr, callee will copy */
278
          break;
279
 
280
        default: /* <= 32-bit values */
281
          z++;
282
        }
283
    }
284
 
285
  /* We can fit up to 6 args in the default 64-byte stack frame,
286
     if we need more, we need more stack.  */
287
  if (z <= 6)
288
    cif->bytes = MIN_STACK_SIZE; /* min stack size */
289
  else
290
    cif->bytes = 64 + ROUND_UP((z - 6) * sizeof(UINT32), MIN_STACK_SIZE);
291
 
292
  debug(3, "Calculated stack size is %u bytes\n", cif->bytes);
293
}
294
 
295
/* Perform machine dependent cif processing.  */
296
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
297
{
298
  /* Set the return type flag */
299
  switch (cif->rtype->type)
300
    {
301
    case FFI_TYPE_VOID:
302
    case FFI_TYPE_FLOAT:
303
    case FFI_TYPE_DOUBLE:
304
      cif->flags = (unsigned) cif->rtype->type;
305
      break;
306
 
307
    case FFI_TYPE_STRUCT:
308
      /* For the return type we have to check the size of the structures.
309
         If the size is smaller or equal 4 bytes, the result is given back
310
         in one register. If the size is smaller or equal 8 bytes than we
311
         return the result in two registers. But if the size is bigger than
312
         8 bytes, we work with pointers.  */
313
      cif->flags = ffi_struct_type(cif->rtype);
314
      break;
315
 
316
    case FFI_TYPE_UINT64:
317
    case FFI_TYPE_SINT64:
318
      cif->flags = FFI_TYPE_UINT64;
319
      break;
320
 
321
    default:
322
      cif->flags = FFI_TYPE_INT;
323
      break;
324
    }
325
 
326
  /* Lucky us, because of the unique PA ABI we get to do our
327
     own stack sizing.  */
328
  switch (cif->abi)
329
    {
330
    case FFI_LINUX:
331
      ffi_size_stack_LINUX(cif);
332
      break;
333
 
334
    default:
335
      FFI_ASSERT(0);
336
      break;
337
    }
338
 
339
  return FFI_OK;
340
}
341
 
342
/*@-declundef@*/
343
/*@-exportheader@*/
344
extern void ffi_call_LINUX(void (*)(UINT32 *, extended_cif *, unsigned),
345
                           /*@out@*/ extended_cif *,
346
                           unsigned, unsigned,
347
                           /*@out@*/ unsigned *,
348
                           void (*fn)());
349
/*@=declundef@*/
350
/*@=exportheader@*/
351
 
352
void ffi_call(/*@dependent@*/ ffi_cif *cif,
353
              void (*fn)(),
354
              /*@out@*/ void *rvalue,
355
              /*@dependent@*/ void **avalue)
356
{
357
  extended_cif ecif;
358
 
359
  ecif.cif = cif;
360
  ecif.avalue = avalue;
361
 
362
  /* If the return value is a struct and we don't have a return
363
     value address then we need to make one.  */
364
 
365
  if ((rvalue == NULL) &&
366
      (cif->rtype->type == FFI_TYPE_STRUCT))
367
    {
368
      /*@-sysunrecog@*/
369
      ecif.rvalue = alloca(cif->rtype->size);
370
      /*@=sysunrecog@*/
371
    }
372
  else
373
    ecif.rvalue = rvalue;
374
 
375
 
376
  switch (cif->abi)
377
    {
378
    case FFI_LINUX:
379
      /*@-usedef@*/
380
      debug(2, "Calling ffi_call_LINUX: ecif=%p, bytes=%u, flags=%u, rvalue=%p, fn=%p\n", &ecif, cif->bytes, cif->flags, ecif.rvalue, (void *)fn);
381
      ffi_call_LINUX(ffi_prep_args_LINUX, &ecif, cif->bytes,
382
                     cif->flags, ecif.rvalue, fn);
383
      /*@=usedef@*/
384
      break;
385
 
386
    default:
387
      FFI_ASSERT(0);
388
      break;
389
    }
390
}
391
 
392
#if FFI_CLOSURES
393
/* This is more-or-less an inverse of ffi_call -- we have arguments on
394
   the stack, and we need to fill them into a cif structure and invoke
395
   the user function. This really ought to be in asm to make sure
396
   the compiler doesn't do things we don't expect.  */
397
UINT32 ffi_closure_inner_LINUX(ffi_closure *closure, UINT32 *stack)
398
{
399
  ffi_cif *cif;
400
  void **avalue;
401
  void *rvalue;
402
  UINT32 ret[2]; /* function can return up to 64-bits in registers */
403
  ffi_type **p_arg;
404
  char *tmp;
405
  int i, avn, slot = FIRST_ARG_SLOT - 1;
406
  register UINT32 r28 asm("r28");
407
 
408
  cif = closure->cif;
409
 
410
  /* If returning via structure, callee will write to our pointer.  */
411
  if (cif->flags == FFI_TYPE_STRUCT)
412
    rvalue = (void *)r28;
413
  else
414
    rvalue = &ret[0];
415
 
416
  avalue = (void **)alloca(cif->nargs * FFI_SIZEOF_ARG);
417
  avn = cif->nargs;
418
  p_arg = cif->arg_types;
419
 
420
  for (i = 0; i < avn; i++)
421
    {
422
      int type = (*p_arg)->type;
423
 
424
      switch (type)
425
        {
426
        case FFI_TYPE_SINT8:
427
        case FFI_TYPE_UINT8:
428
        case FFI_TYPE_SINT16:
429
        case FFI_TYPE_UINT16:
430
        case FFI_TYPE_SINT32:
431
        case FFI_TYPE_UINT32:
432
        case FFI_TYPE_POINTER:
433
          slot++;
434
          avalue[i] = (char *)(stack - slot) + sizeof(UINT32) - (*p_arg)->size;
435
          break;
436
 
437
        case FFI_TYPE_SINT64:
438
        case FFI_TYPE_UINT64:
439
          slot += 2;
440
          if (slot & 1)
441
            slot++;
442
          avalue[i] = (void *)(stack - slot);
443
          break;
444
 
445
        case FFI_TYPE_FLOAT:
446
          slot++;
447
          switch (slot - FIRST_ARG_SLOT)
448
            {
449
            case 0: fstw(fr4, (void *)(stack - slot)); break;
450
            case 1: fstw(fr5, (void *)(stack - slot)); break;
451
            case 2: fstw(fr6, (void *)(stack - slot)); break;
452
            case 3: fstw(fr7, (void *)(stack - slot)); break;
453
            }
454
          avalue[i] = (void *)(stack - slot);
455
          break;
456
 
457
        case FFI_TYPE_DOUBLE:
458
          slot += 2;
459
          if (slot & 1)
460
            slot++;
461
          switch (slot - FIRST_ARG_SLOT + 1)
462
            {
463
            case 2: fstd(fr5, (void *)(stack - slot)); break;
464
            case 4: fstd(fr7, (void *)(stack - slot)); break;
465
            }
466
          avalue[i] = (void *)(stack - slot);
467
          break;
468
 
469
        case FFI_TYPE_STRUCT:
470
          /* Structs smaller or equal than 4 bytes are passed in one
471
             register. Structs smaller or equal 8 bytes are passed in two
472
             registers. Larger structures are passed by pointer.  */
473
          if((*p_arg)->size <= 4) {
474
            slot++;
475
            avalue[i] = (void *)(stack - slot) + sizeof(UINT32) -
476
              (*p_arg)->size;
477
          } else if ((*p_arg)->size <= 8) {
478
            slot += 2;
479
            if (slot & 1)
480
              slot++;
481
            avalue[i] = (void *)(stack - slot) + sizeof(UINT64) -
482
              (*p_arg)->size;
483
          } else {
484
            slot++;
485
            avalue[i] = (void *) *(stack - slot);
486
          }
487
          break;
488
 
489
        default:
490
          FFI_ASSERT(0);
491
        }
492
 
493
      p_arg++;
494
    }
495
 
496
  /* Invoke the closure.  */
497
  (closure->fun) (cif, rvalue, avalue, closure->user_data);
498
 
499
  debug(3, "after calling function, ret[0] = %08x, ret[1] = %08x\n", ret[0], ret[1]);
500
 
501
  /* Store the result */
502
  switch (cif->flags)
503
    {
504
    case FFI_TYPE_UINT8:
505
      *(stack - FIRST_ARG_SLOT) = (UINT8)(ret[0] >> 24);
506
      break;
507
    case FFI_TYPE_SINT8:
508
      *(stack - FIRST_ARG_SLOT) = (SINT8)(ret[0] >> 24);
509
      break;
510
    case FFI_TYPE_UINT16:
511
      *(stack - FIRST_ARG_SLOT) = (UINT16)(ret[0] >> 16);
512
      break;
513
    case FFI_TYPE_SINT16:
514
      *(stack - FIRST_ARG_SLOT) = (SINT16)(ret[0] >> 16);
515
      break;
516
    case FFI_TYPE_INT:
517
    case FFI_TYPE_SINT32:
518
    case FFI_TYPE_UINT32:
519
      *(stack - FIRST_ARG_SLOT) = ret[0];
520
      break;
521
    case FFI_TYPE_SINT64:
522
    case FFI_TYPE_UINT64:
523
      *(stack - FIRST_ARG_SLOT) = ret[0];
524
      *(stack - FIRST_ARG_SLOT - 1) = ret[1];
525
      break;
526
 
527
    case FFI_TYPE_DOUBLE:
528
      fldd(rvalue, fr4);
529
      break;
530
 
531
    case FFI_TYPE_FLOAT:
532
      fldw(rvalue, fr4);
533
      break;
534
 
535
    case FFI_TYPE_STRUCT:
536
      /* Don't need a return value, done by caller.  */
537
      break;
538
 
539
    case FFI_TYPE_SMALL_STRUCT3:
540
      tmp = (void*)(stack -  FIRST_ARG_SLOT);
541
      tmp += 4 - cif->rtype->size;
542
      memcpy((void*)tmp, &ret[0], cif->rtype->size);
543
      break;
544
 
545
    case FFI_TYPE_SMALL_STRUCT5:
546
    case FFI_TYPE_SMALL_STRUCT6:
547
    case FFI_TYPE_SMALL_STRUCT7:
548
      {
549
        unsigned int ret2[2];
550
        int off;
551
 
552
        /* Right justify ret[0] and ret[1] */
553
        switch (cif->flags)
554
          {
555
            case FFI_TYPE_SMALL_STRUCT5: off = 3; break;
556
            case FFI_TYPE_SMALL_STRUCT6: off = 2; break;
557
            case FFI_TYPE_SMALL_STRUCT7: off = 1; break;
558
            default: off = 0; break;
559
          }
560
 
561
        memset (ret2, 0, sizeof (ret2));
562
        memcpy ((char *)ret2 + off, ret, 8 - off);
563
 
564
        *(stack - FIRST_ARG_SLOT) = ret2[0];
565
        *(stack - FIRST_ARG_SLOT - 1) = ret2[1];
566
      }
567
      break;
568
 
569
    case FFI_TYPE_POINTER:
570
    case FFI_TYPE_VOID:
571
      break;
572
 
573
    default:
574
      debug(0, "assert with cif->flags: %d\n",cif->flags);
575
      FFI_ASSERT(0);
576
      break;
577
    }
578
  return FFI_OK;
579
}
580
 
581
/* Fill in a closure to refer to the specified fun and user_data.
582
   cif specifies the argument and result types for fun.
583
   The cif must already be prep'ed.  */
584
 
585
void ffi_closure_LINUX(void);
586
 
587
ffi_status
588
ffi_prep_closure (ffi_closure* closure,
589
                  ffi_cif* cif,
590
                  void (*fun)(ffi_cif*,void*,void**,void*),
591
                  void *user_data)
592
{
593
  UINT32 *tramp = (UINT32 *)(closure->tramp);
594
 
595
  FFI_ASSERT (cif->abi == FFI_LINUX);
596
 
597
  /* Make a small trampoline that will branch to our
598
     handler function. Use PC-relative addressing.  */
599
 
600
  tramp[0] = 0xeaa00000; /* b,l  .+8, %r21      ; %r21 <- pc+8 */
601
  tramp[1] = 0xd6a01c1e; /* depi 0,31,2, %r21   ; mask priv bits */
602
  tramp[2] = 0x4aa10028; /* ldw  20(%r21), %r1  ; load plabel */
603
  tramp[3] = 0x36b53ff1; /* ldo  -8(%r21), %r21 ; get closure addr */
604
  tramp[4] = 0x0c201096; /* ldw  0(%r1), %r22   ; address of handler */
605
  tramp[5] = 0xeac0c000; /* bv   %r0(%r22)      ; branch to handler */
606
  tramp[6] = 0x0c281093; /* ldw  4(%r1), %r19   ; GP of handler */
607
  tramp[7] = ((UINT32)(ffi_closure_LINUX) & ~2);
608
 
609
  /* Flush d/icache -- have to flush up 2 two lines because of
610
     alignment.  */
611
  asm volatile (
612
                "fdc 0(%0)\n"
613
                "fdc %1(%0)\n"
614
                "fic 0(%%sr4, %0)\n"
615
                "fic %1(%%sr4, %0)\n"
616
                "sync\n"
617
                : : "r"((unsigned long)tramp & ~31), "r"(32 /* stride */));
618
 
619
  closure->cif  = cif;
620
  closure->user_data = user_data;
621
  closure->fun  = fun;
622
 
623
  return FFI_OK;
624
}
625
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.