revision 569:a1c49e1e8776
summary |
tree |
shortlog |
changelog |
graph |
changeset |
raw | bz2 | zip | gz changeset | 569:a1c49e1e8776 |
parent | 568:61e7bb716644 |
child | 570:d2893980fbf5 |
author | nkeynes |
date | Fri Jan 04 11:54:17 2008 +0000 (16 years ago) |
branch | lxdream-mmu |
Bring icache partially into line with the mmu, a little less slow with AT off
now.
now.
src/lxdream.h | view | annotate | diff | log | ||
src/sh4/ia32abi.h | view | annotate | diff | log | ||
src/sh4/ia32mac.h | view | annotate | diff | log | ||
src/sh4/ia64abi.h | view | annotate | diff | log | ||
src/sh4/mmu.c | view | annotate | diff | log | ||
src/sh4/sh4.c | view | annotate | diff | log | ||
src/sh4/sh4core.c | view | annotate | diff | log | ||
src/sh4/sh4core.h | view | annotate | diff | log | ||
src/sh4/sh4core.in | view | annotate | diff | log | ||
src/sh4/sh4dasm.c | view | annotate | diff | log | ||
src/sh4/sh4dasm.h | view | annotate | diff | log | ||
src/sh4/sh4dasm.in | view | annotate | diff | log | ||
src/sh4/sh4mem.c | view | annotate | diff | log | ||
src/sh4/sh4trans.c | view | annotate | diff | log | ||
src/sh4/sh4x86.c | view | annotate | diff | log | ||
src/sh4/sh4x86.in | view | annotate | diff | log | ||
src/sh4/x86op.h | view | annotate | diff | log | ||
src/sh4/xltcache.c | view | annotate | diff | log | ||
src/sh4/xltcache.h | view | annotate | diff | log |
1.1 --- a/src/lxdream.h Tue Jan 01 10:54:22 2008 +00001.2 +++ b/src/lxdream.h Fri Jan 04 11:54:17 2008 +00001.3 @@ -39,9 +39,15 @@1.4 #endif1.6 /**1.7 - * A 32-bit address in SH4 space1.8 + * A 29-bit address in SH4 external address space1.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 memory1.19 */
2.1 --- a/src/sh4/ia32abi.h Tue Jan 01 10:54:22 2008 +00002.2 +++ b/src/sh4/ia32abi.h Fri Jan 04 11:54:17 2008 +00002.3 @@ -119,12 +119,12 @@2.4 * Exit the block with sh4r.pc already written2.5 * Bytes: 152.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 ); // 52.11 ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 62.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.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();
3.1 --- a/src/sh4/ia32mac.h Tue Jan 01 10:54:22 2008 +00003.2 +++ b/src/sh4/ia32mac.h Fri Jan 04 11:54:17 2008 +00003.3 @@ -142,12 +142,12 @@3.4 * Exit the block with sh4r.pc already written3.5 * Bytes: 153.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 ); // 53.11 ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 63.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.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();
4.1 --- a/src/sh4/ia64abi.h Tue Jan 01 10:54:22 2008 +00004.2 +++ b/src/sh4/ia64abi.h Fri Jan 04 11:54:17 2008 +00004.3 @@ -109,12 +109,12 @@4.4 * Exit the block with sh4r.pc already written4.5 * Bytes: 154.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 ); // 54.11 ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 64.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.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.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();
5.1 --- a/src/sh4/mmu.c Tue Jan 01 10:54:22 2008 +00005.2 +++ b/src/sh4/mmu.c Fri Jan 04 11:54:17 2008 +00005.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 asid5.9 static sh4ptr_t cache = NULL;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 changed5.18 + }5.19 break;5.20 case PTEL:5.21 val &= 0x1FFFFDFF;5.22 @@ -234,17 +239,15 @@5.23 */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 found5.30 * -1 No match - raise a tlb data miss exception5.31 * -2 Multiple matches - raise a multi-hit exception (reset)5.32 * @param vpn virtual address to resolve5.33 - * @param asid Address space identifier5.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.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.78 /**5.79 + * Perform the actual utlb lookup matching on vpn only5.80 + * Possible utcomes are:5.81 + * 0..63 Single match - good, return entry found5.82 + * -1 No match - raise a tlb data miss exception5.83 + * -2 Multiple matches - raise a multi-hit exception (reset)5.84 + * @param vpn virtual address to resolve5.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 normal5.112 * lookup but ignores the valid bit.5.113 */5.114 @@ -300,53 +323,9 @@5.115 }5.117 /**5.118 - * Perform the actual itlb lookup.5.119 - * Possible utcomes are:5.120 - * 0..63 Single match - good, return entry found5.121 - * -1 No match - raise a tlb data miss exception5.122 - * -2 Multiple matches - raise a multi-hit exception (reset)5.123 - * @param vpn virtual address to resolve5.124 - * @param asid Address space identifier5.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.173 /**5.174 + * Perform the actual itlb lookup w/ asid protection5.175 + * Possible utcomes are:5.176 + * 0..63 Single match - good, return entry found5.177 + * -1 No match - raise a tlb data miss exception5.178 + * -2 Multiple matches - raise a multi-hit exception (reset)5.179 + * @param vpn virtual address to resolve5.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 only5.219 + * Possible utcomes are:5.220 + * 0..63 Single match - good, return entry found5.221 + * -1 No match - raise a tlb data miss exception5.222 + * -2 Multiple matches - raise a multi-hit exception (reset)5.223 + * @param vpn virtual address to resolve5.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 normal5.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.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.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.284 /**5.285 * Abort with a non-MMU address error. Caused by user-mode code attempting5.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.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.304 @@ -450,28 +513,31 @@5.305 }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.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.337 if( (mmu_utlb[entryNo].flags & TLB_DIRTY) == 0 ) {5.338 MMU_TLB_INITIAL_WRITE_ERROR(addr);5.339 + return 0x100000000LL;5.340 }5.342 /* finally generate the target address */5.343 @@ -482,64 +548,6 @@5.345 }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.416 @@ -564,24 +573,26 @@5.417 }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.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.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 address5.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 the5.480 + * given vma. If the address does not reference a RAM/ROM region, the icache5.481 + * will be invalidated instead.5.482 + * If AT is on, this method will raise TLB exceptions normally5.483 + * (hence this method should only be used immediately prior to execution of5.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 in5.486 + * the icache.5.487 + * @return TRUE if the update completed (successfully or otherwise), FALSE5.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 +00006.2 +++ b/src/sh4/sh4.c Fri Jan 04 11:54:17 2008 +00006.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.22 void sh4_set_use_xlat( gboolean use )6.23 {
7.1 --- a/src/sh4/sh4core.c Tue Jan 01 10:54:22 2008 +00007.2 +++ b/src/sh4/sh4core.c Fri Jan 04 11:54:17 2008 +00007.3 @@ -38,9 +38,6 @@7.5 /********************** SH4 Module Definition ****************************/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.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 IO7.28 - * region, fallback on the full-blown memory read7.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 +00008.2 +++ b/src/sh4/sh4core.h Fri Jan 04 11:54:17 2008 +00008.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, this8.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 of8.13 + * assumptions about the "current page" that we can't make in general for8.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 page8.20 + uint32_t mask; // page mask8.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 entry8.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 is8.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 is8.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.39 /* SH4 module functions */8.40 void sh4_init( void );8.41 @@ -74,9 +105,10 @@8.42 void signsat48(void);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.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 +00009.2 +++ b/src/sh4/sh4core.in Fri Jan 04 11:54:17 2008 +00009.3 @@ -38,9 +38,6 @@9.5 /********************** SH4 Module Definition ****************************/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.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 IO9.28 - * region, fallback on the full-blown memory read9.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 +000010.2 +++ b/src/sh4/sh4dasm.c Fri Jan 04 11:54:17 2008 +000010.3 @@ -1550,19 +1550,16 @@10.4 }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.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 +000011.2 +++ b/src/sh4/sh4dasm.h Fri Jan 04 11:54:17 2008 +000011.3 @@ -28,7 +28,7 @@11.4 #include <stdio.h>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.10 extern const struct cpu_desc_struct sh4_cpu_desc;
12.1 --- a/src/sh4/sh4dasm.in Tue Jan 01 10:54:22 2008 +000012.2 +++ b/src/sh4/sh4dasm.in Fri Jan 04 11:54:17 2008 +000012.3 @@ -285,19 +285,16 @@12.4 }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.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 +000013.2 +++ b/src/sh4/sh4mem.c Fri Jan 04 11:54:17 2008 +000013.3 @@ -67,7 +67,6 @@13.5 extern struct mem_region mem_rgn[];13.6 extern struct mmio_region *P4_io[];13.7 -sh4ptr_t sh4_main_ram;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 +000014.2 +++ b/src/sh4/sh4trans.c Fri Jan 04 11:54:17 2008 +000014.3 @@ -61,19 +61,8 @@14.4 sh4r.pc = sh4r.pr;14.5 }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, exception14.13 - ppa = mmu_vma_to_phys_exec( sh4r.pc );14.14 - if( ppa>>32 ) {14.15 - // double fault - halt14.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 +000015.2 +++ b/src/sh4/sh4x86.c Fri Jan 04 11:54:17 2008 +000015.3 @@ -318,9 +318,6 @@15.5 #define SLOTILLEGAL() JMP_exc(EXC_SLOT_ILLEGAL); sh4_x86.in_delay_slot = FALSE; return 1;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_6415.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 IO15.27 - * region, fallback on the full-blown memory read15.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), Rn15.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's15.82 + // pretty safe to just ref it directly and circumvent the whole15.83 + // memory subsystem. (this is a big performance win)15.84 +15.85 + // FIXME: There's a corner-case that's not handled here when15.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 SH415.88 + // behaviour to confirm) Unlikely to be anyone depending on this15.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 a15.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 +000016.2 +++ b/src/sh4/sh4x86.in Fri Jan 04 11:54:17 2008 +000016.3 @@ -318,9 +318,6 @@16.5 #define SLOTILLEGAL() JMP_exc(EXC_SLOT_ILLEGAL); sh4_x86.in_delay_slot = FALSE; return 1;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_6416.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 IO16.27 - * region, fallback on the full-blown memory read16.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's16.49 + // pretty safe to just ref it directly and circumvent the whole16.50 + // memory subsystem. (this is a big performance win)16.51 +16.52 + // FIXME: There's a corner-case that's not handled here when16.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 SH416.55 + // behaviour to confirm) Unlikely to be anyone depending on this16.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 a16.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), Rn16.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 +000017.2 +++ b/src/sh4/x86op.h Fri Jan 04 11:54:17 2008 +000017.3 @@ -99,6 +99,7 @@17.4 #define R_VBR REG_OFFSET(vbr)17.5 #define R_MACH REG_OFFSET(mac)+417.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 +000018.2 +++ b/src/sh4/xltcache.c Fri Jan 04 11:54:17 2008 +000018.3 @@ -21,6 +21,7 @@18.4 #include <assert.h>18.6 #include "dreamcast.h"18.7 +#include "sh4/sh4core.h"18.8 #include "sh4/xltcache.h"18.9 #include "x86dasm/x86dasm.h"18.11 @@ -207,6 +208,29 @@18.12 return result;18.13 }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 handler18.23 + if( !mmu_update_icache(sh4r.pc) ) {18.24 + // double fault - halt18.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 +000019.2 +++ b/src/sh4/xltcache.h Fri Jan 04 11:54:17 2008 +000019.3 @@ -74,6 +74,14 @@19.4 void *xlat_get_code( sh4addr_t address );19.6 /**19.7 + * Retrieve the entry point for the translated code corresponding to the given19.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 miss19.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 the19.16 * given SH4 address.19.17 */
.