Search
lxdream.org :: lxdream/src/sh4/ia32abi.h
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/ia32abi.h
changeset 991:60c7fab9c880
prev968:6fb1481859a4
author nkeynes
date Wed Mar 04 23:12:21 2009 +0000 (10 years ago)
permissions -rw-r--r--
last change Move xltcache to xlat/ src directory
Commit new and improved x86 opcode file - cleaned up and added support for amd64 extended registers
view annotate diff log raw
     1 /**
     2  * $Id$
     3  * 
     4  * Provides the implementation for the ia32 ABI variant 
     5  * (eg prologue, epilogue, and calling conventions). Stack frame is
     6  * aligned on 16-byte boundaries for the benefit of OS X (which 
     7  * requires it).
     8  *
     9  * Copyright (c) 2007 Nathan Keynes.
    10  *
    11  * This program is free software; you can redistribute it and/or modify
    12  * it under the terms of the GNU General Public License as published by
    13  * the Free Software Foundation; either version 2 of the License, or
    14  * (at your option) any later version.
    15  *
    16  * This program is distributed in the hope that it will be useful,
    17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    19  * GNU General Public License for more details.
    20  */
    22 #ifndef lxdream_ia32mac_H
    23 #define lxdream_ia32mac_H 1
    25 #define load_ptr( reg, ptr ) load_imm32( reg, (uint32_t)ptr );
    27 static inline void decode_address( int addr_reg )
    28 {
    29     uintptr_t base = (sh4r.xlat_sh4_mode&SR_MD) ? (uintptr_t)sh4_address_space : (uintptr_t)sh4_user_address_space;
    30     MOVL_r32_r32( addr_reg, REG_ECX ); 
    31     SHRL_imm_r32( 12, REG_ECX ); 
    32     MOVP_sib_rptr( 2, REG_ECX, -1, base, REG_ECX );
    33 }
    35 /**
    36  * Note: clobbers EAX to make the indirect call - this isn't usually
    37  * a problem since the callee will usually clobber it anyway.
    38  */
    39 static inline void call_func0( void *ptr )
    40 {
    41     load_imm32(REG_ECX, (uint32_t)ptr);
    42     CALL_r32(REG_ECX);
    43 }
    45 #ifdef HAVE_FASTCALL
    46 static inline void call_func1( void *ptr, int arg1 )
    47 {
    48     if( arg1 != REG_EAX ) {
    49         MOVL_r32_r32( arg1, REG_EAX );
    50     }
    51     MOVP_immptr_rptr((uintptr_t)ptr, REG_ECX);
    52     CALL_r32(REG_ECX);
    53 }
    55 static inline void call_func1_r32( int addr_reg, int arg1 )
    56 {
    57     if( arg1 != REG_EAX ) {
    58         MOVL_r32_r32( arg1, REG_EAX );
    59     }
    60     CALL_r32(addr_reg);
    61 }
    63 static inline void call_func1_r32disp8( int preg, uint32_t disp8, int arg1 )
    64 {
    65     if( arg1 != REG_EAX ) {
    66         MOVL_r32_r32( arg1, REG_EAX );
    67     }
    68     CALL_r32disp(preg, disp8);
    69 }
    71 static inline void call_func1_r32disp8_exc( int preg, uint32_t disp8, int arg1, int pc )
    72 {
    73     if( arg1 != REG_EAX ) {
    74         MOVL_r32_r32( arg1, REG_EAX );
    75     }
    76     MOVP_immptr_rptr(0,REG_EDX);
    77     sh4_x86_add_backpatch(xlat_output, pc, -2);
    78     CALL_r32disp(preg, disp8);
    79 }
    81 static inline void call_func2( void *ptr, int arg1, int arg2 )
    82 {
    83     if( arg2 != REG_EDX ) {
    84         MOVL_r32_r32( arg2, REG_EDX );
    85     }
    86     if( arg1 != REG_EAX ) {
    87         MOVL_r32_r32( arg1, REG_EAX );
    88     }
    89     MOVP_immptr_rptr((uint32_t)ptr, REG_ECX);
    90     CALL_r32(REG_ECX);
    91 }
    93 static inline void call_func2_r32( int addr_reg, int arg1, int arg2 )
    94 {
    95     if( arg2 != REG_EDX ) {
    96         MOVL_r32_r32( arg2, REG_EDX );
    97     }
    98     if( arg1 != REG_EAX ) {
    99         MOVL_r32_r32( arg1, REG_EAX );
   100     }
   101     CALL_r32(addr_reg);
   102 }
   104 static inline void call_func2_r32disp8( int preg, uint32_t disp8, int arg1, int arg2 )
   105 {
   106     if( arg2 != REG_EDX ) {
   107         MOVL_r32_r32( arg2, REG_EDX );
   108     }
   109     if( arg1 != REG_EAX ) {
   110         MOVL_r32_r32( arg1, REG_EAX );
   111     }
   112     CALL_r32disp(preg, disp8);
   113 }
   115 static inline void call_func2_r32disp8_exc( int preg, uint32_t disp8, int arg1, int arg2, int pc )
   116 {
   117     if( arg2 != REG_EDX ) {
   118         MOVL_r32_r32( arg2, REG_EDX );
   119     }
   120     if( arg1 != REG_EAX ) {
   121         MOVL_r32_r32( arg1, REG_EAX );
   122     }
   123     MOVL_imm32_rspdisp(0,0);
   124     sh4_x86_add_backpatch(xlat_output, pc, -2);
   125     CALL_r32disp(preg, disp8);
   126 }
   130 static inline void call_func1_exc( void *ptr, int arg1, int pc )
   131 {
   132     if( arg1 != REG_EAX ) {
   133         MOVL_r32_r32( arg1, REG_EAX );
   134     }
   135     MOVP_immptr_rptr(0,REG_EDX);
   136     sh4_x86_add_backpatch(xlat_output, pc, -2);
   137     MOVP_immptr_rptr((uint32_t)ptr, REG_ECX);
   138     CALL_r32(REG_ECX);
   139 }   
   141 static inline void call_func2_exc( void *ptr, int arg1, int arg2, int pc )
   142 {
   143     if( arg2 != REG_EDX ) {
   144         MOVL_r32_r32( arg2, REG_EDX );
   145     }
   146     if( arg1 != REG_EAX ) {
   147         MOVL_r32_r32( arg1, REG_EAX );
   148     }
   149     MOVL_imm32_rspdisp(0,0);
   150     sh4_x86_add_backpatch(xlat_output, pc, -2);
   151     MOVP_immptr_rptr((uint32_t)ptr, REG_ECX);
   152     CALL_r32(REG_ECX);
   153 }
   155 #else
   156 static inline void call_func1( void *ptr, int arg1 )
   157 {
   158     SUBL_imms_r32( 12, REG_ESP );
   159     PUSH_r32(arg1);
   160     MOVP_immptr_rptr((uint32_t)ptr, REG_ECX);
   161     CALL_r32(REG_ECX);
   162     ADDL_imms_r32( 16, REG_ESP );
   163 }
   165 static inline void call_func2( void *ptr, int arg1, int arg2 )
   166 {
   167     SUBL_imms_r32( 8, REG_ESP );
   168     PUSH_r32(arg2);
   169     PUSH_r32(arg1);
   170     MOVP_immptr_rptr((uint32_t)ptr, REG_ECX);
   171     CALL_r32(REG_ECX);
   172     ADDL_imms_r32( 16, REG_ESP );
   173 }
   175 #endif
   177 /**
   178  * Emit the 'start of block' assembly. Sets up the stack frame and save
   179  * SI/DI as required
   180  * Allocates 8 bytes for local variables, which also has the convenient
   181  * side-effect of aligning the stack.
   182  */
   183 void enter_block( ) 
   184 {
   185     PUSH_r32(REG_EBP);
   186     load_ptr( REG_EBP, ((uint8_t *)&sh4r) + 128 );
   187     SUBL_imms_r32( 8, REG_ESP ); 
   188 }
   190 static inline void exit_block( )
   191 {
   192     ADDL_imms_r32( 8, REG_ESP );
   193     POP_r32(REG_EBP);
   194     RET();
   195 }
   197 /**
   198  * Exit the block with sh4r.new_pc written with the target pc
   199  */
   200 void exit_block_pcset( sh4addr_t pc )
   201 {
   202     load_imm32( REG_ECX, ((pc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
   203     ADDL_r32_rbpdisp( REG_ECX, REG_OFFSET(slice_cycle) );    // 6
   204     load_spreg( REG_EAX, R_PC );
   205     if( sh4_x86.tlb_on ) {
   206         call_func1(xlat_get_code_by_vma,REG_EAX);
   207     } else {
   208         call_func1(xlat_get_code,REG_EAX);
   209     }
   210     exit_block();
   211 }
   213 /**
   214  * Exit the block with sh4r.new_pc written with the target pc
   215  */
   216 void exit_block_newpcset( sh4addr_t pc )
   217 {
   218     load_imm32( REG_ECX, ((pc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
   219     ADDL_r32_rbpdisp( REG_ECX, REG_OFFSET(slice_cycle) );    // 6
   220     load_spreg( REG_EAX, R_NEW_PC );
   221     store_spreg( REG_EAX, R_PC );
   222     if( sh4_x86.tlb_on ) {
   223         call_func1(xlat_get_code_by_vma,REG_EAX);
   224     } else {
   225         call_func1(xlat_get_code,REG_EAX);
   226     }
   227     exit_block();
   228 }
   231 /**
   232  * Exit the block to an absolute PC
   233  */
   234 void exit_block_abs( sh4addr_t pc, sh4addr_t endpc )
   235 {
   236     load_imm32( REG_ECX, pc );                            // 5
   237     store_spreg( REG_ECX, REG_OFFSET(pc) );               // 3
   238     if( IS_IN_ICACHE(pc) ) {
   239         MOVP_moffptr_rax( xlat_get_lut_entry(GET_ICACHE_PHYS(pc)) ); // 5
   240         ANDL_imms_r32( 0xFFFFFFFC, REG_EAX ); // 3
   241     } else if( sh4_x86.tlb_on ) {
   242         call_func1(xlat_get_code_by_vma,REG_ECX);
   243     } else {
   244         call_func1(xlat_get_code,REG_ECX);
   245     }
   246     load_imm32( REG_ECX, ((endpc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
   247     ADDL_r32_rbpdisp( REG_ECX, REG_OFFSET(slice_cycle) );     // 6
   248     exit_block();
   249 }
   251 /**
   252  * Exit the block to a relative PC
   253  */
   254 void exit_block_rel( sh4addr_t pc, sh4addr_t endpc )
   255 {
   256     load_imm32( REG_ECX, pc - sh4_x86.block_start_pc );   // 5
   257     ADDL_rbpdisp_r32( R_PC, REG_ECX );
   258     store_spreg( REG_ECX, R_PC );               // 3
   259     if( IS_IN_ICACHE(pc) ) {
   260         MOVP_moffptr_rax( xlat_get_lut_entry(GET_ICACHE_PHYS(pc)) ); // 5
   261         ANDL_imms_r32( 0xFFFFFFFC, REG_EAX ); // 3
   262     } else if( sh4_x86.tlb_on ) {
   263         call_func1(xlat_get_code_by_vma,REG_ECX);
   264     } else {
   265         call_func1(xlat_get_code,REG_ECX);
   266     }
   267     load_imm32( REG_ECX, ((endpc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
   268     ADDL_r32_rbpdisp( REG_ECX, REG_OFFSET(slice_cycle) );     // 6
   269     exit_block();
   270 }
   272 /**
   273  * Exit unconditionally with a general exception
   274  */
   275 void exit_block_exc( int code, sh4addr_t pc )
   276 {
   277     load_imm32( REG_ECX, pc - sh4_x86.block_start_pc );   // 5
   278     ADDL_r32_rbpdisp( REG_ECX, R_PC );
   279     load_imm32( REG_ECX, ((pc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
   280     ADDL_r32_rbpdisp( REG_ECX, REG_OFFSET(slice_cycle) );     // 6
   281     load_imm32( REG_EAX, code );
   282     call_func1( sh4_raise_exception, REG_EAX );
   284     load_spreg( REG_EAX, R_PC );
   285     if( sh4_x86.tlb_on ) {
   286         call_func1(xlat_get_code_by_vma,REG_EAX);
   287     } else {
   288         call_func1(xlat_get_code,REG_EAX);
   289     }
   291     exit_block();
   292 }    
   294 /**
   295  * Write the block trailer (exception handling block)
   296  */
   297 void sh4_translate_end_block( sh4addr_t pc ) {
   298     if( sh4_x86.branch_taken == FALSE ) {
   299         // Didn't exit unconditionally already, so write the termination here
   300         exit_block_rel( pc, pc );
   301     }
   302     if( sh4_x86.backpatch_posn != 0 ) {
   303         unsigned int i;
   304         // Raise exception
   305         uint8_t *end_ptr = xlat_output;
   306         MOVL_r32_r32( REG_EDX, REG_ECX );
   307         ADDL_r32_r32( REG_EDX, REG_ECX );
   308         ADDL_r32_rbpdisp( REG_ECX, R_PC );
   309         MOVL_moffptr_eax( &sh4_cpu_period );
   310         MULL_r32( REG_EDX );
   311         ADDL_r32_rbpdisp( REG_EAX, REG_OFFSET(slice_cycle) );
   313         POP_r32(REG_EAX);
   314         call_func1( sh4_raise_exception, REG_EAX );
   315         load_spreg( REG_EAX, R_PC );
   316         if( sh4_x86.tlb_on ) {
   317             call_func1(xlat_get_code_by_vma,REG_EAX);
   318         } else {
   319             call_func1(xlat_get_code,REG_EAX);
   320         }
   321         exit_block();
   323         // Exception already raised - just cleanup
   324         uint8_t *preexc_ptr = xlat_output;
   325         MOVL_r32_r32( REG_EDX, REG_ECX );
   326         ADDL_r32_r32( REG_EDX, REG_ECX );
   327         ADDL_r32_rbpdisp( REG_ECX, R_SPC );
   328         MOVL_moffptr_eax( &sh4_cpu_period );
   329         MULL_r32( REG_EDX );
   330         ADDL_r32_rbpdisp( REG_EAX, REG_OFFSET(slice_cycle) );
   331         load_spreg( REG_EAX, R_PC );
   332         if( sh4_x86.tlb_on ) {
   333             call_func1(xlat_get_code_by_vma,REG_EAX);
   334         } else {
   335             call_func1(xlat_get_code,REG_EAX);
   336         }
   337         exit_block();
   339         for( i=0; i< sh4_x86.backpatch_posn; i++ ) {
   340             uint32_t *fixup_addr = (uint32_t *)&xlat_current_block->code[sh4_x86.backpatch_list[i].fixup_offset];
   341             if( sh4_x86.backpatch_list[i].exc_code < 0 ) {
   342                 if( sh4_x86.backpatch_list[i].exc_code == -2 ) {
   343                     *fixup_addr = (uint32_t)xlat_output;
   344                 } else {
   345                     *fixup_addr += xlat_output - (uint8_t *)&xlat_current_block->code[sh4_x86.backpatch_list[i].fixup_offset] - 4;
   346                 }
   347                 load_imm32( REG_EDX, sh4_x86.backpatch_list[i].fixup_icount );
   348                 int rel = preexc_ptr - xlat_output;
   349                 JMP_prerel(rel);
   350             } else {
   351                 *fixup_addr += xlat_output - (uint8_t *)&xlat_current_block->code[sh4_x86.backpatch_list[i].fixup_offset] - 4;
   352                 PUSH_imm32( sh4_x86.backpatch_list[i].exc_code );
   353                 load_imm32( REG_EDX, sh4_x86.backpatch_list[i].fixup_icount );
   354                 int rel = end_ptr - xlat_output;
   355                 JMP_prerel(rel);
   356             }
   357         }
   358     }
   359 }
   362 /**
   363  * The unwind methods only work if we compiled with DWARF2 frame information
   364  * (ie -fexceptions), otherwise we have to use the direct frame scan.
   365  */
   366 #ifdef HAVE_EXCEPTIONS
   367 #include <unwind.h>
   369 struct UnwindInfo {
   370     uintptr_t block_start;
   371     uintptr_t block_end;
   372     void *pc;
   373 };
   375 _Unwind_Reason_Code xlat_check_frame( struct _Unwind_Context *context, void *arg )
   376 {
   377     struct UnwindInfo *info = arg;
   378     void *pc = (void *)_Unwind_GetIP(context);
   379     if( ((uintptr_t)pc) >= info->block_start && ((uintptr_t)pc) < info->block_end ) {
   380         info->pc = pc;
   381         return _URC_NORMAL_STOP;
   382     }
   384     return _URC_NO_REASON;
   385 }
   387 void *xlat_get_native_pc( void *code, uint32_t code_size )
   388 {
   389     struct _Unwind_Exception exc;
   390     struct UnwindInfo info;
   392     info.pc = NULL;
   393     info.block_start = (uintptr_t)code;
   394     info.block_end = info.block_start + code_size;
   395     void *result = NULL;
   396     _Unwind_Backtrace( xlat_check_frame, &info );
   397     return info.pc;
   398 }
   399 #else 
   400 void *xlat_get_native_pc( void *code, uint32_t code_size )
   401 {
   402     void *result = NULL;
   403     asm(
   404         "mov %%ebp, %%eax\n\t"
   405         "mov $0x8, %%ecx\n\t"
   406         "mov %1, %%edx\n"
   407         "frame_loop: test %%eax, %%eax\n\t"
   408         "je frame_not_found\n\t"
   409         "cmp (%%eax), %%edx\n\t"
   410         "je frame_found\n\t"
   411         "sub $0x1, %%ecx\n\t"
   412         "je frame_not_found\n\t"
   413         "movl (%%eax), %%eax\n\t"
   414         "jmp frame_loop\n"
   415         "frame_found: movl 0x4(%%eax), %0\n"
   416         "frame_not_found:"
   417         : "=r" (result)
   418         : "r" (((uint8_t *)&sh4r) + 128 )
   419         : "eax", "ecx", "edx" );
   420     return result;
   421 }
   422 #endif
   424 #endif /* !lxdream_ia32mac.h */
.