Search
lxdream.org :: lxdream :: r569:a1c49e1e8776
lxdream 0.9.1
released Jun 29
Download Now
changeset569:a1c49e1e8776 lxdream-mmu
parent568:61e7bb716644
child570:d2893980fbf5
authornkeynes
dateFri Jan 04 11:54:17 2008 +0000 (16 years ago)
branchlxdream-mmu
Bring icache partially into line with the mmu, a little less slow with AT off
now.
src/lxdream.h
src/sh4/ia32abi.h
src/sh4/ia32mac.h
src/sh4/ia64abi.h
src/sh4/mmu.c
src/sh4/sh4.c
src/sh4/sh4core.c
src/sh4/sh4core.h
src/sh4/sh4core.in
src/sh4/sh4dasm.c
src/sh4/sh4dasm.h
src/sh4/sh4dasm.in
src/sh4/sh4mem.c
src/sh4/sh4trans.c
src/sh4/sh4x86.c
src/sh4/sh4x86.in
src/sh4/x86op.h
src/sh4/xltcache.c
src/sh4/xltcache.h
1.1 --- a/src/lxdream.h Tue Jan 01 10:54:22 2008 +0000
1.2 +++ b/src/lxdream.h Fri Jan 04 11:54:17 2008 +0000
1.3 @@ -39,9 +39,15 @@
1.4 #endif
1.5
1.6 /**
1.7 - * A 32-bit address in SH4 space
1.8 + * A 29-bit address in SH4 external address space
1.9 */
1.10 typedef uint32_t sh4addr_t;
1.11 +
1.12 +/**
1.13 + * A 32-bit address in SH4 virtual address space.
1.14 + */
1.15 +typedef uint32_t sh4vma_t;
1.16 +
1.17 /**
1.18 * A direct pointer into SH4 memory
1.19 */
2.1 --- a/src/sh4/ia32abi.h Tue Jan 01 10:54:22 2008 +0000
2.2 +++ b/src/sh4/ia32abi.h Fri Jan 04 11:54:17 2008 +0000
2.3 @@ -119,12 +119,12 @@
2.4 * Exit the block with sh4r.pc already written
2.5 * Bytes: 15
2.6 */
2.7 -void exit_block_pcset( pc )
2.8 +void exit_block_pcset( sh4addr_t pc )
2.9 {
2.10 load_imm32( R_ECX, ((pc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
2.11 ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6
2.12 load_spreg( R_EAX, REG_OFFSET(pc) );
2.13 - call_func1(xlat_get_code,R_EAX);
2.14 + call_func1(xlat_get_code_by_vma,R_EAX);
2.15 POP_r32(R_EBP);
2.16 RET();
2.17 }
2.18 @@ -167,7 +167,7 @@
2.19 call_func0( sh4_raise_exception );
2.20 ADD_imm8s_r32( 4, R_ESP );
2.21 load_spreg( R_EAX, REG_OFFSET(pc) );
2.22 - call_func1(xlat_get_code,R_EAX);
2.23 + call_func1(xlat_get_code_by_vma,R_EAX);
2.24 POP_r32(R_EBP);
2.25 RET();
2.26
2.27 @@ -181,7 +181,7 @@
2.28 MUL_r32( R_EDX );
2.29 ADD_r32_sh4r( R_EAX, REG_OFFSET(slice_cycle) );
2.30 load_spreg( R_EAX, REG_OFFSET(pc) );
2.31 - call_func1(xlat_get_code,R_EAX);
2.32 + call_func1(xlat_get_code_by_vma,R_EAX);
2.33 POP_r32(R_EBP);
2.34 RET();
2.35
3.1 --- a/src/sh4/ia32mac.h Tue Jan 01 10:54:22 2008 +0000
3.2 +++ b/src/sh4/ia32mac.h Fri Jan 04 11:54:17 2008 +0000
3.3 @@ -142,12 +142,12 @@
3.4 * Exit the block with sh4r.pc already written
3.5 * Bytes: 15
3.6 */
3.7 -void exit_block_pcset( pc )
3.8 +void exit_block_pcset( sh4addr_t pc )
3.9 {
3.10 load_imm32( R_ECX, ((pc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
3.11 ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6
3.12 load_spreg( R_EAX, REG_OFFSET(pc) );
3.13 - call_func1(xlat_get_code,R_EAX);
3.14 + call_func1(xlat_get_code_by_vma,R_EAX);
3.15 POP_r32(R_EBP);
3.16 RET();
3.17 }
3.18 @@ -190,7 +190,7 @@
3.19 POP_r32(R_EDX);
3.20 call_func1( sh4_raise_exception, R_EDX );
3.21 load_spreg( R_EAX, REG_OFFSET(pc) );
3.22 - call_func1(xlat_get_code,R_EAX);
3.23 + call_func1(xlat_get_code_by_vma,R_EAX);
3.24 POP_r32(R_EBP);
3.25 RET();
3.26
3.27 @@ -204,7 +204,7 @@
3.28 MUL_r32( R_EDX );
3.29 ADD_r32_sh4r( R_EAX, REG_OFFSET(slice_cycle) );
3.30 load_spreg( R_EAX, REG_OFFSET(pc) );
3.31 - call_func1(xlat_get_code,R_EAX);
3.32 + call_func1(xlat_get_code_by_vma,R_EAX);
3.33 POP_r32(R_EBP);
3.34 RET();
3.35
4.1 --- a/src/sh4/ia64abi.h Tue Jan 01 10:54:22 2008 +0000
4.2 +++ b/src/sh4/ia64abi.h Fri Jan 04 11:54:17 2008 +0000
4.3 @@ -109,12 +109,12 @@
4.4 * Exit the block with sh4r.pc already written
4.5 * Bytes: 15
4.6 */
4.7 -void exit_block_pcset( pc )
4.8 +void exit_block_pcset( sh4addr_t pc )
4.9 {
4.10 load_imm32( R_ECX, ((pc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
4.11 ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6
4.12 load_spreg( R_EAX, REG_OFFSET(pc) );
4.13 - call_func1(xlat_get_code,R_EAX);
4.14 + call_func1(xlat_get_code_by_vma,R_EAX);
4.15 POP_r32(R_EBP);
4.16 RET();
4.17 }
4.18 @@ -157,7 +157,7 @@
4.19
4.20 call_func0( sh4_raise_exception );
4.21 load_spreg( R_EAX, REG_OFFSET(pc) );
4.22 - call_func1(xlat_get_code,R_EAX);
4.23 + call_func1(xlat_get_code_by_vma,R_EAX);
4.24 POP_r32(R_EBP);
4.25 RET();
4.26
4.27 @@ -171,7 +171,7 @@
4.28 MUL_r32( R_EDX );
4.29 ADD_r32_sh4r( R_EAX, REG_OFFSET(slice_cycle) );
4.30 load_spreg( R_EAX, REG_OFFSET(pc) );
4.31 - call_func1(xlat_get_code,R_EAX);
4.32 + call_func1(xlat_get_code_by_vma,R_EAX);
4.33 POP_r32(R_EBP);
4.34 RET();
4.35
5.1 --- a/src/sh4/mmu.c Tue Jan 01 10:54:22 2008 +0000
5.2 +++ b/src/sh4/mmu.c Fri Jan 04 11:54:17 2008 +0000
5.3 @@ -70,6 +70,7 @@
5.4 static uint32_t mmu_urc;
5.5 static uint32_t mmu_urb;
5.6 static uint32_t mmu_lrui;
5.7 +static uint32_t mmu_asid; // current asid
5.8
5.9 static sh4ptr_t cache = NULL;
5.10
5.11 @@ -101,6 +102,10 @@
5.12 switch(reg) {
5.13 case PTEH:
5.14 val &= 0xFFFFFCFF;
5.15 + if( (val & 0xFF) != mmu_asid ) {
5.16 + mmu_asid = val&0xFF;
5.17 + sh4_icache.page_vma = -1; // invalidate icache as asid has changed
5.18 + }
5.19 break;
5.20 case PTEL:
5.21 val &= 0x1FFFFDFF;
5.22 @@ -234,17 +239,15 @@
5.23 */
5.24
5.25 /**
5.26 - * Perform the actual utlb lookup.
5.27 + * Perform the actual utlb lookup w/ asid matching.
5.28 * Possible utcomes are:
5.29 * 0..63 Single match - good, return entry found
5.30 * -1 No match - raise a tlb data miss exception
5.31 * -2 Multiple matches - raise a multi-hit exception (reset)
5.32 * @param vpn virtual address to resolve
5.33 - * @param asid Address space identifier
5.34 - * @param use_asid whether to require an asid match on non-shared pages.
5.35 * @return the resultant UTLB entry, or an error.
5.36 */
5.37 -static inline int mmu_utlb_lookup_vpn( uint32_t vpn, uint32_t asid, int use_asid )
5.38 +static inline int mmu_utlb_lookup_vpn_asid( uint32_t vpn )
5.39 {
5.40 int result = -1;
5.41 unsigned int i;
5.42 @@ -254,32 +257,52 @@
5.43 mmu_urc = 0;
5.44 }
5.45
5.46 - if( use_asid ) {
5.47 - for( i = 0; i < UTLB_ENTRY_COUNT; i++ ) {
5.48 - if( (mmu_utlb[i].flags & TLB_VALID) &&
5.49 - ((mmu_utlb[i].flags & TLB_SHARE) || asid == mmu_utlb[i].asid) &&
5.50 - ((mmu_utlb[i].vpn ^ vpn) & mmu_utlb[i].mask) == 0 ) {
5.51 - if( result != -1 ) {
5.52 - return -2;
5.53 - }
5.54 - result = i;
5.55 + for( i = 0; i < UTLB_ENTRY_COUNT; i++ ) {
5.56 + if( (mmu_utlb[i].flags & TLB_VALID) &&
5.57 + ((mmu_utlb[i].flags & TLB_SHARE) || mmu_asid == mmu_utlb[i].asid) &&
5.58 + ((mmu_utlb[i].vpn ^ vpn) & mmu_utlb[i].mask) == 0 ) {
5.59 + if( result != -1 ) {
5.60 + return -2;
5.61 }
5.62 - }
5.63 - } else {
5.64 - for( i = 0; i < UTLB_ENTRY_COUNT; i++ ) {
5.65 - if( (mmu_utlb[i].flags & TLB_VALID) &&
5.66 - ((mmu_utlb[i].vpn ^ vpn) & mmu_utlb[i].mask) == 0 ) {
5.67 - if( result != -1 ) {
5.68 - return -2;
5.69 - }
5.70 - result = i;
5.71 - }
5.72 + result = i;
5.73 }
5.74 }
5.75 return result;
5.76 }
5.77
5.78 /**
5.79 + * Perform the actual utlb lookup matching on vpn only
5.80 + * Possible utcomes are:
5.81 + * 0..63 Single match - good, return entry found
5.82 + * -1 No match - raise a tlb data miss exception
5.83 + * -2 Multiple matches - raise a multi-hit exception (reset)
5.84 + * @param vpn virtual address to resolve
5.85 + * @return the resultant UTLB entry, or an error.
5.86 + */
5.87 +static inline int mmu_utlb_lookup_vpn( uint32_t vpn )
5.88 +{
5.89 + int result = -1;
5.90 + unsigned int i;
5.91 +
5.92 + mmu_urc++;
5.93 + if( mmu_urc == mmu_urb || mmu_urc == 0x40 ) {
5.94 + mmu_urc = 0;
5.95 + }
5.96 +
5.97 + for( i = 0; i < UTLB_ENTRY_COUNT; i++ ) {
5.98 + if( (mmu_utlb[i].flags & TLB_VALID) &&
5.99 + ((mmu_utlb[i].vpn ^ vpn) & mmu_utlb[i].mask) == 0 ) {
5.100 + if( result != -1 ) {
5.101 + return -2;
5.102 + }
5.103 + result = i;
5.104 + }
5.105 + }
5.106 +
5.107 + return result;
5.108 +}
5.109 +
5.110 +/**
5.111 * Find a UTLB entry for the associative TLB write - same as the normal
5.112 * lookup but ignores the valid bit.
5.113 */
5.114 @@ -300,53 +323,9 @@
5.115 }
5.116
5.117 /**
5.118 - * Perform the actual itlb lookup.
5.119 - * Possible utcomes are:
5.120 - * 0..63 Single match - good, return entry found
5.121 - * -1 No match - raise a tlb data miss exception
5.122 - * -2 Multiple matches - raise a multi-hit exception (reset)
5.123 - * @param vpn virtual address to resolve
5.124 - * @param asid Address space identifier
5.125 - * @param use_asid whether to require an asid match on non-shared pages.
5.126 - * @return the resultant ITLB entry, or an error.
5.127 + * Update the ITLB by replacing the LRU entry with the specified UTLB entry.
5.128 + * @return the number (0-3) of the replaced entry.
5.129 */
5.130 -static inline int mmu_itlb_lookup_vpn( uint32_t vpn, uint32_t asid, int use_asid )
5.131 -{
5.132 - int result = -1;
5.133 - unsigned int i;
5.134 - if( use_asid ) {
5.135 - for( i = 0; i < ITLB_ENTRY_COUNT; i++ ) {
5.136 - if( (mmu_itlb[i].flags & TLB_VALID) &&
5.137 - ((mmu_itlb[i].flags & TLB_SHARE) || asid == mmu_itlb[i].asid) &&
5.138 - ((mmu_itlb[i].vpn ^ vpn) & mmu_itlb[i].mask) == 0 ) {
5.139 - if( result != -1 ) {
5.140 - return -2;
5.141 - }
5.142 - result = i;
5.143 - }
5.144 - }
5.145 - } else {
5.146 - for( i = 0; i < ITLB_ENTRY_COUNT; i++ ) {
5.147 - if( (mmu_itlb[i].flags & TLB_VALID) &&
5.148 - ((mmu_itlb[i].vpn ^ vpn) & mmu_itlb[i].mask) == 0 ) {
5.149 - if( result != -1 ) {
5.150 - return -2;
5.151 - }
5.152 - result = i;
5.153 - }
5.154 - }
5.155 - }
5.156 -
5.157 - switch( result ) {
5.158 - case 0: mmu_lrui = (mmu_lrui & 0x07); break;
5.159 - case 1: mmu_lrui = (mmu_lrui & 0x19) | 0x20; break;
5.160 - case 2: mmu_lrui = (mmu_lrui & 0x3E) | 0x14; break;
5.161 - case 3: mmu_lrui = (mmu_lrui | 0x0B); break;
5.162 - }
5.163 -
5.164 - return result;
5.165 -}
5.166 -
5.167 static int inline mmu_itlb_update_from_utlb( int entryNo )
5.168 {
5.169 int replace;
5.170 @@ -374,6 +353,93 @@
5.171 }
5.172
5.173 /**
5.174 + * Perform the actual itlb lookup w/ asid protection
5.175 + * Possible utcomes are:
5.176 + * 0..63 Single match - good, return entry found
5.177 + * -1 No match - raise a tlb data miss exception
5.178 + * -2 Multiple matches - raise a multi-hit exception (reset)
5.179 + * @param vpn virtual address to resolve
5.180 + * @return the resultant ITLB entry, or an error.
5.181 + */
5.182 +static inline int mmu_itlb_lookup_vpn_asid( uint32_t vpn )
5.183 +{
5.184 + int result = -1;
5.185 + unsigned int i;
5.186 +
5.187 + for( i = 0; i < ITLB_ENTRY_COUNT; i++ ) {
5.188 + if( (mmu_itlb[i].flags & TLB_VALID) &&
5.189 + ((mmu_itlb[i].flags & TLB_SHARE) || mmu_asid == mmu_itlb[i].asid) &&
5.190 + ((mmu_itlb[i].vpn ^ vpn) & mmu_itlb[i].mask) == 0 ) {
5.191 + if( result != -1 ) {
5.192 + return -2;
5.193 + }
5.194 + result = i;
5.195 + }
5.196 + }
5.197 +
5.198 + if( result == -1 ) {
5.199 + int utlbEntry = mmu_utlb_lookup_vpn( vpn );
5.200 + if( utlbEntry == -1 ) {
5.201 + return -1;
5.202 + } else {
5.203 + return mmu_itlb_update_from_utlb( utlbEntry );
5.204 + }
5.205 + }
5.206 +
5.207 + switch( result ) {
5.208 + case 0: mmu_lrui = (mmu_lrui & 0x07); break;
5.209 + case 1: mmu_lrui = (mmu_lrui & 0x19) | 0x20; break;
5.210 + case 2: mmu_lrui = (mmu_lrui & 0x3E) | 0x14; break;
5.211 + case 3: mmu_lrui = (mmu_lrui | 0x0B); break;
5.212 + }
5.213 +
5.214 + return result;
5.215 +}
5.216 +
5.217 +/**
5.218 + * Perform the actual itlb lookup on vpn only
5.219 + * Possible utcomes are:
5.220 + * 0..63 Single match - good, return entry found
5.221 + * -1 No match - raise a tlb data miss exception
5.222 + * -2 Multiple matches - raise a multi-hit exception (reset)
5.223 + * @param vpn virtual address to resolve
5.224 + * @return the resultant ITLB entry, or an error.
5.225 + */
5.226 +static inline int mmu_itlb_lookup_vpn( uint32_t vpn )
5.227 +{
5.228 + int result = -1;
5.229 + unsigned int i;
5.230 +
5.231 + for( i = 0; i < ITLB_ENTRY_COUNT; i++ ) {
5.232 + if( (mmu_itlb[i].flags & TLB_VALID) &&
5.233 + ((mmu_itlb[i].vpn ^ vpn) & mmu_itlb[i].mask) == 0 ) {
5.234 + if( result != -1 ) {
5.235 + return -2;
5.236 + }
5.237 + result = i;
5.238 + }
5.239 + }
5.240 +
5.241 + if( result == -1 ) {
5.242 + int utlbEntry = mmu_utlb_lookup_vpn( vpn );
5.243 + if( utlbEntry == -1 ) {
5.244 + return -1;
5.245 + } else {
5.246 + return mmu_itlb_update_from_utlb( utlbEntry );
5.247 + }
5.248 + }
5.249 +
5.250 + switch( result ) {
5.251 + case 0: mmu_lrui = (mmu_lrui & 0x07); break;
5.252 + case 1: mmu_lrui = (mmu_lrui & 0x19) | 0x20; break;
5.253 + case 2: mmu_lrui = (mmu_lrui & 0x3E) | 0x14; break;
5.254 + case 3: mmu_lrui = (mmu_lrui | 0x0B); break;
5.255 + }
5.256 +
5.257 + return result;
5.258 +}
5.259 +
5.260 +/**
5.261 * Find a ITLB entry for the associative TLB write - same as the normal
5.262 * lookup but ignores the valid bit.
5.263 */
5.264 @@ -396,18 +462,15 @@
5.265 #define RAISE_TLB_ERROR(code, vpn) \
5.266 MMIO_WRITE(MMU, TEA, vpn); \
5.267 MMIO_WRITE(MMU, PTEH, ((MMIO_READ(MMU, PTEH) & 0x000003FF) | (vpn&0xFFFFFC00))); \
5.268 - sh4_raise_tlb_exception(code); \
5.269 - return (((uint64_t)code)<<32)
5.270 + sh4_raise_tlb_exception(code);
5.271
5.272 #define RAISE_MEM_ERROR(code, vpn) \
5.273 MMIO_WRITE(MMU, TEA, vpn); \
5.274 MMIO_WRITE(MMU, PTEH, ((MMIO_READ(MMU, PTEH) & 0x000003FF) | (vpn&0xFFFFFC00))); \
5.275 - sh4_raise_exception(code); \
5.276 - return (((uint64_t)code)<<32)
5.277 + sh4_raise_exception(code);
5.278
5.279 #define RAISE_OTHER_ERROR(code) \
5.280 - sh4_raise_exception(code); \
5.281 - return (((uint64_t)EXV_EXCEPTION)<<32)
5.282 + sh4_raise_exception(code);
5.283
5.284 /**
5.285 * Abort with a non-MMU address error. Caused by user-mode code attempting
5.286 @@ -423,8 +486,7 @@
5.287 #define MMU_TLB_WRITE_PROT_ERROR(vpn) RAISE_MEM_ERROR(EXC_TLB_PROT_WRITE, vpn)
5.288 #define MMU_TLB_MULTI_HIT_ERROR(vpn) sh4_raise_reset(EXC_TLB_MULTI_HIT); \
5.289 MMIO_WRITE(MMU, TEA, vpn); \
5.290 - MMIO_WRITE(MMU, PTEH, ((MMIO_READ(MMU, PTEH) & 0x000003FF) | (vpn&0xFFFFFC00))); \
5.291 - return (((uint64_t)EXC_TLB_MULTI_HIT)<<32)
5.292 + MMIO_WRITE(MMU, PTEH, ((MMIO_READ(MMU, PTEH) & 0x000003FF) | (vpn&0xFFFFFC00)));
5.293
5.294 uint64_t mmu_vma_to_phys_write( sh4addr_t addr )
5.295 {
5.296 @@ -442,6 +504,7 @@
5.297 return (uint64_t)addr;
5.298 }
5.299 MMU_WRITE_ADDR_ERROR();
5.300 + return 0x100000000LL;
5.301 }
5.302 }
5.303
5.304 @@ -450,28 +513,31 @@
5.305 }
5.306
5.307 /* If we get this far, translation is required */
5.308 -
5.309 - int use_asid = ((mmucr & MMUCR_SV) == 0) || !IS_SH4_PRIVMODE();
5.310 - uint32_t asid = MMIO_READ( MMU, PTEH ) & 0xFF;
5.311 -
5.312 - int entryNo = mmu_utlb_lookup_vpn( addr, asid, use_asid );
5.313 + int entryNo;
5.314 + if( ((mmucr & MMUCR_SV) == 0) || !IS_SH4_PRIVMODE() ) {
5.315 + entryNo = mmu_utlb_lookup_vpn_asid( addr );
5.316 + } else {
5.317 + entryNo = mmu_utlb_lookup_vpn( addr );
5.318 + }
5.319
5.320 switch(entryNo) {
5.321 case -1:
5.322 MMU_TLB_WRITE_MISS_ERROR(addr);
5.323 - break;
5.324 + return 0x100000000LL;
5.325 case -2:
5.326 MMU_TLB_MULTI_HIT_ERROR(addr);
5.327 - break;
5.328 + return 0x100000000LL;
5.329 default:
5.330 if( IS_SH4_PRIVMODE() ? ((mmu_utlb[entryNo].flags & TLB_WRITABLE) == 0)
5.331 : ((mmu_utlb[entryNo].flags & TLB_USERWRITABLE) != TLB_USERWRITABLE) ) {
5.332 /* protection violation */
5.333 MMU_TLB_WRITE_PROT_ERROR(addr);
5.334 + return 0x100000000LL;
5.335 }
5.336
5.337 if( (mmu_utlb[entryNo].flags & TLB_DIRTY) == 0 ) {
5.338 MMU_TLB_INITIAL_WRITE_ERROR(addr);
5.339 + return 0x100000000LL;
5.340 }
5.341
5.342 /* finally generate the target address */
5.343 @@ -482,64 +548,6 @@
5.344
5.345 }
5.346
5.347 -uint64_t mmu_vma_to_phys_exec( sh4addr_t addr )
5.348 -{
5.349 - uint32_t mmucr = MMIO_READ(MMU,MMUCR);
5.350 - if( addr & 0x80000000 ) {
5.351 - if( IS_SH4_PRIVMODE() ) {
5.352 - if( addr < 0xC0000000 ) {
5.353 - /* P1, P2 and P4 regions are pass-through (no translation) */
5.354 - return (uint64_t)addr;
5.355 - } else if( addr >= 0xE0000000 ) {
5.356 - MMU_READ_ADDR_ERROR();
5.357 - }
5.358 - } else {
5.359 - MMU_READ_ADDR_ERROR();
5.360 - }
5.361 - }
5.362 -
5.363 - if( (mmucr & MMUCR_AT) == 0 ) {
5.364 - return (uint64_t)addr;
5.365 - }
5.366 -
5.367 - /* If we get this far, translation is required */
5.368 - int use_asid = ((mmucr & MMUCR_SV) == 0) || !IS_SH4_PRIVMODE();
5.369 - uint32_t asid = MMIO_READ( MMU, PTEH ) & 0xFF;
5.370 -
5.371 - int entryNo = mmu_itlb_lookup_vpn( addr, asid, use_asid );
5.372 - if( entryNo == -1 ) {
5.373 - entryNo = mmu_utlb_lookup_vpn( addr, asid, use_asid );
5.374 - if( entryNo >= 0 ) {
5.375 - entryNo = mmu_itlb_update_from_utlb( entryNo );
5.376 - }
5.377 - }
5.378 - switch(entryNo) {
5.379 - case -1:
5.380 - MMU_TLB_READ_MISS_ERROR(addr);
5.381 - break;
5.382 - case -2:
5.383 - MMU_TLB_MULTI_HIT_ERROR(addr);
5.384 - break;
5.385 - default:
5.386 - if( (mmu_itlb[entryNo].flags & TLB_USERMODE) == 0 &&
5.387 - !IS_SH4_PRIVMODE() ) {
5.388 - /* protection violation */
5.389 - MMU_TLB_READ_PROT_ERROR(addr);
5.390 - }
5.391 -
5.392 - /* finally generate the target address */
5.393 - return (mmu_itlb[entryNo].ppn & mmu_itlb[entryNo].mask) |
5.394 - (addr & (~mmu_itlb[entryNo].mask));
5.395 - }
5.396 - return -1;
5.397 -}
5.398 -
5.399 -uint64_t mmu_vma_to_phys_read_noexc( sh4addr_t addr ) {
5.400 -
5.401 -
5.402 -}
5.403 -
5.404 -
5.405 uint64_t mmu_vma_to_phys_read( sh4addr_t addr )
5.406 {
5.407 uint32_t mmucr = MMIO_READ(MMU,MMUCR);
5.408 @@ -556,6 +564,7 @@
5.409 return (uint64_t)addr;
5.410 }
5.411 MMU_READ_ADDR_ERROR();
5.412 + return 0x100000000LL;
5.413 }
5.414 }
5.415
5.416 @@ -564,24 +573,26 @@
5.417 }
5.418
5.419 /* If we get this far, translation is required */
5.420 -
5.421 - int use_asid = ((mmucr & MMUCR_SV) == 0) || !IS_SH4_PRIVMODE();
5.422 - uint32_t asid = MMIO_READ( MMU, PTEH ) & 0xFF;
5.423 -
5.424 - int entryNo = mmu_utlb_lookup_vpn( addr, asid, use_asid );
5.425 + int entryNo;
5.426 + if( ((mmucr & MMUCR_SV) == 0) || !IS_SH4_PRIVMODE() ) {
5.427 + entryNo = mmu_utlb_lookup_vpn_asid( addr );
5.428 + } else {
5.429 + entryNo = mmu_utlb_lookup_vpn( addr );
5.430 + }
5.431
5.432 switch(entryNo) {
5.433 case -1:
5.434 MMU_TLB_READ_MISS_ERROR(addr);
5.435 - break;
5.436 + return 0x100000000LL;
5.437 case -2:
5.438 MMU_TLB_MULTI_HIT_ERROR(addr);
5.439 - break;
5.440 + return 0x100000000LL;
5.441 default:
5.442 if( (mmu_utlb[entryNo].flags & TLB_USERMODE) == 0 &&
5.443 !IS_SH4_PRIVMODE() ) {
5.444 /* protection violation */
5.445 MMU_TLB_READ_PROT_ERROR(addr);
5.446 + return 0x100000000LL;
5.447 }
5.448
5.449 /* finally generate the target address */
5.450 @@ -720,3 +731,106 @@
5.451 void mmu_ocache_data_write( sh4addr_t addr, uint32_t val )
5.452 {
5.453 }
5.454 +
5.455 +/**
5.456 + * Update the icache for an untranslated address
5.457 + */
5.458 +void mmu_update_icache_phys( sh4addr_t addr )
5.459 +{
5.460 + if( (addr & 0x1C000000) == 0x0C000000 ) {
5.461 + /* Main ram */
5.462 + sh4_icache.page_vma = addr & 0xFF000000;
5.463 + sh4_icache.page_ppa = 0x0C000000;
5.464 + sh4_icache.mask = 0xFF000000;
5.465 + sh4_icache.page = sh4_main_ram;
5.466 + } else if( (addr & 0x1FE00000 == 0 ) ) {
5.467 + /* BIOS ROM */
5.468 + sh4_icache.page_vma = addr & 0xFFE00000;
5.469 + sh4_icache.page_ppa = 0;
5.470 + sh4_icache.mask = 0xFFE00000;
5.471 + sh4_icache.page = mem_get_region(0);
5.472 + } else {
5.473 + /* not supported */
5.474 + sh4_icache.page_vma = -1;
5.475 + }
5.476 +}
5.477 +
5.478 +/**
5.479 + * Update the sh4_icache structure to describe the page(s) containing the
5.480 + * given vma. If the address does not reference a RAM/ROM region, the icache
5.481 + * will be invalidated instead.
5.482 + * If AT is on, this method will raise TLB exceptions normally
5.483 + * (hence this method should only be used immediately prior to execution of
5.484 + * code), and otherwise will set the icache according to the matching TLB entry.
5.485 + * If AT is off, this method will set the entire referenced RAM/ROM region in
5.486 + * the icache.
5.487 + * @return TRUE if the update completed (successfully or otherwise), FALSE
5.488 + * if an exception was raised.
5.489 + */
5.490 +gboolean mmu_update_icache( sh4vma_t addr )
5.491 +{
5.492 + int entryNo;
5.493 + if( IS_SH4_PRIVMODE() ) {
5.494 + if( addr & 0x80000000 ) {
5.495 + if( addr < 0xC0000000 ) {
5.496 + /* P1, P2 and P4 regions are pass-through (no translation) */
5.497 + mmu_update_icache_phys(addr);
5.498 + return TRUE;
5.499 + } else if( addr >= 0xE0000000 && addr < 0xFFFFFF00 ) {
5.500 + MMU_READ_ADDR_ERROR();
5.501 + return FALSE;
5.502 + }
5.503 + } else {
5.504 + MMU_READ_ADDR_ERROR();
5.505 + return FALSE;
5.506 + }
5.507 +
5.508 + uint32_t mmucr = MMIO_READ(MMU,MMUCR);
5.509 + if( (mmucr & MMUCR_AT) == 0 ) {
5.510 + mmu_update_icache_phys(addr);
5.511 + return TRUE;
5.512 + }
5.513 +
5.514 + entryNo = mmu_itlb_lookup_vpn( addr );
5.515 + } else {
5.516 + if( addr & 0x80000000 ) {
5.517 + MMU_READ_ADDR_ERROR();
5.518 + return FALSE;
5.519 + }
5.520 +
5.521 + uint32_t mmucr = MMIO_READ(MMU,MMUCR);
5.522 + if( (mmucr & MMUCR_AT) == 0 ) {
5.523 + mmu_update_icache_phys(addr);
5.524 + return TRUE;
5.525 + }
5.526 +
5.527 + if( mmucr & MMUCR_SV ) {
5.528 + entryNo = mmu_itlb_lookup_vpn( addr );
5.529 + } else {
5.530 + entryNo = mmu_itlb_lookup_vpn_asid( addr );
5.531 + }
5.532 + if( entryNo != -1 && (mmu_itlb[entryNo].flags & TLB_USERMODE) == 0 ) {
5.533 + MMU_TLB_READ_PROT_ERROR(addr);
5.534 + return FALSE;
5.535 + }
5.536 + }
5.537 +
5.538 + switch(entryNo) {
5.539 + case -1:
5.540 + MMU_TLB_READ_MISS_ERROR(addr);
5.541 + return FALSE;
5.542 + case -2:
5.543 + MMU_TLB_MULTI_HIT_ERROR(addr);
5.544 + return FALSE;
5.545 + default:
5.546 + sh4_icache.page_ppa = mmu_itlb[entryNo].ppn & mmu_itlb[entryNo].mask;
5.547 + sh4_icache.page = mem_get_region( sh4_icache.page_ppa );
5.548 + if( sh4_icache.page == NULL ) {
5.549 + sh4_icache.page_vma = -1;
5.550 + } else {
5.551 + sh4_icache.page_vma = mmu_itlb[entryNo].vpn & mmu_itlb[entryNo].mask;
5.552 + sh4_icache.mask = mmu_itlb[entryNo].mask;
5.553 + }
5.554 + return TRUE;
5.555 + }
5.556 +}
6.1 --- a/src/sh4/sh4.c Tue Jan 01 10:54:22 2008 +0000
6.2 +++ b/src/sh4/sh4.c Fri Jan 04 11:54:17 2008 +0000
6.3 @@ -48,18 +48,9 @@
6.4 struct sh4_registers sh4r;
6.5 struct breakpoint_struct sh4_breakpoints[MAX_BREAKPOINTS];
6.6 int sh4_breakpoint_count = 0;
6.7 -extern sh4ptr_t sh4_main_ram;
6.8 +sh4ptr_t sh4_main_ram;
6.9 static gboolean sh4_use_translator = FALSE;
6.10 -
6.11 -struct sh4_icache_info {
6.12 - char *page;
6.13 - uint32_t page_start;
6.14 - uint32_t page_size;
6.15 -};
6.16 -
6.17 -extern struct sh4_icache_info sh4_icache;
6.18 -
6.19 -// struct sh4_icache_info sh4_icache = { NULL, -1, -1 };
6.20 +struct sh4_icache_struct sh4_icache = { NULL, -1, -1, 0 };
6.21
6.22 void sh4_set_use_xlat( gboolean use )
6.23 {
7.1 --- a/src/sh4/sh4core.c Tue Jan 01 10:54:22 2008 +0000
7.2 +++ b/src/sh4/sh4core.c Fri Jan 04 11:54:17 2008 +0000
7.3 @@ -38,9 +38,6 @@
7.4
7.5 /********************** SH4 Module Definition ****************************/
7.6
7.7 -uint16_t *sh4_icache = NULL;
7.8 -uint32_t sh4_icache_addr = 0;
7.9 -
7.10 uint32_t sh4_run_slice( uint32_t nanosecs )
7.11 {
7.12 int i;
7.13 @@ -238,20 +235,13 @@
7.14
7.15 /* Read instruction */
7.16 uint32_t pageaddr = pc >> 12;
7.17 - if( sh4_icache != NULL && pageaddr == sh4_icache_addr ) {
7.18 - ir = sh4_icache[(pc&0xFFF)>>1];
7.19 + if( !IS_IN_ICACHE(pc) ) {
7.20 + mmu_update_icache(pc);
7.21 + }
7.22 + if( IS_IN_ICACHE(pc) ) {
7.23 + ir = *(uint16_t *)GET_ICACHE_PTR(pc);
7.24 } else {
7.25 - sh4_icache = (uint16_t *)mem_get_page(pc);
7.26 - if( ((uintptr_t)sh4_icache) < MAX_IO_REGIONS ) {
7.27 - /* If someone's actually been so daft as to try to execute out of an IO
7.28 - * region, fallback on the full-blown memory read
7.29 - */
7.30 - sh4_icache = NULL;
7.31 - MEM_READ_WORD(pc, ir);
7.32 - } else {
7.33 - sh4_icache_addr = pageaddr;
7.34 - ir = sh4_icache[(pc&0xFFF)>>1];
7.35 - }
7.36 + ir = sh4_read_word(pc);
7.37 }
7.38 switch( (ir&0xF000) >> 12 ) {
7.39 case 0x0:
8.1 --- a/src/sh4/sh4core.h Tue Jan 01 10:54:22 2008 +0000
8.2 +++ b/src/sh4/sh4core.h Fri Jan 04 11:54:17 2008 +0000
8.3 @@ -33,6 +33,37 @@
8.4 /* Breakpoint data structure */
8.5 extern struct breakpoint_struct sh4_breakpoints[MAX_BREAKPOINTS];
8.6 extern int sh4_breakpoint_count;
8.7 +extern sh4ptr_t sh4_main_ram;
8.8 +
8.9 +/**
8.10 + * Cached direct pointer to the current instruction page. If AT is on, this
8.11 + * is derived from the ITLB, otherwise this will be the entire memory region.
8.12 + * This is actually a fairly useful optimization, as we can make a lot of
8.13 + * assumptions about the "current page" that we can't make in general for
8.14 + * arbitrary virtual addresses.
8.15 + */
8.16 +struct sh4_icache_struct {
8.17 + sh4ptr_t page; // Page pointer (NULL if no page)
8.18 + sh4vma_t page_vma; // virtual address of the page.
8.19 + sh4addr_t page_ppa; // physical address of the page
8.20 + uint32_t mask; // page mask
8.21 +};
8.22 +extern struct sh4_icache_struct sh4_icache;
8.23 +
8.24 +/**
8.25 + * Test if a given address is contained in the current icache entry
8.26 + */
8.27 +#define IS_IN_ICACHE(addr) (sh4_icache.page_vma == ((addr) & sh4_icache.mask))
8.28 +/**
8.29 + * Return a pointer for the given vma, under the assumption that it is
8.30 + * actually contained in the current icache entry.
8.31 + */
8.32 +#define GET_ICACHE_PTR(addr) (sh4_icache.page + ((addr)-sh4_icache.page_vma))
8.33 +/**
8.34 + * Return the physical (external) address for the given vma, assuming that it is
8.35 + * actually contained in the current icache entry.
8.36 + */
8.37 +#define GET_ICACHE_PHYS(addr) (sh4_icache.page_ppa + ((addr)-sh4_icache.page_vma))
8.38
8.39 /* SH4 module functions */
8.40 void sh4_init( void );
8.41 @@ -74,9 +105,10 @@
8.42 void signsat48(void);
8.43
8.44 /* SH4 Memory */
8.45 -uint64_t mmu_vma_to_phys_read( sh4addr_t addr );
8.46 -uint64_t mmu_vma_to_phys_write( sh4addr_t addr );
8.47 -uint64_t mmu_vma_to_phys_exec( sh4addr_t addr );
8.48 +gboolean mmu_update_icache( sh4vma_t addr );
8.49 +uint64_t mmu_vma_to_phys_read( sh4vma_t addr );
8.50 +uint64_t mmu_vma_to_phys_write( sh4vma_t addr );
8.51 +uint64_t mmu_vma_to_phys_exec( sh4vma_t addr );
8.52
8.53 int64_t sh4_read_quad( sh4addr_t addr );
8.54 int64_t sh4_read_long( sh4addr_t addr );
9.1 --- a/src/sh4/sh4core.in Tue Jan 01 10:54:22 2008 +0000
9.2 +++ b/src/sh4/sh4core.in Fri Jan 04 11:54:17 2008 +0000
9.3 @@ -38,9 +38,6 @@
9.4
9.5 /********************** SH4 Module Definition ****************************/
9.6
9.7 -uint16_t *sh4_icache = NULL;
9.8 -uint32_t sh4_icache_addr = 0;
9.9 -
9.10 uint32_t sh4_run_slice( uint32_t nanosecs )
9.11 {
9.12 int i;
9.13 @@ -238,20 +235,13 @@
9.14
9.15 /* Read instruction */
9.16 uint32_t pageaddr = pc >> 12;
9.17 - if( sh4_icache != NULL && pageaddr == sh4_icache_addr ) {
9.18 - ir = sh4_icache[(pc&0xFFF)>>1];
9.19 + if( !IS_IN_ICACHE(pc) ) {
9.20 + mmu_update_icache(pc);
9.21 + }
9.22 + if( IS_IN_ICACHE(pc) ) {
9.23 + ir = *(uint16_t *)GET_ICACHE_PTR(pc);
9.24 } else {
9.25 - sh4_icache = (uint16_t *)mem_get_page(pc);
9.26 - if( ((uintptr_t)sh4_icache) < MAX_IO_REGIONS ) {
9.27 - /* If someone's actually been so daft as to try to execute out of an IO
9.28 - * region, fallback on the full-blown memory read
9.29 - */
9.30 - sh4_icache = NULL;
9.31 - MEM_READ_WORD(pc, ir);
9.32 - } else {
9.33 - sh4_icache_addr = pageaddr;
9.34 - ir = sh4_icache[(pc&0xFFF)>>1];
9.35 - }
9.36 + ir = sh4_read_word(pc);
9.37 }
9.38 %%
9.39 AND Rm, Rn {: sh4r.r[Rn] &= sh4r.r[Rm]; :}
10.1 --- a/src/sh4/sh4dasm.c Tue Jan 01 10:54:22 2008 +0000
10.2 +++ b/src/sh4/sh4dasm.c Fri Jan 04 11:54:17 2008 +0000
10.3 @@ -1550,19 +1550,16 @@
10.4 }
10.5
10.6
10.7 -void sh4_disasm_region( const gchar *filename, int from, int to )
10.8 +void sh4_disasm_region( FILE *f, int from, int to )
10.9 {
10.10 int pc;
10.11 char buf[80];
10.12 char opcode[16];
10.13 - FILE *f;
10.14
10.15 - f = fopen( filename, "w" );
10.16 for( pc = from; pc < to; pc+=2 ) {
10.17 buf[0] = '\0';
10.18 sh4_disasm_instruction( pc,
10.19 buf, sizeof(buf), opcode );
10.20 fprintf( f, " %08x: %s %s\n", pc, opcode, buf );
10.21 }
10.22 - fclose(f);
10.23 }
11.1 --- a/src/sh4/sh4dasm.h Tue Jan 01 10:54:22 2008 +0000
11.2 +++ b/src/sh4/sh4dasm.h Fri Jan 04 11:54:17 2008 +0000
11.3 @@ -28,7 +28,7 @@
11.4 #include <stdio.h>
11.5
11.6 uint32_t sh4_disasm_instruction( uint32_t pc, char *buf, int len, char * );
11.7 -void sh4_disasm_region( const gchar *filename, int from, int to );
11.8 +void sh4_disasm_region( FILE *f, int from, int to );
11.9
11.10 extern const struct cpu_desc_struct sh4_cpu_desc;
11.11
12.1 --- a/src/sh4/sh4dasm.in Tue Jan 01 10:54:22 2008 +0000
12.2 +++ b/src/sh4/sh4dasm.in Fri Jan 04 11:54:17 2008 +0000
12.3 @@ -285,19 +285,16 @@
12.4 }
12.5
12.6
12.7 -void sh4_disasm_region( const gchar *filename, int from, int to )
12.8 +void sh4_disasm_region( FILE *f, int from, int to )
12.9 {
12.10 int pc;
12.11 char buf[80];
12.12 char opcode[16];
12.13 - FILE *f;
12.14
12.15 - f = fopen( filename, "w" );
12.16 for( pc = from; pc < to; pc+=2 ) {
12.17 buf[0] = '\0';
12.18 sh4_disasm_instruction( pc,
12.19 buf, sizeof(buf), opcode );
12.20 fprintf( f, " %08x: %s %s\n", pc, opcode, buf );
12.21 }
12.22 - fclose(f);
12.23 }
13.1 --- a/src/sh4/sh4mem.c Tue Jan 01 10:54:22 2008 +0000
13.2 +++ b/src/sh4/sh4mem.c Fri Jan 04 11:54:17 2008 +0000
13.3 @@ -67,7 +67,6 @@
13.4
13.5 extern struct mem_region mem_rgn[];
13.6 extern struct mmio_region *P4_io[];
13.7 -sh4ptr_t sh4_main_ram;
13.8
13.9 int32_t sh4_read_p4( sh4addr_t addr )
13.10 {
14.1 --- a/src/sh4/sh4trans.c Tue Jan 01 10:54:22 2008 +0000
14.2 +++ b/src/sh4/sh4trans.c Fri Jan 04 11:54:17 2008 +0000
14.3 @@ -61,19 +61,8 @@
14.4 sh4r.pc = sh4r.pr;
14.5 }
14.6
14.7 - code = xlat_get_code(sh4r.pc);
14.8 + code = xlat_get_code_by_vma( sh4r.pc );
14.9 if( code == NULL ) {
14.10 - uint64_t ppa = mmu_vma_to_phys_exec( sh4r.pc );
14.11 - if( ppa>>32 ) {
14.12 - // not found, exception
14.13 - ppa = mmu_vma_to_phys_exec( sh4r.pc );
14.14 - if( ppa>>32 ) {
14.15 - // double fault - halt
14.16 - dreamcast_stop();
14.17 - ERROR( "Double fault - halting" );
14.18 - return nanosecs;
14.19 - }
14.20 - }
14.21 code = sh4_translate_basic_block( sh4r.pc );
14.22 }
14.23 }
15.1 --- a/src/sh4/sh4x86.c Tue Jan 01 10:54:22 2008 +0000
15.2 +++ b/src/sh4/sh4x86.c Fri Jan 04 11:54:17 2008 +0000
15.3 @@ -318,9 +318,6 @@
15.4
15.5 #define SLOTILLEGAL() JMP_exc(EXC_SLOT_ILLEGAL); sh4_x86.in_delay_slot = FALSE; return 1;
15.6
15.7 -extern uint16_t *sh4_icache;
15.8 -extern uint32_t sh4_icache_addr;
15.9 -
15.10 /****** Import appropriate calling conventions ******/
15.11 #if SH4_TRANSLATOR == TARGET_X86_64
15.12 #include "sh4/ia64abi.h"
15.13 @@ -345,24 +342,11 @@
15.14 {
15.15 uint32_t ir;
15.16 /* Read instruction */
15.17 - uint32_t pageaddr = pc >> 12;
15.18 - if( sh4_icache != NULL && pageaddr == sh4_icache_addr ) {
15.19 - ir = sh4_icache[(pc&0xFFF)>>1];
15.20 + if( IS_IN_ICACHE(pc) ) {
15.21 + ir = *(uint16_t *)GET_ICACHE_PTR(pc);
15.22 } else {
15.23 - uint64_t phys = mmu_vma_to_phys_exec(pc);
15.24 - sh4_icache = (uint16_t *)mem_get_page((uint32_t)phys);
15.25 - if( ((uintptr_t)sh4_icache) < MAX_IO_REGIONS ) {
15.26 - /* If someone's actually been so daft as to try to execute out of an IO
15.27 - * region, fallback on the full-blown memory read
15.28 - */
15.29 - sh4_icache = NULL;
15.30 - ir = sh4_read_word(pc);
15.31 - } else {
15.32 - sh4_icache_addr = pageaddr;
15.33 - ir = sh4_icache[(pc&0xFFF)>>1];
15.34 - }
15.35 + ir = sh4_read_word(pc);
15.36 }
15.37 -
15.38 switch( (ir&0xF000) >> 12 ) {
15.39 case 0x0:
15.40 switch( ir&0xF ) {
15.41 @@ -2367,10 +2351,19 @@
15.42 if( sh4_x86.in_delay_slot ) {
15.43 SLOTILLEGAL();
15.44 } else {
15.45 - load_imm32( R_ECX, pc + disp + 4 );
15.46 - MEM_READ_WORD( R_ECX, R_EAX );
15.47 + // See comments for MOV.L @(disp, PC), Rn
15.48 + uint32_t target = pc + disp + 4;
15.49 + if( IS_IN_ICACHE(target) ) {
15.50 + sh4ptr_t ptr = GET_ICACHE_PTR(target);
15.51 + MOV_moff32_EAX( ptr );
15.52 + MOVSX_r16_r32( R_EAX, R_EAX );
15.53 + } else {
15.54 + load_imm32( R_ECX, (pc - sh4_x86.block_start_pc) + disp + 4 );
15.55 + ADD_sh4r_r32( R_PC, R_ECX );
15.56 + MEM_READ_WORD( R_ECX, R_EAX );
15.57 + sh4_x86.tstate = TSTATE_NONE;
15.58 + }
15.59 store_reg( R_EAX, Rn );
15.60 - sh4_x86.tstate = TSTATE_NONE;
15.61 }
15.62 }
15.63 break;
15.64 @@ -2493,7 +2486,8 @@
15.65 if( sh4_x86.in_delay_slot ) {
15.66 SLOTILLEGAL();
15.67 } else {
15.68 - load_imm32( R_ECX, (pc & 0xFFFFFFFC) + disp + 4 );
15.69 + load_imm32( R_ECX, (pc - sh4_x86.block_start_pc) + disp + 4 - (pc&0x03) );
15.70 + ADD_sh4r_r32( R_PC, R_ECX );
15.71 store_reg( R_ECX, 0 );
15.72 }
15.73 }
15.74 @@ -2597,15 +2591,28 @@
15.75 SLOTILLEGAL();
15.76 } else {
15.77 uint32_t target = (pc & 0xFFFFFFFC) + disp + 4;
15.78 - sh4ptr_t ptr = sh4_get_region_by_vma(target);
15.79 - if( ptr != NULL ) {
15.80 + if( IS_IN_ICACHE(target) ) {
15.81 + // If the target address is in the same page as the code, it's
15.82 + // pretty safe to just ref it directly and circumvent the whole
15.83 + // memory subsystem. (this is a big performance win)
15.84 +
15.85 + // FIXME: There's a corner-case that's not handled here when
15.86 + // the current code-page is in the ITLB but not in the UTLB.
15.87 + // (should generate a TLB miss although need to test SH4
15.88 + // behaviour to confirm) Unlikely to be anyone depending on this
15.89 + // behaviour though.
15.90 + sh4ptr_t ptr = GET_ICACHE_PTR(target);
15.91 MOV_moff32_EAX( ptr );
15.92 } else {
15.93 - load_imm32( R_ECX, target );
15.94 + // Note: we use sh4r.pc for the calc as we could be running at a
15.95 + // different virtual address than the translation was done with,
15.96 + // but we can safely assume that the low bits are the same.
15.97 + load_imm32( R_ECX, (pc-sh4_x86.block_start_pc) + disp + 4 - (pc&0x03) );
15.98 + ADD_sh4r_r32( R_PC, R_ECX );
15.99 MEM_READ_LONG( R_ECX, R_EAX );
15.100 + sh4_x86.tstate = TSTATE_NONE;
15.101 }
15.102 store_reg( R_EAX, Rn );
15.103 - sh4_x86.tstate = TSTATE_NONE;
15.104 }
15.105 }
15.106 break;
16.1 --- a/src/sh4/sh4x86.in Tue Jan 01 10:54:22 2008 +0000
16.2 +++ b/src/sh4/sh4x86.in Fri Jan 04 11:54:17 2008 +0000
16.3 @@ -318,9 +318,6 @@
16.4
16.5 #define SLOTILLEGAL() JMP_exc(EXC_SLOT_ILLEGAL); sh4_x86.in_delay_slot = FALSE; return 1;
16.6
16.7 -extern uint16_t *sh4_icache;
16.8 -extern uint32_t sh4_icache_addr;
16.9 -
16.10 /****** Import appropriate calling conventions ******/
16.11 #if SH4_TRANSLATOR == TARGET_X86_64
16.12 #include "sh4/ia64abi.h"
16.13 @@ -345,24 +342,11 @@
16.14 {
16.15 uint32_t ir;
16.16 /* Read instruction */
16.17 - uint32_t pageaddr = pc >> 12;
16.18 - if( sh4_icache != NULL && pageaddr == sh4_icache_addr ) {
16.19 - ir = sh4_icache[(pc&0xFFF)>>1];
16.20 + if( IS_IN_ICACHE(pc) ) {
16.21 + ir = *(uint16_t *)GET_ICACHE_PTR(pc);
16.22 } else {
16.23 - uint64_t phys = mmu_vma_to_phys_exec(pc);
16.24 - sh4_icache = (uint16_t *)mem_get_page((uint32_t)phys);
16.25 - if( ((uintptr_t)sh4_icache) < MAX_IO_REGIONS ) {
16.26 - /* If someone's actually been so daft as to try to execute out of an IO
16.27 - * region, fallback on the full-blown memory read
16.28 - */
16.29 - sh4_icache = NULL;
16.30 - ir = sh4_read_word(pc);
16.31 - } else {
16.32 - sh4_icache_addr = pageaddr;
16.33 - ir = sh4_icache[(pc&0xFFF)>>1];
16.34 - }
16.35 + ir = sh4_read_word(pc);
16.36 }
16.37 -
16.38 %%
16.39 /* ALU operations */
16.40 ADD Rm, Rn {:
16.41 @@ -1126,15 +1110,28 @@
16.42 SLOTILLEGAL();
16.43 } else {
16.44 uint32_t target = (pc & 0xFFFFFFFC) + disp + 4;
16.45 - sh4ptr_t ptr = sh4_get_region_by_vma(target);
16.46 - if( ptr != NULL ) {
16.47 + if( IS_IN_ICACHE(target) ) {
16.48 + // If the target address is in the same page as the code, it's
16.49 + // pretty safe to just ref it directly and circumvent the whole
16.50 + // memory subsystem. (this is a big performance win)
16.51 +
16.52 + // FIXME: There's a corner-case that's not handled here when
16.53 + // the current code-page is in the ITLB but not in the UTLB.
16.54 + // (should generate a TLB miss although need to test SH4
16.55 + // behaviour to confirm) Unlikely to be anyone depending on this
16.56 + // behaviour though.
16.57 + sh4ptr_t ptr = GET_ICACHE_PTR(target);
16.58 MOV_moff32_EAX( ptr );
16.59 } else {
16.60 - load_imm32( R_ECX, target );
16.61 + // Note: we use sh4r.pc for the calc as we could be running at a
16.62 + // different virtual address than the translation was done with,
16.63 + // but we can safely assume that the low bits are the same.
16.64 + load_imm32( R_ECX, (pc-sh4_x86.block_start_pc) + disp + 4 - (pc&0x03) );
16.65 + ADD_sh4r_r32( R_PC, R_ECX );
16.66 MEM_READ_LONG( R_ECX, R_EAX );
16.67 + sh4_x86.tstate = TSTATE_NONE;
16.68 }
16.69 store_reg( R_EAX, Rn );
16.70 - sh4_x86.tstate = TSTATE_NONE;
16.71 }
16.72 :}
16.73 MOV.L @(disp, Rm), Rn {:
16.74 @@ -1224,10 +1221,19 @@
16.75 if( sh4_x86.in_delay_slot ) {
16.76 SLOTILLEGAL();
16.77 } else {
16.78 - load_imm32( R_ECX, pc + disp + 4 );
16.79 - MEM_READ_WORD( R_ECX, R_EAX );
16.80 + // See comments for MOV.L @(disp, PC), Rn
16.81 + uint32_t target = pc + disp + 4;
16.82 + if( IS_IN_ICACHE(target) ) {
16.83 + sh4ptr_t ptr = GET_ICACHE_PTR(target);
16.84 + MOV_moff32_EAX( ptr );
16.85 + MOVSX_r16_r32( R_EAX, R_EAX );
16.86 + } else {
16.87 + load_imm32( R_ECX, (pc - sh4_x86.block_start_pc) + disp + 4 );
16.88 + ADD_sh4r_r32( R_PC, R_ECX );
16.89 + MEM_READ_WORD( R_ECX, R_EAX );
16.90 + sh4_x86.tstate = TSTATE_NONE;
16.91 + }
16.92 store_reg( R_EAX, Rn );
16.93 - sh4_x86.tstate = TSTATE_NONE;
16.94 }
16.95 :}
16.96 MOV.W @(disp, Rm), R0 {:
16.97 @@ -1242,7 +1248,8 @@
16.98 if( sh4_x86.in_delay_slot ) {
16.99 SLOTILLEGAL();
16.100 } else {
16.101 - load_imm32( R_ECX, (pc & 0xFFFFFFFC) + disp + 4 );
16.102 + load_imm32( R_ECX, (pc - sh4_x86.block_start_pc) + disp + 4 - (pc&0x03) );
16.103 + ADD_sh4r_r32( R_PC, R_ECX );
16.104 store_reg( R_ECX, 0 );
16.105 }
16.106 :}
17.1 --- a/src/sh4/x86op.h Tue Jan 01 10:54:22 2008 +0000
17.2 +++ b/src/sh4/x86op.h Fri Jan 04 11:54:17 2008 +0000
17.3 @@ -99,6 +99,7 @@
17.4 #define R_VBR REG_OFFSET(vbr)
17.5 #define R_MACH REG_OFFSET(mac)+4
17.6 #define R_MACL REG_OFFSET(mac)
17.7 +#define R_PC REG_OFFSET(pc)
17.8 #define R_PR REG_OFFSET(pr)
17.9 #define R_SGR REG_OFFSET(sgr)
17.10 #define R_FPUL REG_OFFSET(fpul)
18.1 --- a/src/sh4/xltcache.c Tue Jan 01 10:54:22 2008 +0000
18.2 +++ b/src/sh4/xltcache.c Fri Jan 04 11:54:17 2008 +0000
18.3 @@ -21,6 +21,7 @@
18.4 #include <assert.h>
18.5
18.6 #include "dreamcast.h"
18.7 +#include "sh4/sh4core.h"
18.8 #include "sh4/xltcache.h"
18.9 #include "x86dasm/x86dasm.h"
18.10
18.11 @@ -207,6 +208,29 @@
18.12 return result;
18.13 }
18.14
18.15 +void *xlat_get_code_by_vma( sh4vma_t vma )
18.16 +{
18.17 + void *result = NULL;
18.18 +
18.19 +
18.20 + if( !IS_IN_ICACHE(vma) ) {
18.21 + if( !mmu_update_icache(sh4r.pc) ) {
18.22 + // fault - off to the fault handler
18.23 + if( !mmu_update_icache(sh4r.pc) ) {
18.24 + // double fault - halt
18.25 + dreamcast_stop();
18.26 + ERROR( "Double fault - halting" );
18.27 + return NULL;
18.28 + }
18.29 + }
18.30 + }
18.31 + if( sh4_icache.page_vma != -1 ) {
18.32 + result = xlat_get_code( GET_ICACHE_PHYS(vma) );
18.33 + }
18.34 +
18.35 + return result;
18.36 +}
18.37 +
18.38 void **xlat_get_lut_entry( sh4addr_t address )
18.39 {
18.40 void **page = xlat_lut[XLAT_LUT_PAGE(address)];
19.1 --- a/src/sh4/xltcache.h Tue Jan 01 10:54:22 2008 +0000
19.2 +++ b/src/sh4/xltcache.h Fri Jan 04 11:54:17 2008 +0000
19.3 @@ -74,6 +74,14 @@
19.4 void *xlat_get_code( sh4addr_t address );
19.5
19.6 /**
19.7 + * Retrieve the entry point for the translated code corresponding to the given
19.8 + * SH4 virtual address, or NULL if there is no code for the address.
19.9 + * If the virtual address cannot be resolved, this method will raise a TLB miss
19.10 + * exception, and return NULL.
19.11 + */
19.12 +void *xlat_get_code_by_vma( sh4vma_t address );
19.13 +
19.14 +/**
19.15 * Retrieve the address of the lookup table entry corresponding to the
19.16 * given SH4 address.
19.17 */
.