nkeynes@539: /** nkeynes@586: * $Id$ nkeynes@539: * nkeynes@736: * Provides the implementation for the AMD64 ABI (eg prologue, epilogue, and nkeynes@539: * calling conventions) nkeynes@539: * nkeynes@539: * Copyright (c) 2007 Nathan Keynes. nkeynes@539: * nkeynes@539: * This program is free software; you can redistribute it and/or modify nkeynes@539: * it under the terms of the GNU General Public License as published by nkeynes@539: * the Free Software Foundation; either version 2 of the License, or nkeynes@539: * (at your option) any later version. nkeynes@539: * nkeynes@539: * This program is distributed in the hope that it will be useful, nkeynes@539: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@539: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@539: * GNU General Public License for more details. nkeynes@539: */ nkeynes@539: nkeynes@995: #define REG_ARG1 REG_RDI nkeynes@995: #define REG_ARG2 REG_RSI nkeynes@995: #define REG_ARG3 REG_RDX nkeynes@995: #define REG_RESULT1 REG_RAX nkeynes@995: #define MAX_REG_ARG 3 /* There's more, but we don't use more than 3 here anyway */ nkeynes@736: nkeynes@991: static inline void decode_address( int addr_reg ) nkeynes@953: { nkeynes@953: uintptr_t base = (sh4r.xlat_sh4_mode&SR_MD) ? (uintptr_t)sh4_address_space : (uintptr_t)sh4_user_address_space; nkeynes@995: MOVL_r32_r32( addr_reg, REG_ECX ); nkeynes@995: SHRL_imm_r32( 12, REG_ECX ); nkeynes@991: MOVP_immptr_rptr( base, REG_RDI ); nkeynes@995: MOVP_sib_rptr( 3, REG_RCX, REG_RDI, 0, REG_RCX ); nkeynes@953: } nkeynes@953: nkeynes@539: /** nkeynes@995: * Note: clobbers ECX to make the indirect call - this isn't usually nkeynes@995: * a problem since the callee will generally clobber it anyway. nkeynes@539: * Size: 12 bytes nkeynes@539: */ nkeynes@995: static inline void CALL_ptr( void *ptr ) nkeynes@539: { nkeynes@995: MOVP_immptr_rptr( (uintptr_t)ptr, REG_ECX ); nkeynes@995: CALL_r32(REG_ECX); nkeynes@539: } nkeynes@539: nkeynes@995: static inline void CALL1_ptr_r32( void *ptr, int arg1 ) nkeynes@539: { nkeynes@995: if( arg1 != REG_ARG1 ) { nkeynes@995: MOVQ_r64_r64( arg1, REG_ARG1 ); nkeynes@995: } nkeynes@995: CALL_ptr(ptr); nkeynes@539: } nkeynes@539: nkeynes@995: static inline void CALL1_r32disp_r32( int preg, uint32_t disp, int arg1 ) nkeynes@927: { nkeynes@995: if( arg1 != REG_ARG1 ) { nkeynes@995: MOVQ_r64_r64( arg1, REG_ARG1 ); nkeynes@995: } nkeynes@995: CALL_r32disp(preg, disp); nkeynes@927: } nkeynes@927: nkeynes@995: static inline void CALL2_ptr_r32_r32( void *ptr, int arg1, int arg2 ) nkeynes@953: { nkeynes@995: if( arg2 != REG_ARG2 ) { nkeynes@995: MOVQ_r64_r64( arg2, REG_ARG2 ); nkeynes@995: } nkeynes@995: if( arg1 != REG_ARG1 ) { nkeynes@995: MOVQ_r64_r64( arg1, REG_ARG1 ); nkeynes@995: } nkeynes@995: CALL_ptr(ptr); nkeynes@953: } nkeynes@953: nkeynes@995: static inline void CALL2_r32disp_r32_r32( int preg, uint32_t disp, int arg1, int arg2 ) nkeynes@953: { nkeynes@995: if( arg2 != REG_ARG2 ) { nkeynes@995: MOVQ_r64_r64( arg2, REG_ARG2 ); nkeynes@995: } nkeynes@995: if( arg1 != REG_ARG1 ) { nkeynes@995: MOVQ_r64_r64( arg1, REG_ARG1 ); nkeynes@995: } nkeynes@995: CALL_r32disp(preg, disp); nkeynes@953: } nkeynes@953: nkeynes@995: static inline void CALL3_r32disp_r32_r32_r32( int preg, uint32_t disp, int arg1, int arg2, int arg3 ) nkeynes@539: { nkeynes@995: if( arg3 != REG_ARG3 ) { nkeynes@995: MOVQ_r64_r64( arg3, REG_ARG3 ); nkeynes@995: } nkeynes@995: if( arg2 != REG_ARG2 ) { nkeynes@995: MOVQ_r64_r64( arg2, REG_ARG2 ); nkeynes@995: } nkeynes@995: if( arg1 != REG_ARG1 ) { nkeynes@995: MOVQ_r64_r64( arg1, REG_ARG1 ); nkeynes@995: } nkeynes@995: CALL_r32disp(preg, disp); nkeynes@539: } nkeynes@539: nkeynes@539: /** nkeynes@539: * Emit the 'start of block' assembly. Sets up the stack frame and save nkeynes@539: * SI/DI as required nkeynes@539: */ nkeynes@995: static inline void enter_block( ) nkeynes@539: { nkeynes@991: PUSH_r32(REG_RBP); nkeynes@995: MOVP_immptr_rptr( ((uint8_t *)&sh4r) + 128, REG_EBP ); nkeynes@995: SUBQ_imms_r64( 16, REG_RSP ); nkeynes@926: } nkeynes@926: nkeynes@926: static inline void exit_block( ) nkeynes@926: { nkeynes@991: ADDQ_imms_r64( 16, REG_RSP ); nkeynes@991: POP_r32(REG_RBP); nkeynes@926: RET(); nkeynes@539: }