X-Git-Url: http://4ch.mooo.com/gitweb/?p=16.git;a=blobdiff_plain;f=16%2Fkeen456%2FKEEN4-6%2FID_MM.C;fp=16%2Fkeen456%2FKEEN4-6%2FID_MM.C;h=07fdb7c253883b0349635f25a3ce82cb6ce23df5;hp=0000000000000000000000000000000000000000;hb=7d1948e210bb7b58af0a0412e71f2a0a0a2010af;hpb=ebc247a0a67daa69a027f31d9d7d9572db765e56 diff --git a/16/keen456/KEEN4-6/ID_MM.C b/16/keen456/KEEN4-6/ID_MM.C new file mode 100755 index 00000000..07fdb7c2 --- /dev/null +++ b/16/keen456/KEEN4-6/ID_MM.C @@ -0,0 +1,1136 @@ +/* Reconstructed Commander Keen 4-6 Source Code + * Copyright (C) 2021 K1n9_Duk3 + * + * This file is primarily based on: + * Catacomb 3-D Source Code + * Copyright (C) 1993-2014 Flat Rock Software + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +// 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_CheckForEMS += += Routine from p36 of Extending DOS += +======================= +*/ + +char emmname[9] = "EMMXXXX0"; + +boolean MML_CheckForEMS (void) +{ +asm mov dx,OFFSET emmname[0] +asm mov ax,0x3d00 +asm int 0x21 // try to open EMMXXXX0 device +asm jc error + +asm mov bx,ax +asm mov ax,0x4400 + +asm int 0x21 // get device info +asm jc error + +asm and dx,0x80 +asm jz error + +asm mov ax,0x4407 + +asm int 0x21 // get status +asm jc error +asm or al,al +asm jz error + +asm mov ah,0x3e +asm int 0x21 // close handle +asm jc error + +// +// EMS is good +// + return true; + +error: +// +// EMS is bad +// + return false; +} + + +/* +====================== += += MML_SetupEMS += +======================= +*/ + +void MML_SetupEMS (void) +{ + char str[80],str2[10]; + unsigned error; + + totalEMSpages = freeEMSpages = EMSpageframe = EMSpagesmapped = 0; + +asm { + mov ah,EMS_STATUS + int EMS_INT // make sure EMS hardware is present + or ah,ah + jnz error + + mov ah,EMS_VERSION + int EMS_INT + or ah,ah + jnz error + cmp al,0x32 // only work on ems 3.2 or greater + jb error + + mov ah,EMS_GETFRAME + int EMS_INT // find the page frame address + or ah,ah + jnz error + mov [EMSpageframe],bx + + mov ah,EMS_GETPAGES + int EMS_INT // find out how much EMS is there + or ah,ah + jnz error + mov [totalEMSpages],dx + mov [freeEMSpages],bx + or bx,bx + jz noEMS // no EMS at all to allocate + + cmp bx,4 + jle getpages // there is only 1,2,3,or 4 pages + mov bx,4 // we can't use more than 4 pages + } + +getpages: +asm { + mov [EMSpagesmapped],bx + mov ah,EMS_ALLOCPAGES // allocate up to 64k of EMS + int EMS_INT + or ah,ah + jnz error + mov [EMShandle],dx + } + return; + +error: + error = _AH; + strcpy (str,"MML_SetupEMS: EMS error 0x"); + itoa(error,str2,16); + strcpy (str,str2); + Quit (str); + +noEMS: +; +} + + +/* +====================== += += MML_ShutdownEMS += +======================= +*/ + +void MML_ShutdownEMS (void) +{ + if (!EMShandle) + return; + +asm { + mov ah,EMS_FREEPAGES + mov dx,[EMShandle] + int EMS_INT + or ah,ah + jz ok + } + + Quit ("MML_ShutdownEMS: Error freeing EMS!"); + +ok: +; +} + +/* +==================== += += MM_MapEMS += += Maps the 64k of EMS used by memory manager into the page frame += for general use. This only needs to be called if you are keeping += other things in EMS. += +==================== +*/ + +void MM_MapEMS (void) +{ + char str[80],str2[10]; + unsigned error; + int i; + + for (i=0;istart+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; // Keen addition + + 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;istart = 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; + + +// +// detect EMS and allocate up to 64K at page frame +// + mminfo.EMSmem = 0; + for (i = 1;i < _argc;i++) + { + if ( US_CheckParm(_argv[i],ParmStrings) == 0) + goto emsskip; // param NOEMS + } + + if (MML_CheckForEMS()) + { + MML_SetupEMS(); // allocate space + MML_UseSpace (EMSpageframe,EMSpagesmapped*0x400); + MM_MapEMS(); // map in used pages + mminfo.EMSmem = EMSpagesmapped*0x4000l; + } + +// +// detect XMS and get upper memory blocks +// +emsskip: + mminfo.XMSmem = 0; + for (i = 1;i < _argc;i++) + { + if ( US_CheckParm(_argv[i],ParmStrings) == 0) // BUG: NOXMS is index 1, not 0 + goto xmsskip; // param NOXMS + } + + if (MML_CheckForXMS()) + MML_SetupXMS(); // allocate as many UMBs as possible + +// +// allocate the misc buffer +// +xmsskip: + 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_ShutdownEMS (); + 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; + + 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; + } + + startseg = lastscan->start + lastscan->length; + + while (scan != endscan) + { + if (scan->start - startseg >= needed) + { + // + // got enough space between the end of lastscan and + // the start of scan, so throw out anything in the middle + // and allocate the new block + // + purge = lastscan->next; + lastscan->next = mmnew; + mmnew->start = *(unsigned *)baseptr = startseg; + mmnew->next = scan; + while ( purge != scan) + { // free the purgable block + next = purge->next; + FREEBLOCK(purge); + purge = next; // purge another if not at scan + } + mmrover = mmnew; + return; // good allocation! + } + + // + // if this block is purge level zero or locked, skip past it + // + if ( (scan->attributes & LOCKBIT) + || !(scan->attributes & PURGEBITS) ) + { + lastscan = scan; + startseg = lastscan->start + lastscan->length; + } + + + scan=scan->next; // look at next line + } + } + + if (bombonerror) + Quit ("MM_GetPtr: Out of memory!"); + else + mmerror = true; +} + +//========================================================================== + +/* +==================== += += MM_FreePtr += += Allocates an unlocked, unpurgable block += +==================== +*/ + +void MM_FreePtr (memptr *baseptr) +{ + mmblocktype far *scan,far *last; + + last = mmhead; + scan = last->next; + + if (baseptr == mmrover->useptr) // removed the last allocated block + mmrover = mmhead; + + while (scan->useptr != baseptr && scan) + { + last = scan; + scan = scan->next; + } + + if (!scan) + Quit ("MM_FreePtr: Block not found!"); + + last->next = scan->next; + + FREEBLOCK(scan); +} +//========================================================================== + +/* +===================== += += MM_SetPurge += += Sets the purge level for a block (locked blocks cannot be made purgable) += +===================== +*/ + +void MM_SetPurge (memptr *baseptr, int purge) +{ + mmblocktype far *start; + + start = mmrover; + + do + { + if (mmrover->useptr == baseptr) + break; + + mmrover = mmrover->next; + + if (!mmrover) + mmrover = mmhead; + else if (mmrover == start) + Quit ("MM_SetPurge: Block not found!"); + + } while (1); + + mmrover->attributes &= ~PURGEBITS; + mmrover->attributes |= purge; +} + +//========================================================================== + +/* +===================== += += MM_SetLock += += Locks / unlocks the block += +===================== +*/ + +void MM_SetLock (memptr *baseptr, boolean locked) +{ + mmblocktype far *start; + + start = mmrover; + + do + { + if (mmrover->useptr == baseptr) + break; + + mmrover = mmrover->next; + + if (!mmrover) + mmrover = mmhead; + else if (mmrover == start) + Quit ("MM_SetLock: Block not found!"); + + } while (1); + + mmrover->attributes &= ~LOCKBIT; + mmrover->attributes |= locked*LOCKBIT; +} + +//========================================================================== + +/* +===================== += += MM_SortMem += += Throws out all purgable stuff and compresses movable blocks += +===================== +*/ + +void MM_SortMem (void) +{ + mmblocktype far *scan,far *last,far *next; + unsigned start,length,source,dest,oldborder; + int playing; + + // + // lock down a currently playing sound + // + playing = SD_SoundPlaying (); + if (playing) + { + switch (SoundMode) + { + case sdm_PC: + playing += STARTPCSOUNDS; + break; + case sdm_AdLib: + playing += STARTADLIBSOUNDS; + break; + } + MM_SetLock(&(memptr)audiosegs[playing],true); + } + + + SD_StopSound(); + oldborder = bordercolor; + VW_ColorBorder (15); + + if (beforesort) + beforesort(); + + scan = mmhead; + + last = NULL; // shut up compiler warning + + while (scan) + { + if (scan->attributes & LOCKBIT) + { + // + // block is locked, so try to pile later blocks right after it + // + start = scan->start + scan->length; + } + else + { + if (scan->attributes & PURGEBITS) + { + // + // throw out the purgable block + // + next = scan->next; + FREEBLOCK(scan); + last->next = next; + scan = next; + continue; + } + else + { + // + // push the non purgable block on top of the last moved block + // + if (scan->start != start) + { + length = scan->length; + source = scan->start; + dest = start; + while (length > 0xf00) + { + movedata(source,0,dest,0,0xf00*16); + length -= 0xf00; + source += 0xf00; + dest += 0xf00; + } + movedata(source,0,dest,0,length*16); + + scan->start = start; + *(unsigned *)scan->useptr = start; + } + start = scan->start + scan->length; + } + } + + last = scan; + scan = scan->next; // go to next block + } + + mmrover = mmhead; + + if (aftersort) + aftersort(); + + VW_ColorBorder (oldborder); + + if (playing) + MM_SetLock(&(memptr)audiosegs[playing],false); +} + + +//========================================================================== + +/* +===================== += += MM_ShowMemory += +===================== +*/ + +void MM_ShowMemory (void) +{ + mmblocktype far *scan; + unsigned color,temp; + long end,owner; + char scratch[80],str[10]; + + VW_SetDefaultColors(); + VW_SetLineWidth(40); + temp = bufferofs; + bufferofs = 0; + VW_SetScreen (0,0); + + scan = mmhead; + + end = -1; + +//CA_OpenDebug (); + + while (scan) + { + if (scan->attributes & PURGEBITS) + color = 5; // dark purple = purgable + else + color = 9; // medium blue = non purgable + if (scan->attributes & LOCKBIT) + color = 12; // red = locked + if (scan->start<=end) + Quit ("MM_ShowMemory: Memory block order corrupted!"); + end = scan->start+scan->length-1; + VW_Hlin(scan->start,(unsigned)end,0,color); + VW_Plot(scan->start,0,15); + if (scan->next->start > end+1) + VW_Hlin(end+1,scan->next->start,0,0); // black = free + +#if 0 +strcpy (scratch,"Size:"); +ltoa ((long)scan->length*16,str,10); +strcat (scratch,str); +strcat (scratch,"\tOwner:0x"); +owner = (unsigned)scan->useptr; +ultoa (owner,str,16); +strcat (scratch,str); +strcat (scratch,"\n"); +write (debughandle,scratch,strlen(scratch)); +#endif + + scan = scan->next; + } + +//CA_CloseDebug (); + + IN_Ack(); + VW_SetLineWidth(64); + bufferofs = temp; +} + +//========================================================================== + + +/* +====================== += += MM_UnusedMemory += += Returns the total free space without purging += +====================== +*/ + +long MM_UnusedMemory (void) +{ + unsigned free; + mmblocktype far *scan; + + free = 0; + scan = mmhead; + + while (scan->next) + { + free += scan->next->start - (scan->start + scan->length); + scan = scan->next; + } + + return free*16l; +} + +//========================================================================== + + +/* +====================== += += MM_TotalFree += += Returns the total free space with purging += +====================== +*/ + +long MM_TotalFree (void) +{ + unsigned free; + mmblocktype far *scan; + + free = 0; + scan = mmhead; + + while (scan->next) + { + if ((scan->attributes&PURGEBITS) && !(scan->attributes&LOCKBIT)) + free += scan->length; + free += scan->next->start - (scan->start + scan->length); + scan = scan->next; + } + + return free*16l; +} + +//========================================================================== + +/* +===================== += += MM_BombOnError += +===================== +*/ + +void MM_BombOnError (boolean bomb) +{ + bombonerror = bomb; +} + +