1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/sh4/ia64abi.h Wed Nov 21 11:40:15 2007 +0000
1.5 + * $Id: ia64abi.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_x86_64abi_H
1.24 +#define __lxdream_x86_64abi_H 1
1.27 +#define load_ptr( reg, ptr ) load_imm64( reg, (uint64_t)ptr );
1.30 + * Note: clobbers EAX to make the indirect call - this isn't usually
1.31 + * a problem since the callee will usually clobber it anyway.
1.34 +#define CALL_FUNC0_SIZE 12
1.35 +static inline void call_func0( void *ptr )
1.37 + load_imm64(R_EAX, (uint64_t)ptr);
1.41 +#define CALL_FUNC1_SIZE 14
1.42 +static inline void call_func1( void *ptr, int arg1 )
1.44 + MOV_r32_r32(arg1, R_EDI);
1.48 +#define CALL_FUNC2_SIZE 16
1.49 +static inline void call_func2( void *ptr, int arg1, int arg2 )
1.51 + MOV_r32_r32(arg1, R_EDI);
1.52 + MOV_r32_r32(arg2, R_ESI);
1.56 +#define MEM_WRITE_DOUBLE_SIZE 39
1.58 + * Write a double (64-bit) value into memory, with the first word in arg2a, and
1.59 + * the second in arg2b
1.61 +static inline void MEM_WRITE_DOUBLE( int addr, int arg2a, int arg2b )
1.65 + call_func2(sh4_write_long, addr, arg2a);
1.68 + ADD_imm8s_r32(4, addr);
1.69 + call_func2(sh4_write_long, addr, arg2b);
1.72 +#define MEM_READ_DOUBLE_SIZE 35
1.74 + * Read a double (64-bit) value from memory, writing the first word into arg2a
1.75 + * and the second into arg2b. The addr must not be in EAX
1.77 +static inline void MEM_READ_DOUBLE( int addr, int arg2a, int arg2b )
1.80 + call_func1(sh4_read_long, addr);
1.83 + ADD_imm8s_r32(4, R_EDI);
1.84 + call_func0(sh4_read_long);
1.85 + MOV_r32_r32(R_EAX, arg2b);
1.91 + * Emit the 'start of block' assembly. Sets up the stack frame and save
1.92 + * SI/DI as required
1.94 +void sh4_translate_begin_block( sh4addr_t pc )
1.97 + /* mov &sh4r, ebp */
1.98 + load_ptr( R_EBP, &sh4r );
1.100 + sh4_x86.in_delay_slot = FALSE;
1.101 + sh4_x86.priv_checked = FALSE;
1.102 + sh4_x86.fpuen_checked = FALSE;
1.103 + sh4_x86.branch_taken = FALSE;
1.104 + sh4_x86.backpatch_posn = 0;
1.105 + sh4_x86.block_start_pc = pc;
1.106 + sh4_x86.tstate = TSTATE_NONE;
1.107 + sh4_x86.stack_posn = 0;
1.111 + * Exit the block with sh4r.pc already written
1.114 +void exit_block_pcset( pc )
1.116 + load_imm32( R_ECX, ((pc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
1.117 + ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6
1.118 + load_spreg( R_EAX, REG_OFFSET(pc) );
1.119 + call_func1(xlat_get_code,R_EAX);
1.124 +#define EXIT_BLOCK_SIZE 35
1.126 + * Exit the block to an absolute PC
1.128 +void exit_block( sh4addr_t pc, sh4addr_t endpc )
1.130 + load_imm32( R_ECX, pc ); // 5
1.131 + store_spreg( R_ECX, REG_OFFSET(pc) ); // 3
1.132 + REXW(); MOV_moff32_EAX( xlat_get_lut_entry(pc) );
1.133 + REXW(); AND_imm8s_r32( 0xFC, R_EAX ); // 3
1.134 + load_imm32( R_ECX, ((endpc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
1.135 + ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6
1.142 + * Write the block trailer (exception handling block)
1.144 +void sh4_translate_end_block( sh4addr_t pc ) {
1.145 + if( sh4_x86.branch_taken == FALSE ) {
1.146 + // Didn't exit unconditionally already, so write the termination here
1.147 + exit_block( pc, pc );
1.149 + if( sh4_x86.backpatch_posn != 0 ) {
1.150 + uint8_t *end_ptr = xlat_output;
1.151 + // Exception termination. Jump block for various exception codes:
1.152 + load_imm32( R_EDI, EXC_DATA_ADDR_READ );
1.153 + JMP_rel8( 33, target1 );
1.154 + load_imm32( R_EDI, EXC_DATA_ADDR_WRITE );
1.155 + JMP_rel8( 26, target2 );
1.156 + load_imm32( R_EDI, EXC_ILLEGAL );
1.157 + JMP_rel8( 19, target3 );
1.158 + load_imm32( R_EDI, EXC_SLOT_ILLEGAL );
1.159 + JMP_rel8( 12, target4 );
1.160 + load_imm32( R_EDI, EXC_FPU_DISABLED );
1.161 + JMP_rel8( 5, target5 );
1.162 + load_imm32( R_EDI, EXC_SLOT_FPU_DISABLED );
1.164 + JMP_TARGET(target1);
1.165 + JMP_TARGET(target2);
1.166 + JMP_TARGET(target3);
1.167 + JMP_TARGET(target4);
1.168 + JMP_TARGET(target5);
1.169 + // Raise exception
1.170 + load_spreg( R_ECX, REG_OFFSET(pc) );
1.171 + ADD_r32_r32( R_EDX, R_ECX );
1.172 + ADD_r32_r32( R_EDX, R_ECX );
1.173 + store_spreg( R_ECX, REG_OFFSET(pc) );
1.174 + MOV_moff32_EAX( &sh4_cpu_period );
1.175 + MUL_r32( R_EDX );
1.176 + ADD_r32_sh4r( R_EAX, REG_OFFSET(slice_cycle) );
1.178 + call_func0( sh4_raise_exception );
1.179 + load_spreg( R_EAX, REG_OFFSET(pc) );
1.180 + call_func1(xlat_get_code,R_EAX);
1.184 + sh4_x86_do_backpatch( end_ptr );
1.189 \ No newline at end of file