Search
lxdream.org :: lxdream/src/sh4/ia32abi.h :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/ia32abi.h
changeset 539:75f3e594d4a7
next559:06714bc64271
next586:2a3ba82cf243
author nkeynes
date Thu Dec 06 10:37:55 2007 +0000 (16 years ago)
permissions -rw-r--r--
last change Fix stack alignment on x86-64
file annotate diff log raw
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/sh4/ia32abi.h Thu Dec 06 10:37:55 2007 +0000
1.3 @@ -0,0 +1,197 @@
1.4 +/**
1.5 + * $Id: sh4x86.in,v 1.20 2007-11-08 11:54:16 nkeynes Exp $
1.6 + *
1.7 + * Provides the implementation for the ia32 ABI (eg prologue, epilogue, and
1.8 + * calling conventions)
1.9 + *
1.10 + * Copyright (c) 2007 Nathan Keynes.
1.11 + *
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.16 + *
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.21 + */
1.22 +
1.23 +#ifndef __lxdream_ia32abi_H
1.24 +#define __lxdream_ia32abi_H 1
1.25 +
1.26 +#define load_ptr( reg, ptr ) load_imm32( reg, (uint32_t)ptr );
1.27 +
1.28 +/**
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.31 + */
1.32 +#define CALL_FUNC0_SIZE 7
1.33 +static inline void call_func0( void *ptr )
1.34 +{
1.35 + load_imm32(R_EAX, (uint32_t)ptr);
1.36 + CALL_r32(R_EAX);
1.37 +}
1.38 +
1.39 +#define CALL_FUNC1_SIZE 11
1.40 +static inline void call_func1( void *ptr, int arg1 )
1.41 +{
1.42 + PUSH_r32(arg1);
1.43 + call_func0(ptr);
1.44 + ADD_imm8s_r32( 4, R_ESP );
1.45 +}
1.46 +
1.47 +#define CALL_FUNC2_SIZE 12
1.48 +static inline void call_func2( void *ptr, int arg1, int arg2 )
1.49 +{
1.50 + PUSH_r32(arg2);
1.51 + PUSH_r32(arg1);
1.52 + call_func0(ptr);
1.53 + ADD_imm8s_r32( 8, R_ESP );
1.54 +}
1.55 +
1.56 +/**
1.57 + * Write a double (64-bit) value into memory, with the first word in arg2a, and
1.58 + * the second in arg2b
1.59 + * NB: 30 bytes
1.60 + */
1.61 +#define MEM_WRITE_DOUBLE_SIZE 30
1.62 +static inline void MEM_WRITE_DOUBLE( int addr, int arg2a, int arg2b )
1.63 +{
1.64 + ADD_imm8s_r32( 4, addr );
1.65 + PUSH_r32(arg2b);
1.66 + PUSH_r32(addr);
1.67 + ADD_imm8s_r32( -4, addr );
1.68 + PUSH_r32(arg2a);
1.69 + PUSH_r32(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.74 +}
1.75 +
1.76 +/**
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.79 + * NB: 27 bytes
1.80 + */
1.81 +#define MEM_READ_DOUBLE_SIZE 27
1.82 +static inline void MEM_READ_DOUBLE( int addr, int arg2a, int arg2b )
1.83 +{
1.84 + PUSH_r32(addr);
1.85 + call_func0(sh4_read_long);
1.86 + POP_r32(addr);
1.87 + PUSH_r32(R_EAX);
1.88 + ADD_imm8s_r32( 4, addr );
1.89 + PUSH_r32(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.93 + POP_r32(arg2a);
1.94 +}
1.95 +
1.96 +#define EXIT_BLOCK_SIZE 29
1.97 +
1.98 +
1.99 +/**
1.100 + * Emit the 'start of block' assembly. Sets up the stack frame and save
1.101 + * SI/DI as required
1.102 + */
1.103 +void sh4_translate_begin_block( sh4addr_t pc )
1.104 +{
1.105 + PUSH_r32(R_EBP);
1.106 + /* mov &sh4r, ebp */
1.107 + load_ptr( R_EBP, &sh4r );
1.108 +
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.118 +#endif
1.119 +}
1.120 +
1.121 +/**
1.122 + * Exit the block with sh4r.pc already written
1.123 + * Bytes: 15
1.124 + */
1.125 +void exit_block_pcset( pc )
1.126 +{
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.131 + POP_r32(R_EBP);
1.132 + RET();
1.133 +}
1.134 +
1.135 +/**
1.136 + * Exit the block to an absolute PC
1.137 + */
1.138 +void exit_block( sh4addr_t pc, sh4addr_t endpc )
1.139 +{
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.146 + POP_r32(R_EBP);
1.147 + RET();
1.148 +}
1.149 +
1.150 +/**
1.151 + * Write the block trailer (exception handling block)
1.152 + */
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.157 + }
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.172 + // target
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.186 +
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.191 + POP_r32(R_EBP);
1.192 + RET();
1.193 +
1.194 + sh4_x86_do_backpatch( end_ptr );
1.195 + }
1.196 +}
1.197 +
1.198 +#endif
1.199 +
1.200 +
.