📄 id_pm.c
字号:
EMSList[emspage].lastHit = PMFrameCount;
offset = emspage * EMSPageSizeSeg;
offset += emsoff * PMPageSizeSeg;
return((memptr)(EMSPageFrame + offset));
}
#else
memptr
PML_GetEMSAddress(int page,PMLockType lock)
{
word emspage;
emspage = (lock < pml_EMSLock)? 3 : (lock - pml_EMSLock);
PML_MapEMS(page / PMEMSSubPage,emspage);
return((memptr)(EMSPageFrame + (emspage * EMSPageSizeSeg)
+ ((page & (PMEMSSubPage - 1)) * PMPageSizeSeg)));
}
#endif
//
// PM_GetPageAddress() - Returns the address of a given page
// Maps in EMS if necessary
// Returns nil if block isn't cached into Main Memory or EMS
//
//
memptr
PM_GetPageAddress(int pagenum)
{
PageListStruct far *page;
page = &PMPages[pagenum];
if (page->mainPage != -1)
return(MainMemPages[page->mainPage]);
else if (page->emsPage != -1)
return(PML_GetEMSAddress(page->emsPage,page->locked));
else
return(nil);
}
//
// PML_GiveLRUPage() - Returns the page # of the least recently used
// present & unlocked main/EMS page (or main page if mainonly is true)
//
int
PML_GiveLRUPage(boolean mainonly)
{
int i,lru;
long last;
PageListStruct far *page;
for (i = 0,page = PMPages,lru = -1,last = MAXLONG;i < ChunksInFile;i++,page++)
{
if
(
(page->lastHit < last)
&& ((page->emsPage != -1) || (page->mainPage != -1))
&& (page->locked == pml_Unlocked)
&& (!(mainonly && (page->mainPage == -1)))
)
{
last = page->lastHit;
lru = i;
}
}
if (lru == -1)
Quit("PML_GiveLRUPage: LRU Search failed");
return(lru);
}
//
// PML_GiveLRUXMSPage() - Returns the page # of the least recently used
// (and present) XMS page.
// This routine won't return the XMS page protected (by XMSProtectPage)
//
int
PML_GiveLRUXMSPage(void)
{
int i,lru;
long last;
PageListStruct far *page;
for (i = 0,page = PMPages,lru = -1,last = MAXLONG;i < ChunksInFile;i++,page++)
{
if
(
(page->xmsPage != -1)
&& (page->lastHit < last)
&& (i != XMSProtectPage)
)
{
last = page->lastHit;
lru = i;
}
}
return(lru);
}
//
// PML_PutPageInXMS() - If page isn't in XMS, find LRU XMS page and replace
// it with the main/EMS page
//
void
PML_PutPageInXMS(int pagenum)
{
int usexms;
PageListStruct far *page;
if (!XMSPresent)
return;
page = &PMPages[pagenum];
if (page->xmsPage != -1)
return; // Already in XMS
if (XMSPagesUsed < XMSPagesAvail)
page->xmsPage = XMSPagesUsed++;
else
{
usexms = PML_GiveLRUXMSPage();
if (usexms == -1)
Quit("PML_PutPageInXMS: No XMS LRU");
page->xmsPage = PMPages[usexms].xmsPage;
PMPages[usexms].xmsPage = -1;
}
PML_CopyToXMS(PM_GetPageAddress(pagenum),page->xmsPage,page->length);
}
//
// PML_TransferPageSpace() - A page is being replaced, so give the new page
// the old one's address space. Returns the address of the new page.
//
memptr
PML_TransferPageSpace(int orig,int new)
{
memptr addr;
PageListStruct far *origpage,far *newpage;
if (orig == new)
Quit("PML_TransferPageSpace: Identity replacement");
origpage = &PMPages[orig];
newpage = &PMPages[new];
if (origpage->locked != pml_Unlocked)
Quit("PML_TransferPageSpace: Killing locked page");
if ((origpage->emsPage == -1) && (origpage->mainPage == -1))
Quit("PML_TransferPageSpace: Reusing non-existent page");
// Copy page that's about to be purged into XMS
PML_PutPageInXMS(orig);
// Get the address, and force EMS into a physical page if necessary
addr = PM_GetPageAddress(orig);
// Steal the address
newpage->emsPage = origpage->emsPage;
newpage->mainPage = origpage->mainPage;
// Mark replaced page as purged
origpage->mainPage = origpage->emsPage = -1;
if (!addr)
Quit("PML_TransferPageSpace: Zero replacement");
return(addr);
}
//
// PML_GetAPageBuffer() - A page buffer is needed. Either get it from the
// main/EMS free pool, or use PML_GiveLRUPage() to find which page to
// steal the buffer from. Returns a far pointer to the page buffer, and
// sets the fields inside the given page structure appropriately.
// If mainonly is true, free EMS will be ignored, and only main pages
// will be looked at by PML_GiveLRUPage().
//
byte far *
PML_GetAPageBuffer(int pagenum,boolean mainonly)
{
byte far *addr = nil;
int i,n;
PMBlockAttr *used;
PageListStruct far *page;
page = &PMPages[pagenum];
if ((EMSPagesUsed < EMSPagesAvail) && !mainonly)
{
// There's remaining EMS - use it
page->emsPage = EMSPagesUsed++;
addr = PML_GetEMSAddress(page->emsPage,page->locked);
}
else if (MainPagesUsed < MainPagesAvail)
{
// There's remaining main memory - use it
for (i = 0,n = -1,used = MainMemUsed;i < PMMaxMainMem;i++,used++)
{
if ((*used & pmba_Allocated) && !(*used & pmba_Used))
{
n = i;
*used |= pmba_Used;
break;
}
}
if (n == -1)
Quit("PML_GetPageBuffer: MainPagesAvail lied");
addr = MainMemPages[n];
if (!addr)
Quit("PML_GetPageBuffer: Purged main block");
page->mainPage = n;
MainPagesUsed++;
}
else
addr = PML_TransferPageSpace(PML_GiveLRUPage(mainonly),pagenum);
if (!addr)
Quit("PML_GetPageBuffer: Search failed");
return(addr);
}
//
// PML_GetPageFromXMS() - If page is in XMS, find LRU main/EMS page and
// replace it with the page from XMS. If mainonly is true, will only
// search for LRU main page.
// XMSProtectPage is set to the page to be retrieved from XMS, so that if
// the page from which we're stealing the main/EMS from isn't in XMS,
// it won't copy over the page that we're trying to get from XMS.
// (pages that are being purged are copied into XMS, if possible)
//
memptr
PML_GetPageFromXMS(int pagenum,boolean mainonly)
{
byte far *checkaddr;
memptr addr = nil;
PageListStruct far *page;
page = &PMPages[pagenum];
if (XMSPresent && (page->xmsPage != -1))
{
XMSProtectPage = pagenum;
checkaddr = PML_GetAPageBuffer(pagenum,mainonly);
if (FP_OFF(checkaddr))
Quit("PML_GetPageFromXMS: Non segment pointer");
addr = (memptr)FP_SEG(checkaddr);
PML_CopyFromXMS(addr,page->xmsPage,page->length);
XMSProtectPage = -1;
}
return(addr);
}
//
// PML_LoadPage() - A page is not in main/EMS memory, and it's not in XMS.
// Load it into either main or EMS. If mainonly is true, the page will
// only be loaded into main.
//
void
PML_LoadPage(int pagenum,boolean mainonly)
{
byte far *addr;
PageListStruct far *page;
addr = PML_GetAPageBuffer(pagenum,mainonly);
page = &PMPages[pagenum];
PML_ReadFromFile(addr,page->offset,page->length);
}
//
// PM_GetPage() - Returns the address of the page, loading it if necessary
// First, check if in Main Memory or EMS
// Then, check XMS
// If not in XMS, load into Main Memory or EMS
//
#pragma warn -pia
memptr
PM_GetPage(int pagenum)
{
memptr result;
if (pagenum >= ChunksInFile)
Quit("PM_GetPage: Invalid page request");
#if 0 // for debugging
asm mov dx,STATUS_REGISTER_1
asm in al,dx
asm mov dx,ATR_INDEX
asm mov al,ATR_OVERSCAN
asm out dx,al
asm mov al,10 // bright green
asm out dx,al
#endif
if (!(result = PM_GetPageAddress(pagenum)))
{
boolean mainonly = (pagenum >= PMSoundStart);
if (!PMPages[pagenum].offset) // JDC: sparse page
Quit ("Tried to load a sparse page!");
if (!(result = PML_GetPageFromXMS(pagenum,mainonly)))
{
if (PMPages[pagenum].lastHit == PMFrameCount)
PMThrashing++;
PML_LoadPage(pagenum,mainonly);
result = PM_GetPageAddress(pagenum);
}
}
PMPages[pagenum].lastHit = PMFrameCount;
#if 0 // for debugging
asm mov dx,STATUS_REGISTER_1
asm in al,dx
asm mov dx,ATR_INDEX
asm mov al,ATR_OVERSCAN
asm out dx,al
asm mov al,3 // blue
asm out dx,al
asm mov al,0x20 // normal
asm out dx,al
#endif
return(result);
}
#pragma warn +pia
//
// PM_SetPageLock() - Sets the lock type on a given page
// pml_Unlocked: Normal, page can be purged
// pml_Locked: Cannot be purged
// pml_EMS?: Same as pml_Locked, but if in EMS, use the physical page
// specified when returning the address. For sound stuff.
//
void
PM_SetPageLock(int pagenum,PMLockType lock)
{
if (pagenum < PMSoundStart)
Quit("PM_SetPageLock: Locking/unlocking non-sound page");
PMPages[pagenum].locked = lock;
}
//
// PM_Preload() - Loads as many pages as possible into all types of memory.
// Calls the update function after each load, indicating the current
// page, and the total pages that need to be loaded (for thermometer).
//
void
PM_Preload(boolean (*update)(word current,word total))
{
int i,j,
page,oogypage;
word current,total,
totalnonxms,totalxms,
mainfree,maintotal,
emsfree,emstotal,
xmsfree,xmstotal;
memptr addr;
PageListStruct far *p;
mainfree = (MainPagesAvail - MainPagesUsed) + (EMSPagesAvail - EMSPagesUsed);
xmsfree = (XMSPagesAvail - XMSPagesUsed);
xmstotal = maintotal = 0;
for (i = 0;i < ChunksInFile;i++)
{
if (!PMPages[i].offset)
continue; // sparse
if ( PMPages[i].emsPage != -1 || PMPages[i].mainPage != -1 )
continue; // already in main mem
if ( mainfree )
{
maintotal++;
mainfree--;
}
else if ( xmsfree && (PMPages[i].xmsPage == -1) )
{
xmstotal++;
xmsfree--;
}
}
total = maintotal + xmstotal;
if (!total)
return;
page = 0;
current = 0;
//
// cache main/ems blocks
//
while (maintotal)
{
while ( !PMPages[page].offset || PMPages[page].mainPage != -1
|| PMPages[page].emsPage != -1 )
page++;
if (page >= ChunksInFile)
Quit ("PM_Preload: Pages>=ChunksInFile");
PM_GetPage(page);
page++;
current++;
maintotal--;
update(current,total);
}
//
// load stuff to XMS
//
if (xmstotal)
{
for (oogypage = 0 ; PMPages[oogypage].mainPage == -1 ; oogypage++)
;
addr = PM_GetPage(oogypage);
if (!addr)
Quit("PM_Preload: XMS buffer failed");
while (xmstotal)
{
while ( !PMPages[page].offset || PMPages[page].xmsPage != -1 )
page++;
if (page >= ChunksInFile)
Quit ("PM_Preload: Pages>=ChunksInFile");
p = &PMPages[page];
p->xmsPage = XMSPagesUsed++;
if (XMSPagesUsed > XMSPagesAvail)
Quit("PM_Preload: Exceeded XMS pages");
if (p->length > PMPageSize)
Quit("PM_Preload: Page too long");
PML_ReadFromFile((byte far *)addr,p->offset,p->length);
PML_CopyToXMS((byte far *)addr,p->xmsPage,p->length);
page++;
current++;
xmstotal--;
update(current,total);
}
p = &PMPages[oogypage];
PML_ReadFromFile((byte far *)addr,p->offset,p->length);
}
update(total,total);
}
/////////////////////////////////////////////////////////////////////////////
//
// General code
//
/////////////////////////////////////////////////////////////////////////////
//
// PM_NextFrame() - Increments the frame counter and adjusts the thrash
// avoidence variables
//
// If currently in panic mode (to avoid thrashing), check to see if the
// appropriate number of frames have passed since the last time that
// we would have thrashed. If so, take us out of panic mode.
//
//
void
PM_NextFrame(void)
{
int i;
// Frame count overrun - kill the LRU hit entries & reset frame count
if (++PMFrameCount >= MAXLONG - 4)
{
for (i = 0;i < PMNumBlocks;i++)
PMPages[i].lastHit = 0;
PMFrameCount = 0;
}
#if 0
for (i = 0;i < PMSoundStart;i++)
{
if (PMPages[i].locked)
{
char buf[40];
sprintf(buf,"PM_NextFrame: Page %d is locked",i);
Quit(buf);
}
}
#endif
if (PMPanicMode)
{
// DEBUG - set border color
if ((!PMThrashing) && (!--PMPanicMode))
{
// DEBUG - reset border color
}
}
if (PMThrashing >= PMThrashThreshold)
PMPanicMode = PMUnThrashThreshold;
PMThrashing = false;
}
//
// PM_Reset() - Sets up caching structures
//
void
PM_Reset(void)
{
int i;
PageListStruct far *page;
XMSPagesAvail = XMSAvail / PMPageSizeKB;
EMSPagesAvail = EMSAvail * (EMSPageSizeKB / PMPageSizeKB);
EMSPhysicalPage = 0;
MainPagesUsed = EMSPagesUsed = XMSPagesUsed = 0;
PMPanicMode = false;
// Initialize page list
for (i = 0,page = PMPages;i < PMNumBlocks;i++,page++)
{
page->mainPage = -1;
page->emsPage = -1;
page->xmsPage = -1;
page->locked = false;
}
}
//
// PM_Startup() - Start up the Page Mgr
//
void
PM_Startup(void)
{
boolean nomain,noems,noxms;
int i;
if (PMStarted)
return;
nomain = noems = noxms = false;
for (i = 1;i < _argc;i++)
{
switch (US_CheckParm(_argv[i],ParmStrings))
{
case 0:
nomain = true;
break;
case 1:
noems = true;
break;
case 2:
noxms = true;
break;
}
}
PML_OpenPageFile();
if (!noems)
PML_StartupEMS();
if (!noxms)
PML_StartupXMS();
if (nomain && !EMSPresent)
Quit("PM_Startup: No main or EMS");
else
PML_StartupMainMem();
PM_Reset();
PMStarted = true;
}
//
// PM_Shutdown() - Shut down the Page Mgr
//
void
PM_Shutdown(void)
{
PML_ShutdownXMS();
PML_ShutdownEMS();
if (!PMStarted)
return;
PML_ClosePageFile();
PML_ShutdownMainMem();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -