--- trunk/src/cpus/cpu_mips_instr.c 2007/10/08 16:20:32 29 +++ trunk/src/cpus/cpu_mips_instr.c 2007/10/08 16:20:40 30 @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: cpu_mips_instr.c,v 1.97 2006/07/20 03:20:03 debug Exp $ + * $Id: cpu_mips_instr.c,v 1.104 2006/08/14 17:45:47 debug Exp $ * * MIPS instructions. * @@ -1679,8 +1679,10 @@ uint32_t cause = cpu->cd.mips.coproc[0]->reg[COP0_CAUSE]; /* NOTE: STATUS_IE happens to match the enable bit also on R2000/R3000, so this is ok. */ - if (status & (STATUS_EXL | STATUS_ERL)) - status &= ~STATUS_IE; + if (cpu->cd.mips.cpu_type.exc_model != EXC3K) { + if (status & (STATUS_EXL | STATUS_ERL)) + status &= ~STATUS_IE; + } /* Ugly R5900 special case: (TODO: move this?) */ if (cpu->cd.mips.cpu_type.rev == MIPS_R5900 && !(status & R5900_STATUS_EIE)) @@ -1807,6 +1809,12 @@ cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); mips_cpu_exception(cpu, EXCEPTION_BP, 0, 0, 0, 0, 0, 0); } +X(reboot) +{ + cpu->running = 0; + debugger_n_steps_left_before_interaction = 0; + cpu->cd.mips.next_ic = ¬hing_call; +} /* @@ -1952,6 +1960,54 @@ /* + * wait: Wait for external interrupt. + */ +X(wait) +{ + /* + * If there is an interrupt, then just return. Otherwise + * re-run the wait instruction (after a delay). + */ + uint32_t status = cpu->cd.mips.coproc[0]->reg[COP0_STATUS]; + uint32_t cause = cpu->cd.mips.coproc[0]->reg[COP0_CAUSE]; + + /* NOTE: STATUS_IE happens to match the enable bit also + on R2000/R3000, so this is ok. */ + if (cpu->cd.mips.cpu_type.exc_model != EXC3K) { + if (status & (STATUS_EXL | STATUS_ERL)) + status &= ~STATUS_IE; + } + /* Ugly R5900 special case: (TODO: move this?) */ + if (cpu->cd.mips.cpu_type.rev == MIPS_R5900 && + !(status & R5900_STATUS_EIE)) + status &= ~STATUS_IE; + if (status & STATUS_IE && (status & cause & STATUS_IM_MASK)) + return; + + cpu->cd.mips.next_ic = ic; + cpu->is_halted = 1; + + /* + * There was no interrupt. Go to sleep. + * + * TODO: + * + * Think about how to actually implement this usleep stuff, + * in an SMP and/or timing accurate environment. + */ + + if (cpu->machine->ncpus == 1) { + static int x = 0; + if ((++x) == 600) { + usleep(1); + x = 0; + } + cpu->n_translated_instrs += N_SAFE_DYNTRANS_LIMIT / 6; + } +} + + +/* * rdhwr: Read hardware register into gpr (MIPS32/64 rev 2). * * arg[0] = ptr to rt (destination register) @@ -2381,7 +2437,7 @@ if (cpu->delay_slot || page == NULL || (rX & 3) != 0 || rZ != 0) { instr(addiu)(cpu, ic); return; - } + } if (rYp == (uint64_t *) ic->arg[0]) rYp = (uint64_t *) ic[1].arg[1]; @@ -2410,13 +2466,80 @@ } +#ifdef MODE32 /* - * multi_sw_3: + * multi_sw_2, _3, _4: * * sw r?,ofs(rX) r?=arg[0], rX=arg[1], ofs=arg[2] - * sw r?,ofs(rX) r?=arg[0], rX=arg[1], ofs=arg[2] - * sw r?,ofs(rX) r?=arg[0], rX=arg[1], ofs=arg[2] */ +X(multi_sw_2_le) +{ + uint32_t *page; + MODE_uint_t rX = reg(ic[0].arg[1]), r1, r2; + MODE_uint_t addr0 = rX + (int32_t)ic[0].arg[2]; + MODE_uint_t addr1 = rX + (int32_t)ic[1].arg[2]; + uint32_t index0 = addr0 >> 12, index1 = addr1 >> 12; + + page = (uint32_t *) cpu->cd.mips.host_store[index0]; + + /* Fallback: */ + if (cpu->delay_slot || + page == NULL || (addr0 & 3) != 0 || (addr1 & 3) != 0 || + index0 != index1) { + /* Normal safe sw: */ + mips32_loadstore[8 + 2 * 2](cpu, ic); + return; + } + + addr0 = (addr0 >> 2) & 0x3ff; + addr1 = (addr1 >> 2) & 0x3ff; + + r1 = reg(ic[0].arg[0]); + r2 = reg(ic[1].arg[0]); + + r1 = LE32_TO_HOST(r1); + r2 = LE32_TO_HOST(r2); + + page[addr0] = r1; + page[addr1] = r2; + + cpu->n_translated_instrs ++; + cpu->cd.mips.next_ic ++; +} +X(multi_sw_2_be) +{ + uint32_t *page; + MODE_uint_t rX = reg(ic[0].arg[1]), r1, r2; + MODE_uint_t addr0 = rX + (int32_t)ic[0].arg[2]; + MODE_uint_t addr1 = rX + (int32_t)ic[1].arg[2]; + uint32_t index0 = addr0 >> 12, index1 = addr1 >> 12; + + page = (uint32_t *) cpu->cd.mips.host_store[index0]; + + /* Fallback: */ + if (cpu->delay_slot || + page == NULL || (addr0 & 3) != 0 || (addr1 & 3) != 0 || + index0 != index1) { + /* Normal safe sw: */ + mips32_loadstore[16 + 8 + 2 * 2](cpu, ic); + return; + } + + addr0 = (addr0 >> 2) & 0x3ff; + addr1 = (addr1 >> 2) & 0x3ff; + + r1 = reg(ic[0].arg[0]); + r2 = reg(ic[1].arg[0]); + + r1 = BE32_TO_HOST(r1); + r2 = BE32_TO_HOST(r2); + + page[addr0] = r1; + page[addr1] = r2; + + cpu->n_translated_instrs ++; + cpu->cd.mips.next_ic ++; +} X(multi_sw_3_le) { uint32_t *page; @@ -2434,7 +2557,7 @@ page == NULL || (addr0 & 3) != 0 || (addr1 & 3) != 0 || (addr2 & 3) != 0 || index0 != index1 || index0 != index2) { /* Normal safe sw: */ - ic[1].f(cpu, ic); + mips32_loadstore[8 + 2 * 2](cpu, ic); return; } @@ -2458,7 +2581,7 @@ page[addr2] = r3; cpu->n_translated_instrs += 2; - cpu->cd.mips.next_ic = (struct mips_instr_call *) &ic[3]; + cpu->cd.mips.next_ic += 2; } X(multi_sw_3_be) { @@ -2477,7 +2600,7 @@ page == NULL || (addr0 & 3) != 0 || (addr1 & 3) != 0 || (addr2 & 3) != 0 || index0 != index1 || index0 != index2) { /* Normal safe sw: */ - ic[1].f(cpu, ic); + mips32_loadstore[16 + 8 + 2 * 2](cpu, ic); return; } @@ -2501,7 +2624,374 @@ page[addr2] = r3; cpu->n_translated_instrs += 2; - cpu->cd.mips.next_ic = (struct mips_instr_call *) &ic[3]; + cpu->cd.mips.next_ic += 2; +} +X(multi_sw_4_le) +{ + uint32_t *page; + MODE_uint_t rX = reg(ic[0].arg[1]), r1, r2, r3, r4; + MODE_uint_t addr0 = rX + (int32_t)ic[0].arg[2]; + MODE_uint_t addr1 = rX + (int32_t)ic[1].arg[2]; + MODE_uint_t addr2 = rX + (int32_t)ic[2].arg[2]; + MODE_uint_t addr3 = rX + (int32_t)ic[3].arg[2]; + uint32_t index0 = addr0 >> 12, index1 = addr1 >> 12, + index2 = addr2 >> 12, index3 = addr3 >> 12; + + page = (uint32_t *) cpu->cd.mips.host_store[index0]; + + /* Fallback: */ + if (cpu->delay_slot || + page == NULL || (addr0 & 3) != 0 || (addr1 & 3) != 0 || + (addr2 & 3) != 0 || (addr3 & 3) != 0 || index0 != index1 || + index0 != index2 || index0 != index3) { + /* Normal safe sw: */ + mips32_loadstore[8 + 2 * 2](cpu, ic); + return; + } + + addr0 = (addr0 >> 2) & 0x3ff; + addr1 = (addr1 >> 2) & 0x3ff; + addr2 = (addr2 >> 2) & 0x3ff; + addr3 = (addr3 >> 2) & 0x3ff; + + r1 = reg(ic[0].arg[0]); + r2 = reg(ic[1].arg[0]); + r3 = reg(ic[2].arg[0]); + r4 = reg(ic[3].arg[0]); + + r1 = LE32_TO_HOST(r1); + r2 = LE32_TO_HOST(r2); + r3 = LE32_TO_HOST(r3); + r4 = LE32_TO_HOST(r4); + + page[addr0] = r1; + page[addr1] = r2; + page[addr2] = r3; + page[addr3] = r4; + + cpu->n_translated_instrs += 3; + cpu->cd.mips.next_ic += 3; +} +X(multi_sw_4_be) +{ + uint32_t *page; + MODE_uint_t rX = reg(ic[0].arg[1]), r1, r2, r3, r4; + MODE_uint_t addr0 = rX + (int32_t)ic[0].arg[2]; + MODE_uint_t addr1 = rX + (int32_t)ic[1].arg[2]; + MODE_uint_t addr2 = rX + (int32_t)ic[2].arg[2]; + MODE_uint_t addr3 = rX + (int32_t)ic[3].arg[2]; + uint32_t index0 = addr0 >> 12, index1 = addr1 >> 12, + index2 = addr2 >> 12, index3 = addr3 >> 12; + + page = (uint32_t *) cpu->cd.mips.host_store[index0]; + + /* Fallback: */ + if (cpu->delay_slot || + page == NULL || (addr0 & 3) != 0 || (addr1 & 3) != 0 || + (addr2 & 3) != 0 || (addr3 & 3) != 0 || index0 != index1 || + index0 != index2 || index0 != index3) { + /* Normal safe sw: */ + mips32_loadstore[16 + 8 + 2 * 2](cpu, ic); + return; + } + + addr0 = (addr0 >> 2) & 0x3ff; + addr1 = (addr1 >> 2) & 0x3ff; + addr2 = (addr2 >> 2) & 0x3ff; + addr3 = (addr3 >> 2) & 0x3ff; + + r1 = reg(ic[0].arg[0]); + r2 = reg(ic[1].arg[0]); + r3 = reg(ic[2].arg[0]); + r4 = reg(ic[3].arg[0]); + + r1 = BE32_TO_HOST(r1); + r2 = BE32_TO_HOST(r2); + r3 = BE32_TO_HOST(r3); + r4 = BE32_TO_HOST(r4); + + page[addr0] = r1; + page[addr1] = r2; + page[addr2] = r3; + page[addr3] = r4; + + cpu->n_translated_instrs += 3; + cpu->cd.mips.next_ic += 3; +} +#endif + + +#ifdef MODE32 +/* + * multi_lw_2, _3, _4: + * + * lw r?,ofs(rX) r?=arg[0], rX=arg[1], ofs=arg[2] + */ +X(multi_lw_2_le) +{ + uint32_t *page; + MODE_uint_t rX = reg(ic[0].arg[1]), r1, r2; + MODE_uint_t addr0 = rX + (int32_t)ic[0].arg[2]; + MODE_uint_t addr1 = rX + (int32_t)ic[1].arg[2]; + uint32_t index0 = addr0 >> 12, index1 = addr1 >> 12; + + page = (uint32_t *) cpu->cd.mips.host_load[index0]; + + /* Fallback: */ + if (cpu->delay_slot || + page == NULL || (addr0 & 3) != 0 || (addr1 & 3) != 0 || + index0 != index1) { + /* Normal safe lw: */ + mips32_loadstore[2 * 2 + 1](cpu, ic); + return; + } + + addr0 = (addr0 >> 2) & 0x3ff; + addr1 = (addr1 >> 2) & 0x3ff; + + r1 = page[addr0]; + r2 = page[addr1]; + + r1 = LE32_TO_HOST(r1); + r2 = LE32_TO_HOST(r2); + + reg(ic[0].arg[0]) = r1; + reg(ic[1].arg[0]) = r2; + + cpu->n_translated_instrs ++; + cpu->cd.mips.next_ic ++; +} +X(multi_lw_2_be) +{ + uint32_t *page; + MODE_uint_t rX = reg(ic[0].arg[1]), r1, r2; + MODE_uint_t addr0 = rX + (int32_t)ic[0].arg[2]; + MODE_uint_t addr1 = rX + (int32_t)ic[1].arg[2]; + uint32_t index0 = addr0 >> 12, index1 = addr1 >> 12; + + page = (uint32_t *) cpu->cd.mips.host_load[index0]; + + /* Fallback: */ + if (cpu->delay_slot || + page == NULL || (addr0 & 3) != 0 || (addr1 & 3) != 0 || + index0 != index1) { + /* Normal safe lw: */ + mips32_loadstore[16 + 2 * 2 + 1](cpu, ic); + return; + } + + addr0 = (addr0 >> 2) & 0x3ff; + addr1 = (addr1 >> 2) & 0x3ff; + + r1 = page[addr0]; + r2 = page[addr1]; + + r1 = BE32_TO_HOST(r1); + r2 = BE32_TO_HOST(r2); + + reg(ic[0].arg[0]) = r1; + reg(ic[1].arg[0]) = r2; + + cpu->n_translated_instrs ++; + cpu->cd.mips.next_ic ++; +} +X(multi_lw_3_le) +{ + uint32_t *page; + MODE_uint_t rX = reg(ic[0].arg[1]), r1, r2, r3; + MODE_uint_t addr0 = rX + (int32_t)ic[0].arg[2]; + MODE_uint_t addr1 = rX + (int32_t)ic[1].arg[2]; + MODE_uint_t addr2 = rX + (int32_t)ic[2].arg[2]; + uint32_t index0 = addr0 >> 12, index1 = addr1 >> 12, + index2 = addr2 >> 12; + + page = (uint32_t *) cpu->cd.mips.host_load[index0]; + + /* Fallback: */ + if (cpu->delay_slot || + page == NULL || (addr0 & 3) != 0 || (addr1 & 3) != 0 || + (addr2 & 3) != 0 || index0 != index1 || index0 != index2) { + /* Normal safe lw: */ + mips32_loadstore[2 * 2 + 1](cpu, ic); + return; + } + + addr0 = (addr0 >> 2) & 0x3ff; + addr1 = (addr1 >> 2) & 0x3ff; + addr2 = (addr2 >> 2) & 0x3ff; + + /* printf("addr0=%x 1=%x 2=%x\n", + (int)addr0, (int)addr1, (int)addr2); */ + + r1 = page[addr0]; + r2 = page[addr1]; + r3 = page[addr2]; + + r1 = LE32_TO_HOST(r1); + r2 = LE32_TO_HOST(r2); + r3 = LE32_TO_HOST(r3); + + reg(ic[0].arg[0]) = r1; + reg(ic[1].arg[0]) = r2; + reg(ic[2].arg[0]) = r3; + + cpu->n_translated_instrs += 2; + cpu->cd.mips.next_ic += 2; +} +X(multi_lw_3_be) +{ + uint32_t *page; + MODE_uint_t rX = reg(ic[0].arg[1]), r1, r2, r3; + MODE_uint_t addr0 = rX + (int32_t)ic[0].arg[2]; + MODE_uint_t addr1 = rX + (int32_t)ic[1].arg[2]; + MODE_uint_t addr2 = rX + (int32_t)ic[2].arg[2]; + uint32_t index0 = addr0 >> 12, index1 = addr1 >> 12, + index2 = addr2 >> 12; + + page = (uint32_t *) cpu->cd.mips.host_load[index0]; + + /* Fallback: */ + if (cpu->delay_slot || + page == NULL || (addr0 & 3) != 0 || (addr1 & 3) != 0 || + (addr2 & 3) != 0 || index0 != index1 || index0 != index2) { + /* Normal safe lw: */ + mips32_loadstore[16 + 2 * 2 + 1](cpu, ic); + return; + } + + addr0 = (addr0 >> 2) & 0x3ff; + addr1 = (addr1 >> 2) & 0x3ff; + addr2 = (addr2 >> 2) & 0x3ff; + + /* printf("addr0=%x 1=%x 2=%x\n", + (int)addr0, (int)addr1, (int)addr2); */ + + r1 = page[addr0]; + r2 = page[addr1]; + r3 = page[addr2]; + + r1 = BE32_TO_HOST(r1); + r2 = BE32_TO_HOST(r2); + r3 = BE32_TO_HOST(r3); + + reg(ic[0].arg[0]) = r1; + reg(ic[1].arg[0]) = r2; + reg(ic[2].arg[0]) = r3; + + cpu->n_translated_instrs += 2; + cpu->cd.mips.next_ic += 2; +} +X(multi_lw_4_le) +{ + uint32_t *page; + MODE_uint_t rX = reg(ic[0].arg[1]), r1, r2, r3, r4; + MODE_uint_t addr0 = rX + (int32_t)ic[0].arg[2]; + MODE_uint_t addr1 = rX + (int32_t)ic[1].arg[2]; + MODE_uint_t addr2 = rX + (int32_t)ic[2].arg[2]; + MODE_uint_t addr3 = rX + (int32_t)ic[3].arg[2]; + uint32_t index0 = addr0 >> 12, index1 = addr1 >> 12, + index2 = addr2 >> 12, index3 = addr3 >> 12; + + page = (uint32_t *) cpu->cd.mips.host_load[index0]; + + /* Fallback: */ + if (cpu->delay_slot || + page == NULL || (addr0 & 3) != 0 || (addr1 & 3) != 0 || + (addr2 & 3) != 0 || (addr3 & 3) != 0 || + index0 != index1 || index0 != index2 || index0 != index3) { + /* Normal safe lw: */ + mips32_loadstore[2 * 2 + 1](cpu, ic); + return; + } + + addr0 = (addr0 >> 2) & 0x3ff; + addr1 = (addr1 >> 2) & 0x3ff; + addr2 = (addr2 >> 2) & 0x3ff; + addr3 = (addr3 >> 2) & 0x3ff; + + r1 = page[addr0]; + r2 = page[addr1]; + r3 = page[addr2]; + r4 = page[addr3]; + + r1 = LE32_TO_HOST(r1); + r2 = LE32_TO_HOST(r2); + r3 = LE32_TO_HOST(r3); + r4 = LE32_TO_HOST(r4); + + reg(ic[0].arg[0]) = r1; + reg(ic[1].arg[0]) = r2; + reg(ic[2].arg[0]) = r3; + reg(ic[3].arg[0]) = r4; + + cpu->n_translated_instrs += 3; + cpu->cd.mips.next_ic += 3; +} +X(multi_lw_4_be) +{ + uint32_t *page; + MODE_uint_t rX = reg(ic[0].arg[1]), r1, r2, r3, r4; + MODE_uint_t addr0 = rX + (int32_t)ic[0].arg[2]; + MODE_uint_t addr1 = rX + (int32_t)ic[1].arg[2]; + MODE_uint_t addr2 = rX + (int32_t)ic[2].arg[2]; + MODE_uint_t addr3 = rX + (int32_t)ic[3].arg[2]; + uint32_t index0 = addr0 >> 12, index1 = addr1 >> 12, + index2 = addr2 >> 12, index3 = addr3 >> 12; + + page = (uint32_t *) cpu->cd.mips.host_load[index0]; + + /* Fallback: */ + if (cpu->delay_slot || + page == NULL || (addr0 & 3) != 0 || (addr1 & 3) != 0 || + (addr2 & 3) != 0 || (addr3 & 3) != 0 || + index0 != index1 || index0 != index2 || index0 != index3) { + /* Normal safe lw: */ + mips32_loadstore[16 + 2 * 2 + 1](cpu, ic); + return; + } + + addr0 = (addr0 >> 2) & 0x3ff; + addr1 = (addr1 >> 2) & 0x3ff; + addr2 = (addr2 >> 2) & 0x3ff; + addr3 = (addr3 >> 2) & 0x3ff; + + r1 = page[addr0]; + r2 = page[addr1]; + r3 = page[addr2]; + r4 = page[addr3]; + + r1 = BE32_TO_HOST(r1); + r2 = BE32_TO_HOST(r2); + r3 = BE32_TO_HOST(r3); + r4 = BE32_TO_HOST(r4); + + reg(ic[0].arg[0]) = r1; + reg(ic[1].arg[0]) = r2; + reg(ic[2].arg[0]) = r3; + reg(ic[3].arg[0]) = r4; + + cpu->n_translated_instrs += 3; + cpu->cd.mips.next_ic += 3; +} +#endif + + +/* + * multi_addu_3: + */ +X(multi_addu_3) +{ + /* Fallback: */ + if (cpu->delay_slot) { + instr(addu)(cpu, ic); + return; + } + + reg(ic[0].arg[2]) = (int32_t)(reg(ic[0].arg[0]) + reg(ic[0].arg[1])); + reg(ic[1].arg[2]) = (int32_t)(reg(ic[1].arg[0]) + reg(ic[1].arg[1])); + reg(ic[2].arg[2]) = (int32_t)(reg(ic[2].arg[0]) + reg(ic[2].arg[1])); + cpu->n_translated_instrs += 2; + cpu->cd.mips.next_ic += 2; } @@ -2592,14 +3082,104 @@ /* - * lui_32bit: - * - * Combination of lui and addiu. - * Note: All 32 bits of arg[2] of the lui instr_call are used. + * addiu_bne_samepage_addiu: */ -X(lui_32bit) +X(addiu_bne_samepage_addiu) { - reg(ic[0].arg[0]) = (int32_t) ic[0].arg[2]; + MODE_uint_t rs, rt; + + if (cpu->delay_slot) { + instr(addiu)(cpu, ic); + return; + } + + cpu->n_translated_instrs += 2; + reg(ic[0].arg[1]) = (int32_t) + ((int32_t)reg(ic[0].arg[0]) + (int32_t)ic[0].arg[2]); + rs = reg(ic[1].arg[0]); + rt = reg(ic[1].arg[1]); + reg(ic[2].arg[1]) = (int32_t) + ((int32_t)reg(ic[2].arg[0]) + (int32_t)ic[2].arg[2]); + if (rs != rt) + cpu->cd.mips.next_ic = (struct mips_instr_call *) ic[1].arg[2]; + else + cpu->cd.mips.next_ic += 2; +} + + +/* + * xor_andi_sll: + */ +X(xor_andi_sll) +{ + /* Fallback: */ + if (cpu->delay_slot) { + instr(xor)(cpu, ic); + return; + } + + reg(ic[0].arg[2]) = reg(ic[0].arg[0]) ^ reg(ic[0].arg[1]); + reg(ic[1].arg[1]) = reg(ic[1].arg[0]) & (uint32_t)ic[1].arg[2]; + reg(ic[2].arg[2]) = (int32_t)(reg(ic[2].arg[0])<<(int32_t)ic[2].arg[1]); + + cpu->n_translated_instrs += 2; + cpu->cd.mips.next_ic += 2; +} + + +/* + * andi_sll: + */ +X(andi_sll) +{ + /* Fallback: */ + if (cpu->delay_slot) { + instr(andi)(cpu, ic); + return; + } + + reg(ic[0].arg[1]) = reg(ic[0].arg[0]) & (uint32_t)ic[0].arg[2]; + reg(ic[1].arg[2]) = (int32_t)(reg(ic[1].arg[0])<<(int32_t)ic[1].arg[1]); + + cpu->n_translated_instrs ++; + cpu->cd.mips.next_ic ++; +} + + +/* + * lui_ori: + */ +X(lui_ori) +{ + /* Fallback: */ + if (cpu->delay_slot) { + instr(set)(cpu, ic); + return; + } + + reg(ic[0].arg[0]) = (int32_t)ic[0].arg[1]; + reg(ic[1].arg[1]) = reg(ic[1].arg[0]) | (uint32_t)ic[1].arg[2]; + + cpu->n_translated_instrs ++; + cpu->cd.mips.next_ic ++; +} + + +/* + * lui_addiu: + */ +X(lui_addiu) +{ + /* Fallback: */ + if (cpu->delay_slot) { + instr(set)(cpu, ic); + return; + } + + reg(ic[0].arg[0]) = (int32_t)ic[0].arg[1]; + reg(ic[1].arg[1]) = (int32_t) + ((int32_t)reg(ic[1].arg[0]) + (int32_t)ic[1].arg[2]); + cpu->n_translated_instrs ++; cpu->cd.mips.next_ic ++; } @@ -2739,11 +3319,12 @@ ic[0].arg[0] != ic[0].arg[1] && ic[0].arg[1] == ic[-2].arg[0] && (int32_t)ic[0].arg[2] == -4) { ic[-2].f = instr(sw_loop); - combined; } } +/* Only for 32-bit virtual address translation so far. */ +#ifdef MODE32 /* * Combine: Multiple SW in a row using the same base register * @@ -2758,28 +3339,91 @@ int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) & (MIPS_IC_ENTRIES_PER_PAGE - 1); - /* Only for 32-bit virtual address translation so far. */ - if (!cpu->is_32bit) + if (n_back < 3) return; - if (n_back < 4) - return; + /* Convert a multi_sw_3 to a multi_sw_4: */ + if ((ic[-3].f == instr(multi_sw_3_be) || + ic[-3].f == instr(multi_sw_3_le)) && + ic[-3].arg[1] == ic[0].arg[1]) { + if (cpu->byte_order == EMUL_LITTLE_ENDIAN) + ic[-3].f = instr(multi_sw_4_le); + else + ic[-3].f = instr(multi_sw_4_be); + } - /* Avoid "overlapping" instruction combinations: */ - if (ic[-4].f == instr(multi_sw_3_be)||ic[-3].f == instr(multi_sw_3_be)|| - ic[-4].f == instr(multi_sw_3_le)||ic[-3].f == instr(multi_sw_3_le)) + /* Convert a multi_sw_2 to a multi_sw_3: */ + if ((ic[-2].f == instr(multi_sw_2_be) || + ic[-2].f == instr(multi_sw_2_le)) && + ic[-2].arg[1] == ic[0].arg[1]) { + if (cpu->byte_order == EMUL_LITTLE_ENDIAN) + ic[-2].f = instr(multi_sw_3_le); + else + ic[-2].f = instr(multi_sw_3_be); + } + + if (ic[-1].f == ic[0].f && ic[-1].arg[1] == ic[0].arg[1]) { + if (cpu->byte_order == EMUL_LITTLE_ENDIAN) + ic[-1].f = instr(multi_sw_2_le); + else + ic[-1].f = instr(multi_sw_2_be); + } +} +#endif + + +/* Only for 32-bit virtual address translation so far. */ +#ifdef MODE32 +/* + * Combine: Multiple LW in a row using the same base register + * + * lw r?,???(rX) + * lw r?,???(rX) + * lw r?,???(rX) + * ... + */ +void COMBINE(multi_lw)(struct cpu *cpu, struct mips_instr_call *ic, + int low_addr) +{ + int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) + & (MIPS_IC_ENTRIES_PER_PAGE - 1); + + if (n_back < 3) return; - if (ic[-2].f == ic[0].f && ic[-1].f == ic[0].f && + /* Convert a multi_lw_3 to a multi_lw_4: */ + if ((ic[-3].f == instr(multi_lw_3_be) || + ic[-3].f == instr(multi_lw_3_le)) && + ic[-3].arg[1] == ic[0].arg[1] && + ic[-1].arg[0] != ic[0].arg[1]) { + if (cpu->byte_order == EMUL_LITTLE_ENDIAN) + ic[-3].f = instr(multi_lw_4_le); + else + ic[-3].f = instr(multi_lw_4_be); + } + + /* Convert a multi_lw_2 to a multi_lw_3: */ + if ((ic[-2].f == instr(multi_lw_2_be) || + ic[-2].f == instr(multi_lw_2_le)) && ic[-2].arg[1] == ic[0].arg[1] && - ic[-1].arg[1] == ic[0].arg[1]) { + ic[-1].arg[0] != ic[0].arg[1]) { if (cpu->byte_order == EMUL_LITTLE_ENDIAN) - ic[-2].f = instr(multi_sw_3_le); + ic[-2].f = instr(multi_lw_3_le); else - ic[-2].f = instr(multi_sw_3_be); - combined; + ic[-2].f = instr(multi_lw_3_be); + } + + /* Note: Loads to the base register are not allowed in slot -1. */ + if (ic[-1].f == ic[0].f && + ic[-1].arg[1] == ic[0].arg[1] && + ic[-1].arg[0] != ic[0].arg[1]) { + if (cpu->byte_order == EMUL_LITTLE_ENDIAN) + ic[-1].f = instr(multi_lw_2_le); + else + ic[-1].f = instr(multi_lw_2_be); } } +#endif /* @@ -2815,7 +3459,6 @@ ic[-3].arg[1] == ic[-5].arg[0] && ic[-2].f == instr(nop) && ic[-1].f == instr(nop)) { ic[-8].f = instr(netbsd_r3k_picache_do_inv); - combined; } } @@ -2844,7 +3487,6 @@ ic[-1].arg[1] == (size_t) &cpu->cd.mips.gpr[MIPS_GPR_ZERO] && ic[-1].f == instr(bne_samepage)) { ic[-3].f = instr(netbsd_strlen); - combined; return; } #endif @@ -2854,13 +3496,11 @@ if (ic[-1].f == instr(bne_samepage)) { ic[-1].f = instr(bne_samepage_nop); - combined; return; } if (ic[-1].f == instr(beq_samepage)) { ic[-1].f = instr(beq_samepage_nop); - combined; return; } @@ -2871,46 +3511,111 @@ /* * Combine: * + * xor + andi + sll + * andi + sll + */ +void COMBINE(sll)(struct cpu *cpu, struct mips_instr_call *ic, int low_addr) +{ + int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) + & (MIPS_IC_ENTRIES_PER_PAGE - 1); + + if (n_back < 2) + return; + + if (ic[-2].f == instr(xor) && ic[-1].f == instr(andi)) { + ic[-2].f = instr(xor_andi_sll); + return; + } + + if (ic[-1].f == instr(andi)) { + ic[-1].f = instr(andi_sll); + return; + } +} + + +/* + * lui + ori + */ +void COMBINE(ori)(struct cpu *cpu, struct mips_instr_call *ic, int low_addr) +{ + int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) + & (MIPS_IC_ENTRIES_PER_PAGE - 1); + + if (n_back < 1) + return; + + if (ic[-1].f == instr(set)) { + ic[-1].f = instr(lui_ori); + return; + } +} + + +/* + * addu + addu + addu + */ +void COMBINE(addu)(struct cpu *cpu, struct mips_instr_call *ic, int low_addr) +{ + int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) + & (MIPS_IC_ENTRIES_PER_PAGE - 1); + + if (n_back < 4) + return; + + /* Avoid "overlapping" instruction combinations: */ + if (ic[-4].f == instr(multi_addu_3) || + ic[-3].f == instr(multi_addu_3)) + return; + + if (ic[-2].f == instr(addu) && ic[-1].f == instr(addu)) { + ic[-2].f = instr(multi_addu_3); + return; + } +} + + +/* + * Combine: + * * [Conditional] branch, followed by addiu. - * lui + addiu. */ void COMBINE(addiu)(struct cpu *cpu, struct mips_instr_call *ic, int low_addr) { int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) & (MIPS_IC_ENTRIES_PER_PAGE - 1); - if (n_back < 1) + if (n_back < 2) + return; + + if (ic[-2].f == instr(addiu) && + ic[-1].f == instr(bne_samepage)) { + ic[-2].f = instr(addiu_bne_samepage_addiu); return; + } - if (ic[-1].f == instr(set) && ic[-1].arg[0] == ic[0].arg[0] && - ic[0].arg[0] == ic[0].arg[1]) { - ic[-1].f = instr(lui_32bit); - ic[-1].arg[2] = (int32_t) (ic[-1].arg[1] + ic[0].arg[2]); - combined; + if (ic[-1].f == instr(set)) { + ic[-1].f = instr(lui_addiu); return; } if (ic[-1].f == instr(b_samepage)) { ic[-1].f = instr(b_samepage_addiu); - combined; return; } if (ic[-1].f == instr(beq_samepage)) { ic[-1].f = instr(beq_samepage_addiu); - combined; return; } if (ic[-1].f == instr(bne_samepage)) { ic[-1].f = instr(bne_samepage_addiu); - combined; return; } if (ic[-1].f == instr(jr_ra)) { ic[-1].f = instr(jr_ra_addiu); - combined; return; } @@ -2932,7 +3637,6 @@ if (ic[-1].f == instr(b_samepage)) { ic[-1].f = instr(b_samepage_daddiu); - combined; } /* TODO: other branches that are followed by daddiu should be here */ @@ -3089,6 +3793,8 @@ ic->arg[2] = (size_t)&cpu->cd.mips.gpr[rd]; if (rd == MIPS_GPR_ZERO) ic->f = instr(nop); + if (ic->f == instr(sll)) + cpu->cd.mips.combination_check = COMBINE(sll); break; case SPECIAL_ADD: @@ -3220,6 +3926,9 @@ default:if (rd == MIPS_GPR_ZERO) ic->f = instr(nop); } + + if (ic->f == instr(addu)) + cpu->cd.mips.combination_check = COMBINE(addu); break; case SPECIAL_JR: @@ -3263,7 +3972,12 @@ break; case SPECIAL_BREAK: - ic->f = instr(break); + if (((iword >> 6) & 0xfffff) == 0x30378) { + /* "Magic trap" for REBOOT: */ + ic->f = instr(reboot); + } else { + ic->f = instr(break); + } break; case SPECIAL_SYNC: @@ -3390,6 +4104,8 @@ if (rt == MIPS_GPR_ZERO) ic->f = instr(nop); + if (ic->f == instr(ori)) + cpu->cd.mips.combination_check = COMBINE(ori); if (ic->f == instr(addiu)) cpu->cd.mips.combination_check = COMBINE(addiu); if (ic->f == instr(daddiu)) @@ -3455,7 +4171,22 @@ case COP0_DERET: ic->f = instr(deret); break; - case COP0_IDLE: + case COP0_WAIT: + ic->f = instr(wait); + if (cpu->cd.mips.cpu_type.rev != MIPS_RM5200 && + cpu->cd.mips.cpu_type.isa_level < 32) { + static int warned = 0; + ic->f = instr(reserved); + if (!warned) { + fatal("{ WARNING: Attempt to " + "execute the WAIT instruct" + "ion, but the emulated CPU " + "is neither RM52xx, nor " + "MIPS32/64! }\n"); + warned = 1; + } + } + break; case COP0_STANDBY: case COP0_SUSPEND: case COP0_HIBERNATE: @@ -3830,11 +4561,14 @@ if (!store && rt == MIPS_GPR_ZERO) ic->arg[0] = (size_t)&cpu->cd.mips.scratch; - /* Check for multiple stores in a row using the same + /* Check for multiple loads or stores in a row using the same base register: */ - if (main_opcode == HI6_SW && rs == MIPS_GPR_SP) +#ifdef MODE32 + if (main_opcode == HI6_LW) + cpu->cd.mips.combination_check = COMBINE(multi_lw); + if (main_opcode == HI6_SW) cpu->cd.mips.combination_check = COMBINE(multi_sw); - +#endif break; case HI6_LL: