mirror of
https://github.com/holub/mame
synced 2025-06-05 12:26:35 +03:00
Added a quick & dirty attempt at implementing tlb_mismatch. It's likely wrong,
but it's better than nothing. Also added an assertion if you jump to unmapped code and added handling for compile-time page faults.
This commit is contained in:
parent
be680b1346
commit
271ac2a7a2
@ -278,7 +278,7 @@ static opcode_desc *describe_one(drcfe_state *drcfe, offs_t curpc)
|
|||||||
{
|
{
|
||||||
/* uh-oh: a page fault; leave the description empty and just if this is the first instruction, leave it empty and */
|
/* uh-oh: a page fault; leave the description empty and just if this is the first instruction, leave it empty and */
|
||||||
/* mark as needing to validate; otherwise, just end the sequence here */
|
/* mark as needing to validate; otherwise, just end the sequence here */
|
||||||
desc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_COMPILER_PAGE_FAULT | OPFLAG_VIRTUAL_NOOP;
|
desc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_COMPILER_PAGE_FAULT | OPFLAG_VIRTUAL_NOOP | OPFLAG_END_SEQUENCE;
|
||||||
return desc;
|
return desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,7 +289,7 @@ static opcode_desc *describe_one(drcfe_state *drcfe, offs_t curpc)
|
|||||||
if (desc->opptr.v == NULL)
|
if (desc->opptr.v == NULL)
|
||||||
{
|
{
|
||||||
/* address is unmapped; report it as such */
|
/* address is unmapped; report it as such */
|
||||||
desc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_COMPILER_UNMAPPED | OPFLAG_VIRTUAL_NOOP;
|
desc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_COMPILER_UNMAPPED | OPFLAG_VIRTUAL_NOOP | OPFLAG_END_SEQUENCE;
|
||||||
return desc;
|
return desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,6 +80,7 @@ extern unsigned dasmmips3(char *buffer, unsigned pc, UINT32 op);
|
|||||||
/* exit codes */
|
/* exit codes */
|
||||||
#define EXECUTE_OUT_OF_CYCLES 0
|
#define EXECUTE_OUT_OF_CYCLES 0
|
||||||
#define EXECUTE_MISSING_CODE 1
|
#define EXECUTE_MISSING_CODE 1
|
||||||
|
#define EXECUTE_UNMAPPED_CODE 2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -194,7 +195,7 @@ struct _mips3_regs
|
|||||||
drcuml_codehandle * entry; /* entry point */
|
drcuml_codehandle * entry; /* entry point */
|
||||||
drcuml_codehandle * nocode; /* nocode exception handler */
|
drcuml_codehandle * nocode; /* nocode exception handler */
|
||||||
drcuml_codehandle * out_of_cycles; /* out of cycles exception handler */
|
drcuml_codehandle * out_of_cycles; /* out of cycles exception handler */
|
||||||
drcuml_codehandle * tlb_mismatch; /* tlb mismatch at current PC */
|
drcuml_codehandle * tlb_mismatch; /* tlb mismatch handler */
|
||||||
drcuml_codehandle * read8; /* read byte */
|
drcuml_codehandle * read8; /* read byte */
|
||||||
drcuml_codehandle * write8; /* write byte */
|
drcuml_codehandle * write8; /* write byte */
|
||||||
drcuml_codehandle * read16; /* read half */
|
drcuml_codehandle * read16; /* read half */
|
||||||
@ -235,6 +236,7 @@ static void cfunc_printf_probe(void *param);
|
|||||||
static void static_generate_entry_point(drcuml_state *drcuml);
|
static void static_generate_entry_point(drcuml_state *drcuml);
|
||||||
static void static_generate_nocode_handler(drcuml_state *drcuml);
|
static void static_generate_nocode_handler(drcuml_state *drcuml);
|
||||||
static void static_generate_out_of_cycles(drcuml_state *drcuml);
|
static void static_generate_out_of_cycles(drcuml_state *drcuml);
|
||||||
|
static void static_generate_tlb_mismatch(drcuml_state *drcuml);
|
||||||
static void static_generate_exception(drcuml_state *drcuml, UINT8 exception, int recover, const char *name);
|
static void static_generate_exception(drcuml_state *drcuml, UINT8 exception, int recover, const char *name);
|
||||||
static void static_generate_memory_accessor(drcuml_state *drcuml, int size, int iswrite, int ismasked, const char *name, drcuml_codehandle **handleptr);
|
static void static_generate_memory_accessor(drcuml_state *drcuml, int size, int iswrite, int ismasked, const char *name, drcuml_codehandle **handleptr);
|
||||||
|
|
||||||
@ -749,6 +751,8 @@ static int mips3_execute(int cycles)
|
|||||||
/* if we need to recompile, do it */
|
/* if we need to recompile, do it */
|
||||||
if (execute_result == EXECUTE_MISSING_CODE)
|
if (execute_result == EXECUTE_MISSING_CODE)
|
||||||
code_compile_block(drcuml, mips3.cstate->mode, mips3.core->pc);
|
code_compile_block(drcuml, mips3.cstate->mode, mips3.core->pc);
|
||||||
|
else if (execute_result == EXECUTE_UNMAPPED_CODE)
|
||||||
|
fatalerror("Attempted to execute unmapped code at PC=%08X\n", mips3.core->pc);
|
||||||
|
|
||||||
} while (execute_result != EXECUTE_OUT_OF_CYCLES);
|
} while (execute_result != EXECUTE_OUT_OF_CYCLES);
|
||||||
|
|
||||||
@ -837,6 +841,7 @@ static void code_flush_cache(drcuml_state *drcuml)
|
|||||||
static_generate_entry_point(drcuml);
|
static_generate_entry_point(drcuml);
|
||||||
static_generate_nocode_handler(drcuml);
|
static_generate_nocode_handler(drcuml);
|
||||||
static_generate_out_of_cycles(drcuml);
|
static_generate_out_of_cycles(drcuml);
|
||||||
|
static_generate_tlb_mismatch(drcuml);
|
||||||
|
|
||||||
/* append exception handlers for various types */
|
/* append exception handlers for various types */
|
||||||
static_generate_exception(drcuml, EXCEPTION_INTERRUPT, TRUE, "exception_interrupt");
|
static_generate_exception(drcuml, EXCEPTION_INTERRUPT, TRUE, "exception_interrupt");
|
||||||
@ -1160,6 +1165,41 @@ static void static_generate_out_of_cycles(drcuml_state *drcuml)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
static_generate_tlb_mismatch - generate a
|
||||||
|
TLB mismatch handler
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
static void static_generate_tlb_mismatch(drcuml_state *drcuml)
|
||||||
|
{
|
||||||
|
drcuml_block *block;
|
||||||
|
jmp_buf errorbuf;
|
||||||
|
|
||||||
|
/* if we get an error back, we're screwed */
|
||||||
|
if (setjmp(errorbuf) != 0)
|
||||||
|
fatalerror("Unrecoverable error in static_generate_tlb_mismatch");
|
||||||
|
|
||||||
|
/* forward references */
|
||||||
|
alloc_handle(drcuml, &mips3.exception[EXCEPTION_TLBLOAD], "exception_tlbload");
|
||||||
|
|
||||||
|
/* begin generating */
|
||||||
|
block = drcuml_block_begin(drcuml, 20, &errorbuf);
|
||||||
|
|
||||||
|
/* generate a hash jump via the current mode and PC */
|
||||||
|
alloc_handle(drcuml, &mips3.tlb_mismatch, "tlb_mismatch");
|
||||||
|
UML_HANDLE(block, mips3.tlb_mismatch); // handle tlb_mismatch
|
||||||
|
UML_RECOVER(block, IREG(0), MAPVAR_PC); // recover i0,PC
|
||||||
|
UML_MOV(block, MEM(&mips3.core->pc), IREG(0)); // mov <pc>,i0
|
||||||
|
UML_SHR(block, IREG(1), IREG(0), IMM(12)); // shr i1,i0,12
|
||||||
|
UML_LOAD4(block, IREG(1), mips3.core->tlb_table, IREG(1)); // load4 i1,[tlb_table],i1
|
||||||
|
UML_TEST(block, IREG(1), IMM(2)); // test i1,2
|
||||||
|
UML_EXHc(block, IF_NE, mips3.exception[EXCEPTION_TLBLOAD], IREG(0)); // exh exception[TLBLOAD],i0
|
||||||
|
UML_EXIT(block, IMM(EXECUTE_OUT_OF_CYCLES)); // exit EXECUTE_MISSING_CODE
|
||||||
|
|
||||||
|
drcuml_block_end(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------
|
/*-------------------------------------------------
|
||||||
static_generate_exception - generate a static
|
static_generate_exception - generate a static
|
||||||
exception handler
|
exception handler
|
||||||
@ -1584,21 +1624,40 @@ static void generate_sequence_instruction(drcuml_block *block, compiler_state *c
|
|||||||
UML_MOV(block, MEM(&mips3.core->pc), IMM(desc->pc)); // mov [pc],desc->pc
|
UML_MOV(block, MEM(&mips3.core->pc), IMM(desc->pc)); // mov [pc],desc->pc
|
||||||
UML_DEBUG(block, IMM(desc->pc)); // debug desc->pc
|
UML_DEBUG(block, IMM(desc->pc)); // debug desc->pc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* if we hit an unmapped address, fatal error */
|
||||||
|
if (desc->flags & OPFLAG_COMPILER_UNMAPPED)
|
||||||
|
{
|
||||||
|
UML_MOV(block, MEM(&mips3.core->pc), IMM(desc->pc)); // mov [pc],desc->pc
|
||||||
|
UML_EXIT(block, IMM(EXECUTE_UNMAPPED_CODE)); // exit EXECUTE_UNMAPPED_CODE
|
||||||
|
}
|
||||||
|
|
||||||
/* validate our TLB entry at this PC; if we fail, we need to recompile */
|
/* if we hit a compiler page fault, it's just like a TLB mismatch */
|
||||||
|
if (desc->flags & OPFLAG_COMPILER_PAGE_FAULT)
|
||||||
|
UML_EXH(block, mips3.tlb_mismatch, IMM(0)); // exh tlb_mismatch,0
|
||||||
|
|
||||||
|
/* validate our TLB entry at this PC; if we fail, we need to handle it */
|
||||||
if ((desc->flags & OPFLAG_VALIDATE_TLB) && (desc->pc < 0x80000000 || desc->pc >= 0xc0000000))
|
if ((desc->flags & OPFLAG_VALIDATE_TLB) && (desc->pc < 0x80000000 || desc->pc >= 0xc0000000))
|
||||||
{
|
{
|
||||||
UML_CMP(block, MEM(&mips3.core->tlb_table[desc->pc >> 12]),
|
/* if we currently have a valid TLB read entry, we just verify */
|
||||||
IMM(mips3.core->tlb_table[desc->pc >> 12])); // cmp [tlbentry],*tlbentry
|
if (mips3.core->tlb_table[desc->pc >> 12] & 2)
|
||||||
UML_EXHc(block, IF_NE, mips3.tlb_mismatch, IMM(0)); // exh tlb_mismatch,0,NE
|
{
|
||||||
|
UML_LOAD4(block, IREG(0), &mips3.core->tlb_table[desc->pc >> 12], IMM(0));// load4 i0,tlb_table[desc->pc >> 12]
|
||||||
|
UML_CMP(block, IREG(0), IMM(mips3.core->tlb_table[desc->pc >> 12])); // cmp i0,*tlbentry
|
||||||
|
UML_EXHc(block, IF_NE, mips3.tlb_mismatch, IMM(0)); // exh tlb_mismatch,0,NE
|
||||||
|
}
|
||||||
|
|
||||||
|
/* otherwise, we generate an unconditional exception */
|
||||||
|
else
|
||||||
|
UML_EXH(block, mips3.tlb_mismatch, IMM(0)); // exh tlb_mismatch,0
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if this is an invalid opcode, generate the exception now */
|
/* if this is an invalid opcode, generate the exception now */
|
||||||
if (desc->flags & OPFLAG_INVALID_OPCODE)
|
if (desc->flags & OPFLAG_INVALID_OPCODE)
|
||||||
UML_EXH(block, mips3.exception[EXCEPTION_INVALIDOP], IMM(0)); // exh invalidop,0
|
UML_EXH(block, mips3.exception[EXCEPTION_INVALIDOP], IMM(0)); // exh invalidop,0
|
||||||
|
|
||||||
/* otherwise, it's a regular instruction */
|
/* otherwise, unless this is a virtual no-op, it's a regular instruction */
|
||||||
else
|
else if (!(desc->flags & OPFLAG_VIRTUAL_NOOP))
|
||||||
{
|
{
|
||||||
/* compile the instruction */
|
/* compile the instruction */
|
||||||
if (!generate_opcode(block, compiler, desc))
|
if (!generate_opcode(block, compiler, desc))
|
||||||
|
Loading…
Reference in New Issue
Block a user