Search
lxdream.org :: lxdream/src/sh4/ia32mac.h :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/ia32mac.h
changeset 539:75f3e594d4a7
next559:06714bc64271
next586:2a3ba82cf243
author nkeynes
date Tue Jan 01 04:49:57 2008 +0000 (16 years ago)
branchlxdream-mmu
permissions -rw-r--r--
last change Add command line option to control default log level
file annotate diff log raw
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/sh4/ia32mac.h Tue Jan 01 04:49:57 2008 +0000
1.3 @@ -0,0 +1,220 @@
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 13
1.33 +static inline void call_func0( void *ptr )
1.34 +{
1.35 + int adj = (-sh4_x86.stack_posn)&0x0F;
1.36 + SUB_imm8s_r32( adj, R_ESP );
1.37 + load_imm32(R_EAX, (uint32_t)ptr);
1.38 + CALL_r32(R_EAX);
1.39 + ADD_imm8s_r32( adj, R_ESP );
1.40 +}
1.41 +
1.42 +#define CALL_FUNC1_SIZE 14
1.43 +static inline void call_func1( void *ptr, int arg1 )
1.44 +{
1.45 + int adj = (-4-sh4_x86.stack_posn)&0x0F;
1.46 + SUB_imm8s_r32( adj, R_ESP );
1.47 + PUSH_r32(arg1);
1.48 + load_imm32(R_EAX, (uint32_t)ptr);
1.49 + CALL_r32(R_EAX);
1.50 + ADD_imm8s_r32( adj+4, R_ESP );
1.51 + sh4_x86.stack_posn -= 4;
1.52 +}
1.53 +
1.54 +#define CALL_FUNC2_SIZE 15
1.55 +static inline void call_func2( void *ptr, int arg1, int arg2 )
1.56 +{
1.57 + int adj = (-8-sh4_x86.stack_posn)&0x0F;
1.58 + SUB_imm8s_r32( adj, R_ESP );
1.59 + PUSH_r32(arg2);
1.60 + PUSH_r32(arg1);
1.61 + load_imm32(R_EAX, (uint32_t)ptr);
1.62 + CALL_r32(R_EAX);
1.63 + ADD_imm8s_r32( adj+8, R_ESP );
1.64 + sh4_x86.stack_posn -= 8;
1.65 +}
1.66 +
1.67 +/**
1.68 + * Write a double (64-bit) value into memory, with the first word in arg2a, and
1.69 + * the second in arg2b
1.70 + * NB: 30 bytes
1.71 + */
1.72 +#define MEM_WRITE_DOUBLE_SIZE 36
1.73 +static inline void MEM_WRITE_DOUBLE( int addr, int arg2a, int arg2b )
1.74 +{
1.75 + int adj = (-8-sh4_x86.stack_posn)&0x0F;
1.76 + SUB_imm8s_r32( adj, R_ESP );
1.77 + ADD_imm8s_r32( 4, addr );
1.78 + PUSH_r32(arg2b);
1.79 + PUSH_r32(addr);
1.80 + ADD_imm8s_r32( -4, addr );
1.81 + SUB_imm8s_r32( 8, R_ESP );
1.82 + PUSH_r32(arg2a);
1.83 + PUSH_r32(addr);
1.84 + load_imm32(R_EAX, (uint32_t)sh4_write_long);
1.85 + CALL_r32(R_EAX);
1.86 + ADD_imm8s_r32( 16, R_ESP );
1.87 + load_imm32(R_EAX, (uint32_t)sh4_write_long);
1.88 + CALL_r32(R_EAX);
1.89 + ADD_imm8s_r32( adj+8, R_ESP );
1.90 + sh4_x86.stack_posn -= 16;
1.91 +}
1.92 +
1.93 +/**
1.94 + * Read a double (64-bit) value from memory, writing the first word into arg2a
1.95 + * and the second into arg2b. The addr must not be in EAX
1.96 + * NB: 27 bytes
1.97 + */
1.98 +#define MEM_READ_DOUBLE_SIZE 36
1.99 +static inline void MEM_READ_DOUBLE( int addr, int arg2a, int arg2b )
1.100 +{
1.101 + int adj = (-4-sh4_x86.stack_posn)&0x0F;
1.102 + int adj2 = (-8-sh4_x86.stack_posn)&0x0F;
1.103 + SUB_imm8s_r32( adj, R_ESP );
1.104 + PUSH_r32(addr);
1.105 + load_imm32(R_EAX, (uint32_t)sh4_read_long);
1.106 + CALL_r32(R_EAX);
1.107 + POP_r32(addr);
1.108 + SUB_imm8s_r32( adj2-adj, R_ESP );
1.109 + PUSH_r32(R_EAX);
1.110 + ADD_imm8s_r32( 4, addr );
1.111 + PUSH_r32(addr);
1.112 + load_imm32(R_EAX, (uint32_t)sh4_read_long);
1.113 + CALL_r32(R_EAX);
1.114 + ADD_imm8s_r32( 4, R_ESP );
1.115 + MOV_r32_r32( R_EAX, arg2b );
1.116 + POP_r32(arg2a);
1.117 + ADD_imm8s_r32( adj2, R_ESP );
1.118 + sh4_x86.stack_posn -= 4;
1.119 +}
1.120 +
1.121 +#define EXIT_BLOCK_SIZE 29
1.122 +
1.123 +
1.124 +/**
1.125 + * Emit the 'start of block' assembly. Sets up the stack frame and save
1.126 + * SI/DI as required
1.127 + */
1.128 +void sh4_translate_begin_block( sh4addr_t pc )
1.129 +{
1.130 + PUSH_r32(R_EBP);
1.131 + /* mov &sh4r, ebp */
1.132 + load_ptr( R_EBP, &sh4r );
1.133 +
1.134 + sh4_x86.in_delay_slot = FALSE;
1.135 + sh4_x86.priv_checked = FALSE;
1.136 + sh4_x86.fpuen_checked = FALSE;
1.137 + sh4_x86.branch_taken = FALSE;
1.138 + sh4_x86.backpatch_posn = 0;
1.139 + sh4_x86.block_start_pc = pc;
1.140 + sh4_x86.tstate = TSTATE_NONE;
1.141 + sh4_x86.stack_posn = 8;
1.142 +}
1.143 +
1.144 +/**
1.145 + * Exit the block with sh4r.pc already written
1.146 + * Bytes: 15
1.147 + */
1.148 +void exit_block_pcset( pc )
1.149 +{
1.150 + load_imm32( R_ECX, ((pc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
1.151 + ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6
1.152 + load_spreg( R_EAX, REG_OFFSET(pc) );
1.153 + call_func1(xlat_get_code,R_EAX);
1.154 + POP_r32(R_EBP);
1.155 + RET();
1.156 +}
1.157 +
1.158 +/**
1.159 + * Exit the block to an absolute PC
1.160 + */
1.161 +void exit_block( sh4addr_t pc, sh4addr_t endpc )
1.162 +{
1.163 + load_imm32( R_ECX, pc ); // 5
1.164 + store_spreg( R_ECX, REG_OFFSET(pc) ); // 3
1.165 + MOV_moff32_EAX( xlat_get_lut_entry(pc) ); // 5
1.166 + AND_imm8s_r32( 0xFC, R_EAX ); // 3
1.167 + load_imm32( R_ECX, ((endpc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
1.168 + ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6
1.169 + POP_r32(R_EBP);
1.170 + RET();
1.171 +}
1.172 +
1.173 +/**
1.174 + * Write the block trailer (exception handling block)
1.175 + */
1.176 +void sh4_translate_end_block( sh4addr_t pc ) {
1.177 + if( sh4_x86.branch_taken == FALSE ) {
1.178 + // Didn't exit unconditionally already, so write the termination here
1.179 + exit_block( pc, pc );
1.180 + }
1.181 + if( sh4_x86.backpatch_posn != 0 ) {
1.182 + uint8_t *end_ptr = xlat_output;
1.183 + // Exception termination. Jump block for various exception codes:
1.184 + PUSH_imm32( EXC_DATA_ADDR_READ );
1.185 + JMP_rel8( 33, target1 );
1.186 + PUSH_imm32( EXC_DATA_ADDR_WRITE );
1.187 + JMP_rel8( 26, target2 );
1.188 + PUSH_imm32( EXC_ILLEGAL );
1.189 + JMP_rel8( 19, target3 );
1.190 + PUSH_imm32( EXC_SLOT_ILLEGAL );
1.191 + JMP_rel8( 12, target4 );
1.192 + PUSH_imm32( EXC_FPU_DISABLED );
1.193 + JMP_rel8( 5, target5 );
1.194 + PUSH_imm32( EXC_SLOT_FPU_DISABLED );
1.195 + // target
1.196 + JMP_TARGET(target1);
1.197 + JMP_TARGET(target2);
1.198 + JMP_TARGET(target3);
1.199 + JMP_TARGET(target4);
1.200 + JMP_TARGET(target5);
1.201 + // Raise exception
1.202 + load_spreg( R_ECX, REG_OFFSET(pc) );
1.203 + ADD_r32_r32( R_EDX, R_ECX );
1.204 + ADD_r32_r32( R_EDX, R_ECX );
1.205 + store_spreg( R_ECX, REG_OFFSET(pc) );
1.206 + MOV_moff32_EAX( &sh4_cpu_period );
1.207 + MUL_r32( R_EDX );
1.208 + ADD_r32_sh4r( R_EAX, REG_OFFSET(slice_cycle) );
1.209 +
1.210 + POP_r32(R_EDX);
1.211 + call_func1( sh4_raise_exception, R_EDX );
1.212 + load_spreg( R_EAX, REG_OFFSET(pc) );
1.213 + call_func1(xlat_get_code,R_EAX);
1.214 + POP_r32(R_EBP);
1.215 + RET();
1.216 +
1.217 + sh4_x86_do_backpatch( end_ptr );
1.218 + }
1.219 +}
1.220 +
1.221 +#endif
1.222 +
1.223 +
.