mirror of
https://github.com/mupen64plus/mupen64plus-core.git
synced 2024-06-02 19:27:51 -04:00
efdeaf32c7
s/interupt/interrupt/
263 lines
12 KiB
Modula-2
263 lines
12 KiB
Modula-2
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Mupen64plus - interpreter_tlb.def *
|
|
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
|
* Copyright (C) 2002 Hacktarux *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License *
|
|
* along with this program; if not, write to the *
|
|
* Free Software Foundation, Inc., *
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
#include <zlib.h> // For adler32()
|
|
|
|
DECLARE_INSTRUCTION(TLBR)
|
|
{
|
|
uint32_t* cp0_regs = r4300_cp0_regs();
|
|
|
|
int index;
|
|
index = cp0_regs[CP0_INDEX_REG] & UINT32_C(0x1F);
|
|
cp0_regs[CP0_PAGEMASK_REG] = g_dev.r4300.cp0.tlb.entries[index].mask << 13;
|
|
cp0_regs[CP0_ENTRYHI_REG] = ((g_dev.r4300.cp0.tlb.entries[index].vpn2 << 13) | g_dev.r4300.cp0.tlb.entries[index].asid);
|
|
cp0_regs[CP0_ENTRYLO0_REG] = (g_dev.r4300.cp0.tlb.entries[index].pfn_even << 6) | (g_dev.r4300.cp0.tlb.entries[index].c_even << 3)
|
|
| (g_dev.r4300.cp0.tlb.entries[index].d_even << 2) | (g_dev.r4300.cp0.tlb.entries[index].v_even << 1)
|
|
| g_dev.r4300.cp0.tlb.entries[index].g;
|
|
cp0_regs[CP0_ENTRYLO1_REG] = (g_dev.r4300.cp0.tlb.entries[index].pfn_odd << 6) | (g_dev.r4300.cp0.tlb.entries[index].c_odd << 3)
|
|
| (g_dev.r4300.cp0.tlb.entries[index].d_odd << 2) | (g_dev.r4300.cp0.tlb.entries[index].v_odd << 1)
|
|
| g_dev.r4300.cp0.tlb.entries[index].g;
|
|
ADD_TO_PC(1);
|
|
}
|
|
|
|
static void TLBWrite(unsigned int idx)
|
|
{
|
|
uint32_t* cp0_regs = r4300_cp0_regs();
|
|
|
|
if (g_dev.r4300.emumode != EMUMODE_PURE_INTERPRETER)
|
|
{
|
|
unsigned int i;
|
|
if (g_dev.r4300.cp0.tlb.entries[idx].v_even)
|
|
{
|
|
for (i=g_dev.r4300.cp0.tlb.entries[idx].start_even>>12; i<=g_dev.r4300.cp0.tlb.entries[idx].end_even>>12; i++)
|
|
{
|
|
if(!g_dev.r4300.cached_interp.invalid_code[i] &&(g_dev.r4300.cached_interp.invalid_code[g_dev.r4300.cp0.tlb.LUT_r[i]>>12] ||
|
|
g_dev.r4300.cached_interp.invalid_code[(g_dev.r4300.cp0.tlb.LUT_r[i]>>12)+0x20000]))
|
|
g_dev.r4300.cached_interp.invalid_code[i] = 1;
|
|
if (!g_dev.r4300.cached_interp.invalid_code[i])
|
|
{
|
|
/*int j;
|
|
md5_state_t state;
|
|
md5_byte_t digest[16];
|
|
md5_init(&state);
|
|
md5_append(&state,
|
|
(const md5_byte_t*)&g_dev.ri.rdram.dram[(g_dev.r4300.cp0.tlb.LUT_r[i]&0x7FF000)/4],
|
|
0x1000);
|
|
md5_finish(&state, digest);
|
|
for (j=0; j<16; j++) g_dev.r4300.cached_interp.blocks[i]->md5[j] = digest[j];*/
|
|
|
|
g_dev.r4300.cached_interp.blocks[i]->adler32 = adler32(0, (const unsigned char *)&g_dev.ri.rdram.dram[(g_dev.r4300.cp0.tlb.LUT_r[i]&0x7FF000)/4], 0x1000);
|
|
|
|
g_dev.r4300.cached_interp.invalid_code[i] = 1;
|
|
}
|
|
else if (g_dev.r4300.cached_interp.blocks[i])
|
|
{
|
|
/*int j;
|
|
for (j=0; j<16; j++) g_dev.r4300.cached_interp.blocks[i]->md5[j] = 0;*/
|
|
g_dev.r4300.cached_interp.blocks[i]->adler32 = 0;
|
|
}
|
|
}
|
|
}
|
|
if (g_dev.r4300.cp0.tlb.entries[idx].v_odd)
|
|
{
|
|
for (i=g_dev.r4300.cp0.tlb.entries[idx].start_odd>>12; i<=g_dev.r4300.cp0.tlb.entries[idx].end_odd>>12; i++)
|
|
{
|
|
if(!g_dev.r4300.cached_interp.invalid_code[i] &&(g_dev.r4300.cached_interp.invalid_code[g_dev.r4300.cp0.tlb.LUT_r[i]>>12] ||
|
|
g_dev.r4300.cached_interp.invalid_code[(g_dev.r4300.cp0.tlb.LUT_r[i]>>12)+0x20000]))
|
|
g_dev.r4300.cached_interp.invalid_code[i] = 1;
|
|
if (!g_dev.r4300.cached_interp.invalid_code[i])
|
|
{
|
|
/*int j;
|
|
md5_state_t state;
|
|
md5_byte_t digest[16];
|
|
md5_init(&state);
|
|
md5_append(&state,
|
|
(const md5_byte_t*)&g_dev.ri.rdram.dram[(g_dev.r4300.cp0.tlb.LUT_r[i]&0x7FF000)/4],
|
|
0x1000);
|
|
md5_finish(&state, digest);
|
|
for (j=0; j<16; j++) g_dev.r4300.cached_interp.blocks[i]->md5[j] = digest[j];*/
|
|
|
|
g_dev.r4300.cached_interp.blocks[i]->adler32 = adler32(0, (const unsigned char *)&g_dev.ri.rdram.dram[(g_dev.r4300.cp0.tlb.LUT_r[i]&0x7FF000)/4], 0x1000);
|
|
|
|
g_dev.r4300.cached_interp.invalid_code[i] = 1;
|
|
}
|
|
else if (g_dev.r4300.cached_interp.blocks[i])
|
|
{
|
|
/*int j;
|
|
for (j=0; j<16; j++) g_dev.r4300.cached_interp.blocks[i]->md5[j] = 0;*/
|
|
g_dev.r4300.cached_interp.blocks[i]->adler32 = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
tlb_unmap(&g_dev.r4300.cp0.tlb, idx);
|
|
|
|
g_dev.r4300.cp0.tlb.entries[idx].g = (cp0_regs[CP0_ENTRYLO0_REG] & cp0_regs[CP0_ENTRYLO1_REG] & 1);
|
|
g_dev.r4300.cp0.tlb.entries[idx].pfn_even = (cp0_regs[CP0_ENTRYLO0_REG] & UINT32_C(0x3FFFFFC0)) >> 6;
|
|
g_dev.r4300.cp0.tlb.entries[idx].pfn_odd = (cp0_regs[CP0_ENTRYLO1_REG] & UINT32_C(0x3FFFFFC0)) >> 6;
|
|
g_dev.r4300.cp0.tlb.entries[idx].c_even = (cp0_regs[CP0_ENTRYLO0_REG] & UINT32_C(0x38)) >> 3;
|
|
g_dev.r4300.cp0.tlb.entries[idx].c_odd = (cp0_regs[CP0_ENTRYLO1_REG] & UINT32_C(0x38)) >> 3;
|
|
g_dev.r4300.cp0.tlb.entries[idx].d_even = (cp0_regs[CP0_ENTRYLO0_REG] & UINT32_C(0x4)) >> 2;
|
|
g_dev.r4300.cp0.tlb.entries[idx].d_odd = (cp0_regs[CP0_ENTRYLO1_REG] & UINT32_C(0x4)) >> 2;
|
|
g_dev.r4300.cp0.tlb.entries[idx].v_even = (cp0_regs[CP0_ENTRYLO0_REG] & UINT32_C(0x2)) >> 1;
|
|
g_dev.r4300.cp0.tlb.entries[idx].v_odd = (cp0_regs[CP0_ENTRYLO1_REG] & UINT32_C(0x2)) >> 1;
|
|
g_dev.r4300.cp0.tlb.entries[idx].asid = (cp0_regs[CP0_ENTRYHI_REG] & UINT32_C(0xFF));
|
|
g_dev.r4300.cp0.tlb.entries[idx].vpn2 = (cp0_regs[CP0_ENTRYHI_REG] & UINT32_C(0xFFFFE000)) >> 13;
|
|
//g_dev.r4300.cp0.tlb.entries[idx].r = (cp0_regs[CP0_ENTRYHI_REG] & 0xC000000000000000LL) >> 62;
|
|
g_dev.r4300.cp0.tlb.entries[idx].mask = (cp0_regs[CP0_PAGEMASK_REG] & UINT32_C(0x1FFE000)) >> 13;
|
|
|
|
g_dev.r4300.cp0.tlb.entries[idx].start_even = g_dev.r4300.cp0.tlb.entries[idx].vpn2 << 13;
|
|
g_dev.r4300.cp0.tlb.entries[idx].end_even = g_dev.r4300.cp0.tlb.entries[idx].start_even+
|
|
(g_dev.r4300.cp0.tlb.entries[idx].mask << 12) + UINT32_C(0xFFF);
|
|
g_dev.r4300.cp0.tlb.entries[idx].phys_even = g_dev.r4300.cp0.tlb.entries[idx].pfn_even << 12;
|
|
|
|
|
|
g_dev.r4300.cp0.tlb.entries[idx].start_odd = g_dev.r4300.cp0.tlb.entries[idx].end_even+1;
|
|
g_dev.r4300.cp0.tlb.entries[idx].end_odd = g_dev.r4300.cp0.tlb.entries[idx].start_odd+
|
|
(g_dev.r4300.cp0.tlb.entries[idx].mask << 12) + UINT32_C(0xFFF);
|
|
g_dev.r4300.cp0.tlb.entries[idx].phys_odd = g_dev.r4300.cp0.tlb.entries[idx].pfn_odd << 12;
|
|
|
|
tlb_map(&g_dev.r4300.cp0.tlb, idx);
|
|
|
|
if (g_dev.r4300.emumode != EMUMODE_PURE_INTERPRETER)
|
|
{
|
|
unsigned int i;
|
|
if (g_dev.r4300.cp0.tlb.entries[idx].v_even)
|
|
{
|
|
for (i=g_dev.r4300.cp0.tlb.entries[idx].start_even>>12; i<=g_dev.r4300.cp0.tlb.entries[idx].end_even>>12; i++)
|
|
{
|
|
/*if (g_dev.r4300.cached_interp.blocks[i] && (g_dev.r4300.cached_interp.blocks[i]->md5[0] || g_dev.r4300.cached_interp.blocks[i]->md5[1] ||
|
|
g_dev.r4300.cached_interp.blocks[i]->md5[2] || g_dev.r4300.cached_interp.blocks[i]->md5[3]))
|
|
{
|
|
int j;
|
|
int equal = 1;
|
|
md5_state_t state;
|
|
md5_byte_t digest[16];
|
|
md5_init(&state);
|
|
md5_append(&state,
|
|
(const md5_byte_t*)&g_dev.ri.rdram.dram[(g_dev.r4300.cp0.tlb.LUT_r[i]&0x7FF000)/4],
|
|
0x1000);
|
|
md5_finish(&state, digest);
|
|
for (j=0; j<16; j++)
|
|
if (digest[j] != g_dev.r4300.cached_interp.blocks[i]->md5[j])
|
|
equal = 0;
|
|
if (equal) g_dev.r4300.cached_interp.invalid_code[i] = 0;
|
|
}*/
|
|
if(g_dev.r4300.cached_interp.blocks[i] && g_dev.r4300.cached_interp.blocks[i]->adler32)
|
|
{
|
|
if(g_dev.r4300.cached_interp.blocks[i]->adler32 == adler32(0,(const unsigned char *)&g_dev.ri.rdram.dram[(g_dev.r4300.cp0.tlb.LUT_r[i]&0x7FF000)/4],0x1000))
|
|
g_dev.r4300.cached_interp.invalid_code[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (g_dev.r4300.cp0.tlb.entries[idx].v_odd)
|
|
{
|
|
for (i=g_dev.r4300.cp0.tlb.entries[idx].start_odd>>12; i<=g_dev.r4300.cp0.tlb.entries[idx].end_odd>>12; i++)
|
|
{
|
|
/*if (g_dev.r4300.cached_interp.blocks[i] && (g_dev.r4300.cached_interp.blocks[i]->md5[0] || g_dev.r4300.cached_interp.blocks[i]->md5[1] ||
|
|
g_dev.r4300.cached_interp.blocks[i]->md5[2] || g_dev.r4300.cached_interp.blocks[i]->md5[3]))
|
|
{
|
|
int j;
|
|
int equal = 1;
|
|
md5_state_t state;
|
|
md5_byte_t digest[16];
|
|
md5_init(&state);
|
|
md5_append(&state,
|
|
(const md5_byte_t*)&g_dev.ri.rdram.dram[(g_dev.r4300.cp0.tlb.LUT_r[i]&0x7FF000)/4],
|
|
0x1000);
|
|
md5_finish(&state, digest);
|
|
for (j=0; j<16; j++)
|
|
if (digest[j] != g_dev.r4300.cached_interp.blocks[i]->md5[j])
|
|
equal = 0;
|
|
if (equal) g_dev.r4300.cached_interp.invalid_code[i] = 0;
|
|
}*/
|
|
if(g_dev.r4300.cached_interp.blocks[i] && g_dev.r4300.cached_interp.blocks[i]->adler32)
|
|
{
|
|
if(g_dev.r4300.cached_interp.blocks[i]->adler32 == adler32(0,(const unsigned char *)&g_dev.ri.rdram.dram[(g_dev.r4300.cp0.tlb.LUT_r[i]&0x7FF000)/4],0x1000))
|
|
g_dev.r4300.cached_interp.invalid_code[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DECLARE_INSTRUCTION(TLBWI)
|
|
{
|
|
uint32_t* cp0_regs = r4300_cp0_regs();
|
|
|
|
TLBWrite(cp0_regs[CP0_INDEX_REG] & UINT32_C(0x3F));
|
|
ADD_TO_PC(1);
|
|
}
|
|
|
|
DECLARE_INSTRUCTION(TLBWR)
|
|
{
|
|
uint32_t* cp0_regs = r4300_cp0_regs();
|
|
cp0_update_count();
|
|
cp0_regs[CP0_RANDOM_REG] = (cp0_regs[CP0_COUNT_REG]/2 % (32 - cp0_regs[CP0_WIRED_REG]))
|
|
+ cp0_regs[CP0_WIRED_REG];
|
|
TLBWrite(cp0_regs[CP0_RANDOM_REG]);
|
|
ADD_TO_PC(1);
|
|
}
|
|
|
|
DECLARE_INSTRUCTION(TLBP)
|
|
{
|
|
int i;
|
|
uint32_t* cp0_regs = r4300_cp0_regs();
|
|
|
|
cp0_regs[CP0_INDEX_REG] |= UINT32_C(0x80000000);
|
|
for (i=0; i<32; i++)
|
|
{
|
|
if (((g_dev.r4300.cp0.tlb.entries[i].vpn2 & (~g_dev.r4300.cp0.tlb.entries[i].mask)) ==
|
|
(((cp0_regs[CP0_ENTRYHI_REG] & UINT32_C(0xFFFFE000)) >> 13) & (~g_dev.r4300.cp0.tlb.entries[i].mask))) &&
|
|
((g_dev.r4300.cp0.tlb.entries[i].g) ||
|
|
(g_dev.r4300.cp0.tlb.entries[i].asid == (cp0_regs[CP0_ENTRYHI_REG] & UINT32_C(0xFF)))))
|
|
{
|
|
cp0_regs[CP0_INDEX_REG] = i;
|
|
break;
|
|
}
|
|
}
|
|
ADD_TO_PC(1);
|
|
}
|
|
|
|
DECLARE_INSTRUCTION(ERET)
|
|
{
|
|
uint32_t* cp0_regs = r4300_cp0_regs();
|
|
unsigned int* cp0_next_interrupt = r4300_cp0_next_interrupt();
|
|
|
|
cp0_update_count();
|
|
if (cp0_regs[CP0_STATUS_REG] & CP0_STATUS_ERL)
|
|
{
|
|
DebugMessage(M64MSG_ERROR, "error in ERET");
|
|
*r4300_stop()=1;
|
|
}
|
|
else
|
|
{
|
|
cp0_regs[CP0_STATUS_REG] &= ~CP0_STATUS_EXL;
|
|
generic_jump_to(&g_dev.r4300, cp0_regs[CP0_EPC_REG]);
|
|
}
|
|
g_dev.r4300.llbit = 0;
|
|
check_interrupt();
|
|
g_dev.r4300.cp0.last_addr = PCADDR;
|
|
if (*cp0_next_interrupt <= cp0_regs[CP0_COUNT_REG]) gen_interrupt();
|
|
}
|