25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: cpu_mips_instr.c,v 1.87 2006/06/25 02:46:08 debug Exp $ |
* $Id: cpu_mips_instr.c,v 1.97 2006/07/20 03:20:03 debug Exp $ |
29 |
* |
* |
30 |
* MIPS instructions. |
* MIPS instructions. |
31 |
* |
* |
135 |
} |
} |
136 |
cpu->delay_slot = NOT_DELAYED; |
cpu->delay_slot = NOT_DELAYED; |
137 |
} |
} |
138 |
|
X(beq_samepage_addiu) |
139 |
|
{ |
140 |
|
MODE_uint_t rs = reg(ic->arg[0]), rt = reg(ic->arg[1]); |
141 |
|
cpu->n_translated_instrs ++; |
142 |
|
reg(ic[1].arg[1]) = (int32_t) |
143 |
|
((int32_t)reg(ic[1].arg[0]) + (int32_t)ic[1].arg[2]); |
144 |
|
if (rs == rt) |
145 |
|
cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2]; |
146 |
|
else |
147 |
|
cpu->cd.mips.next_ic ++; |
148 |
|
} |
149 |
|
X(beq_samepage_nop) |
150 |
|
{ |
151 |
|
MODE_uint_t rs = reg(ic->arg[0]), rt = reg(ic->arg[1]); |
152 |
|
cpu->n_translated_instrs ++; |
153 |
|
if (rs == rt) |
154 |
|
cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2]; |
155 |
|
else |
156 |
|
cpu->cd.mips.next_ic ++; |
157 |
|
} |
158 |
X(bne) |
X(bne) |
159 |
{ |
{ |
160 |
MODE_int_t old_pc = cpu->pc; |
MODE_int_t old_pc = cpu->pc; |
192 |
} |
} |
193 |
cpu->delay_slot = NOT_DELAYED; |
cpu->delay_slot = NOT_DELAYED; |
194 |
} |
} |
195 |
|
X(bne_samepage_addiu) |
196 |
|
{ |
197 |
|
MODE_uint_t rs = reg(ic->arg[0]), rt = reg(ic->arg[1]); |
198 |
|
cpu->n_translated_instrs ++; |
199 |
|
reg(ic[1].arg[1]) = (int32_t) |
200 |
|
((int32_t)reg(ic[1].arg[0]) + (int32_t)ic[1].arg[2]); |
201 |
|
if (rs != rt) |
202 |
|
cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2]; |
203 |
|
else |
204 |
|
cpu->cd.mips.next_ic ++; |
205 |
|
} |
206 |
|
X(bne_samepage_nop) |
207 |
|
{ |
208 |
|
MODE_uint_t rs = reg(ic->arg[0]), rt = reg(ic->arg[1]); |
209 |
|
cpu->n_translated_instrs ++; |
210 |
|
if (rs != rt) |
211 |
|
cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2]; |
212 |
|
else |
213 |
|
cpu->cd.mips.next_ic ++; |
214 |
|
} |
215 |
X(b) |
X(b) |
216 |
{ |
{ |
217 |
MODE_int_t old_pc = cpu->pc; |
MODE_int_t old_pc = cpu->pc; |
936 |
} else |
} else |
937 |
cpu->delay_slot = NOT_DELAYED; |
cpu->delay_slot = NOT_DELAYED; |
938 |
} |
} |
939 |
|
X(jr_ra_addiu) |
940 |
|
{ |
941 |
|
/* jr ra, followed by an addiu */ |
942 |
|
MODE_int_t rs = cpu->cd.mips.gpr[MIPS_GPR_RA]; |
943 |
|
reg(ic[1].arg[1]) = (int32_t) |
944 |
|
((int32_t)reg(ic[1].arg[0]) + (int32_t)ic[1].arg[2]); |
945 |
|
cpu->pc = rs; |
946 |
|
quick_pc_to_pointers(cpu); |
947 |
|
cpu->n_translated_instrs ++; |
948 |
|
} |
949 |
X(jr_ra_trace) |
X(jr_ra_trace) |
950 |
{ |
{ |
951 |
MODE_int_t rs = cpu->cd.mips.gpr[MIPS_GPR_RA]; |
MODE_int_t rs = cpu->cd.mips.gpr[MIPS_GPR_RA]; |
1063 |
*/ |
*/ |
1064 |
X(cache) |
X(cache) |
1065 |
{ |
{ |
1066 |
/* TODO. For now, just clear the rmw bit: */ |
/* TODO: Implement cache operations. */ |
|
cpu->cd.mips.rmw = 0; |
|
1067 |
|
|
1068 |
/* TODO: fix */ |
/* Make sure the rmw bit is cleared: */ |
1069 |
cpu->invalidate_code_translation(cpu, 0, INVALIDATE_ALL); |
cpu->cd.mips.rmw = 0; |
|
cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); |
|
|
/* cpu_create_or_reset_tc(cpu); */ |
|
1070 |
} |
} |
1071 |
|
|
1072 |
|
|
1896 |
*/ |
*/ |
1897 |
X(rfe) |
X(rfe) |
1898 |
{ |
{ |
1899 |
coproc_rfe(cpu); |
/* Just rotate the interrupt/user bits: */ |
1900 |
|
cpu->cd.mips.coproc[0]->reg[COP0_STATUS] = |
1901 |
|
(cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & ~0x3f) | |
1902 |
|
((cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & 0x3c) >> 2); |
1903 |
|
|
1904 |
/* Note: no pc to pointers conversion is necessary here. */ |
/* |
1905 |
|
* Note: no pc to pointers conversion is necessary here. Usually the |
1906 |
|
* rfe instruction resides in the delay slot of a jr k0/k1, and |
1907 |
|
* it is up to that instruction to do the pointer conversion. |
1908 |
|
*/ |
1909 |
} |
} |
1910 |
|
|
1911 |
|
|
1912 |
/* |
/* |
1913 |
* eret: Return from exception handler |
* eret: Return from exception handler (non-R3000 style) |
1914 |
*/ |
*/ |
1915 |
X(eret) |
X(eret) |
1916 |
{ |
{ |
1917 |
coproc_eret(cpu); |
if (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_ERL) { |
1918 |
|
cpu->pc = cpu->cd.mips.coproc[0]->reg[COP0_ERROREPC]; |
1919 |
|
cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_ERL; |
1920 |
|
} else { |
1921 |
|
cpu->pc = cpu->cd.mips.coproc[0]->reg[COP0_EPC]; |
1922 |
|
cpu->delay_slot = 0; |
1923 |
|
cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_EXL; |
1924 |
|
} |
1925 |
|
|
1926 |
quick_pc_to_pointers(cpu); |
quick_pc_to_pointers(cpu); |
1927 |
|
|
1928 |
|
cpu->cd.mips.rmw = 0; /* the "LL bit" */ |
1929 |
} |
} |
1930 |
|
|
1931 |
|
|
2361 |
|
|
2362 |
|
|
2363 |
/* |
/* |
2364 |
|
* sw_loop: |
2365 |
|
* |
2366 |
|
* s: addiu rX,rX,4 rX = arg[0] and arg[1] |
2367 |
|
* bne rY,rX,s (or rX,rY,s) rt=arg[1], rs=arg[0] |
2368 |
|
* sw rZ,-4(rX) rt=arg[0], rs=arg[1] |
2369 |
|
*/ |
2370 |
|
X(sw_loop) |
2371 |
|
{ |
2372 |
|
MODE_uint_t rX = reg(ic->arg[0]), rZ = reg(ic[2].arg[0]); |
2373 |
|
uint64_t *rYp = (uint64_t *) ic[1].arg[0]; |
2374 |
|
MODE_uint_t rY, bytes_to_write; |
2375 |
|
unsigned char *page; |
2376 |
|
int partial = 0; |
2377 |
|
|
2378 |
|
page = cpu->cd.mips.host_store[rX >> 12]; |
2379 |
|
|
2380 |
|
/* Fallback: */ |
2381 |
|
if (cpu->delay_slot || page == NULL || (rX & 3) != 0 || rZ != 0) { |
2382 |
|
instr(addiu)(cpu, ic); |
2383 |
|
return; |
2384 |
|
} |
2385 |
|
|
2386 |
|
if (rYp == (uint64_t *) ic->arg[0]) |
2387 |
|
rYp = (uint64_t *) ic[1].arg[1]; |
2388 |
|
|
2389 |
|
rY = reg(rYp); |
2390 |
|
|
2391 |
|
bytes_to_write = rY - rX; |
2392 |
|
if ((rX & 0xfff) + bytes_to_write > 0x1000) { |
2393 |
|
bytes_to_write = 0x1000 - (rX & 0xfff); |
2394 |
|
partial = 1; |
2395 |
|
} |
2396 |
|
|
2397 |
|
/* printf("rX = %08x\n", (int)rX); |
2398 |
|
printf("rY = %08x\n", (int)rY); |
2399 |
|
printf("rZ = %08x\n", (int)rZ); |
2400 |
|
printf("%i bytes\n", (int)bytes_to_write); */ |
2401 |
|
|
2402 |
|
memset(page + (rX & 0xfff), 0, bytes_to_write); |
2403 |
|
|
2404 |
|
reg(ic->arg[0]) = rX + bytes_to_write; |
2405 |
|
|
2406 |
|
cpu->n_translated_instrs += bytes_to_write / 4 * 3 - 1; |
2407 |
|
cpu->cd.mips.next_ic = partial? |
2408 |
|
(struct mips_instr_call *) &ic[0] : |
2409 |
|
(struct mips_instr_call *) &ic[3]; |
2410 |
|
} |
2411 |
|
|
2412 |
|
|
2413 |
|
/* |
2414 |
|
* multi_sw_3: |
2415 |
|
* |
2416 |
|
* sw r?,ofs(rX) r?=arg[0], rX=arg[1], ofs=arg[2] |
2417 |
|
* sw r?,ofs(rX) r?=arg[0], rX=arg[1], ofs=arg[2] |
2418 |
|
* sw r?,ofs(rX) r?=arg[0], rX=arg[1], ofs=arg[2] |
2419 |
|
*/ |
2420 |
|
X(multi_sw_3_le) |
2421 |
|
{ |
2422 |
|
uint32_t *page; |
2423 |
|
MODE_uint_t rX = reg(ic[0].arg[1]), r1, r2, r3; |
2424 |
|
MODE_uint_t addr0 = rX + (int32_t)ic[0].arg[2]; |
2425 |
|
MODE_uint_t addr1 = rX + (int32_t)ic[1].arg[2]; |
2426 |
|
MODE_uint_t addr2 = rX + (int32_t)ic[2].arg[2]; |
2427 |
|
uint32_t index0 = addr0 >> 12, index1 = addr1 >> 12, |
2428 |
|
index2 = addr2 >> 12; |
2429 |
|
|
2430 |
|
page = (uint32_t *) cpu->cd.mips.host_store[index0]; |
2431 |
|
|
2432 |
|
/* Fallback: */ |
2433 |
|
if (cpu->delay_slot || |
2434 |
|
page == NULL || (addr0 & 3) != 0 || (addr1 & 3) != 0 || |
2435 |
|
(addr2 & 3) != 0 || index0 != index1 || index0 != index2) { |
2436 |
|
/* Normal safe sw: */ |
2437 |
|
ic[1].f(cpu, ic); |
2438 |
|
return; |
2439 |
|
} |
2440 |
|
|
2441 |
|
addr0 = (addr0 >> 2) & 0x3ff; |
2442 |
|
addr1 = (addr1 >> 2) & 0x3ff; |
2443 |
|
addr2 = (addr2 >> 2) & 0x3ff; |
2444 |
|
|
2445 |
|
/* printf("addr0=%x 1=%x 2=%x\n", |
2446 |
|
(int)addr0, (int)addr1, (int)addr2); */ |
2447 |
|
|
2448 |
|
r1 = reg(ic[0].arg[0]); |
2449 |
|
r2 = reg(ic[1].arg[0]); |
2450 |
|
r3 = reg(ic[2].arg[0]); |
2451 |
|
|
2452 |
|
r1 = LE32_TO_HOST(r1); |
2453 |
|
r2 = LE32_TO_HOST(r2); |
2454 |
|
r3 = LE32_TO_HOST(r3); |
2455 |
|
|
2456 |
|
page[addr0] = r1; |
2457 |
|
page[addr1] = r2; |
2458 |
|
page[addr2] = r3; |
2459 |
|
|
2460 |
|
cpu->n_translated_instrs += 2; |
2461 |
|
cpu->cd.mips.next_ic = (struct mips_instr_call *) &ic[3]; |
2462 |
|
} |
2463 |
|
X(multi_sw_3_be) |
2464 |
|
{ |
2465 |
|
uint32_t *page; |
2466 |
|
MODE_uint_t rX = reg(ic[0].arg[1]), r1, r2, r3; |
2467 |
|
MODE_uint_t addr0 = rX + (int32_t)ic[0].arg[2]; |
2468 |
|
MODE_uint_t addr1 = rX + (int32_t)ic[1].arg[2]; |
2469 |
|
MODE_uint_t addr2 = rX + (int32_t)ic[2].arg[2]; |
2470 |
|
uint32_t index0 = addr0 >> 12, index1 = addr1 >> 12, |
2471 |
|
index2 = addr2 >> 12; |
2472 |
|
|
2473 |
|
page = (uint32_t *) cpu->cd.mips.host_store[index0]; |
2474 |
|
|
2475 |
|
/* Fallback: */ |
2476 |
|
if (cpu->delay_slot || |
2477 |
|
page == NULL || (addr0 & 3) != 0 || (addr1 & 3) != 0 || |
2478 |
|
(addr2 & 3) != 0 || index0 != index1 || index0 != index2) { |
2479 |
|
/* Normal safe sw: */ |
2480 |
|
ic[1].f(cpu, ic); |
2481 |
|
return; |
2482 |
|
} |
2483 |
|
|
2484 |
|
addr0 = (addr0 >> 2) & 0x3ff; |
2485 |
|
addr1 = (addr1 >> 2) & 0x3ff; |
2486 |
|
addr2 = (addr2 >> 2) & 0x3ff; |
2487 |
|
|
2488 |
|
/* printf("addr0=%x 1=%x 2=%x\n", |
2489 |
|
(int)addr0, (int)addr1, (int)addr2); */ |
2490 |
|
|
2491 |
|
r1 = reg(ic[0].arg[0]); |
2492 |
|
r2 = reg(ic[1].arg[0]); |
2493 |
|
r3 = reg(ic[2].arg[0]); |
2494 |
|
|
2495 |
|
r1 = BE32_TO_HOST(r1); |
2496 |
|
r2 = BE32_TO_HOST(r2); |
2497 |
|
r3 = BE32_TO_HOST(r3); |
2498 |
|
|
2499 |
|
page[addr0] = r1; |
2500 |
|
page[addr1] = r2; |
2501 |
|
page[addr2] = r3; |
2502 |
|
|
2503 |
|
cpu->n_translated_instrs += 2; |
2504 |
|
cpu->cd.mips.next_ic = (struct mips_instr_call *) &ic[3]; |
2505 |
|
} |
2506 |
|
|
2507 |
|
|
2508 |
|
/* |
2509 |
|
* netbsd_r3k_picache_do_inv: |
2510 |
|
* |
2511 |
|
* ic[0] mtc0 rV,status |
2512 |
|
* 1 nop |
2513 |
|
* 2 nop |
2514 |
|
* 3 s: addiu rX,rX,4 |
2515 |
|
* 4 bne rY,rX,s |
2516 |
|
* 5 sb zr,-4(rX) |
2517 |
|
* 6 nop |
2518 |
|
* 7 nop |
2519 |
|
* 8 mtc0 rT,status |
2520 |
|
*/ |
2521 |
|
X(netbsd_r3k_picache_do_inv) |
2522 |
|
{ |
2523 |
|
MODE_uint_t rx = reg(ic[3].arg[0]), ry = reg(ic[4].arg[1]); |
2524 |
|
|
2525 |
|
/* Fallback if the environment isn't exactly right: */ |
2526 |
|
if (!(reg(ic[0].arg[0]) & MIPS1_ISOL_CACHES) || |
2527 |
|
(rx & 3) || (ry & 3) || cpu->delay_slot) { |
2528 |
|
instr(mtc0)(cpu, ic); |
2529 |
|
return; |
2530 |
|
} |
2531 |
|
|
2532 |
|
reg(ic[3].arg[0]) = ry; |
2533 |
|
cpu->n_translated_instrs += (ry - rx + 4) / 4 * 3 + 4; |
2534 |
|
|
2535 |
|
/* Run the last mtc0 instruction: */ |
2536 |
|
cpu->cd.mips.next_ic = (struct mips_instr_call *) &ic[8]; |
2537 |
|
} |
2538 |
|
|
2539 |
|
|
2540 |
|
#ifdef MODE32 |
2541 |
|
/* |
2542 |
|
* netbsd_strlen(): |
2543 |
|
* |
2544 |
|
* lb rV,0(rX) |
2545 |
|
* s: addiu rX,rX,1 |
2546 |
|
* bne zr,rV,s |
2547 |
|
* nop |
2548 |
|
*/ |
2549 |
|
X(netbsd_strlen) |
2550 |
|
{ |
2551 |
|
MODE_uint_t rx = reg(ic[0].arg[1]); |
2552 |
|
MODE_int_t rv; |
2553 |
|
signed char *page; |
2554 |
|
uint32_t pageindex = rx >> 12; |
2555 |
|
int i; |
2556 |
|
|
2557 |
|
page = (signed char *) cpu->cd.mips.host_load[pageindex]; |
2558 |
|
|
2559 |
|
/* Fallback: */ |
2560 |
|
if (cpu->delay_slot || page == NULL) { |
2561 |
|
/* |
2562 |
|
* Normal lb: NOTE: It doesn't matter whether [1] or |
2563 |
|
* [16+1] is called here, because endianness for 8-bit |
2564 |
|
* loads is irrelevant. :-) |
2565 |
|
*/ |
2566 |
|
mips32_loadstore[1](cpu, ic); |
2567 |
|
return; |
2568 |
|
} |
2569 |
|
|
2570 |
|
i = rx & 0xfff; |
2571 |
|
|
2572 |
|
/* |
2573 |
|
* TODO: This loop can be optimized further for optimal |
2574 |
|
* performance on the host, e.g. by reading full words... |
2575 |
|
*/ |
2576 |
|
do { |
2577 |
|
rv = page[i ++]; |
2578 |
|
} while (i < 0x1000 && rv != 0); |
2579 |
|
|
2580 |
|
cpu->n_translated_instrs += (i - (rx & 0xfff)) * 4 - 1; |
2581 |
|
|
2582 |
|
reg(ic[0].arg[1]) = (rx & ~0xfff) + i; |
2583 |
|
reg(ic[2].arg[0]) = rv; |
2584 |
|
|
2585 |
|
/* Done with the loop? Or continue on the next rx page? */ |
2586 |
|
if (rv == 0) |
2587 |
|
cpu->cd.mips.next_ic = (struct mips_instr_call *) &ic[4]; |
2588 |
|
else |
2589 |
|
cpu->cd.mips.next_ic = (struct mips_instr_call *) &ic[0]; |
2590 |
|
} |
2591 |
|
#endif |
2592 |
|
|
2593 |
|
|
2594 |
|
/* |
2595 |
|
* lui_32bit: |
2596 |
|
* |
2597 |
|
* Combination of lui and addiu. |
2598 |
|
* Note: All 32 bits of arg[2] of the lui instr_call are used. |
2599 |
|
*/ |
2600 |
|
X(lui_32bit) |
2601 |
|
{ |
2602 |
|
reg(ic[0].arg[0]) = (int32_t) ic[0].arg[2]; |
2603 |
|
cpu->n_translated_instrs ++; |
2604 |
|
cpu->cd.mips.next_ic ++; |
2605 |
|
} |
2606 |
|
|
2607 |
|
|
2608 |
|
/* |
2609 |
* b_samepage_addiu: |
* b_samepage_addiu: |
2610 |
* |
* |
2611 |
* Combination of branch within the same page, followed by addiu. |
* Combination of branch within the same page, followed by addiu. |
2711 |
|
|
2712 |
|
|
2713 |
/* |
/* |
2714 |
* Combine: [Conditional] branch, followed by addiu. |
* Combine: Memory fill loop (addiu, bne, sw) |
2715 |
|
* |
2716 |
|
* s: addiu rX,rX,4 |
2717 |
|
* bne rY,rX,s |
2718 |
|
* sw rZ,-4(rX) |
2719 |
*/ |
*/ |
2720 |
void COMBINE(b_addiu)(struct cpu *cpu, struct mips_instr_call *ic, |
void COMBINE(sw_loop)(struct cpu *cpu, struct mips_instr_call *ic, int low_addr) |
2721 |
|
{ |
2722 |
|
int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) |
2723 |
|
& (MIPS_IC_ENTRIES_PER_PAGE - 1); |
2724 |
|
|
2725 |
|
/* Only for 32-bit virtual address translation so far. */ |
2726 |
|
if (!cpu->is_32bit) |
2727 |
|
return; |
2728 |
|
|
2729 |
|
if (n_back < 2) |
2730 |
|
return; |
2731 |
|
|
2732 |
|
if (ic[-2].f == instr(addiu) && ic[-2].arg[0] == ic[-2].arg[1] && |
2733 |
|
(int32_t)ic[-2].arg[2] == 4 && |
2734 |
|
ic[-1].f == instr(bne_samepage) && |
2735 |
|
(ic[-1].arg[0] == ic[-2].arg[0] || |
2736 |
|
ic[-1].arg[1] == ic[-2].arg[0]) && |
2737 |
|
ic[-1].arg[0] != ic[-1].arg[1] && |
2738 |
|
ic[-1].arg[2] == (size_t) &ic[-2] && |
2739 |
|
ic[0].arg[0] != ic[0].arg[1] && |
2740 |
|
ic[0].arg[1] == ic[-2].arg[0] && (int32_t)ic[0].arg[2] == -4) { |
2741 |
|
ic[-2].f = instr(sw_loop); |
2742 |
|
combined; |
2743 |
|
} |
2744 |
|
} |
2745 |
|
|
2746 |
|
|
2747 |
|
/* |
2748 |
|
* Combine: Multiple SW in a row using the same base register |
2749 |
|
* |
2750 |
|
* sw r?,???(rX) |
2751 |
|
* sw r?,???(rX) |
2752 |
|
* sw r?,???(rX) |
2753 |
|
* ... |
2754 |
|
*/ |
2755 |
|
void COMBINE(multi_sw)(struct cpu *cpu, struct mips_instr_call *ic, |
2756 |
int low_addr) |
int low_addr) |
2757 |
{ |
{ |
2758 |
int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) |
int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) |
2759 |
& (MIPS_IC_ENTRIES_PER_PAGE - 1); |
& (MIPS_IC_ENTRIES_PER_PAGE - 1); |
2760 |
|
|
2761 |
|
/* Only for 32-bit virtual address translation so far. */ |
2762 |
|
if (!cpu->is_32bit) |
2763 |
|
return; |
2764 |
|
|
2765 |
|
if (n_back < 4) |
2766 |
|
return; |
2767 |
|
|
2768 |
|
/* Avoid "overlapping" instruction combinations: */ |
2769 |
|
if (ic[-4].f == instr(multi_sw_3_be)||ic[-3].f == instr(multi_sw_3_be)|| |
2770 |
|
ic[-4].f == instr(multi_sw_3_le)||ic[-3].f == instr(multi_sw_3_le)) |
2771 |
|
return; |
2772 |
|
|
2773 |
|
if (ic[-2].f == ic[0].f && ic[-1].f == ic[0].f && |
2774 |
|
ic[-2].arg[1] == ic[0].arg[1] && |
2775 |
|
ic[-1].arg[1] == ic[0].arg[1]) { |
2776 |
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) |
2777 |
|
ic[-2].f = instr(multi_sw_3_le); |
2778 |
|
else |
2779 |
|
ic[-2].f = instr(multi_sw_3_be); |
2780 |
|
combined; |
2781 |
|
} |
2782 |
|
} |
2783 |
|
|
2784 |
|
|
2785 |
|
/* |
2786 |
|
* Combine: NetBSD/pmax 3.0 R2000/R3000 physical cache invalidation loop |
2787 |
|
* |
2788 |
|
* Instruction cache loop: |
2789 |
|
* |
2790 |
|
* ic[-8] mtc0 rV,status |
2791 |
|
* -7 nop |
2792 |
|
* -6 nop |
2793 |
|
* -5 s: addiu rX,rX,4 |
2794 |
|
* -4 bne rY,rX,s |
2795 |
|
* -3 sb zr,-4(rX) |
2796 |
|
* -2 nop |
2797 |
|
* -1 nop |
2798 |
|
* 0 mtc0 rT,status |
2799 |
|
*/ |
2800 |
|
void COMBINE(netbsd_r3k_cache_inv)(struct cpu *cpu, |
2801 |
|
struct mips_instr_call *ic, int low_addr) |
2802 |
|
{ |
2803 |
|
int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) |
2804 |
|
& (MIPS_IC_ENTRIES_PER_PAGE - 1); |
2805 |
|
|
2806 |
|
if (n_back < 8) |
2807 |
|
return; |
2808 |
|
|
2809 |
|
if (ic[-8].f == instr(mtc0) && ic[-8].arg[1] == COP0_STATUS && |
2810 |
|
ic[-7].f == instr(nop) && ic[-6].f == instr(nop) && |
2811 |
|
ic[-5].f == instr(addiu) && ic[-5].arg[0] == ic[-5].arg[1] && |
2812 |
|
(int32_t)ic[-5].arg[2] == 4 && ic[-4].f == instr(bne_samepage) && |
2813 |
|
ic[-4].arg[0] == ic[-5].arg[0] && ic[-4].arg[0] != ic[-4].arg[1] && |
2814 |
|
ic[-4].arg[2] == (size_t) &ic[-5] && |
2815 |
|
ic[-3].arg[1] == ic[-5].arg[0] && |
2816 |
|
ic[-2].f == instr(nop) && ic[-1].f == instr(nop)) { |
2817 |
|
ic[-8].f = instr(netbsd_r3k_picache_do_inv); |
2818 |
|
combined; |
2819 |
|
} |
2820 |
|
} |
2821 |
|
|
2822 |
|
|
2823 |
|
/* |
2824 |
|
* Combine: something ending with a nop. |
2825 |
|
* |
2826 |
|
* NetBSD's strlen core. |
2827 |
|
* [Conditional] branch, followed by nop. |
2828 |
|
*/ |
2829 |
|
void COMBINE(nop)(struct cpu *cpu, struct mips_instr_call *ic, int low_addr) |
2830 |
|
{ |
2831 |
|
int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) |
2832 |
|
& (MIPS_IC_ENTRIES_PER_PAGE - 1); |
2833 |
|
|
2834 |
|
#ifdef MODE32 |
2835 |
|
if (n_back < 3) |
2836 |
|
return; |
2837 |
|
|
2838 |
|
if ((ic[-3].f == mips32_loadstore[1] || |
2839 |
|
ic[-3].f == mips32_loadstore[16 + 1]) && |
2840 |
|
ic[-3].arg[2] == 0 && |
2841 |
|
ic[-3].arg[0] == ic[-1].arg[0] && ic[-3].arg[1] == ic[-2].arg[0] && |
2842 |
|
ic[-2].arg[0] == ic[-2].arg[1] && ic[-2].arg[2] == 1 && |
2843 |
|
ic[-2].f == instr(addiu) && ic[-1].arg[2] == (size_t) &ic[-3] && |
2844 |
|
ic[-1].arg[1] == (size_t) &cpu->cd.mips.gpr[MIPS_GPR_ZERO] && |
2845 |
|
ic[-1].f == instr(bne_samepage)) { |
2846 |
|
ic[-3].f = instr(netbsd_strlen); |
2847 |
|
combined; |
2848 |
|
return; |
2849 |
|
} |
2850 |
|
#endif |
2851 |
|
|
2852 |
if (n_back < 1) |
if (n_back < 1) |
2853 |
return; |
return; |
2854 |
|
|
2855 |
|
if (ic[-1].f == instr(bne_samepage)) { |
2856 |
|
ic[-1].f = instr(bne_samepage_nop); |
2857 |
|
combined; |
2858 |
|
return; |
2859 |
|
} |
2860 |
|
|
2861 |
|
if (ic[-1].f == instr(beq_samepage)) { |
2862 |
|
ic[-1].f = instr(beq_samepage_nop); |
2863 |
|
combined; |
2864 |
|
return; |
2865 |
|
} |
2866 |
|
|
2867 |
|
/* TODO: other branches that are followed by nop should be here */ |
2868 |
|
} |
2869 |
|
|
2870 |
|
|
2871 |
|
/* |
2872 |
|
* Combine: |
2873 |
|
* |
2874 |
|
* [Conditional] branch, followed by addiu. |
2875 |
|
* lui + addiu. |
2876 |
|
*/ |
2877 |
|
void COMBINE(addiu)(struct cpu *cpu, struct mips_instr_call *ic, int low_addr) |
2878 |
|
{ |
2879 |
|
int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) |
2880 |
|
& (MIPS_IC_ENTRIES_PER_PAGE - 1); |
2881 |
|
|
2882 |
|
if (n_back < 1) |
2883 |
|
return; |
2884 |
|
|
2885 |
|
if (ic[-1].f == instr(set) && ic[-1].arg[0] == ic[0].arg[0] && |
2886 |
|
ic[0].arg[0] == ic[0].arg[1]) { |
2887 |
|
ic[-1].f = instr(lui_32bit); |
2888 |
|
ic[-1].arg[2] = (int32_t) (ic[-1].arg[1] + ic[0].arg[2]); |
2889 |
|
combined; |
2890 |
|
return; |
2891 |
|
} |
2892 |
|
|
2893 |
if (ic[-1].f == instr(b_samepage)) { |
if (ic[-1].f == instr(b_samepage)) { |
2894 |
ic[-1].f = instr(b_samepage_addiu); |
ic[-1].f = instr(b_samepage_addiu); |
2895 |
combined; |
combined; |
2896 |
|
return; |
2897 |
|
} |
2898 |
|
|
2899 |
|
if (ic[-1].f == instr(beq_samepage)) { |
2900 |
|
ic[-1].f = instr(beq_samepage_addiu); |
2901 |
|
combined; |
2902 |
|
return; |
2903 |
|
} |
2904 |
|
|
2905 |
|
if (ic[-1].f == instr(bne_samepage)) { |
2906 |
|
ic[-1].f = instr(bne_samepage_addiu); |
2907 |
|
combined; |
2908 |
|
return; |
2909 |
|
} |
2910 |
|
|
2911 |
|
if (ic[-1].f == instr(jr_ra)) { |
2912 |
|
ic[-1].f = instr(jr_ra_addiu); |
2913 |
|
combined; |
2914 |
|
return; |
2915 |
} |
} |
2916 |
|
|
2917 |
/* TODO: other branches that are followed by addiu should be here */ |
/* TODO: other branches that are followed by addiu should be here */ |
3379 |
case HI6_XORI: ic->f = instr(xori); break; |
case HI6_XORI: ic->f = instr(xori); break; |
3380 |
} |
} |
3381 |
|
|
3382 |
|
if (ic->arg[2] == 0) { |
3383 |
|
if ((cpu->is_32bit && ic->f == instr(addiu)) || |
3384 |
|
(!cpu->is_32bit && ic->f == instr(daddiu))) { |
3385 |
|
ic->f = instr(mov); |
3386 |
|
ic->arg[2] = ic->arg[1]; |
3387 |
|
} |
3388 |
|
} |
3389 |
|
|
3390 |
if (rt == MIPS_GPR_ZERO) |
if (rt == MIPS_GPR_ZERO) |
3391 |
ic->f = instr(nop); |
ic->f = instr(nop); |
3392 |
|
|
3393 |
if (ic->f == instr(addiu)) |
if (ic->f == instr(addiu)) |
3394 |
cpu->cd.mips.combination_check = COMBINE(b_addiu); |
cpu->cd.mips.combination_check = COMBINE(addiu); |
3395 |
if (ic->f == instr(daddiu)) |
if (ic->f == instr(daddiu)) |
3396 |
cpu->cd.mips.combination_check = COMBINE(b_daddiu); |
cpu->cd.mips.combination_check = COMBINE(b_daddiu); |
3397 |
break; |
break; |
3400 |
ic->f = instr(set); |
ic->f = instr(set); |
3401 |
ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; |
ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; |
3402 |
ic->arg[1] = (int32_t) (imm << 16); |
ic->arg[1] = (int32_t) (imm << 16); |
3403 |
|
/* NOTE: Don't use arg[2] here. It can be used with |
3404 |
|
instruction combinations, to do lui + addiu, etc. */ |
3405 |
if (rt == MIPS_GPR_ZERO) |
if (rt == MIPS_GPR_ZERO) |
3406 |
ic->f = instr(nop); |
ic->f = instr(nop); |
3407 |
break; |
break; |
3506 |
ic->arg[1] = rd + ((iword & 7) << 5); |
ic->arg[1] = rd + ((iword & 7) << 5); |
3507 |
ic->arg[2] = addr & 0xffc; |
ic->arg[2] = addr & 0xffc; |
3508 |
ic->f = rs == COPz_MTCz? instr(mtc0) : instr(dmtc0); |
ic->f = rs == COPz_MTCz? instr(mtc0) : instr(dmtc0); |
3509 |
|
|
3510 |
|
if (cpu->cd.mips.cpu_type.exc_model == EXC3K && |
3511 |
|
rs == COPz_MTCz && rd == COP0_STATUS) |
3512 |
|
cpu->cd.mips.combination_check = |
3513 |
|
COMBINE(netbsd_r3k_cache_inv); |
3514 |
|
|
3515 |
break; |
break; |
3516 |
case 8: if (iword == 0x4100ffff) { |
case 8: if (iword == 0x4100ffff) { |
3517 |
/* R2020 DECstation write-loop thingy. */ |
/* R2020 DECstation write-loop thingy. */ |
3829 |
/* Load into the dummy scratch register, if rt = zero */ |
/* Load into the dummy scratch register, if rt = zero */ |
3830 |
if (!store && rt == MIPS_GPR_ZERO) |
if (!store && rt == MIPS_GPR_ZERO) |
3831 |
ic->arg[0] = (size_t)&cpu->cd.mips.scratch; |
ic->arg[0] = (size_t)&cpu->cd.mips.scratch; |
3832 |
|
|
3833 |
|
/* Check for multiple stores in a row using the same |
3834 |
|
base register: */ |
3835 |
|
if (main_opcode == HI6_SW && rs == MIPS_GPR_SP) |
3836 |
|
cpu->cd.mips.combination_check = COMBINE(multi_sw); |
3837 |
|
|
3838 |
break; |
break; |
3839 |
|
|
3840 |
case HI6_LL: |
case HI6_LL: |
3954 |
cpu->cd.mips.cpu_type.isa_revision < 2) { |
cpu->cd.mips.cpu_type.isa_revision < 2) { |
3955 |
static int warning = 0; |
static int warning = 0; |
3956 |
if (!warning) { |
if (!warning) { |
3957 |
fatal("[ WARNING! SPECIAL3 opcode used on a" |
fatal("[ WARNING! SPECIAL3 opcode used, but" |
3958 |
" cpu which doesn't implement it ]\n"); |
" the %s processor does not implement " |
3959 |
|
"such instructions. Only printing this " |
3960 |
|
"warning once. ]\n", |
3961 |
|
cpu->cd.mips.cpu_type.name); |
3962 |
warning = 1; |
warning = 1; |
3963 |
} |
} |
3964 |
ic->f = instr(reserved); |
ic->f = instr(reserved); |
4007 |
} |
} |
4008 |
#endif |
#endif |
4009 |
|
|
4010 |
|
if (ic->f == instr(nop) && cpu->cd.mips.combination_check == NULL) |
4011 |
|
cpu->cd.mips.combination_check = COMBINE(nop); |
4012 |
|
|
4013 |
|
|
4014 |
#define DYNTRANS_TO_BE_TRANSLATED_TAIL |
#define DYNTRANS_TO_BE_TRANSLATED_TAIL |
4015 |
#include "cpu_dyntrans.c" |
#include "cpu_dyntrans.c" |