25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: cpu_mips_coproc.c,v 1.11 2005/03/15 06:52:14 debug Exp $ |
* $Id: cpu_mips_coproc.c,v 1.17 2005/04/22 16:03:43 debug Exp $ |
29 |
* |
* |
30 |
* Emulation of MIPS coprocessors. |
* Emulation of MIPS coprocessors. |
31 |
*/ |
*/ |
684 |
for (a=0; a<0x400; a++) { |
for (a=0; a<0x400; a++) { |
685 |
tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a]; |
tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a]; |
686 |
if (tbl1 != cpu->cd.mips.vaddr_to_hostaddr_nulltable) { |
if (tbl1 != cpu->cd.mips.vaddr_to_hostaddr_nulltable) { |
687 |
for (b=0; b<0x400; b++) |
for (b=0; b<0x400; b++) { |
688 |
|
tbl1->haddr_entry[b] = NULL; |
689 |
|
tbl1->paddr_entry[b] = 0; |
690 |
tbl1->bintrans_chunks[b] = NULL; |
tbl1->bintrans_chunks[b] = NULL; |
691 |
|
} |
692 |
} |
} |
693 |
} |
} |
694 |
} |
} |
952 |
if (cp->coproc_nr==0 && reg_nr==COP0_PAGEMASK) unimpl = 0; |
if (cp->coproc_nr==0 && reg_nr==COP0_PAGEMASK) unimpl = 0; |
953 |
if (cp->coproc_nr==0 && reg_nr==COP0_WIRED) unimpl = 0; |
if (cp->coproc_nr==0 && reg_nr==COP0_WIRED) unimpl = 0; |
954 |
if (cp->coproc_nr==0 && reg_nr==COP0_BADVADDR) unimpl = 0; |
if (cp->coproc_nr==0 && reg_nr==COP0_BADVADDR) unimpl = 0; |
955 |
if (cp->coproc_nr==0 && reg_nr==COP0_COUNT) unimpl = 0; |
if (cp->coproc_nr==0 && reg_nr==COP0_COUNT) { |
956 |
|
/* |
957 |
|
* This speeds up delay-loops that just read the count |
958 |
|
* register until it has reached a certain value. (Only for |
959 |
|
* R4000 etc.) |
960 |
|
* |
961 |
|
* TODO: Maybe this should be optional? |
962 |
|
*/ |
963 |
|
if (cpu->cd.mips.cpu_type.exc_model != EXC3K) { |
964 |
|
int increase = 500; |
965 |
|
int32_t x = cp->reg[COP0_COUNT]; |
966 |
|
int32_t y = cp->reg[COP0_COMPARE]; |
967 |
|
int32_t diff = x - y; |
968 |
|
if (diff < 0 && diff + increase >= 0 |
969 |
|
&& cpu->cd.mips.compare_register_set) { |
970 |
|
mips_cpu_interrupt(cpu, 7); |
971 |
|
cpu->cd.mips.compare_register_set = 0; |
972 |
|
} |
973 |
|
cp->reg[COP0_COUNT] = (int64_t) |
974 |
|
(int32_t)(cp->reg[COP0_COUNT] + increase); |
975 |
|
} |
976 |
|
|
977 |
|
unimpl = 0; |
978 |
|
} |
979 |
if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYHI) unimpl = 0; |
if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYHI) unimpl = 0; |
980 |
if (cp->coproc_nr==0 && reg_nr==COP0_COMPARE) unimpl = 0; |
if (cp->coproc_nr==0 && reg_nr==COP0_COMPARE) unimpl = 0; |
981 |
if (cp->coproc_nr==0 && reg_nr==COP0_STATUS) unimpl = 0; |
if (cp->coproc_nr==0 && reg_nr==COP0_STATUS) unimpl = 0; |
1198 |
case COP0_STATUS: |
case COP0_STATUS: |
1199 |
oldmode = cp->reg[COP0_STATUS]; |
oldmode = cp->reg[COP0_STATUS]; |
1200 |
tmp &= ~(1 << 21); /* bit 21 is read-only */ |
tmp &= ~(1 << 21); /* bit 21 is read-only */ |
1201 |
|
#if 0 |
1202 |
|
/* Why was this here? It should not be necessary. */ |
1203 |
|
|
1204 |
/* Changing from kernel to user mode? Then |
/* Changing from kernel to user mode? Then |
1205 |
invalidate some translation caches: */ |
invalidate some translation caches: */ |
1206 |
if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) { |
if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) { |
1214 |
invalidate_translation_caches( |
invalidate_translation_caches( |
1215 |
cpu, 0, 0, 1, 0); |
cpu, 0, 0, 1, 0); |
1216 |
} |
} |
1217 |
|
#endif |
1218 |
|
|
1219 |
|
#ifdef BINTRANS |
1220 |
|
if (cpu->cd.mips.cpu_type.mmu_model == MMU3K && |
1221 |
|
(oldmode & MIPS1_ISOL_CACHES) != |
1222 |
|
(tmp & MIPS1_ISOL_CACHES)) { |
1223 |
|
/* R3000-style caches when isolated are |
1224 |
|
treated in bintrans mode by changing |
1225 |
|
the vaddr_to_hostaddr_table0 pointer: */ |
1226 |
|
if (tmp & MIPS1_ISOL_CACHES) { |
1227 |
|
/* cpu->cd.mips. |
1228 |
|
dont_run_next_bintrans = 1; */ |
1229 |
|
cpu->cd.mips.vaddr_to_hostaddr_table0 = |
1230 |
|
tmp & MIPS1_SWAP_CACHES? |
1231 |
|
cpu->cd.mips. |
1232 |
|
vaddr_to_hostaddr_table0_cacheisol_i |
1233 |
|
: cpu->cd.mips. |
1234 |
|
vaddr_to_hostaddr_table0_cacheisol_d; |
1235 |
|
} else { |
1236 |
|
cpu->cd.mips.vaddr_to_hostaddr_table0 = |
1237 |
|
cpu->cd.mips. |
1238 |
|
vaddr_to_hostaddr_table0_kernel; |
1239 |
|
|
1240 |
|
/* TODO: cpu->cd.mips. |
1241 |
|
vaddr_to_hostaddr_table0_user; */ |
1242 |
|
} |
1243 |
|
} |
1244 |
|
#endif |
1245 |
unimpl = 0; |
unimpl = 0; |
1246 |
break; |
break; |
1247 |
case COP0_CAUSE: |
case COP0_CAUSE: |
2264 |
|
|
2265 |
/* TODO: Bug? Why does this if need to be commented out? */ |
/* TODO: Bug? Why does this if need to be commented out? */ |
2266 |
|
|
2267 |
/* if (cp->tlbs[index].lo0 & ENTRYLO_V) */ |
/* if (cp->tlbs[index].lo0 & ENTRYLO_V) */ |
2268 |
invalidate_translation_caches(cpu, 0, oldvaddr, 0, 0); |
invalidate_translation_caches(cpu, 0, oldvaddr, 0, 0); |
2269 |
break; |
break; |
2270 |
default: |
default: |
2293 |
} |
} |
2294 |
|
|
2295 |
|
|
2296 |
|
/* |
2297 |
|
* Check for duplicate entries. (There should not be two mappings |
2298 |
|
* from one virtual address to physical addresses.) |
2299 |
|
* |
2300 |
|
* TODO: Do this for MMU3K and R4100 too. |
2301 |
|
* |
2302 |
|
* TODO: Make this detection more robust. |
2303 |
|
*/ |
2304 |
|
if (cpu->cd.mips.cpu_type.mmu_model != MMU3K && |
2305 |
|
cpu->cd.mips.cpu_type.rev != MIPS_R4100) { |
2306 |
|
uint64_t vaddr1, vaddr2; |
2307 |
|
int i, asid; |
2308 |
|
|
2309 |
|
vaddr1 = cp->reg[COP0_ENTRYHI] & ENTRYHI_VPN2_MASK_R10K; |
2310 |
|
asid = cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID; |
2311 |
|
/* Since this is just a warning, it's probably not necessary |
2312 |
|
to use R4000 masks etc. */ |
2313 |
|
|
2314 |
|
for (i=0; i<cp->nr_of_tlbs; i++) { |
2315 |
|
if (i == index && !randomflag) |
2316 |
|
continue; |
2317 |
|
|
2318 |
|
if (!(cp->tlbs[i].hi & TLB_G) && |
2319 |
|
(cp->tlbs[i].hi & ENTRYHI_ASID) != asid) |
2320 |
|
continue; |
2321 |
|
|
2322 |
|
vaddr2 = cp->tlbs[i].hi & ENTRYHI_VPN2_MASK_R10K; |
2323 |
|
if (vaddr1 == vaddr2 && ((cp->tlbs[i].lo0 & |
2324 |
|
ENTRYLO_V) || (cp->tlbs[i].lo1 & ENTRYLO_V))) |
2325 |
|
fatal("\n[ WARNING! tlbw%s vaddr=0x%llx is " |
2326 |
|
"already in the TLB! ]\n\n", randomflag? |
2327 |
|
"r" : "i", (long long)vaddr1); |
2328 |
|
} |
2329 |
|
} |
2330 |
|
|
2331 |
|
|
2332 |
/* Write the new entry: */ |
/* Write the new entry: */ |
2333 |
|
|
2334 |
if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) { |
if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) { |
2462 |
(cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & 1) == 0) |
(cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & 1) == 0) |
2463 |
newmode = 1; |
newmode = 1; |
2464 |
|
|
2465 |
|
#if 0 |
2466 |
/* Changing from kernel to user mode? |
/* Changing from kernel to user mode? |
2467 |
Then this is necessary: TODO */ |
Then this is necessary: TODO */ |
2468 |
if (oldmode && !newmode) |
if (oldmode && !newmode) |
2469 |
invalidate_translation_caches(cpu, 0, 0, 1, 0); |
invalidate_translation_caches(cpu, 0, 0, 1, 0); |
2470 |
|
#endif |
2471 |
} |
} |
2472 |
|
|
2473 |
|
|