Apollo64/source/TLB.cpp
2021-12-12 21:39:10 -06:00

456 lines
13 KiB
C++

/*
Todo list for New TLB
- I need to search through the TLBList for matching TLB entries (needed for speed)
- I need to delete unused TLB entries
- I need to detect a TLB Clear
- I need to implement Miss and Invalid exception handling
- I need to implement Random TLB
- I need to clear out TLB on rom reset
- I need to setup direct TLBTable access
- Clean Code... TLBAddEntry and TLBDelEntry functions would come in handy
*/
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <stdio.h>
#include <stdlib.h>
#include "WinMain.h"
#include "EmuMain.h"
#include "CpuMain.h"
#include "resource.h"
#define MMU_INDEX MmuRegs[0]
#define MMU_RANDOM MmuRegs[1]
#define MMU_ENTRYLO0 MmuRegs[2]
#define MMU_ENTRYLO1 MmuRegs[3]
#define MMU_CONTEXT MmuRegs[4]
#define MMU_PAGEMASK MmuRegs[5]
#define MMU_WIRED MmuRegs[6]
#define MMU_BADVADDR MmuRegs[8]
#define MMU_ENTRYHI MmuRegs[10]
#define TLB_LOAD 2
#define TLB_STORE 3
extern s_tlb tlb[32];
extern bool tlbinvalid;
void GenerateException(DWORD addr, DWORD type);
r4300iTLB TLBLUT;
extern int inDelay;
void GenerateTLBException (DWORD addr, DWORD type) {
MMU_RANDOM = instructions & 0x1F;
if (MMU_RANDOM < MMU_WIRED)
MMU_RANDOM = 0x1F;
//Debug (0, "MMU_RANDOM = %i", MMU_RANDOM);
MMU_CONTEXT &= 0xFF800000;
MMU_CONTEXT |= (addr >> 13) << 4;
MMU_ENTRYHI &= 0x00001FFF;
MMU_ENTRYHI = (addr & 0xFFFFE000);
MMU_BADVADDR = addr;
if (pc != addr)
pc -= 4;
Debug (0, "TLB Exception... pc = %08X - addr = %08X", pc, addr);
if (inDelay == 1)
Debug (0, "TLB Exception in Delay Slot at PC = %08X", pc);
if (TLBLUT[addr >> 12] == 0xFFFFFFFE)
tlbinvalid = true;
if (type)
GenerateException(pc, TLB_STORE);
else
GenerateException(pc, TLB_LOAD);
//MMU_INDEX = 0;
//Emulate ();
//RaiseException (0xc0001337, 0,0, NULL); // TLB Exception
}
// Golden Eye Range... 7f000000,10034b30,1000000 (borrowed from UltraHLE 1.0)
void r4300iTLB::mapmem (u32 tlbaddy, u32 mapaddy, u32 size) {
u32 thesize = size / 0x1000;
u32 addy = tlbaddy >> 12;
Debug (0, "Mapping Address %08X to %08X of size %08X", tlbaddy, mapaddy, size);
for (u32 i = 0x0; i < thesize; i++) {
this->TLBTable[addy+i] = (mapaddy+(i << 12));
}
}
void r4300iTLB::ResetTLB(void) {
memset(this->TLBTable, 0xFF, 0x400000); // 4MB Memory LUT
memset(this->TLBList , 0x00, sizeof(s_tlb) * listSize); // 4MB Memory LUT
for (DWORD i = 0x0; i < 0x800; i++) {
this->TLBTable[0x80000+i] = ((0x80000+i) << 12);
this->TLBTable[0xA0000+i] = ((0xA0000+i) << 12);
//this->TLBTable[0x80000+i] = valloc + (i << 12);
//this->TLBTable[0xA0000+i] = valloc + (i << 12);
}
}
void r4300iTLB:: ResizeTLBList (void) {
s_tlb *oldTLBList = this->TLBList;
this->listSize <<= 1; // Double the TLB List
this->TLBList = (s_tlb *)VirtualAlloc(NULL, sizeof(s_tlb) * listSize, MEM_COMMIT, PAGE_READWRITE);
memcpy (TLBList, oldTLBList, listSize >> 1); // Copy it over
VirtualFree(oldTLBList, 0, MEM_RELEASE); // Free the old List
}
void RecreateLUT () {
}
// Clears an Entry
void r4300iTLB::ClearEntry (int index) {
int page = ((tlb[index].hh >> 13) + 1) * 4096;
int mask = ~(tlb[index].hh | 0x1fff);
int maskLow = (tlb[index].hh | 0x1fff);
u32 TLBStartLoc = (tlb[index].hl & mask) >> 12; // Start of TLB Entry
u32 TLBLength = (maskLow+1) >> 10;//tlb[index].hh; // Length of TLB Entry
if ((TLBStartLoc >= 0x80000) && (TLBStartLoc < 0xBFFFF)) // Never unmap these locations
return;
memset (&this->TLBTable[TLBStartLoc], 0xFF, TLBLength);
}
// This should place the TLB entry in the Main TLB List...
// Should I be picky about its location in the Main TLB List?
void r4300iTLB::Probe () {
// TODO: Before I can do this, I will need to keep a list of things like the mask...
//if (TLBTable[MMU_ENTRYHI >> 12] < 0xFFFFFFF0)
/*
for (int i=0; i < 32; i++) {
u32 mask = ~(TLBList[i].hh | 0x1fff);//& 0xffffe000;
if((TLBList[i].hl&mask) == (MMU_ENTRYHI&mask)) {
tlb[0x13].hh = TLBList[i].hh; tlb[0x13].hl = TLBList[i].hl;
tlb[0x13].lh = TLBList[i].lh; tlb[0x13].ll = TLBList[i].ll;
tlb[0x13].isGlobal = TLBList[i].isGlobal;
MMU_INDEX=0x13;
return;
}
}
*/
}
// Index Entry will ALWAYS overwrite previous entries
void r4300iTLB::IndexEntry (int index) {
/* Not sure how I will handle this or if I will. Perhaps I will replace it
entry by entry.
if (MMU_ENTRYHI == 0x80000000) {
this->RecreateLUT (); // Allows for the case where the TLB Tables are cleared
}
*/
int page = ((tlb[index].hh >> 13) + 1) * 4096;
int mask = ~(tlb[index].hh | 0x1fff);
int maskLow = (tlb[index].hh | 0x1fff);
// TODO!!!! : This NEEDS to be changed!!! I need to seek out the old entry
// in the TLB List and delete it and all its entries in the TLBTable!!!
// A MUST for GoldenEye
TLBList[index].hh = tlb[index].hh; TLBList[index].hl = tlb[index].hl;
TLBList[index].lh = tlb[index].lh; TLBList[index].ll = tlb[index].ll;
TLBList[index].isGlobal = tlb[index].isGlobal;
if (MMU_ENTRYHI != 0x80000000) { // This ignores possible clearing! :-/
u32 TLBStartLoc = (tlb[index].hl & mask); // Start of TLB Entry
u32 TLBLength = maskLow+1;//tlb[index].hh; // Length of TLB Entry
u32 addr = TLBStartLoc;
u32 cnt = 0;
do {
if (addr & page) {//odd page
if (tlb[index].ll & 0x2) {
this->TLBTable[addr >> 12] = 0x80000000 | ((tlb[index].ll << 6) & (mask >> 1)) | (addr & (maskLow >> 1));
} else {
this->TLBTable[addr >> 12] = 0xFFFFFFFE; // This should signify invalid entry when exception happens
}
} else {//even page
if (tlb[index].lh & 0x2) {
this->TLBTable[addr >> 12] = 0x80000000 | ((tlb[index].lh << 6) & (mask >> 1)) | (addr & (maskLow >> 1));
} else {
this->TLBTable[addr >> 12] = 0xFFFFFFFE; // This should signify invalid entry when exception happens
}
}
//Debug (2, " Mapped %08X to %08X", addr, this->TLBTable[addr >> 12]);
addr += 0x1000; // 4K is minimum TLB Entry size
} while (addr < (TLBLength+TLBStartLoc));
}
// Check
}
// Random Entry will NEVER Overwrite previous entries
void r4300iTLB::RandomEntry (int index) {
// Command will be the most complicated to keep accurate (and the reason for a TLB list)
/*MMU_RANDOM = instructions & 0x1F;
if (MMU_RANDOM < MMU_WIRED)
MMU_RANDOM = 0x1F;*/
IndexEntry (index);
//__asm int 3;
}
void DisassembleRange (u32 Start, u32 End);
#ifdef USE_NEW_TLB
u32 VirtualToPhysical(u32 addr, int type) {
u32 oldAddr = addr;
u32 pAddr = addr;
bool match = false;
/*
if (addr == 0xFFFFFFFC) {
DisassembleRange (0x80004090, 0x80005410);
__asm int 3;
}*/
if (TLBLUT[addr >> 12] < 0xFFFFFFFE) {
return oldAddr = TLBLUT[addr>>12] + (addr & 0xfff);
} else {
// Debug (0, "TLB Issue at PC %08X accessing addr %08X %08X", pc, addr);
// RaiseException (0xc0001337, 0,0, NULL); // TLB Exception
// oldAddr = TLBLUT[addr>>12];
// Invalid or Miss Exception!
// Debug (1, "Unhandled Miss/Invalid Exception! (Unimplemented in New TLB)");
// cpuIsDone = true;
// cpuIsReset = true;
if (TLBLUT[addr >> 12] == 0xFFFFFFFE)
tlbinvalid = true;
}
// __asm int 3;
/*
if ((addr & 0xC0000000)==0xC0000000) ;
else if (addr & 0x80000000) {
return addr;
}
*/
/*
int page;
int mask;
int maskLow;
int i;
for (i=31; i >= 0; i--) {
page = ((tlb[i].hh >> 13) + 1) * 4096;
mask = ~(tlb[i].hh | 0x1fff);
maskLow = (tlb[i].hh | 0x1fff);
if ((addr & mask) == (tlb[i].hl & mask)) {
//match
match = true;
if (addr & page) {//odd page
if (tlb[i].ll & 0x2)
addr = 0x80000000 | ((tlb[i].ll << 6) & (mask >> 1)) | (addr & (maskLow >> 1));
else {
match = false;
tlbinvalid = true;
//Debug (0, "%08X: TLB Invalid Exception %08X", pc, addr);
}
} else {//even page
if (tlb[i].lh & 0x2) {
addr = 0x80000000 | ((tlb[i].lh << 6) & (mask >> 1)) | (addr & (maskLow >> 1));
} else {
match = false;
tlbinvalid = true;
//Debug (0, "%08X: TLB Invalid Exception %08X", pc, addr);
}
}
if (match != false) {
if (addr != oldAddr)
__asm int 3;
}
break;
}
}
*/
if (match == false) { // TLB Hacks galore!!!
Debug (0, "TLB Miss: %08X", pc);
/* if (tlbinvalid == true) {
if (oldAddr != 0xFFFFFFFE)
__asm int 3;
} else {
if (oldAddr != 0xFFFFFFFF) {
__asm int 3;
cpuIsDone = cpuIsReset = true;
}
}*/
//if (type)
// Debug(0,"TLB Store Miss at %08X, pc:%08X, exception!",addr,pc-4);
//else
// Debug(0,"TLB Load Miss at %08X, pc:%08X, exception!",addr,pc-4);
/*for (int i = MMU_WIRED; i < 32; i++) {
if (tlb[i].hl == 0x80000000)
break;
if ((tlb[i].ll & tlb[i].lh & 2)==0)
break;
}
if (i < 32) {
MMU_RANDOM = i;
} else*/ {
MMU_RANDOM = instructions & 0x1F;
if (MMU_RANDOM < MMU_WIRED)
MMU_RANDOM = 0x1F;
}
//Debug (0, "MMU_RANDOM = %i", MMU_RANDOM);
MMU_CONTEXT &= 0xFF800000;
MMU_CONTEXT |= (addr >> 13) << 4;
MMU_ENTRYHI &= 0x00001FFF;
MMU_ENTRYHI = (addr & 0xFFFFE000);
MMU_BADVADDR = addr;
if (pc != addr) {
//if ((pc != 0x150A916C) && (pc != 0x150A914C))
// Debug (2, "%08X: Non Instruction Miss\n", pc);
pc -= 4;
}
// Debug (2, "TLB Miss or Invalid at %08X\n", addr);
//Debug (2, "%08X: ", addr);
//if (inDelay == 1)
// Debug (0, "TLB Exception in Delay Slot!");
if (type)
GenerateException(pc, TLB_STORE);
else
GenerateException(pc, TLB_LOAD);
//MMU_INDEX = 0;
//Emulate ();
RaiseException (0xc0001337, 0,0, NULL); // TLB Exception
return 0;
}
return addr;
//return oldAddr;
}
void QuickTLBExcept () {
if (TLBLUT[pc >> 12] == 0xFFFFFFFE) {
tlbinvalid = true;
MMU_RANDOM = instructions & 0x1F;
if (MMU_RANDOM < MMU_WIRED)
MMU_RANDOM = 0x1F;
}
MMU_CONTEXT &= 0xFF800000;
MMU_CONTEXT |= (pc >> 13) << 4;
MMU_ENTRYHI &= 0x00001FFF;
MMU_ENTRYHI = (pc & 0xFFFFE000);
MMU_BADVADDR = pc;
//Debug (2, "%08X: ", pc);
if (inDelay == 1)
Debug (0, "TLB Exception in Delay Slot at PC = %08X", pc);
GenerateException(pc, TLB_LOAD);
}
void opTLBP(void){
//Debug (0, "TLB Probe");
MMU_INDEX|=0xFFFFFFFF80000000;
TLBLUT.Probe (); // Need to put the current TLB entry in the Table
for (int i=0; i < 32; i++) {
u32 mask = ~(tlb[i].hh | 0x1fff);//& 0xffffe000;
if((tlb[i].hl&mask) == (MMU_ENTRYHI&mask)) {//assumes it is always global
MMU_INDEX=i;
return;
}
}
}
void opTLBR(void){
//Debug (0, "TLB Read");
int j = MMU_INDEX & 0x1f;
MMU_PAGEMASK = tlb[j].hh;
MMU_ENTRYHI = tlb[j].hl & (~tlb[j].hh);
MMU_ENTRYLO0 = tlb[j].lh | tlb[j].isGlobal;
MMU_ENTRYLO1 = tlb[j].ll | tlb[j].isGlobal;
}
void opTLBWI(void){
u32 j = MMU_INDEX & 0x1f;
TLBLUT.ClearEntry (j);
/* if (MMU_ENTRYHI != 0x80000000) {
Debug (0, "TLB Write Index @ %08X", pc-4);
Debug (0, "- INDEX = %08X", MMU_INDEX);
Debug (0, "- PAGEMASK = %08X", MMU_PAGEMASK);
Debug (0, "- ENTRYHI = %08X", MMU_ENTRYHI);
Debug (0, "- ENTRYLO0 = %08X", MMU_ENTRYLO0);
Debug (0, "- ENTRYLO1 = %08X", MMU_ENTRYLO1);
Debug (0, "- G = %08X", (MMU_ENTRYLO0 & MMU_ENTRYLO1 & 0x1));
}//*/
tlb[j].hh = MMU_PAGEMASK;
tlb[j].hl = MMU_ENTRYHI & (~MMU_PAGEMASK);
tlb[j].lh = MMU_ENTRYLO0 & 0xFFFFFFFE;
tlb[j].ll = MMU_ENTRYLO1 & 0xFFFFFFFE;
tlb[j].isGlobal = (u8)(MMU_ENTRYLO0 & MMU_ENTRYLO1 & 0x1);
// int page = ((tlb[j].hh >> 13) + 1) * 4096;
// int mask = ~(tlb[j].hh | 0x1fff);
// int maskLow = (tlb[j].hh | 0x1fff);
// Debug (0, "Page = %08X", page);
// Debug (0, "mask = %08X", mask);
// Debug (0, "maskLow = %08X", maskLow);
// Debug (0, "hl = %08X", tlb[j].hl);
TLBLUT.IndexEntry (j);
}
/*
for (int i=31; i >= 0; i--) {
int page = ((tlb[i].hh >> 13) + 1) * 4096;
int mask = ~(tlb[i].hh | 0x1fff);
int maskLow = (tlb[i].hh | 0x1fff);
if ((addr & mask) == (tlb[i].hl & mask)) {
//match
match = true;
if (addr & page) {//odd page
if (tlb[i].ll & 0x2)
addr = 0x80000000 | ((tlb[i].ll << 6) & (mask >> 1)) | (addr & (maskLow >> 1));
else {
match = false;
tlbinvalid = true;
//Debug (0, "%08X: TLB Invalid Exception %08X", pc, addr);
}
} else {//even page
if (tlb[i].lh & 0x2) {
addr = 0x80000000 | ((tlb[i].lh << 6) & (mask >> 1)) | (addr & (maskLow >> 1));
} else {
match = false;
tlbinvalid = true;
//Debug (0, "%08X: TLB Invalid Exception %08X", pc, addr);
}
}
break;
}
}
*/
void opTLBWR(void){
u32 j = MMU_RANDOM & 0x1f;
TLBLUT.ClearEntry (j); // This shouldn't be here. This will only prove to make things redundant
/* Debug (0, "TLB Write Random @ %08X", pc-4);
Debug (0, "- RANDOM = %08X", MMU_RANDOM);
Debug (0, "- PAGEMASK = %08X", MMU_PAGEMASK);
Debug (0, "- ENTRYHI = %08X", MMU_ENTRYHI);
Debug (0, "- ENTRYLO0 = %08X", MMU_ENTRYLO0);
Debug (0, "- ENTRYLO1 = %08X", MMU_ENTRYLO1);
Debug (0, "- G = %08X", (MMU_ENTRYLO0 & MMU_ENTRYLO1 & 0x1));//*/
tlb[j].hh = MMU_PAGEMASK;
tlb[j].hl = MMU_ENTRYHI & (~MMU_PAGEMASK);
tlb[j].lh = MMU_ENTRYLO0 & 0xFFFFFFFE;
tlb[j].ll = MMU_ENTRYLO1 & 0xFFFFFFFE;
tlb[j].isGlobal = (u8)(MMU_ENTRYLO0 & MMU_ENTRYLO1 & 0x1);
TLBLUT.RandomEntry (j);
}
#endif