1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/sh4/ia32abi.h Wed Nov 21 11:45:33 2007 +0000
1.5 + * $Id: sh4x86.in,v 1.20 2007-11-08 11:54:16 nkeynes Exp $
1.7 + * Provides the implementation for the ia32 ABI (eg prologue, epilogue, and
1.8 + * calling conventions)
1.10 + * Copyright (c) 2007 Nathan Keynes.
1.12 + * This program is free software; you can redistribute it and/or modify
1.13 + * it under the terms of the GNU General Public License as published by
1.14 + * the Free Software Foundation; either version 2 of the License, or
1.15 + * (at your option) any later version.
1.17 + * This program is distributed in the hope that it will be useful,
1.18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.20 + * GNU General Public License for more details.
1.23 +#ifndef __lxdream_ia32abi_H
1.24 +#define __lxdream_ia32abi_H 1
1.26 +#define load_ptr( reg, ptr ) load_imm32( reg, (uint32_t)ptr );
1.29 + * Note: clobbers EAX to make the indirect call - this isn't usually
1.30 + * a problem since the callee will usually clobber it anyway.
1.32 +#define CALL_FUNC0_SIZE 7
1.33 +static inline void call_func0( void *ptr )
1.35 + load_imm32(R_EAX, (uint32_t)ptr);
1.39 +#define CALL_FUNC1_SIZE 11
1.40 +static inline void call_func1( void *ptr, int arg1 )
1.44 + ADD_imm8s_r32( 4, R_ESP );
1.47 +#define CALL_FUNC2_SIZE 12
1.48 +static inline void call_func2( void *ptr, int arg1, int arg2 )
1.53 + ADD_imm8s_r32( 8, R_ESP );
1.57 + * Write a double (64-bit) value into memory, with the first word in arg2a, and
1.58 + * the second in arg2b
1.61 +#define MEM_WRITE_DOUBLE_SIZE 30
1.62 +static inline void MEM_WRITE_DOUBLE( int addr, int arg2a, int arg2b )
1.64 + ADD_imm8s_r32( 4, addr );
1.67 + ADD_imm8s_r32( -4, addr );
1.70 + call_func0(sh4_write_long);
1.71 + ADD_imm8s_r32( 8, R_ESP );
1.72 + call_func0(sh4_write_long);
1.73 + ADD_imm8s_r32( 8, R_ESP );
1.77 + * Read a double (64-bit) value from memory, writing the first word into arg2a
1.78 + * and the second into arg2b. The addr must not be in EAX
1.81 +#define MEM_READ_DOUBLE_SIZE 27
1.82 +static inline void MEM_READ_DOUBLE( int addr, int arg2a, int arg2b )
1.85 + call_func0(sh4_read_long);
1.88 + ADD_imm8s_r32( 4, addr );
1.90 + call_func0(sh4_read_long);
1.91 + ADD_imm8s_r32( 4, R_ESP );
1.92 + MOV_r32_r32( R_EAX, arg2b );
1.96 +#define EXIT_BLOCK_SIZE 29
1.100 + * Emit the 'start of block' assembly. Sets up the stack frame and save
1.101 + * SI/DI as required
1.103 +void sh4_translate_begin_block( sh4addr_t pc )
1.106 + /* mov &sh4r, ebp */
1.107 + load_ptr( R_EBP, &sh4r );
1.109 + sh4_x86.in_delay_slot = FALSE;
1.110 + sh4_x86.priv_checked = FALSE;
1.111 + sh4_x86.fpuen_checked = FALSE;
1.112 + sh4_x86.branch_taken = FALSE;
1.113 + sh4_x86.backpatch_posn = 0;
1.114 + sh4_x86.block_start_pc = pc;
1.115 + sh4_x86.tstate = TSTATE_NONE;
1.116 +#ifdef STACK_ALIGN
1.117 + sh4_x86.stack_posn = 8;
1.122 + * Exit the block with sh4r.pc already written
1.125 +void exit_block_pcset( pc )
1.127 + load_imm32( R_ECX, ((pc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
1.128 + ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6
1.129 + load_spreg( R_EAX, REG_OFFSET(pc) );
1.130 + call_func1(xlat_get_code,R_EAX);
1.136 + * Exit the block to an absolute PC
1.138 +void exit_block( sh4addr_t pc, sh4addr_t endpc )
1.140 + load_imm32( R_ECX, pc ); // 5
1.141 + store_spreg( R_ECX, REG_OFFSET(pc) ); // 3
1.142 + MOV_moff32_EAX( xlat_get_lut_entry(pc) ); // 5
1.143 + AND_imm8s_r32( 0xFC, R_EAX ); // 3
1.144 + load_imm32( R_ECX, ((endpc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
1.145 + ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6
1.151 + * Write the block trailer (exception handling block)
1.153 +void sh4_translate_end_block( sh4addr_t pc ) {
1.154 + if( sh4_x86.branch_taken == FALSE ) {
1.155 + // Didn't exit unconditionally already, so write the termination here
1.156 + exit_block( pc, pc );
1.158 + if( sh4_x86.backpatch_posn != 0 ) {
1.159 + uint8_t *end_ptr = xlat_output;
1.160 + // Exception termination. Jump block for various exception codes:
1.161 + PUSH_imm32( EXC_DATA_ADDR_READ );
1.162 + JMP_rel8( 33, target1 );
1.163 + PUSH_imm32( EXC_DATA_ADDR_WRITE );
1.164 + JMP_rel8( 26, target2 );
1.165 + PUSH_imm32( EXC_ILLEGAL );
1.166 + JMP_rel8( 19, target3 );
1.167 + PUSH_imm32( EXC_SLOT_ILLEGAL );
1.168 + JMP_rel8( 12, target4 );
1.169 + PUSH_imm32( EXC_FPU_DISABLED );
1.170 + JMP_rel8( 5, target5 );
1.171 + PUSH_imm32( EXC_SLOT_FPU_DISABLED );
1.173 + JMP_TARGET(target1);
1.174 + JMP_TARGET(target2);
1.175 + JMP_TARGET(target3);
1.176 + JMP_TARGET(target4);
1.177 + JMP_TARGET(target5);
1.178 + // Raise exception
1.179 + load_spreg( R_ECX, REG_OFFSET(pc) );
1.180 + ADD_r32_r32( R_EDX, R_ECX );
1.181 + ADD_r32_r32( R_EDX, R_ECX );
1.182 + store_spreg( R_ECX, REG_OFFSET(pc) );
1.183 + MOV_moff32_EAX( &sh4_cpu_period );
1.184 + MUL_r32( R_EDX );
1.185 + ADD_r32_sh4r( R_EAX, REG_OFFSET(slice_cycle) );
1.187 + call_func0( sh4_raise_exception );
1.188 + ADD_imm8s_r32( 4, R_ESP );
1.189 + load_spreg( R_EAX, REG_OFFSET(pc) );
1.190 + call_func1(xlat_get_code,R_EAX);
1.194 + sh4_x86_do_backpatch( end_ptr );