Search
lxdream.org :: lxdream/src/sh4/ia32mac.h
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/ia32mac.h
changeset 906:268ea359f884
prev905:4c17ebd9ef5e
author nkeynes
date Thu Dec 11 23:26:03 2008 +0000 (15 years ago)
permissions -rw-r--r--
last change Disable the generational translation cache - I've got no evidence that it
actually helps performance, and it simplifies things to get rid of it (in
particular, translated code doesn't have to worry about being moved now).
view annotate diff log raw
     1 /**
     2  * $Id$
     3  * 
     4  * Provides the implementation for the ia32 Mac OS X ABI variant 
     5  * (eg prologue, epilogue, and calling conventions). Main difference
     6  * from ia32abi is that stack frames are aligned on 16-byte boundaries.
     7  *
     8  * Copyright (c) 2007 Nathan Keynes.
     9  *
    10  * This program is free software; you can redistribute it and/or modify
    11  * it under the terms of the GNU General Public License as published by
    12  * the Free Software Foundation; either version 2 of the License, or
    13  * (at your option) any later version.
    14  *
    15  * This program is distributed in the hope that it will be useful,
    16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    18  * GNU General Public License for more details.
    19  */
    21 #ifndef lxdream_ia32mac_H
    22 #define lxdream_ia32mac_H 1
    24 #define load_ptr( reg, ptr ) load_imm32( reg, (uint32_t)ptr );
    26 /**
    27  * Note: clobbers EAX to make the indirect call - this isn't usually
    28  * a problem since the callee will usually clobber it anyway.
    29  */
    30 #define CALL_FUNC0_SIZE 13
    31 static inline void call_func0( void *ptr )
    32 {
    33     int adj = (-sh4_x86.stack_posn)&0x0F;
    34     SUB_imm8s_r32( adj, R_ESP );
    35     load_imm32(R_ECX, (uint32_t)ptr);
    36     CALL_r32(R_ECX);
    37     ADD_imm8s_r32( adj, R_ESP );
    38 }
    40 #ifdef HAVE_FASTCALL
    41 static inline void call_func1( void *ptr, int arg1 )
    42 {
    43     int adj = (-sh4_x86.stack_posn)&0x0F;
    44     SUB_imm8s_r32( adj, R_ESP );
    45     if( arg1 != R_EAX ) {
    46         MOV_r32_r32( arg1, R_EAX );
    47     }
    48     load_imm32(R_ECX, (uint32_t)ptr);
    49     CALL_r32(R_ECX);
    50     ADD_imm8s_r32( adj, R_ESP );
    51 }
    53 static inline void call_func2( void *ptr, int arg1, int arg2 )
    54 {
    55     int adj = (-sh4_x86.stack_posn)&0x0F;
    56     SUB_imm8s_r32( adj, R_ESP );
    57     if( arg2 != R_EDX ) {
    58         MOV_r32_r32( arg2, R_EDX );
    59     }
    60     if( arg1 != R_EAX ) {
    61         MOV_r32_r32( arg1, R_EAX );
    62     }
    63     load_imm32(R_ECX, (uint32_t)ptr);
    64     CALL_r32(R_ECX);
    65     ADD_imm8s_r32( adj, R_ESP );
    66 }
    68 /**
    69  * Write a double (64-bit) value into memory, with the first word in arg2a, and
    70  * the second in arg2b
    71  */
    72 static inline void MEM_WRITE_DOUBLE( int addr, int arg2a, int arg2b )
    73 {
    74     PUSH_r32(arg2b);
    75     PUSH_r32(addr);
    76     call_func2(sh4_write_long, addr, arg2a);
    77     POP_r32(R_EAX);
    78     POP_r32(R_EDX);
    79     ADD_imm8s_r32(4, R_EAX);
    80     call_func0(sh4_write_long);
    81 }
    83 /**
    84  * Read a double (64-bit) value from memory, writing the first word into arg2a
    85  * and the second into arg2b. The addr must not be in EAX
    86  */
    87 static inline void MEM_READ_DOUBLE( int addr, int arg2a, int arg2b )
    88 {
    89     PUSH_r32(addr);
    90     call_func1(sh4_read_long, addr);
    91     POP_r32(R_ECX);
    92     PUSH_r32(R_EAX);
    93     MOV_r32_r32(R_ECX, R_EAX);
    94     ADD_imm8s_r32(4, R_EAX);
    95     call_func0(sh4_read_long);
    96     if( arg2b != R_EAX ) {
    97         MOV_r32_r32(R_EAX, arg2b);
    98     }
    99     POP_r32(arg2a);
   100 }
   101 #else
   102 static inline void call_func1( void *ptr, int arg1 )
   103 {
   104     int adj = (-4-sh4_x86.stack_posn)&0x0F;
   105     SUB_imm8s_r32( adj, R_ESP );
   106     PUSH_r32(arg1);
   107     load_imm32(R_EAX, (uint32_t)ptr);
   108     CALL_r32(R_EAX);
   109     ADD_imm8s_r32( adj+4, R_ESP );
   110     sh4_x86.stack_posn -= 4;
   111 }
   113 #define CALL_FUNC2_SIZE 15
   114 static inline void call_func2( void *ptr, int arg1, int arg2 )
   115 {
   116     int adj = (-8-sh4_x86.stack_posn)&0x0F;
   117     SUB_imm8s_r32( adj, R_ESP );
   118     PUSH_r32(arg2);
   119     PUSH_r32(arg1);
   120     load_imm32(R_EAX, (uint32_t)ptr);
   121     CALL_r32(R_EAX);
   122     ADD_imm8s_r32( adj+8, R_ESP );
   123     sh4_x86.stack_posn -= 8;
   124 }
   126 /**
   127  * Write a double (64-bit) value into memory, with the first word in arg2a, and
   128  * the second in arg2b
   129  */
   130 static inline void MEM_WRITE_DOUBLE( int addr, int arg2a, int arg2b )
   131 {
   132     int adj = (-8-sh4_x86.stack_posn)&0x0F;
   133     SUB_imm8s_r32( adj, R_ESP );
   134     ADD_imm8s_r32( 4, addr );
   135     PUSH_r32(arg2b);
   136     PUSH_r32(addr);
   137     ADD_imm8s_r32( -4, addr );
   138     SUB_imm8s_r32( 8, R_ESP );
   139     PUSH_r32(arg2a);
   140     PUSH_r32(addr);
   141     load_imm32(R_EAX, (uint32_t)sh4_write_long);
   142     CALL_r32(R_EAX);
   143     ADD_imm8s_r32( 16, R_ESP );
   144     load_imm32(R_EAX, (uint32_t)sh4_write_long);
   145     CALL_r32(R_EAX);
   146     ADD_imm8s_r32( adj+8, R_ESP );
   147     sh4_x86.stack_posn -= 16;
   148 }
   150 /**
   151  * Read a double (64-bit) value from memory, writing the first word into arg2a
   152  * and the second into arg2b. The addr must not be in EAX
   153  */
   154 static inline void MEM_READ_DOUBLE( int addr, int arg2a, int arg2b )
   155 {
   156     int adj = (-4-sh4_x86.stack_posn)&0x0F;
   157     int adj2 = (-8-sh4_x86.stack_posn)&0x0F;
   158     SUB_imm8s_r32( adj, R_ESP );
   159     PUSH_r32(addr);
   160     load_imm32(R_EAX, (uint32_t)sh4_read_long);
   161     CALL_r32(R_EAX);
   162     POP_r32(R_ECX);
   163     SUB_imm8s_r32( adj2-adj, R_ESP );
   164     PUSH_r32(R_EAX);
   165     ADD_imm8s_r32( 4, R_ECX );
   166     PUSH_r32(R_ECX);
   167     load_imm32(R_EAX, (uint32_t)sh4_read_long);
   168     CALL_r32(R_EAX);
   169     ADD_imm8s_r32( 4, R_ESP );
   170     MOV_r32_r32( R_EAX, arg2b );
   171     POP_r32(arg2a);
   172     ADD_imm8s_r32( adj2, R_ESP );
   173     sh4_x86.stack_posn -= 4;
   174 }
   176 #endif
   178 /**
   179  * Emit the 'start of block' assembly. Sets up the stack frame and save
   180  * SI/DI as required
   181  */
   182 void enter_block( ) 
   183 {
   184     PUSH_r32(R_EBP);
   185     /* mov &sh4r, ebp */
   186     load_ptr( R_EBP, ((uint8_t *)&sh4r) + 128 );
   187     sh4_x86.stack_posn = 8;
   188 }
   190 /**
   191  * Exit the block with sh4r.new_pc written with the target pc
   192  */
   193 void exit_block_pcset( sh4addr_t pc )
   194 {
   195     load_imm32( R_ECX, ((pc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
   196     ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) );    // 6
   197     load_spreg( R_EAX, R_PC );
   198     if( sh4_x86.tlb_on ) {
   199         call_func1(xlat_get_code_by_vma,R_EAX);
   200     } else {
   201         call_func1(xlat_get_code,R_EAX);
   202     }
   203     POP_r32(R_EBP);
   204     RET();
   205 }
   207 /**
   208  * Exit the block with sh4r.new_pc written with the target pc
   209  */
   210 void exit_block_newpcset( sh4addr_t pc )
   211 {
   212     load_imm32( R_ECX, ((pc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
   213     ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) );    // 6
   214     load_spreg( R_EAX, R_NEW_PC );
   215     store_spreg( R_EAX, R_PC );
   216     if( sh4_x86.tlb_on ) {
   217         call_func1(xlat_get_code_by_vma,R_EAX);
   218     } else {
   219         call_func1(xlat_get_code,R_EAX);
   220     }
   221     POP_r32(R_EBP);
   222     RET();
   223 }
   226 /**
   227  * Exit the block to an absolute PC
   228  */
   229 void exit_block( sh4addr_t pc, sh4addr_t endpc )
   230 {
   231     load_imm32( R_ECX, pc );                            // 5
   232     store_spreg( R_ECX, REG_OFFSET(pc) );               // 3
   233     if( IS_IN_ICACHE(pc) ) {
   234         MOV_moff32_EAX( xlat_get_lut_entry(GET_ICACHE_PHYS(pc)) ); // 5
   235     } else if( sh4_x86.tlb_on ) {
   236         call_func1(xlat_get_code_by_vma,R_ECX);
   237     } else {
   238         call_func1(xlat_get_code,R_ECX);
   239     }
   240     AND_imm8s_r32( 0xFC, R_EAX ); // 3
   241     load_imm32( R_ECX, ((endpc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
   242     ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) );     // 6
   243     POP_r32(R_EBP);
   244     RET();
   245 }
   247 /**
   248  * Exit the block to a relative PC
   249  */
   250 void exit_block_rel( sh4addr_t pc, sh4addr_t endpc )
   251 {
   252     load_imm32( R_ECX, pc - sh4_x86.block_start_pc );   // 5
   253     ADD_sh4r_r32( R_PC, R_ECX );
   254     store_spreg( R_ECX, REG_OFFSET(pc) );               // 3
   255     if( IS_IN_ICACHE(pc) ) {
   256         MOV_moff32_EAX( xlat_get_lut_entry(GET_ICACHE_PHYS(pc)) ); // 5
   257     } else if( sh4_x86.tlb_on ) {
   258         call_func1(xlat_get_code_by_vma,R_ECX);
   259     } else {
   260         call_func1(xlat_get_code,R_ECX);
   261     }
   262     AND_imm8s_r32( 0xFC, R_EAX ); // 3
   263     load_imm32( R_ECX, ((endpc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
   264     ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) );     // 6
   265     POP_r32(R_EBP);
   266     RET();
   267 }
   269 /**
   270  * Write the block trailer (exception handling block)
   271  */
   272 void sh4_translate_end_block( sh4addr_t pc ) {
   273     if( sh4_x86.branch_taken == FALSE ) {
   274         // Didn't exit unconditionally already, so write the termination here
   275         exit_block_rel( pc, pc );
   276     }
   277     if( sh4_x86.backpatch_posn != 0 ) {
   278         unsigned int i;
   279         // Raise exception
   280         uint8_t *end_ptr = xlat_output;
   281         MOV_r32_r32( R_EDX, R_ECX );
   282         ADD_r32_r32( R_EDX, R_ECX );
   283         ADD_r32_sh4r( R_ECX, R_PC );
   284         MOV_moff32_EAX( &sh4_cpu_period );
   285         MUL_r32( R_EDX );
   286         ADD_r32_sh4r( R_EAX, REG_OFFSET(slice_cycle) );
   288         POP_r32(R_EDX);
   289         call_func1( sh4_raise_exception, R_EDX );
   290         load_spreg( R_EAX, R_PC );
   291         if( sh4_x86.tlb_on ) {
   292             call_func1(xlat_get_code_by_vma,R_EAX);
   293         } else {
   294             call_func1(xlat_get_code,R_EAX);
   295         }
   296         POP_r32(R_EBP);
   297         RET();
   299         // Exception already raised - just cleanup
   300         uint8_t *preexc_ptr = xlat_output;
   301         MOV_r32_r32( R_EDX, R_ECX );
   302         ADD_r32_r32( R_EDX, R_ECX );
   303         ADD_r32_sh4r( R_ECX, R_SPC );
   304         MOV_moff32_EAX( &sh4_cpu_period );
   305         MUL_r32( R_EDX );
   306         ADD_r32_sh4r( R_EAX, REG_OFFSET(slice_cycle) );
   307         load_spreg( R_EAX, R_PC );
   308         if( sh4_x86.tlb_on ) {
   309             call_func1(xlat_get_code_by_vma,R_EAX);
   310         } else {
   311             call_func1(xlat_get_code,R_EAX);
   312         }
   313         POP_r32(R_EBP);
   314         RET();
   316         for( i=0; i< sh4_x86.backpatch_posn; i++ ) {
   317             uint32_t *fixup_addr = (uint32_t *)&xlat_current_block->code[sh4_x86.backpatch_list[i].fixup_offset];
   318             *fixup_addr = xlat_output - (uint8_t *)&xlat_current_block->code[sh4_x86.backpatch_list[i].fixup_offset] - 4;
   319             if( sh4_x86.backpatch_list[i].exc_code < 0 ) {
   320                 load_imm32( R_EDX, sh4_x86.backpatch_list[i].fixup_icount );
   321                 int stack_adj = -1 - sh4_x86.backpatch_list[i].exc_code;
   322                 if( stack_adj > 0 ) { 
   323                     ADD_imm8s_r32( stack_adj, R_ESP );
   324                 }
   325                 int rel = preexc_ptr - xlat_output;
   326                 JMP_rel(rel);
   327             } else {
   328                 PUSH_imm32( sh4_x86.backpatch_list[i].exc_code );
   329                 load_imm32( R_EDX, sh4_x86.backpatch_list[i].fixup_icount );
   330                 int rel = end_ptr - xlat_output;
   331                 JMP_rel(rel);
   332             }
   333         }
   334     }
   335 }
   338 /**
   339  * The unwind methods only work if we compiled with DWARF2 frame information
   340  * (ie -fexceptions), otherwise we have to use the direct frame scan.
   341  */
   342 #ifdef HAVE_EXCEPTIONS
   343 #include <unwind.h>
   345 struct UnwindInfo {
   346     uintptr_t block_start;
   347     uintptr_t block_end;
   348     void *pc;
   349 };
   351 _Unwind_Reason_Code xlat_check_frame( struct _Unwind_Context *context, void *arg )
   352 {
   353     struct UnwindInfo *info = arg;
   354     void *pc = (void *)_Unwind_GetIP(context);
   355     if( ((uintptr_t)pc) >= info->block_start && ((uintptr_t)pc) < info->block_end ) {
   356         info->pc = pc;
   357         return _URC_NORMAL_STOP;
   358     }
   360     return _URC_NO_REASON;
   361 }
   363 void *xlat_get_native_pc( void *code, uint32_t code_size )
   364 {
   365     struct _Unwind_Exception exc;
   366     struct UnwindInfo info;
   368     info.pc = NULL;
   369     info.block_start = (uintptr_t)code;
   370     info.block_end = info.block_start + code_size;
   371     void *result = NULL;
   372     _Unwind_Backtrace( xlat_check_frame, &info );
   373     return info.pc;
   374 }
   375 #else 
   376 void *xlat_get_native_pc( void *code, uint32_t code_size )
   377 {
   378     void *result = NULL;
   379     asm(
   380         "mov %%ebp, %%eax\n\t"
   381         "mov $0x8, %%ecx\n\t"
   382         "mov %1, %%edx\n"
   383         "frame_loop: test %%eax, %%eax\n\t"
   384         "je frame_not_found\n\t"
   385         "cmp (%%eax), %%edx\n\t"
   386         "je frame_found\n\t"
   387         "sub $0x1, %%ecx\n\t"
   388         "je frame_not_found\n\t"
   389         "movl (%%eax), %%eax\n\t"
   390         "jmp frame_loop\n"
   391         "frame_found: movl 0x4(%%eax), %0\n"
   392         "frame_not_found:"
   393         : "=r" (result)
   394         : "r" (((uint8_t *)&sh4r) + 128 )
   395         : "eax", "ecx", "edx" );
   396     return result;
   397 }
   398 #endif
   400 #endif /* !lxdream_ia32mac.h */
.