Implemented new memory mapping to improve performance of self modifying code.
New scheme allows code blocks to cross pages. Reduced code block size down to 2kB.
This commit is contained in:
parent
798c24d7c4
commit
b4592cdea3
14 changed files with 465 additions and 308 deletions
|
|
@ -6,8 +6,8 @@
|
|||
#include "x86.h"
|
||||
#include "x86_ops.h"
|
||||
#include "x87.h"
|
||||
#include "codegen.h"
|
||||
#include "mem.h"
|
||||
#include "codegen.h"
|
||||
#include "cpu.h"
|
||||
#include "fdc.h"
|
||||
#include "timer.h"
|
||||
|
|
@ -1191,11 +1191,11 @@ void exec386(int cycs)
|
|||
|
||||
cycdiff=0;
|
||||
oldcyc=cycles;
|
||||
if (output && CACHE_ON()) pclog("Block %04x:%04x %04x:%08x %i\n", CS, pc, SS,ESP, codeblock_page_dirty[0x1de]);
|
||||
// if (output && CACHE_ON()) pclog("Block %04x:%04x %04x:%08x %i\n", CS, pc, SS,ESP, codeblock_page_dirty[0x1de]);
|
||||
if (!CACHE_ON()) /*Interpret block*/
|
||||
{
|
||||
cpu_block_end = 0;
|
||||
if (output) pclog("Interpret block at %04x:%04x %04x %04x %04x %04x %04x %04x %04x\n", CS, pc, AX, BX, CX, DX, SI, DI, SP);
|
||||
// if (output) pclog("Interpret block at %04x:%04x %04x %04x %04x %04x %04x %04x %04x\n", CS, pc, AX, BX, CX, DX, SI, DI, SP);
|
||||
while (!cpu_block_end)
|
||||
{
|
||||
oldcs=CS;
|
||||
|
|
@ -1217,8 +1217,8 @@ void exec386(int cycs)
|
|||
opcode = fetchdat & 0xFF;
|
||||
fetchdat >>= 8;
|
||||
|
||||
if (output == 3)
|
||||
pclog("int %04X(%06X):%04X : %08X %08X %08X %08X %04X %04X %04X(%08X) %04X %04X %04X(%08X) %08X %08X %08X SP=%04X:%08X %02X %04X %i %08X %08X %i %i %02X %02X %02X %02X %02X %f %02X%02X %02X%02X\n",CS,cs,pc,EAX,EBX,ECX,EDX,CS,DS,ES,es,FS,GS,SS,ss,EDI,ESI,EBP,SS,ESP,opcode,flags,ins,0, ldt.base, CPL, stack32, pic.pend, pic.mask, pic.mask2, pic2.pend, pic2.mask, pit.c[0], ram[0x8f13f], ram[0x8f13e], ram[0x8f141], ram[0x8f140]);
|
||||
// if (output == 3)
|
||||
// pclog("int %04X(%06X):%04X : %08X %08X %08X %08X %04X %04X %04X(%08X) %04X %04X %04X(%08X) %08X %08X %08X SP=%04X:%08X %02X %04X %i %08X %08X %i %i %02X %02X %02X %02X %02X %f %02X%02X %02X%02X\n",CS,cs,pc,EAX,EBX,ECX,EDX,CS,DS,ES,es,FS,GS,SS,ss,EDI,ESI,EBP,SS,ESP,opcode,flags,ins,0, ldt.base, CPL, stack32, pic.pend, pic.mask, pic.mask2, pic2.pend, pic2.mask, pit.c[0], ram[0x8f13f], ram[0x8f13e], ram[0x8f141], ram[0x8f140]);
|
||||
|
||||
pc++;
|
||||
x86_opcodes[(opcode | op32) & 0x3ff](fetchdat);
|
||||
|
|
@ -1257,32 +1257,53 @@ void exec386(int cycs)
|
|||
codeblock_t *block = codeblock_hash[hash];
|
||||
int valid_block = 0;
|
||||
trap = 0;
|
||||
// if ((cs+pc) == 0x100030)
|
||||
// pclog("160070 : phys=%08x %04x(%08x):%08x\n", phys_addr, SS, ss, ESP);
|
||||
|
||||
if (block)
|
||||
{
|
||||
// if ((cs+pc) == 0x100030)
|
||||
// pclog("160070 : block\n", phys_addr);
|
||||
page_t *page = &pages[phys_addr >> 12];
|
||||
|
||||
/*Block must match current CS, PC, code segment size,
|
||||
and physical address. The physical address check will
|
||||
also catch any page faults at this stage*/
|
||||
valid_block = (block->pc == cs + pc) && (block->_cs == cs) &&
|
||||
(block->use32 == use32) && (block->phys == phys_addr);
|
||||
|
||||
if (valid_block && codeblock_page_dirty[phys_addr >> 12])
|
||||
dirty = codegen_check_dirty(phys_addr);
|
||||
|
||||
// if (pc == 0x804003f0)
|
||||
// if (!(valid_block && !dirty))
|
||||
// if ((pc & 0xffffff00) == 0xe00 || (pc & 0xffffff00) == 0xd00)
|
||||
// if ((cs+pc) == 0x100030)
|
||||
// pclog("this block pc=%08x,%08x cs=%08x,%08x use32=%03x,%03x phys=%08x,%08x v=%i d=%i\n",
|
||||
// cs+pc, block->pc, cs, block->_cs, use32, block->use32, phys_addr, block->phys, valid_block, dirty);
|
||||
|
||||
if (valid_block && (block->page_mask & page->dirty_mask))
|
||||
{
|
||||
codegen_check_flush(page, page->dirty_mask, phys_addr);
|
||||
page->dirty_mask = 0;
|
||||
if (!block->pc)
|
||||
valid_block = 0;
|
||||
}
|
||||
if (valid_block && block->page_mask2)
|
||||
{
|
||||
/*We don't want the second page to cause a page
|
||||
fault at this stage - that would break any
|
||||
code crossing a page boundary where the first
|
||||
page is present but the second isn't. Instead
|
||||
allow the first page to be interpreted and for
|
||||
the page fault to occur when the page boundary
|
||||
is actually crossed.*/
|
||||
uint32_t phys_addr_2 = get_phys_noabrt(block->endpc) & ~0xfff;
|
||||
page_t *page_2 = &pages[phys_addr_2 >> 12];
|
||||
|
||||
if ((block->phys_2 ^ phys_addr_2) & ~0xfff)
|
||||
valid_block = 0;
|
||||
else if (block->page_mask2 & page_2->dirty_mask)
|
||||
{
|
||||
codegen_check_flush(page_2, page_2->dirty_mask, phys_addr_2);
|
||||
page_2->dirty_mask = 0;
|
||||
if (!block->pc)
|
||||
valid_block = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
//pclog("block - %08x:%08x %08x %03x %08x %08x %08x %i\n", cs, pc, phys_addr, hash, codeblock_hash_pc[hash], codeblock_hash_cs[hash], codeblock_hash_phys[hash], codeblock_page_dirty[phys_addr >> 12]);
|
||||
|
||||
if (valid_block && !dirty)
|
||||
{
|
||||
void (*code)() = (void *)&block->data[BLOCK_START];
|
||||
|
||||
if (output) pclog("Run block at %04x:%04x %04x %04x %04x %04x %04x %04x ESP=%08x %04x %02x%02x:%02x%02x %02x%02x:%02x%02x %02x%02x:%02x%02x %08x %08x\n", CS, pc, AX, BX, CX, DX, SI, DI, ESP, BP, ram[0x116330+0x6df4+0xa+3], ram[0x116330+0x6df4+0xa+2], ram[0x116330+0x6df4+0xa+1], ram[0x116330+0x6df4+0xa+0], ram[0x11d136+3],ram[0x11d136+2],ram[0x11d136+1],ram[0x11d136+0], ram[(0x119abe)+0x3],ram[(0x119abe)+0x2],ram[(0x119abe)+0x1],ram[(0x119abe)+0x0], get_phys(cs+pc), block->phys);
|
||||
// if (output) pclog("Run block at %04x:%04x %04x %04x %04x %04x %04x %04x ESP=%08x %04x %08x %08x %016llx %08x\n", CS, pc, AX, BX, CX, DX, SI, DI, ESP, BP, get_phys(cs+pc), block->phys, block->page_mask, block->endpc);
|
||||
|
||||
oldcs = CS;
|
||||
oldcpl = CPL;
|
||||
|
|
@ -1299,6 +1320,7 @@ inrecomp=0;
|
|||
else if (!abrt)
|
||||
{
|
||||
uint32_t start_page = pc >> 12;
|
||||
uint32_t start_pc = pc;
|
||||
|
||||
// pclog("Hash %08x %i\n", codeblock_hash_pc[HASH(cs + pc)], codeblock_page_dirty[(cs + pc) >> 12]);
|
||||
cpu_block_end = 0;
|
||||
|
|
@ -1307,13 +1329,7 @@ inrecomp=0;
|
|||
|
||||
codegen_block_init(phys_addr);
|
||||
|
||||
// if (CS == 0x70 && pc == 0x84a)
|
||||
// output = 3;
|
||||
// if (((cs + pc) & ~0x1f) == 0x0010A182)
|
||||
// output |= 2;
|
||||
// if ((cs+pc) == 0xfe771)
|
||||
// output = 1;
|
||||
if (output) pclog("Recompile block at %04x:%04x %04x %04x %04x %04x %04x %04x ESP=%04x %04x %02x%02x:%02x%02x %02x%02x:%02x%02x %02x%02x:%02x%02x\n", CS, pc, AX, BX, CX, DX, SI, DI, ESP, BP, ram[0x116330+0x6df4+0xa+3], ram[0x116330+0x6df4+0xa+2], ram[0x116330+0x6df4+0xa+1], ram[0x116330+0x6df4+0xa+0], ram[0x11d136+3],ram[0x11d136+2],ram[0x11d136+1],ram[0x11d136+0], ram[(0x119abe)+0x3],ram[(0x119abe)+0x2],ram[(0x119abe)+0x1],ram[(0x119abe)+0x0]);
|
||||
// if (output) pclog("Recompile block at %04x:%04x %04x %04x %04x %04x %04x %04x ESP=%04x %04x %02x%02x:%02x%02x %02x%02x:%02x%02x %02x%02x:%02x%02x\n", CS, pc, AX, BX, CX, DX, SI, DI, ESP, BP, ram[0x116330+0x6df4+0xa+3], ram[0x116330+0x6df4+0xa+2], ram[0x116330+0x6df4+0xa+1], ram[0x116330+0x6df4+0xa+0], ram[0x11d136+3],ram[0x11d136+2],ram[0x11d136+1],ram[0x11d136+0], ram[(0x119abe)+0x3],ram[(0x119abe)+0x2],ram[(0x119abe)+0x1],ram[(0x119abe)+0x0]);
|
||||
while (!cpu_block_end)
|
||||
{
|
||||
oldcs=CS;
|
||||
|
|
@ -1337,18 +1353,10 @@ inrecomp=0;
|
|||
opcode = fetchdat & 0xFF;
|
||||
fetchdat >>= 8;
|
||||
|
||||
if (output == 3)
|
||||
pclog("%04X(%06X):%04X : %08X %08X %08X %08X %04X %04X %04X(%08X) %04X %04X %04X(%08X) %08X %08X %08X SP=%04X:%08X %02X %04X %i %08X %08X %i %i %02X %02X %02X %02X %02X %08x %08x\n",CS,cs,pc,EAX,EBX,ECX,EDX,CS,DS,ES,es,FS,GS,SS,ss,EDI,ESI,EBP,SS,ESP,opcode,flags,ins,0, ldt.base, CPL, stack32, pic.pend, pic.mask, pic.mask2, pic2.pend, pic2.mask, cs+pc, pccache);
|
||||
|
||||
if (((cs + pc) >> 12) != pccache)
|
||||
CPU_BLOCK_END();
|
||||
|
||||
if ((pc >> 12) != start_page)
|
||||
CPU_BLOCK_END();
|
||||
// if (output == 3)
|
||||
// pclog("%04X(%06X):%04X : %08X %08X %08X %08X %04X %04X %04X(%08X) %04X %04X %04X(%08X) %08X %08X %08X SP=%04X:%08X %02X %04X %i %08X %08X %i %i %02X %02X %02X %02X %02X %08x %08x\n",CS,cs,pc,EAX,EBX,ECX,EDX,CS,DS,ES,es,FS,GS,SS,ss,EDI,ESI,EBP,SS,ESP,opcode,flags,ins,0, ldt.base, CPL, stack32, pic.pend, pic.mask, pic.mask2, pic2.pend, pic2.mask, cs+pc, pccache);
|
||||
|
||||
pc++;
|
||||
/* if (opcode == 0xf2 || opcode == 0xf3 || ((opcode & ~7) == 0xd8)*/
|
||||
// codegen_set_op32();
|
||||
|
||||
codegen_generate_call(opcode, x86_opcodes[(opcode | op32) & 0x3ff], fetchdat, pc, pc-1);
|
||||
|
||||
|
|
@ -1357,45 +1365,34 @@ inrecomp=0;
|
|||
|
||||
if (!use32) pc &= 0xffff;
|
||||
|
||||
if (((cs + pc) >> 12) != pccache)
|
||||
CPU_BLOCK_END();
|
||||
|
||||
if (codeblock_page_dirty[phys_addr >> 12])
|
||||
/*Cap source code at 4000 bytes per block; this
|
||||
will prevent any block from spanning more than
|
||||
2 pages. In practice this limit will never be
|
||||
hit, as host block size is only 2kB*/
|
||||
if ((pc - start_pc) > 4000)
|
||||
CPU_BLOCK_END();
|
||||
|
||||
if (trap)
|
||||
CPU_BLOCK_END();
|
||||
|
||||
|
||||
//pclog("cpu_block_end=%d %p\n", cpu_block_end, (void *)&cpu_block_end);
|
||||
/* if (ssegs)
|
||||
{
|
||||
ds=oldds;
|
||||
ss=oldss;
|
||||
ssegs=0;
|
||||
codegen_generate_seg_restore();
|
||||
}*/
|
||||
//codegen_check_abrt();
|
||||
if (abrt || codeblock_page_dirty[phys_addr >> 12])
|
||||
if (abrt)
|
||||
{
|
||||
codegen_block_remove();
|
||||
CPU_BLOCK_END();
|
||||
}
|
||||
//if (pc==0x5b42)
|
||||
// cpu_block_end = 1;
|
||||
|
||||
ins++;
|
||||
insc++;
|
||||
}
|
||||
|
||||
if (!abrt && !codeblock_page_dirty[phys_addr >> 12])
|
||||
if (!abrt)
|
||||
codegen_block_end();
|
||||
// output &= ~2;
|
||||
}
|
||||
// if (output && (SP & 1))
|
||||
// fatal("odd SP\n");
|
||||
}
|
||||
//if (CS == 0x9087 && pc == 0x3763)
|
||||
// fatal("Here\n");
|
||||
cycdiff=oldcyc-cycles;
|
||||
tsc += cycdiff;
|
||||
|
||||
|
|
@ -1473,12 +1470,8 @@ inrecomp=0;
|
|||
}
|
||||
}
|
||||
}
|
||||
/* if (SS == 0x30 && stack_check)
|
||||
pclog("Load stack %04x(%08x):%08x\n", SS, ss, ESP);*/
|
||||
}
|
||||
timer_end_period(cycles);
|
||||
//if ((cs + pc) == 0x2ea5e)
|
||||
// fatal("");
|
||||
cycles_main -= (cycles_start - cycles);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "x86_ops.h"
|
||||
#include "x87.h"
|
||||
#include "x86_flags.h"
|
||||
#include "mem.h"
|
||||
#include "codegen.h"
|
||||
|
||||
#define CPU_BLOCK_END() cpu_block_end = 1
|
||||
|
|
|
|||
|
|
@ -652,6 +652,9 @@ void resetx86()
|
|||
mmu_perm=4;
|
||||
memset(inscounts, 0, sizeof(inscounts));
|
||||
x86seg_reset();
|
||||
#ifdef DYNAREC
|
||||
codegen_reset();
|
||||
#endif
|
||||
}
|
||||
|
||||
void softresetx86()
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "ibm.h"
|
||||
#include "x86_ops.h"
|
||||
#include "mem.h"
|
||||
#include "codegen.h"
|
||||
|
||||
void (*codegen_timing_start)();
|
||||
|
|
|
|||
|
|
@ -6,28 +6,60 @@
|
|||
#error Dynamic recompiler not implemented on your platform
|
||||
#endif
|
||||
|
||||
/*Handling self-modifying code (of which there is a lot on x86) :
|
||||
|
||||
PCem tracks a 'dirty mask' for each physical page, in which each bit
|
||||
represents 64 bytes. This is only tracked for pages that have code in - when a
|
||||
page first has a codeblock generated, it is evicted from the writelookup and
|
||||
added to the page_lookup for this purpose. When in the page_lookup, each write
|
||||
will go through the mem_write_ram*_page() functions and set the dirty mask
|
||||
appropriately.
|
||||
|
||||
Each codeblock also contains a code mask (actually two masks, one for each
|
||||
page the block is/may be in), again with each bit representing 64 bytes.
|
||||
|
||||
Each page has a list of codeblocks present in it. As each codeblock can span
|
||||
up to two pages, two lists are present.
|
||||
|
||||
When a codeblock is about to be executed, the code masks are compared with the
|
||||
dirty masks for the relevant pages. If either intersect, then
|
||||
codegen_check_flush() is called on the affected page(s), and all affected
|
||||
blocks are evicted.
|
||||
|
||||
The 64 byte granularity appears to work reasonably well for most cases,
|
||||
avoiding most unnecessary evictions (eg when code & data are stored in the
|
||||
same page).
|
||||
*/
|
||||
|
||||
typedef struct codeblock_t
|
||||
{
|
||||
/*Previous and next pointers, for the codeblock list associated with
|
||||
each physical page. Two sets of pointers, as a codeblock can be
|
||||
present in two pages.*/
|
||||
struct codeblock_t *prev, *next;
|
||||
struct codeblock_t *prev_2, *next_2;
|
||||
|
||||
uint32_t pc;
|
||||
uint32_t _cs;
|
||||
uint32_t endpc;
|
||||
uint32_t checksum;
|
||||
uint32_t phys;
|
||||
uint32_t phys, phys_2;
|
||||
uint32_t use32;
|
||||
int pnt;
|
||||
int ins;
|
||||
uint64_t page_mask, page_mask2;
|
||||
|
||||
uint8_t data[8192];
|
||||
uint8_t data[2048];
|
||||
} codeblock_t;
|
||||
|
||||
#define PAGE_MASK_MASK 63
|
||||
#define PAGE_MASK_SHIFT 6
|
||||
|
||||
extern codeblock_t *codeblock;
|
||||
|
||||
extern codeblock_t **codeblock_hash;
|
||||
extern uint8_t *codeblock_page_dirty;
|
||||
|
||||
void codegen_init();
|
||||
void codegen_reset();
|
||||
void codegen_block_init(uint32_t phys_addr);
|
||||
void codegen_block_remove();
|
||||
void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_pc, uint32_t old_pc);
|
||||
|
|
@ -35,8 +67,7 @@ void codegen_generate_seg_restore();
|
|||
void codegen_check_abrt();
|
||||
void codegen_set_op32();
|
||||
void codegen_flush();
|
||||
void codegen_dirty(uint32_t addr);
|
||||
int codegen_check_dirty(uint32_t phys_addr);
|
||||
void codegen_check_flush(struct page_t *page, uint64_t mask, uint32_t phys_addr);
|
||||
|
||||
extern int cpu_block_end;
|
||||
|
||||
|
|
@ -80,7 +111,7 @@ extern int block_pos;
|
|||
static inline void addbyte(uint8_t val)
|
||||
{
|
||||
codeblock[block_current].data[block_pos++] = val;
|
||||
if (block_pos >= 8000)
|
||||
if (block_pos >= 1850)
|
||||
{
|
||||
CPU_BLOCK_END();
|
||||
}
|
||||
|
|
@ -90,7 +121,7 @@ static inline void addword(uint16_t val)
|
|||
{
|
||||
*(uint16_t *)&codeblock[block_current].data[block_pos] = val;
|
||||
block_pos += 2;
|
||||
if (block_pos >= 8000)
|
||||
if (block_pos >= 1850)
|
||||
{
|
||||
CPU_BLOCK_END();
|
||||
}
|
||||
|
|
@ -100,10 +131,12 @@ static inline void addlong(uint32_t val)
|
|||
{
|
||||
*(uint32_t *)&codeblock[block_current].data[block_pos] = val;
|
||||
block_pos += 4;
|
||||
if (block_pos >= 8000)
|
||||
if (block_pos >= 1850)
|
||||
{
|
||||
CPU_BLOCK_END();
|
||||
}
|
||||
}
|
||||
|
||||
/*Current physical page of block being recompiled. -1 if no recompilation taking place */
|
||||
extern uint32_t recomp_page;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "x86.h"
|
||||
#include "x86_ops.h"
|
||||
#include "x87.h"
|
||||
#include "mem.h"
|
||||
#include "codegen.h"
|
||||
|
||||
#define CYCLES(c) (int *)c
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include "x86.h"
|
||||
#include "x86_ops.h"
|
||||
#include "x87.h"
|
||||
#include "mem.h"
|
||||
#include "codegen.h"
|
||||
|
||||
/*Instruction has different execution time for 16 and 32 bit data. Does not pair */
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
#define CHECKSUM
|
||||
|
||||
#ifdef DYNAREC
|
||||
#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32
|
||||
|
||||
|
|
@ -10,6 +8,7 @@
|
|||
#include "x86_flags.h"
|
||||
#include "x86_ops.h"
|
||||
#include "x87.h"
|
||||
#include "mem.h"
|
||||
|
||||
#include "codegen.h"
|
||||
#include "codegen_ops.h"
|
||||
|
|
@ -17,20 +16,14 @@
|
|||
|
||||
#include "386_common.h"
|
||||
|
||||
#define BLOCK_EXIT_OFFSET 0x1ff0
|
||||
#define BLOCK_EXIT_OFFSET 0x7f0
|
||||
|
||||
uint32_t recomp_page = -1;
|
||||
|
||||
int host_reg_mapping[NR_HOST_REGS];
|
||||
codeblock_t *codeblock;
|
||||
codeblock_t **codeblock_hash;
|
||||
|
||||
typedef struct page_t
|
||||
{
|
||||
codeblock_t *block;
|
||||
} page_t;
|
||||
|
||||
page_t *pages;
|
||||
|
||||
uint8_t *codeblock_page_dirty;
|
||||
|
||||
int block_current = 0;
|
||||
static int block_num;
|
||||
|
|
@ -56,16 +49,17 @@ void codegen_init()
|
|||
|
||||
codeblock = malloc(BLOCK_SIZE * sizeof(codeblock_t));
|
||||
codeblock_hash = malloc(HASH_SIZE * sizeof(codeblock_t *));
|
||||
pages = malloc(((256 * 1024 * 1024) >> 12) * sizeof(page_t));
|
||||
|
||||
memset(codeblock, 0, sizeof(BLOCK_SIZE * sizeof(codeblock_t)));
|
||||
memset(codeblock_hash, 0, HASH_SIZE * sizeof(codeblock_t *));
|
||||
memset(pages, 0, ((256 * 1024 * 1024) >> 12) * sizeof(page_t));
|
||||
|
||||
codeblock_page_dirty = malloc(1 << 20);
|
||||
memset(codeblock_page_dirty, 1, 1 << 20);
|
||||
|
||||
pclog("Codegen is %p\n", (void *)pages[0xfab12 >> 12].block);
|
||||
// pclog("Codegen is %p\n", (void *)pages[0xfab12 >> 12].block);
|
||||
}
|
||||
|
||||
void codegen_reset()
|
||||
{
|
||||
memset(codeblock, 0, sizeof(BLOCK_SIZE * sizeof(codeblock_t)));
|
||||
memset(codeblock_hash, 0, HASH_SIZE * sizeof(codeblock_t *));
|
||||
}
|
||||
|
||||
void dump_block()
|
||||
|
|
@ -86,173 +80,103 @@ void dump_block()
|
|||
pclog("dump_block done\n");
|
||||
}
|
||||
|
||||
int codegen_check_dirty(uint32_t phys_addr)
|
||||
static void delete_block(codeblock_t *block)
|
||||
{
|
||||
#ifdef CHECKSUM
|
||||
int has_evicted = 0;
|
||||
int dirty = 0;
|
||||
codeblock_t *block = pages[phys_addr >> 12].block;
|
||||
//pclog("codegen_check_dirty %08x %08x\n", phys_addr, pages[phys_addr >> 12].block);
|
||||
// if ((phys_addr & ~0xfff) == 0x119000) pclog("dirty start\n");
|
||||
// pclog("delete_block: pc=%08x\n", block->pc);
|
||||
codeblock_hash[HASH(block->phys)] = NULL;
|
||||
|
||||
if (!block->pc)
|
||||
fatal("Deleting deleted block\n");
|
||||
block->pc = 0;
|
||||
|
||||
if (block->prev)
|
||||
{
|
||||
block->prev->next = block->next;
|
||||
if (block->next)
|
||||
block->next->prev = block->prev;
|
||||
}
|
||||
else
|
||||
{
|
||||
pages[block->phys >> 12].block = block->next;
|
||||
if (block->next)
|
||||
block->next->prev = NULL;
|
||||
else
|
||||
mem_flush_write_page(block->phys, 0);
|
||||
}
|
||||
if (!block->page_mask2)
|
||||
{
|
||||
if (block->prev_2 || block->next_2)
|
||||
fatal("Invalid block_2\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (block->prev_2)
|
||||
{
|
||||
block->prev_2->next_2 = block->next_2;
|
||||
if (block->next_2)
|
||||
block->next_2->prev_2 = block->prev_2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// pclog(" pages.block_2=%p 3 %p %p\n", (void *)block->next_2, (void *)block, (void *)pages[block->phys_2 >> 12].block_2);
|
||||
pages[block->phys_2 >> 12].block_2 = block->next_2;
|
||||
if (block->next_2)
|
||||
block->next_2->prev_2 = NULL;
|
||||
else
|
||||
mem_flush_write_page(block->phys_2, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void codegen_check_flush(page_t *page, uint64_t mask, uint32_t phys_addr)
|
||||
{
|
||||
struct codeblock_t *block = page->block;
|
||||
|
||||
while (block)
|
||||
{
|
||||
uint32_t start_pc = (block->pc & 0xffc) | (block->phys & ~0xfff);
|
||||
uint32_t end_pc = (block->endpc & 0xffc) | (block->phys & ~0xfff);
|
||||
uint32_t checksum = 0;
|
||||
// if ((phys_addr & ~0xfff) == 0x119000) pclog(" %08x\n", block->pc);
|
||||
if (!block->pc)
|
||||
fatal("!PC\n");
|
||||
|
||||
// if ((phys_addr & ~0xfff) == 0x119000) dump_block();
|
||||
|
||||
// if ((phys_addr & ~0xfff) == 0x119000) pclog(" %08x-%08x %08x-%08x\n", start_pc, end_pc, block->pc, block->endpc);
|
||||
if (end_pc > start_pc)
|
||||
if (mask & block->page_mask)
|
||||
{
|
||||
for (; start_pc <= end_pc; start_pc += 4)
|
||||
checksum += *(uint32_t *)&ram[start_pc];
|
||||
delete_block(block);
|
||||
cpu_recomp_evicted++;
|
||||
}
|
||||
else
|
||||
checksum = ~block->checksum;
|
||||
|
||||
if (checksum != block->checksum)
|
||||
{
|
||||
// if ((phys_addr & ~0xfff) == 0x119000) pclog(" evict %08x %08x %p\n", checksum, block->checksum, (void *)block->prev);
|
||||
if (block->pc == (cs+pc))
|
||||
dirty = 1;
|
||||
|
||||
block->pc = 0;//xffffffff;
|
||||
|
||||
if (block->prev)
|
||||
{
|
||||
block->prev->next = block->next;
|
||||
if (block->next)
|
||||
block->next->prev = block->prev;
|
||||
}
|
||||
else
|
||||
{
|
||||
pages[block->phys >> 12].block = block->next;
|
||||
if (block->next)
|
||||
block->next->prev = NULL;
|
||||
}
|
||||
|
||||
has_evicted = 1;
|
||||
|
||||
codeblock_hash[HASH(block->phys)] = NULL;
|
||||
}
|
||||
|
||||
if (block == block->next)
|
||||
fatal("Broken 1\n");
|
||||
block = block->next;
|
||||
}
|
||||
// if ((phys_addr & ~0xfff) == 0x8f000) pclog("dirty end\n");
|
||||
if (has_evicted)
|
||||
|
||||
block = page->block_2;
|
||||
|
||||
while (block)
|
||||
{
|
||||
cpu_recomp_evicted++;
|
||||
|
||||
if (mask & block->page_mask2)
|
||||
{
|
||||
delete_block(block);
|
||||
cpu_recomp_evicted++;
|
||||
}
|
||||
if (block == block->next_2)
|
||||
fatal("Broken 2\n");
|
||||
block = block->next_2;
|
||||
}
|
||||
|
||||
mem_flush_write_page(phys_addr, cs+pc);
|
||||
|
||||
codeblock_page_dirty[phys_addr >> 12] = 0;
|
||||
return dirty;
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void codegen_block_init(uint32_t phys_addr)
|
||||
{
|
||||
codeblock_t *block;
|
||||
int has_evicted = 0;
|
||||
// pclog("block_init %08x:%08x hash=%04x %08x\n", cs, pc, HASH(cs + pc), phys_addr);
|
||||
//if (phys_addr > 0x100000)
|
||||
// dump_block();
|
||||
if (codeblock_page_dirty[phys_addr >> 12])
|
||||
{
|
||||
codeblock_t *last_block = NULL;
|
||||
block = pages[phys_addr >> 12].block;
|
||||
// pages[phys_addr >> 12].block = NULL;
|
||||
// if ((phys_addr & ~0xfff) == 0x119000) pclog("Flush %08x\n", phys_addr);
|
||||
//pclog("init start\n");
|
||||
while (block)
|
||||
{
|
||||
codeblock_t *old_block = block;
|
||||
codeblock_t *next_block = block->next;
|
||||
|
||||
uint32_t start_pc = (block->pc & 0xffc) | (block->phys & ~0xfff);
|
||||
uint32_t end_pc = (block->endpc & 0xffc) | (block->phys & ~0xfff);
|
||||
uint32_t checksum = 0;
|
||||
|
||||
if (!block->pc)
|
||||
fatal("!PC on init\n");
|
||||
|
||||
//if ((phys_addr & ~0xfff) == 0x119000) dump_block();
|
||||
|
||||
// if ((phys_addr & ~0xfff) == 0x119000) pclog(" %p : %08x-%08x %08x-%08x\n", (void *)block, start_pc, end_pc, block->pc, block->endpc);
|
||||
if (end_pc > start_pc)
|
||||
{
|
||||
for (; start_pc <= end_pc; start_pc += 4)
|
||||
checksum += *(uint32_t *)&ram[start_pc];
|
||||
}
|
||||
else
|
||||
checksum = ~block->checksum;
|
||||
|
||||
if (checksum != block->checksum)
|
||||
{
|
||||
if ((phys_addr & ~0xfff) == 0x119000) pclog(" evict %08x %08x %08x %p %p\n", block->pc, checksum, block->checksum, (void *)block->prev, (void *)last_block);
|
||||
block->pc = 0;//xffffffff;
|
||||
|
||||
if (block->prev)
|
||||
{
|
||||
block->prev->next = block->next;
|
||||
if (block->next)
|
||||
block->next->prev = block->prev;
|
||||
}
|
||||
else
|
||||
{
|
||||
pages[block->phys >> 12].block = block->next;
|
||||
if (block->next)
|
||||
block->next->prev = NULL;
|
||||
}
|
||||
|
||||
codeblock_hash[HASH(block->phys)] = NULL;
|
||||
|
||||
block->next = NULL;
|
||||
}
|
||||
|
||||
block = next_block;
|
||||
last_block = old_block;
|
||||
}
|
||||
//if ((phys_addr & ~0xfff) == 0x119000) pclog("init end\n");
|
||||
codeblock_page_dirty[phys_addr >> 12] = 0;
|
||||
mem_flush_write_page(phys_addr, cs+pc);
|
||||
}
|
||||
page_t *page = &pages[phys_addr >> 12];
|
||||
|
||||
/* if (has_evicted)
|
||||
cpu_recomp_evicted++;*/
|
||||
// pclog("Build %08x\n",cs+pc);
|
||||
|
||||
if (!page->block)
|
||||
mem_flush_write_page(phys_addr, cs+pc);
|
||||
|
||||
block_current = (block_current + 1) & BLOCK_MASK;
|
||||
block = &codeblock[block_current];
|
||||
if (block->pc != 0)//xffffffff)
|
||||
|
||||
// if (block->pc == 0xb00b4ff5)
|
||||
// pclog("Init target block\n");
|
||||
if (block->pc != 0)
|
||||
{
|
||||
// if ((phys_addr & ~0xfff) == 0x119000) pclog("Block reuse - %04x old_pc=%08x new_pc=%08x\n", block_current, block->pc, cs+pc);
|
||||
// if ((phys_addr & ~0xfff) == 0x119000) dump_block();
|
||||
/*Block currently used - throw out contents*/
|
||||
if (block->prev)
|
||||
{
|
||||
block->prev->next = block->next;
|
||||
if (block->next)
|
||||
block->next->prev = block->prev;
|
||||
}
|
||||
else
|
||||
{
|
||||
pages[block->phys >> 12].block = block->next;
|
||||
if (block->next)
|
||||
block->next->prev = NULL;
|
||||
}
|
||||
codeblock_hash[HASH(block->phys)] = NULL;
|
||||
// pclog("Reuse block : was %08x now %08x\n", block->pc, cs+pc);
|
||||
delete_block(block);
|
||||
cpu_recomp_reuse++;
|
||||
// if ((phys_addr & ~0xfff) == 0x119000) pclog("Block reuse end\n");
|
||||
// if ((phys_addr & ~0xfff) == 0x119000) dump_block();
|
||||
}
|
||||
block_num = HASH(phys_addr);
|
||||
codeblock_hash[block_num] = &codeblock[block_current];
|
||||
|
|
@ -265,7 +189,6 @@ void codegen_block_init(uint32_t phys_addr)
|
|||
block->next = block->prev = NULL;
|
||||
|
||||
block_pos = 0;
|
||||
|
||||
block_pos = BLOCK_EXIT_OFFSET; /*Exit code*/
|
||||
addbyte(0x83); /*ADDL $8,%esp*/
|
||||
addbyte(0xC4);
|
||||
|
|
@ -287,16 +210,21 @@ void codegen_block_init(uint32_t phys_addr)
|
|||
codegen_timing_block_start();
|
||||
|
||||
codegen_block_ins = 0;
|
||||
|
||||
recomp_page = phys_addr & ~0xfff;
|
||||
}
|
||||
|
||||
void codegen_block_remove()
|
||||
{
|
||||
codeblock_t *block = &codeblock[block_current];
|
||||
//if ((block->phys & ~0xfff) == 0x119000) pclog("codegen_block_remove %08x\n", block->pc);
|
||||
// if (block->pc == 0xb00b4ff5)
|
||||
// pclog("Remove target block\n");
|
||||
codeblock_hash[block_num] = NULL;
|
||||
block->pc = 0;//xffffffff;
|
||||
cpu_recomp_removed++;
|
||||
// pclog("Remove block %i\n", block_num);
|
||||
recomp_page = -1;
|
||||
}
|
||||
|
||||
void codegen_block_end()
|
||||
|
|
@ -305,12 +233,12 @@ void codegen_block_end()
|
|||
codeblock_t *block_prev = pages[block->phys >> 12].block;
|
||||
uint32_t start_pc = (block->pc & 0xffc) | (block->phys & ~0xfff);
|
||||
uint32_t end_pc = ((codegen_endpc + 3) & 0xffc) | (block->phys & ~0xfff);
|
||||
uint32_t checksum = 0;
|
||||
|
||||
block->endpc = end_pc;
|
||||
block->endpc = codegen_endpc;
|
||||
|
||||
// if (block->pc == 0xb00b4ff5)
|
||||
// pclog("End target block\n");
|
||||
|
||||
//if ((block->phys & ~0xfff) == 0x119000) pclog("codegen_block_end start\n");
|
||||
//if ((block->phys & ~0xfff) == 0x119000) dump_block();
|
||||
if (block_prev)
|
||||
{
|
||||
block->next = block_prev;
|
||||
|
|
@ -323,21 +251,80 @@ void codegen_block_end()
|
|||
pages[block->phys >> 12].block = block;
|
||||
}
|
||||
|
||||
//if ((block->phys & ~0xfff) == 0x119000) pclog("codegen_block_end end\n");
|
||||
//if ((block->phys & ~0xfff) == 0x119000) dump_block();
|
||||
|
||||
#ifdef CHECKSUM
|
||||
if (end_pc > start_pc)
|
||||
if (block->next)
|
||||
{
|
||||
// pclog("block_end %08x-%08x %08x-%08x\n", start_pc, end_pc, block->pc, block->endpc);
|
||||
for (; start_pc <= end_pc; start_pc += 4)
|
||||
checksum += *(uint32_t *)&ram[start_pc];
|
||||
// pclog(" %08x\n", checksum);
|
||||
// pclog(" next->pc=%08x\n", block->next->pc);
|
||||
if (!block->next->pc)
|
||||
fatal("block->next->pc=0 %p %p %x %x\n", (void *)block->next, (void *)codeblock, block_current, block_pos);
|
||||
}
|
||||
#endif
|
||||
|
||||
block->page_mask = 0;
|
||||
start_pc = block->pc & 0xffc;
|
||||
start_pc &= ~PAGE_MASK_MASK;
|
||||
end_pc = ((block->endpc & 0xffc) + PAGE_MASK_MASK) & ~PAGE_MASK_MASK;
|
||||
if (end_pc > 0xfff || end_pc < start_pc)
|
||||
end_pc = 0xfff;
|
||||
start_pc >>= PAGE_MASK_SHIFT;
|
||||
end_pc >>= PAGE_MASK_SHIFT;
|
||||
|
||||
block->checksum = checksum;
|
||||
// pclog("Checksum for %08x - %08x = %08x\n", codeblock_hash_pc[block_num] & ~3, end_pc, checksum);
|
||||
// pclog("block_end: %08x %08x\n", start_pc, end_pc);
|
||||
for (; start_pc <= end_pc; start_pc++)
|
||||
{
|
||||
block->page_mask |= ((uint64_t)1 << start_pc);
|
||||
// pclog(" %08x %llx\n", start_pc, block->page_mask);
|
||||
}
|
||||
|
||||
pages[block->phys >> 12].code_present_mask |= block->page_mask;
|
||||
|
||||
block->phys_2 = -1;
|
||||
block->page_mask2 = 0;
|
||||
block->next_2 = block->prev_2 = NULL;
|
||||
if ((block->pc ^ block->endpc) & ~0xfff)
|
||||
{
|
||||
block->phys_2 = get_phys_noabrt(block->endpc);
|
||||
if (block->phys_2 != -1)
|
||||
{
|
||||
// pclog("start block - %08x %08x %p %p %p %08x\n", block->pc, block->endpc, (void *)block, (void *)block->next_2, (void *)pages[block->phys_2 >> 12].block_2, block->phys_2);
|
||||
|
||||
if (pages[block->phys_2 >> 12].block_2 == block)
|
||||
fatal("Block same\n");
|
||||
|
||||
block_prev = pages[block->phys_2 >> 12].block_2;
|
||||
|
||||
if (block_prev)
|
||||
{
|
||||
block->next_2 = block_prev;
|
||||
block_prev->prev_2 = block;
|
||||
pages[block->phys_2 >> 12].block_2 = block;
|
||||
// pclog(" pages.block_2=%p\n", (void *)block);
|
||||
}
|
||||
else
|
||||
{
|
||||
block->next_2 = NULL;
|
||||
pages[block->phys_2 >> 12].block_2 = block;
|
||||
// pclog(" pages.block_2=%p 2\n", (void *)block);
|
||||
}
|
||||
|
||||
start_pc = 0;
|
||||
end_pc = (block->endpc & 0xfff) >> PAGE_MASK_SHIFT;
|
||||
for (; start_pc <= end_pc; start_pc++)
|
||||
block->page_mask2 |= ((uint64_t)1 << start_pc);
|
||||
|
||||
if (!pages[block->phys_2 >> 12].block_2)
|
||||
mem_flush_write_page(block->phys_2, block->endpc);
|
||||
// pclog("New block - %08x %08x %p %p phys %08x %08x %016llx\n", block->pc, block->endpc, (void *)block, (void *)block->next_2, block->phys, block->phys_2, block->page_mask2);
|
||||
if (!block->page_mask2)
|
||||
fatal("!page_mask2\n");
|
||||
if (block->next_2)
|
||||
{
|
||||
// pclog(" next_2->pc=%08x\n", block->next_2->pc);
|
||||
if (!block->next_2->pc)
|
||||
fatal("block->next_2->pc=0 %p\n", (void *)block->next_2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pclog("block_end: %08x %08x %016llx\n", block->pc, block->endpc, block->page_mask);
|
||||
|
||||
codegen_timing_block_end();
|
||||
|
||||
|
|
@ -361,6 +348,8 @@ void codegen_block_end()
|
|||
addbyte(0x08);
|
||||
addbyte(0xC3); /*RET*/
|
||||
// pclog("End block %i\n", block_num);
|
||||
|
||||
recomp_page = -1;
|
||||
}
|
||||
|
||||
void codegen_flush()
|
||||
|
|
@ -368,25 +357,6 @@ void codegen_flush()
|
|||
return;
|
||||
}
|
||||
|
||||
void codegen_dirty(uint32_t addr)
|
||||
{
|
||||
codeblock_page_dirty[addr >> 12] = 1;
|
||||
// pclog("codegen_dirty : %08x %04x:%04x\n", addr, CS, pc);
|
||||
// if ((addr >> 12) == 0x152)
|
||||
// pclog("Dirty : %08x %08x\n", addr, cs+pc);
|
||||
/* int c;
|
||||
int offset = HASH(addr & ~0xfff);
|
||||
// pclog("codegen_dirty %08X\n", addr);
|
||||
for (c = 0; c < 0x1000; c++)
|
||||
{
|
||||
if (!((codeblock_hash_pc[(c + offset) & HASH_MASK] ^ addr) & ~0xfff))
|
||||
{
|
||||
// pclog("Throwing out %08X\n", codeblock_hash_pc[(c + offset) & HASH_MASK]);
|
||||
codeblock_hash_pc[(c + offset) & HASH_MASK] = 0xffffffff;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
static int opcode_needs_tempc[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /*00*/
|
||||
|
|
@ -482,7 +452,7 @@ void codegen_debug()
|
|||
{
|
||||
if (output)
|
||||
{
|
||||
pclog("At %04x(%08x):%04x %04x(%08x):%04x EAX=%08x BX=%04x BP=%04x EDX=%08x\n", CS, cs, pc, SS, ss, ESP, EAX, BX,BP, EDX);
|
||||
pclog("At %04x(%08x):%04x %04x(%08x):%04x es=%08x EAX=%08x BX=%04x ECX=%08x BP=%04x EDX=%08x EDI=%08x\n", CS, cs, pc, SS, ss, ESP, es,EAX, BX,ECX,BP, EDX,EDI);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include "io.h"
|
||||
#include "x86_ops.h"
|
||||
#ifdef DYNAREC
|
||||
#include "mem.h"
|
||||
#include "codegen.h"
|
||||
#endif
|
||||
|
||||
|
|
|
|||
185
src/mem.c
185
src/mem.c
|
|
@ -20,6 +20,9 @@
|
|||
#include "codegen.h"
|
||||
#endif
|
||||
|
||||
page_t *pages;
|
||||
page_t **page_lookup;
|
||||
|
||||
static uint8_t (*_mem_read_b[0x40000])(uint32_t addr, void *priv);
|
||||
static uint16_t (*_mem_read_w[0x40000])(uint32_t addr, void *priv);
|
||||
static uint32_t (*_mem_read_l[0x40000])(uint32_t addr, void *priv);
|
||||
|
|
@ -468,6 +471,7 @@ void resetreadlookup()
|
|||
for (c=0;c<256;c++) readlookup[c]=0xFFFFFFFF;
|
||||
readlnext=0;
|
||||
memset(writelookup2,0xFF,1024*1024*sizeof(uintptr_t));
|
||||
memset(page_lookup, 0, (1 << 20) * sizeof(page_t *));
|
||||
for (c=0;c<256;c++) writelookup[c]=0xFFFFFFFF;
|
||||
writelnext=0;
|
||||
pccache=0xFFFFFFFF;
|
||||
|
|
@ -494,10 +498,11 @@ void flushmmucache()
|
|||
readlookup2[readlookup[c]]=0xFFFFFFFF;
|
||||
readlookup[c]=0xFFFFFFFF;
|
||||
}
|
||||
if (writelookup[c]!=0xFFFFFFFF)
|
||||
if (writelookup[c] != 0xFFFFFFFF)
|
||||
{
|
||||
writelookup2[writelookup[c]]=0xFFFFFFFF;
|
||||
writelookup[c]=0xFFFFFFFF;
|
||||
page_lookup[writelookup[c]] = NULL;
|
||||
writelookup2[writelookup[c]] = 0xffffffff;
|
||||
writelookup[c] = 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
mmuflush++;
|
||||
|
|
@ -541,10 +546,11 @@ void flushmmucache_nopc()
|
|||
readlookup2[readlookup[c]]=0xFFFFFFFF;
|
||||
readlookup[c]=0xFFFFFFFF;
|
||||
}
|
||||
if (writelookup[c]!=0xFFFFFFFF)
|
||||
if (writelookup[c] != 0xFFFFFFFF)
|
||||
{
|
||||
writelookup2[writelookup[c]]=0xFFFFFFFF;
|
||||
writelookup[c]=0xFFFFFFFF;
|
||||
page_lookup[writelookup[c]] = NULL;
|
||||
writelookup2[writelookup[c]] = 0xffffffff;
|
||||
writelookup[c] = 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -560,10 +566,11 @@ void flushmmucache_cr3()
|
|||
readlookup2[readlookup[c]]=0xFFFFFFFF;
|
||||
readlookup[c]=0xFFFFFFFF;
|
||||
}
|
||||
if (writelookup[c]!=0xFFFFFFFF)// && !writelookupp[c])
|
||||
if (writelookup[c] != 0xFFFFFFFF)// && !writelookupp[c])
|
||||
{
|
||||
writelookup2[writelookup[c]]=0xFFFFFFFF;
|
||||
writelookup[c]=0xFFFFFFFF;
|
||||
page_lookup[writelookup[c]] = NULL;
|
||||
writelookup2[writelookup[c]] = 0xffffffff;
|
||||
writelookup[c] = 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
/* for (c = 0; c < 1024*1024; c++)
|
||||
|
|
@ -583,19 +590,27 @@ void flushmmucache_cr3()
|
|||
}*/
|
||||
}
|
||||
|
||||
|
||||
void mem_flush_write_page(uint32_t addr, uint32_t virt)
|
||||
{
|
||||
int c;
|
||||
page_t *page_target = &pages[addr >> 12];
|
||||
// pclog("mem_flush_write_page %08x %08x\n", virt, addr);
|
||||
|
||||
for (c = 0; c < 256; c++)
|
||||
{
|
||||
uintptr_t target = (uintptr_t)&ram[(uintptr_t)(addr & ~0xFFF) - (uintptr_t)(writelookup[c] << 12)];
|
||||
|
||||
if (writelookup2[writelookup[c]] == target)
|
||||
if (writelookup[c] != 0xffffffff)
|
||||
{
|
||||
writelookup2[writelookup[c]] = 0xffffffff;
|
||||
writelookup[c] = 0xffffffff;
|
||||
uintptr_t target = (uintptr_t)&ram[(uintptr_t)(addr & ~0xfff) - (virt & ~0xfff)];
|
||||
|
||||
// if ((virt & ~0xfff) == 0xc022e000)
|
||||
// pclog(" Checking %02x %p %p\n", (void *)writelookup2[writelookup[c]], (void *)target);
|
||||
if (writelookup2[writelookup[c]] == target || page_lookup[writelookup[c]] == page_target)
|
||||
{
|
||||
// pclog(" throw out %02x %p %p\n", writelookup[c], (void *)page_lookup[writelookup[c]], (void *)writelookup2[writelookup[c]]);
|
||||
writelookup2[writelookup[c]] = 0xffffffff;
|
||||
page_lookup[writelookup[c]] = NULL;
|
||||
writelookup[c] = 0xffffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -649,7 +664,7 @@ uint32_t mmutranslatereal(uint32_t addr, int rw)
|
|||
if (!(temp&1) || (CPL==3 && !(temp3&4) && !cpl_override) || (rw && !(temp3&2) && (CPL==3 || cr0&WP_FLAG)))
|
||||
{
|
||||
// if (!nopageerrors) pclog("Page not present! %08X %08X %02X %02X %i %08X %04X:%08X %04X:%08X %i %i %i\n",addr,temp,opcode,opcode2,frame,rmdat32, CS,pc,SS,ESP,ins,CPL,rw);
|
||||
|
||||
|
||||
// dumpregs();
|
||||
// exit(-1);
|
||||
// if (addr == 0x815F6E90) output = 3;
|
||||
|
|
@ -677,6 +692,29 @@ uint32_t mmutranslatereal(uint32_t addr, int rw)
|
|||
return (temp&~0xFFF)+(addr&0xFFF);
|
||||
}
|
||||
|
||||
uint32_t mmutranslate_noabrt(uint32_t addr, int rw)
|
||||
{
|
||||
uint32_t addr2;
|
||||
uint32_t temp,temp2,temp3;
|
||||
|
||||
if (abrt)
|
||||
return -1;
|
||||
|
||||
addr2=(cr3+((addr>>20)&0xFFC));
|
||||
temp=temp2=((uint32_t *)ram)[addr2>>2];
|
||||
|
||||
if (!(temp&1))
|
||||
return -1;
|
||||
|
||||
temp=((uint32_t *)ram)[((temp&~0xFFF)+((addr>>10)&0xFFC))>>2];
|
||||
temp3=temp&temp2;
|
||||
|
||||
if (!(temp&1) || (CPL==3 && !(temp3&4) && !cpl_override) || (rw && !(temp3&2) && (CPL==3 || cr0&WP_FLAG)))
|
||||
return -1;
|
||||
|
||||
return (temp&~0xFFF)+(addr&0xFFF);
|
||||
}
|
||||
|
||||
void mmu_invalidate(uint32_t addr)
|
||||
{
|
||||
// readlookup2[addr >> 12] = writelookup2[addr >> 12] = 0xFFFFFFFF;
|
||||
|
|
@ -738,7 +776,7 @@ void addwritelookup(uint32_t virt, uint32_t phys)
|
|||
if (virt == 0xffffffff)
|
||||
return;
|
||||
|
||||
if (writelookup2[virt>>12]!=0xFFFFFFFF)
|
||||
if (page_lookup[virt >> 12])
|
||||
{
|
||||
/* if (writelookup2[virt>>12] != phys&~0xfff)
|
||||
{
|
||||
|
|
@ -761,19 +799,24 @@ void addwritelookup(uint32_t virt, uint32_t phys)
|
|||
}
|
||||
|
||||
cycles-=memwaitstate;
|
||||
if (writelookup[writelnext]!=0xFFFFFFFF)
|
||||
if (writelookup[writelnext] != 0xFFFFFFFF)
|
||||
{
|
||||
page_lookup[writelookup[writelnext]] = NULL;
|
||||
writelookup2[writelookup[writelnext]]=0xFFFFFFFF;
|
||||
// writelnum--;
|
||||
}
|
||||
writelookup2[virt>>12] = (uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)];
|
||||
writelookupp[writelnext]=mmu_perm;
|
||||
writelookup[writelnext++]=virt>>12;
|
||||
writelnext&=(cachesize-1);
|
||||
|
||||
// if (page_lookup[virt >> 12] && (writelookup2[virt>>12] != 0xffffffff))
|
||||
// fatal("Bad write mapping\n");
|
||||
#if DYNAREC
|
||||
codegen_dirty(phys);
|
||||
if (pages[phys >> 12].block || (phys & ~0xfff) == recomp_page)
|
||||
page_lookup[virt >> 12] = &pages[phys >> 12];//(uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)];
|
||||
else
|
||||
#endif
|
||||
writelookup2[virt>>12] = (uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)];
|
||||
// pclog("addwritelookup %08x %08x %p %p %016llx %p\n", virt, phys, (void *)page_lookup[virt >> 12], (void *)writelookup2[virt >> 12], pages[phys >> 12].dirty_mask, (void *)&pages[phys >> 12]);
|
||||
writelookupp[writelnext] = mmu_perm;
|
||||
writelookup[writelnext++] = virt >> 12;
|
||||
writelnext &= (cachesize - 1);
|
||||
}
|
||||
|
||||
#undef printf
|
||||
|
|
@ -827,6 +870,11 @@ void writemembl(uint32_t addr, uint8_t val)
|
|||
{
|
||||
mem_logical_addr = addr;
|
||||
|
||||
if (page_lookup[addr>>12])
|
||||
{
|
||||
page_lookup[addr>>12]->write_b(addr, val, page_lookup[addr>>12]);
|
||||
return;
|
||||
}
|
||||
if (cr0 >> 31)
|
||||
{
|
||||
addr = mmutranslate_write(addr);
|
||||
|
|
@ -875,6 +923,11 @@ void writememb386l(uint32_t seg, uint32_t addr, uint8_t val)
|
|||
}
|
||||
|
||||
mem_logical_addr = addr = addr + seg;
|
||||
if (page_lookup[addr>>12])
|
||||
{
|
||||
page_lookup[addr>>12]->write_b(addr, val, page_lookup[addr>>12]);
|
||||
return;
|
||||
}
|
||||
if (cr0 >> 31)
|
||||
{
|
||||
addr = mmutranslate_write(addr);
|
||||
|
|
@ -957,6 +1010,11 @@ void writememwl(uint32_t seg, uint32_t addr, uint16_t val)
|
|||
printf("NULL segment! ww %04X(%08X):%08X %02X %08X\n",CS,cs,pc,opcode,addr);
|
||||
return;
|
||||
}
|
||||
if (page_lookup[addr2>>12])
|
||||
{
|
||||
page_lookup[addr2>>12]->write_w(addr2, val, page_lookup[addr2>>12]);
|
||||
return;
|
||||
}
|
||||
if (cr0>>31)
|
||||
{
|
||||
addr2 = mmutranslate_write(addr2);
|
||||
|
|
@ -1042,6 +1100,11 @@ void writememll(uint32_t seg, uint32_t addr, uint32_t val)
|
|||
printf("NULL segment! wl %04X(%08X):%08X %02X %08X\n",CS,cs,pc,opcode,addr);
|
||||
return;
|
||||
}
|
||||
if (page_lookup[addr2>>12])
|
||||
{
|
||||
page_lookup[addr2>>12]->write_l(addr2, val, page_lookup[addr2>>12]);
|
||||
return;
|
||||
}
|
||||
if (cr0>>31)
|
||||
{
|
||||
addr2 = mmutranslate_write(addr2);
|
||||
|
|
@ -1112,23 +1175,61 @@ uint32_t mem_read_raml(uint32_t addr, void *priv)
|
|||
return *(uint32_t *)&ram[addr];
|
||||
}
|
||||
|
||||
static void mem_write_ramb_page(uint32_t addr, uint8_t val, page_t *p)
|
||||
{
|
||||
if (p->mem[addr & 0xfff] != val)
|
||||
{
|
||||
#if DYNAREC
|
||||
uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK);
|
||||
// pclog("mem_write_ramb_page: %08x %02x %08x\n", addr, val, cs+pc);
|
||||
p->dirty_mask |= mask;
|
||||
#endif
|
||||
p->mem[addr & 0xfff] = val;
|
||||
}
|
||||
}
|
||||
static void mem_write_ramw_page(uint32_t addr, uint16_t val, page_t *p)
|
||||
{
|
||||
if (*(uint16_t *)&p->mem[addr & 0xfff] != val)
|
||||
{
|
||||
#if DYNAREC
|
||||
uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK);
|
||||
if ((addr & 0x3f) == 0x3f)
|
||||
mask |= (mask << 1);
|
||||
// pclog("mem_write_ramw_page: %08x %04x %08x\n", addr, val, cs+pc);
|
||||
p->dirty_mask |= mask;
|
||||
#endif
|
||||
*(uint16_t *)&p->mem[addr & 0xfff] = val;
|
||||
}
|
||||
}
|
||||
static void mem_write_raml_page(uint32_t addr, uint32_t val, page_t *p)
|
||||
{
|
||||
if (*(uint32_t *)&p->mem[addr & 0xfff] != val)
|
||||
{
|
||||
#if DYNAREC
|
||||
uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK);
|
||||
if ((addr & 0x3f) >= 0x3d)
|
||||
mask |= (mask << 1);
|
||||
// pclog("mem_write_raml_page: %08x %08x %08x\n", addr, val, cs+pc);
|
||||
p->dirty_mask |= mask;
|
||||
#endif
|
||||
*(uint32_t *)&p->mem[addr & 0xfff] = val;
|
||||
}
|
||||
}
|
||||
|
||||
void mem_write_ram(uint32_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
addwritelookup(mem_logical_addr, addr);
|
||||
ram[addr] = val;
|
||||
// if (addr >= 0xc0000 && addr < 0x0c8000) pclog("Write RAMb %08X\n", addr);
|
||||
mem_write_ramb_page(addr, val, &pages[addr >> 12]);
|
||||
}
|
||||
void mem_write_ramw(uint32_t addr, uint16_t val, void *priv)
|
||||
{
|
||||
addwritelookup(mem_logical_addr, addr);
|
||||
*(uint16_t *)&ram[addr] = val;
|
||||
// if (addr >= 0xc0000 && addr < 0x0c8000) pclog("Write RAMw %08X %04X:%04X %i %04X %04X:%04X %04X:%04X\n", addr, CS, pc, ins, val, DS,SI, ES,DI);
|
||||
mem_write_ramw_page(addr, val, &pages[addr >> 12]);
|
||||
}
|
||||
void mem_write_raml(uint32_t addr, uint32_t val, void *priv)
|
||||
{
|
||||
addwritelookup(mem_logical_addr, addr);
|
||||
*(uint32_t *)&ram[addr] = val;
|
||||
// if (addr >= 0xc0000 && addr < 0x0c8000) pclog("Write RAMl %08X %04X:%04X %04X:%04X %04X:%04X\n", addr, CS, pc, DS,SI, ES,DI);
|
||||
mem_write_raml_page(addr, val, &pages[addr >> 12]);
|
||||
}
|
||||
|
||||
uint8_t mem_read_bios(uint32_t addr, void *priv)
|
||||
|
|
@ -1433,8 +1534,21 @@ void mem_init()
|
|||
writelookup2 = malloc(1024 * 1024 * sizeof(uintptr_t));
|
||||
cachelookup2 = malloc(1024 * 1024);
|
||||
biosmask = 0xffff;
|
||||
pages = malloc(((mem_size * 1024 * 1024) >> 12) * sizeof(page_t));
|
||||
page_lookup = malloc((1 << 20) * sizeof(page_t *));
|
||||
|
||||
memset(ram, 0, mem_size * 1024 * 1024);
|
||||
memset(pages, 0, ((mem_size * 1024 * 1024) >> 12) * sizeof(page_t));
|
||||
|
||||
memset(page_lookup, 0, (1 << 20) * sizeof(page_t *));
|
||||
|
||||
for (c = 0; c < ((mem_size * 1024 * 1024) >> 12); c++)
|
||||
{
|
||||
pages[c].mem = &ram[c << 12];
|
||||
pages[c].write_b = mem_write_ramb_page;
|
||||
pages[c].write_w = mem_write_ramw_page;
|
||||
pages[c].write_l = mem_write_raml_page;
|
||||
}
|
||||
|
||||
memset(isram, 0, sizeof(isram));
|
||||
for (c = 0; c < (mem_size * 16); c++)
|
||||
|
|
@ -1476,6 +1590,17 @@ void mem_resize()
|
|||
ram = malloc(mem_size * 1024 * 1024);
|
||||
memset(ram, 0, mem_size * 1024 * 1024);
|
||||
|
||||
free(pages);
|
||||
pages = malloc(((mem_size * 1024 * 1024) >> 12) * sizeof(page_t));
|
||||
memset(pages, 0, ((mem_size * 1024 * 1024) >> 12) * sizeof(page_t));
|
||||
for (c = 0; c < ((mem_size * 1024 * 1024) >> 12); c++)
|
||||
{
|
||||
pages[c].mem = &ram[c << 12];
|
||||
pages[c].write_b = mem_write_ramb_page;
|
||||
pages[c].write_w = mem_write_ramw_page;
|
||||
pages[c].write_l = mem_write_raml_page;
|
||||
}
|
||||
|
||||
memset(isram, 0, sizeof(isram));
|
||||
for (c = 0; c < (mem_size * 16); c++)
|
||||
{
|
||||
|
|
|
|||
36
src/mem.h
36
src/mem.h
|
|
@ -98,3 +98,39 @@ void mem_write_nulll(uint32_t addr, uint32_t val, void *p);
|
|||
FILE *romfopen(char *fn, char *mode);
|
||||
|
||||
mem_mapping_t bios_mapping[8];
|
||||
|
||||
|
||||
typedef struct page_t
|
||||
{
|
||||
void (*write_b)(uint32_t addr, uint8_t val, struct page_t *p);
|
||||
void (*write_w)(uint32_t addr, uint16_t val, struct page_t *p);
|
||||
void (*write_l)(uint32_t addr, uint32_t val, struct page_t *p);
|
||||
|
||||
uint8_t *mem;
|
||||
|
||||
struct codeblock_t *block, *block_2;
|
||||
|
||||
uint64_t code_present_mask, dirty_mask;
|
||||
} page_t;
|
||||
|
||||
extern page_t *pages;
|
||||
|
||||
extern page_t **page_lookup;
|
||||
|
||||
uint32_t mmutranslate_noabrt(uint32_t addr, int rw);
|
||||
|
||||
static inline get_phys(uint32_t addr)
|
||||
{
|
||||
if (!(cr0 >> 31))
|
||||
return addr & rammask;
|
||||
|
||||
return mmutranslatereal(addr, 0) & rammask;
|
||||
}
|
||||
|
||||
static inline get_phys_noabrt(uint32_t addr)
|
||||
{
|
||||
if (!(cr0 >> 31))
|
||||
return addr & rammask;
|
||||
|
||||
return mmutranslate_noabrt(addr, 0) & rammask;
|
||||
}
|
||||
|
|
|
|||
2
src/pc.c
2
src/pc.c
|
|
@ -7,6 +7,7 @@
|
|||
#include "ali1429.h"
|
||||
#include "amstrad.h"
|
||||
#include "cdrom-ioctl.h"
|
||||
#include "mem.h"
|
||||
#ifdef DYNAREC
|
||||
#include "x86_ops.h"
|
||||
#include "codegen.h"
|
||||
|
|
@ -19,7 +20,6 @@
|
|||
#include "sound_gus.h"
|
||||
#include "ide.h"
|
||||
#include "keyboard.h"
|
||||
#include "mem.h"
|
||||
#include "model.h"
|
||||
#include "mouse.h"
|
||||
#include "nvr.h"
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "win.h"
|
||||
#ifdef DYNAREC
|
||||
#include "x86_ops.h"
|
||||
#include "mem.h"
|
||||
#include "codegen.h"
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -101,12 +101,3 @@ extern int inscounts[256];
|
|||
void x86illegal();
|
||||
|
||||
void x86seg_reset();
|
||||
|
||||
|
||||
static inline get_phys(uint32_t addr)
|
||||
{
|
||||
if (!(cr0 >> 31))
|
||||
return addr & rammask;
|
||||
|
||||
return mmutranslatereal(addr, 0) & rammask;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue