📄 id_mm.c
字号:
// NEWMM.C
/*
=============================================================================
ID software memory manager
--------------------------
Primary coder: John Carmack
RELIES ON
---------
Quit (char *error) function
WORK TO DO
----------
MM_SizePtr to change the size of a given pointer
Multiple purge levels utilized
EMS / XMS unmanaged routines
=============================================================================
*/
#include "ID_HEADS.H"
#pragma hdrstop
#pragma warn -pro
#pragma warn -use
/*
=============================================================================
LOCAL INFO
=============================================================================
*/
#define LOCKBIT 0x80 // if set in attributes, block cannot be moved
#define PURGEBITS 3 // 0-3 level, 0= unpurgable, 3= purge first
#define PURGEMASK 0xfffc
#define BASEATTRIBUTES 0 // unlocked, non purgable
#define MAXUMBS 10
typedef struct mmblockstruct
{
unsigned start,length;
unsigned attributes;
memptr *useptr; // pointer to the segment start
struct mmblockstruct far *next;
} mmblocktype;
//#define GETNEWBLOCK {if(!(mmnew=mmfree))Quit("MM_GETNEWBLOCK: No free blocks!")\
// ;mmfree=mmfree->next;}
#define GETNEWBLOCK {if(!mmfree)MML_ClearBlock();mmnew=mmfree;mmfree=mmfree->next;}
#define FREEBLOCK(x) {*x->useptr=NULL;x->next=mmfree;mmfree=x;}
/*
=============================================================================
GLOBAL VARIABLES
=============================================================================
*/
mminfotype mminfo;
memptr bufferseg;
boolean mmerror;
void (* beforesort) (void);
void (* aftersort) (void);
/*
=============================================================================
LOCAL VARIABLES
=============================================================================
*/
boolean mmstarted;
void far *farheap;
void *nearheap;
mmblocktype far mmblocks[MAXBLOCKS]
,far *mmhead,far *mmfree,far *mmrover,far *mmnew;
boolean bombonerror;
//unsigned totalEMSpages,freeEMSpages,EMSpageframe,EMSpagesmapped,EMShandle;
void (* XMSaddr) (void); // far pointer to XMS driver
unsigned numUMBs,UMBbase[MAXUMBS];
//==========================================================================
//
// local prototypes
//
boolean MML_CheckForEMS (void);
void MML_ShutdownEMS (void);
void MM_MapEMS (void);
boolean MML_CheckForXMS (void);
void MML_ShutdownXMS (void);
void MML_UseSpace (unsigned segstart, unsigned seglength);
void MML_ClearBlock (void);
//==========================================================================
/*
======================
=
= MML_CheckForXMS
=
= Check for XMM driver
=
=======================
*/
boolean MML_CheckForXMS (void)
{
numUMBs = 0;
asm {
mov ax,0x4300
int 0x2f // query status of installed diver
cmp al,0x80
je good
}
return false;
good:
return true;
}
/*
======================
=
= MML_SetupXMS
=
= Try to allocate all upper memory block
=
=======================
*/
void MML_SetupXMS (void)
{
unsigned base,size;
asm {
mov ax,0x4310
int 0x2f
mov [WORD PTR XMSaddr],bx
mov [WORD PTR XMSaddr+2],es // function pointer to XMS driver
}
getmemory:
asm {
mov ah,XMS_ALLOCUMB
mov dx,0xffff // try for largest block possible
call [DWORD PTR XMSaddr]
or ax,ax
jnz gotone
cmp bl,0xb0 // error: smaller UMB is available
jne done;
mov ah,XMS_ALLOCUMB
call [DWORD PTR XMSaddr] // DX holds largest available UMB
or ax,ax
jz done // another error...
}
gotone:
asm {
mov [base],bx
mov [size],dx
}
MML_UseSpace (base,size);
mminfo.XMSmem += size*16;
UMBbase[numUMBs] = base;
numUMBs++;
if (numUMBs < MAXUMBS)
goto getmemory;
done:;
}
/*
======================
=
= MML_ShutdownXMS
=
======================
*/
void MML_ShutdownXMS (void)
{
int i;
unsigned base;
for (i=0;i<numUMBs;i++)
{
base = UMBbase[i];
asm mov ah,XMS_FREEUMB
asm mov dx,[base]
asm call [DWORD PTR XMSaddr]
}
}
//==========================================================================
/*
======================
=
= MML_UseSpace
=
= Marks a range of paragraphs as usable by the memory manager
= This is used to mark space for the near heap, far heap, ems page frame,
= and upper memory blocks
=
======================
*/
void MML_UseSpace (unsigned segstart, unsigned seglength)
{
mmblocktype far *scan,far *last;
unsigned oldend;
long extra;
scan = last = mmhead;
mmrover = mmhead; // reset rover to start of memory
//
// search for the block that contains the range of segments
//
while (scan->start+scan->length < segstart)
{
last = scan;
scan = scan->next;
}
//
// take the given range out of the block
//
oldend = scan->start + scan->length;
extra = oldend - (segstart+seglength);
if (extra < 0)
Quit ("MML_UseSpace: Segment spans two blocks!");
if (segstart == scan->start)
{
last->next = scan->next; // unlink block
FREEBLOCK(scan);
scan = last;
}
else
scan->length = segstart-scan->start; // shorten block
if (extra > 0)
{
GETNEWBLOCK;
mmnew->useptr = NULL;
mmnew->next = scan->next;
scan->next = mmnew;
mmnew->start = segstart+seglength;
mmnew->length = extra;
mmnew->attributes = LOCKBIT;
}
}
//==========================================================================
/*
====================
=
= MML_ClearBlock
=
= We are out of blocks, so free a purgable block
=
====================
*/
void MML_ClearBlock (void)
{
mmblocktype far *scan,far *last;
scan = mmhead->next;
while (scan)
{
if (!(scan->attributes&LOCKBIT) && (scan->attributes&PURGEBITS) )
{
MM_FreePtr(scan->useptr);
return;
}
scan = scan->next;
}
Quit ("MM_ClearBlock: No purgable blocks!");
}
//==========================================================================
/*
===================
=
= MM_Startup
=
= Grabs all space from turbo with malloc/farmalloc
= Allocates bufferseg misc buffer
=
===================
*/
static char *ParmStrings[] = {"noems","noxms",""};
void MM_Startup (void)
{
int i;
unsigned long length;
void far *start;
unsigned segstart,seglength,endfree;
if (mmstarted)
MM_Shutdown ();
mmstarted = true;
bombonerror = true;
//
// set up the linked list (everything in the free list;
//
mmhead = NULL;
mmfree = &mmblocks[0];
for (i=0;i<MAXBLOCKS-1;i++)
mmblocks[i].next = &mmblocks[i+1];
mmblocks[i].next = NULL;
//
// locked block of all memory until we punch out free space
//
GETNEWBLOCK;
mmhead = mmnew; // this will allways be the first node
mmnew->start = 0;
mmnew->length = 0xffff;
mmnew->attributes = LOCKBIT;
mmnew->next = NULL;
mmrover = mmhead;
//
// get all available near conventional memory segments
//
length=coreleft();
start = (void far *)(nearheap = malloc(length));
length -= 16-(FP_OFF(start)&15);
length -= SAVENEARHEAP;
seglength = length / 16; // now in paragraphs
segstart = FP_SEG(start)+(FP_OFF(start)+15)/16;
MML_UseSpace (segstart,seglength);
mminfo.nearheap = length;
//
// get all available far conventional memory segments
//
length=farcoreleft();
start = farheap = farmalloc(length);
length -= 16-(FP_OFF(start)&15);
length -= SAVEFARHEAP;
seglength = length / 16; // now in paragraphs
segstart = FP_SEG(start)+(FP_OFF(start)+15)/16;
MML_UseSpace (segstart,seglength);
mminfo.farheap = length;
mminfo.mainmem = mminfo.nearheap + mminfo.farheap;
//
// allocate the misc buffer
//
mmrover = mmhead; // start looking for space after low block
MM_GetPtr (&bufferseg,BUFFERSIZE);
}
//==========================================================================
/*
====================
=
= MM_Shutdown
=
= Frees all conventional, EMS, and XMS allocated
=
====================
*/
void MM_Shutdown (void)
{
if (!mmstarted)
return;
farfree (farheap);
free (nearheap);
// MML_ShutdownXMS ();
}
//==========================================================================
/*
====================
=
= MM_GetPtr
=
= Allocates an unlocked, unpurgable block
=
====================
*/
void MM_GetPtr (memptr *baseptr,unsigned long size)
{
mmblocktype far *scan,far *lastscan,far *endscan
,far *purge,far *next;
int search;
unsigned needed,startseg;
needed = (size+15)/16; // convert size from bytes to paragraphs
GETNEWBLOCK; // fill in start and next after a spot is found
mmnew->length = needed;
mmnew->useptr = baseptr;
mmnew->attributes = BASEATTRIBUTES;
tryagain:
for (search = 0; search<3; search++)
{
//
// first search: try to allocate right after the rover, then on up
// second search: search from the head pointer up to the rover
// third search: compress memory, then scan from start
if (search == 1 && mmrover == mmhead)
search++;
switch (search)
{
case 0:
lastscan = mmrover;
scan = mmrover->next;
endscan = NULL;
break;
case 1:
lastscan = mmhead;
scan = mmhead->next;
endscan = mmrover;
break;
case 2:
MM_SortMem ();
lastscan = mmhead;
scan = mmhead->next;
endscan = NULL;
break;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -