-/* Catacomb Armageddon 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 "src/lib/16_mm.h"
-
-/*
-======================
-=
-= MML_CheckForEMS
-=
-= Routine from p36 of Extending DOS
-=
-=======================
-*/
-
-boolean MML_CheckForEMS (void)
-{
- boolean emmcfems;
- char emmname[] = "EMMXXXX0";
-// mov dx,OFFSET emmname
- __asm {
- LEA DX, emmname //fix by andrius4669
- mov ax,0x3d00
- int 0x21 // try to open EMMXXXX0 device
- jc error
-
- mov bx,ax
- mov ax,0x4400
-
- int 0x21 // get device info
- jc error
-
- and dx,0x80
- jz error
-
- mov ax,0x4407
-
- int 0x21 // get status
- jc error
- or al,al
- jz error
-
- mov ah,0x3e
- int 0x21 // close handle
- jc error
- //
- // EMS is good
- //
- mov emmcfems,1
- jmp End
- error:
- //
- // EMS is bad
- //
- mov emmcfems,0
- End:
- }
- return(emmcfems);
-}
-
-
-/*
-======================
-=
-= MML_SetupEMS
-=
-=======================
-*/
-
-void MML_SetupEMS (void)
-{
- char str[80],str2[10];
- unsigned err;
- boolean errorflag=false;
- union REGS CPURegs;
-
- EMSVer = 0;
- 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
- mov [EMSVer],ax // set EMSVer
- 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:
- mov [EMSpagesmapped],bx
- mov ah,EMS_ALLOCPAGES // allocate up to 64k of EMS
- int EMS_INT
- or ah,ah
- jnz error
- mov [EMShandle],dx
- jmp End
-error:
- mov errorflag,1
- jmp End
-noEMS:
-End:
- }
- if(errorflag==true)
- {
- err = CPURegs.h.ah;
- strcpy(str,"MML_SetupEMS: EMS error 0x");
- itoa(err,str2,16);
- strcpy(str,str2);
- printf("%s\n",str);
- }
-}
-
-
-/*
-======================
-=
-= MML_ShutdownEMS
-=
-=======================
-*/
-
-void MML_ShutdownEMS (void)
-{
- boolean errorflag=false;
- if (!EMShandle)
- return;
- __asm
- {
- mov ah,EMS_FREEPAGES
- mov dx,[EMShandle]
- int EMS_INT
- or ah,ah
- jz ok
- mov errorflag,1
- ok:
- }
- if(errorflag==true) printf("MML_ShutdownEMS: Error freeing EMS!"); //++++ add something
-}
-
-/*
-====================
-=
-= 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 err;
- boolean errorflag=false;
- int i;
- union REGS CPURegs;
-
- for (i=0;i<EMSpagesmapped;i++)
- {
- __asm
- {
- mov ah,EMS_MAPPAGE
- mov bx,[i] // logical page
- mov al,bl // physical page
- mov dx,[EMShandle] // handle
- int EMS_INT
- or ah,ah
- jnz error
- jmp End
- error:
- mov errorflag,1
- End:
- }
- if(errorflag==true)
- {
- err = CPURegs.h.ah;
- strcpy(str,"MM_MapEMS: EMS error 0x");
- itoa(err,str2,16);
- strcpy(str,str2);
- printf("%s\n",str);
- }
- }
- return;
-}
-
-//==========================================================================
-
-/*
-======================
-=
-= MML_CheckForXMS
-=
-= Check for XMM driver
-=
-=======================
-*/
-
-boolean MML_CheckForXMS (void)
-{
- boolean errorflag=false;
- numUMBs = 0;
-
- __asm
- {
- mov ax,0x4300
- int 0x2f // query status of installed diver
- cmp al,0x80
- je good
- mov errorflag,1
- good:
- }
- if(errorflag==true) return false;
- else 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:
- mov [base],bx
- mov [size],dx
-done:
- }
- MML_UseSpace (base,size);
- mminfo.XMSmem += size*16;
- UMBbase[numUMBs] = base;
- numUMBs++;
- if (numUMBs < MAXUMBS)
- goto getmemory;
-}
-
-
-/*
-======================
-=
-= MML_ShutdownXMS
-=
-======================
-*/
-
-void MML_ShutdownXMS (void)
-{
- int i;
- unsigned base;
-
- for (i=0;i<numUMBs;i++)
- {
- base = UMBbase[i];
- __asm
- {
- mov ah,XMS_FREEUMB
- mov dx,[base]
- 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)
- {
- printf("MML_UseSpace: Segment spans two blocks!");
- return;
- }
-
-
- 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->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;
- }
-
- printf("MM_ClearBlock: No purgable blocks!");
-}
-
-
-//==========================================================================
-
-/*
-===================
-=
-= MM_Startup
-=
-= Grabs all space from turbo with malloc/farmalloc
-= Allocates bufferseg misc buffer
-=
-===================
-*/
-
-void MM_Startup (void)
-{
- int i;
- dword 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();
- length=_memavl();
- 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();
- length=_memmax();
- start = farheap = _fmalloc(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],ParmStringsexmm) == 0)
- goto emsskip; // param NOEMS
- }
-
- if (MML_CheckForEMS())
- {
- //printf("EMS1\n");
- MML_SetupEMS(); // allocate space
- //printf("EMS2\n");
- MML_UseSpace (EMSpageframe,EMSpagesmapped*0x400);
- //printf("EMS3\n");
- MM_MapEMS(); // map in used pages
- //printf("EMS4\n");
- 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],ParmStringsexmm) == 0)
- goto xmsskip; // param NOXMS
- }
-
- if (MML_CheckForXMS())
- {
-// printf("XMS!\n");
- 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;
-
- _ffree (farheap);
- free (nearheap);
- hfree(hugeheap);
- MML_ShutdownEMS ();
- MML_ShutdownXMS ();
-}
-
-//==========================================================================
-
-/*
-====================
-=
-= MM_GetPtr
-=
-= Allocates an unlocked, unpurgable block
-=
-====================
-*/
-
-void MM_GetPtr (memptr *baseptr,dword 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)
- printf(OUT_OF_MEM_MSG,(size-mminfo.nearheap));
- 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)
- {
- printf("MM_FreePtr: Block not found!");
- return;
- }
-
- 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)
- {
- printf("MM_SetPurge: Block not found!");
- return;
- }
-
- } 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)
- {
- printf("MM_SetLock: Block not found!");
- return;
- }
-
- } 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);*/
-}
-
-
-//==========================================================================
-
-//****#if 0
-/*
-=====================
-=
-= MM_ShowMemory
-=
-=====================
-*/
-
-void MM_ShowMemory (void)
-{
- mmblocktype far *scan;
- unsigned color,temp;//, i;
- long end,owner;
- char scratch[80],str[10];
-
-//**** VW_SetDefaultColors();
-//**** VW_SetLineWidth(40);
-//++++mh temp = bufferofs;
-//++++mh 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)
- {
- printf("MM_ShowMemory: Memory block order currupted!");
- return;
- }
- 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
-printf("Location:");
-printf("%Fp\t", scan->start);
-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));
-fprintf(stdout, "%s", scratch);
-//****#endif
-
- scan = scan->next;
- }
-
-//CA_CloseDebug ();
-
-//++++mh IN_Ack();
-//**** VW_SetLineWidth(64);
-//++++mh bufferofs = temp;
-}
-//****#endif
-
-//==========================================================================
-
-
-/*
-======================
-=
-= MM_UnusedMemory
-=
-= Returns the total free space without purging
-=
-======================
-*/
-
-dword 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
-=
-======================
-*/
-
-dword 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_Report
-=
-=====================
-*/
-
-void MM_Report(void)
-{
- printf("EMM %x available\n", EMSVer);
- printf("totalEMSpages=%u\n", totalEMSpages);
- printf("freeEMSpages=%u\n", freeEMSpages);
- printf("EMSpageframe=%Fp\n", EMSpageframe);
- printf("UnusedMemory=%lu\n", MM_UnusedMemory());
- printf("TotalFree=%lu\n", MM_TotalFree());
-}
-
-//==========================================================================
-
-/*
-=====================
-=
-= MM_EMSVer
-=
-=====================
-
-
+/* Catacomb Armageddon Source Code\r
+ * Copyright (C) 1993-2014 Flat Rock Software\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+ */\r
+\r
+// NEWMM.C\r
+\r
+/*\r
+=============================================================================\r
+\r
+ ID software memory manager\r
+ --------------------------\r
+\r
+Primary coder: John Carmack\r
+\r
+RELIES ON\r
+---------\r
+Quit (char *error) function\r
+\r
+\r
+WORK TO DO\r
+----------\r
+MM_SizePtr to change the size of a given pointer\r
+\r
+Multiple purge levels utilized\r
+\r
+EMS / XMS unmanaged routines\r
+\r
+=============================================================================\r
+*/\r
+\r
+#include "src/lib/16_mm.h"\r
+\r
+/*\r
+======================\r
+=\r
+= MML_CheckForEMS\r
+=\r
+= Routine from p36 of Extending DOS\r
+=\r
+=======================\r
+*/\r
+\r
+boolean MML_CheckForEMS (void)\r
+{\r
+ boolean emmcfems;\r
+ char emmname[] = "EMMXXXX0";\r
+// mov dx,OFFSET emmname\r
+ __asm {\r
+ LEA DX, emmname //fix by andrius4669\r
+ mov ax,0x3d00\r
+ int 0x21 // try to open EMMXXXX0 device\r
+ jc error\r
+\r
+ mov bx,ax\r
+ mov ax,0x4400\r
+\r
+ int 0x21 // get device info\r
+ jc error\r
+\r
+ and dx,0x80\r
+ jz error\r
+\r
+ mov ax,0x4407\r
+\r
+ int 0x21 // get status\r
+ jc error\r
+ or al,al\r
+ jz error\r
+\r
+ mov ah,0x3e\r
+ int 0x21 // close handle\r
+ jc error\r
+ //\r
+ // EMS is good\r
+ //\r
+ mov emmcfems,1\r
+ jmp End\r
+ error:\r
+ //\r
+ // EMS is bad\r
+ //\r
+ mov emmcfems,0\r
+ End:\r
+ }\r
+ return(emmcfems);\r
+}\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= MML_SetupEMS\r
+=\r
+=======================\r
+*/\r
+\r
+void MML_SetupEMS (void)\r
+{\r
+ char str[80],str2[10];\r
+ unsigned err;\r
+ boolean errorflag=false;\r
+ union REGS CPURegs;\r
+\r
+ EMSVer = 0;\r
+ totalEMSpages = freeEMSpages = EMSpageframe = EMSpagesmapped = 0;\r
+\r
+ __asm\r
+ {\r
+ mov ah,EMS_STATUS\r
+ int EMS_INT // make sure EMS hardware is present\r
+ or ah,ah\r
+ jnz error\r
+\r
+ mov ah,EMS_VERSION\r
+ int EMS_INT\r
+ or ah,ah\r
+ jnz error\r
+ mov [EMSVer],ax // set EMSVer\r
+ cmp al,0x32 // only work on ems 3.2 or greater\r
+ jb error\r
+\r
+ mov ah,EMS_GETFRAME\r
+ int EMS_INT // find the page frame address\r
+ or ah,ah\r
+ jnz error\r
+ mov [EMSpageframe],bx\r
+\r
+ mov ah,EMS_GETPAGES\r
+ int EMS_INT // find out how much EMS is there\r
+ or ah,ah\r
+ jnz error\r
+ mov [totalEMSpages],dx\r
+ mov [freeEMSpages],bx\r
+ or bx,bx\r
+ jz noEMS // no EMS at all to allocate\r
+\r
+ cmp bx,4\r
+ jle getpages // there is only 1,2,3,or 4 pages\r
+ mov bx,4 // we can't use more than 4 pages\r
+\r
+getpages:\r
+ mov [EMSpagesmapped],bx\r
+ mov ah,EMS_ALLOCPAGES // allocate up to 64k of EMS\r
+ int EMS_INT\r
+ or ah,ah\r
+ jnz error\r
+ mov [EMShandle],dx\r
+ jmp End\r
+error:\r
+ mov errorflag,1\r
+ jmp End\r
+noEMS:\r
+End:\r
+ }\r
+ if(errorflag==true)\r
+ {\r
+ err = CPURegs.h.ah;\r
+ strcpy(str,"MML_SetupEMS: EMS error 0x");\r
+ itoa(err,str2,16);\r
+ strcpy(str,str2);\r
+ printf("%s\n",str);\r
+ }\r
+}\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= MML_ShutdownEMS\r
+=\r
+=======================\r
+*/\r
+\r
+void MML_ShutdownEMS (void)\r
+{\r
+ boolean errorflag=false;\r
+ if (!EMShandle)\r
+ return;\r
+ __asm\r
+ {\r
+ mov ah,EMS_FREEPAGES\r
+ mov dx,[EMShandle]\r
+ int EMS_INT\r
+ or ah,ah\r
+ jz ok\r
+ mov errorflag,1\r
+ ok:\r
+ }\r
+ if(errorflag==true) printf("MML_ShutdownEMS: Error freeing EMS!"); //++++ add something\r
+}\r
+\r
+/*\r
+====================\r
+=\r
+= MM_MapEMS\r
+=\r
+= Maps the 64k of EMS used by memory manager into the page frame\r
+= for general use. This only needs to be called if you are keeping\r
+= other things in EMS.\r
+=\r
+====================\r
+*/\r
+\r
+void MM_MapEMS (void)\r
+{\r
+ char str[80],str2[10];\r
+ unsigned err;\r
+ boolean errorflag=false;\r
+ int i;\r
+ union REGS CPURegs;\r
+\r
+ for (i=0;i<EMSpagesmapped;i++)\r
+ {\r
+ __asm\r
+ {\r
+ mov ah,EMS_MAPPAGE\r
+ mov bx,[i] // logical page\r
+ mov al,bl // physical page\r
+ mov dx,[EMShandle] // handle\r
+ int EMS_INT\r
+ or ah,ah\r
+ jnz error\r
+ jmp End\r
+ error:\r
+ mov errorflag,1\r
+ End:\r
+ }\r
+ if(errorflag==true)\r
+ {\r
+ err = CPURegs.h.ah;\r
+ strcpy(str,"MM_MapEMS: EMS error 0x");\r
+ itoa(err,str2,16);\r
+ strcpy(str,str2);\r
+ printf("%s\n",str);\r
+ }\r
+ }\r
+ return;\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+======================\r
+=\r
+= MML_CheckForXMS\r
+=\r
+= Check for XMM driver\r
+=\r
+=======================\r
+*/\r
+\r
+boolean MML_CheckForXMS (void)\r
+{\r
+ boolean errorflag=false;\r
+ numUMBs = 0;\r
+\r
+ __asm\r
+ {\r
+ mov ax,0x4300\r
+ int 0x2f // query status of installed diver\r
+ cmp al,0x80\r
+ je good\r
+ mov errorflag,1\r
+ good:\r
+ }\r
+ if(errorflag==true) return false;\r
+ else return true;\r
+}\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= MML_SetupXMS\r
+=\r
+= Try to allocate all upper memory block\r
+=\r
+=======================\r
+*/\r
+\r
+void MML_SetupXMS (void)\r
+{\r
+ unsigned base,size;\r
+\r
+ __asm\r
+ {\r
+ mov ax,0x4310\r
+ int 0x2f\r
+ mov [WORD PTR XMSaddr],bx\r
+ mov [WORD PTR XMSaddr+2],es // function pointer to XMS driver\r
+ }\r
+getmemory:\r
+ __asm\r
+ {\r
+ mov ah,XMS_ALLOCUMB\r
+ mov dx,0xffff // try for largest block possible\r
+ call [DWORD PTR XMSaddr]\r
+ or ax,ax\r
+ jnz gotone\r
+\r
+ cmp bl,0xb0 // error: smaller UMB is available\r
+ jne done;\r
+\r
+ mov ah,XMS_ALLOCUMB\r
+ call [DWORD PTR XMSaddr] // DX holds largest available UMB\r
+ or ax,ax\r
+ jz done // another error...\r
+\r
+gotone:\r
+ mov [base],bx\r
+ mov [size],dx\r
+done:\r
+ }\r
+ MML_UseSpace (base,size);\r
+ mminfo.XMSmem += size*16;\r
+ UMBbase[numUMBs] = base;\r
+ numUMBs++;\r
+ if (numUMBs < MAXUMBS)\r
+ goto getmemory;\r
+}\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= MML_ShutdownXMS\r
+=\r
+======================\r
+*/\r
+\r
+void MML_ShutdownXMS (void)\r
+{\r
+ int i;\r
+ unsigned base;\r
+\r
+ for (i=0;i<numUMBs;i++)\r
+ {\r
+ base = UMBbase[i];\r
+ __asm\r
+ {\r
+ mov ah,XMS_FREEUMB\r
+ mov dx,[base]\r
+ call [DWORD PTR XMSaddr]\r
+ }\r
+ }\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+======================\r
+=\r
+= MML_UseSpace\r
+=\r
+= Marks a range of paragraphs as usable by the memory manager\r
+= This is used to mark space for the near heap, far heap, ems page frame,\r
+= and upper memory blocks\r
+=\r
+======================\r
+*/\r
+\r
+void MML_UseSpace (unsigned segstart, unsigned seglength)\r
+{\r
+ mmblocktype far *scan,far *last;\r
+ unsigned oldend;\r
+ long extra;\r
+\r
+ scan = last = mmhead;\r
+ mmrover = mmhead; // reset rover to start of memory\r
+\r
+//\r
+// search for the block that contains the range of segments\r
+//\r
+ while (scan->start+scan->length < segstart)\r
+ {\r
+ last = scan;\r
+ scan = scan->next;\r
+ }\r
+\r
+//\r
+// take the given range out of the block\r
+//\r
+ oldend = scan->start + scan->length;\r
+ extra = oldend - (segstart+seglength);\r
+ if (extra < 0)\r
+ {\r
+ printf("MML_UseSpace: Segment spans two blocks!");\r
+ return;\r
+ }\r
+\r
+\r
+ if (segstart == scan->start)\r
+ {\r
+ last->next = scan->next; // unlink block\r
+ FREEBLOCK(scan);\r
+ scan = last;\r
+ }\r
+ else\r
+ scan->length = segstart-scan->start; // shorten block\r
+\r
+ if (extra > 0)\r
+ {\r
+ GETNEWBLOCK;\r
+ mmnew->next = scan->next;\r
+ scan->next = mmnew;\r
+ mmnew->start = segstart+seglength;\r
+ mmnew->length = extra;\r
+ mmnew->attributes = LOCKBIT;\r
+ }\r
+\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+====================\r
+=\r
+= MML_ClearBlock\r
+=\r
+= We are out of blocks, so free a purgable block\r
+=\r
+====================\r
+*/\r
+\r
+void MML_ClearBlock (void)\r
+{\r
+ mmblocktype far *scan,far *last;\r
+\r
+ scan = mmhead->next;\r
+\r
+ while (scan)\r
+ {\r
+ if (!(scan->attributes&LOCKBIT) && (scan->attributes&PURGEBITS) )\r
+ {\r
+ MM_FreePtr(scan->useptr);\r
+ return;\r
+ }\r
+ scan = scan->next;\r
+ }\r
+\r
+ printf("MM_ClearBlock: No purgable blocks!");\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+/*\r
+===================\r
+=\r
+= MM_Startup\r
+=\r
+= Grabs all space from turbo with malloc/farmalloc\r
+= Allocates bufferseg misc buffer\r
+=\r
+===================\r
+*/\r
+\r
+void MM_Startup (void)\r
+{\r
+ int i;\r
+ dword length;\r
+ void far *start;\r
+ unsigned segstart,seglength,endfree;\r
+\r
+ if (mminfo.mmstarted)\r
+ MM_Shutdown ();\r
+\r
+\r
+ mminfo.mmstarted = true;\r
+ mminfo.bombonerror = true;\r
+//\r
+// set up the linked list (everything in the free list;\r
+//\r
+ mmhead = NULL;\r
+ mmfree = &mmblocks[0];\r
+ for (i=0;i<MAXBLOCKS-1;i++)\r
+ mmblocks[i].next = &mmblocks[i+1];\r
+ mmblocks[i].next = NULL;\r
+\r
+//\r
+// locked block of all memory until we punch out free space\r
+//\r
+ GETNEWBLOCK;\r
+ mmhead = mmnew; // this will allways be the first node\r
+ mmnew->start = 0;\r
+ mmnew->length = 0xffff;\r
+ mmnew->attributes = LOCKBIT;\r
+ mmnew->next = NULL;\r
+ mmrover = mmhead;\r
+\r
+\r
+//\r
+// get all available near conventional memory segments\r
+//\r
+//---- length=coreleft();\r
+ length=_memavl();\r
+ start = (void far *)(nearheap = malloc(length));\r
+\r
+ length -= 16-(FP_OFF(start)&15);\r
+ length -= SAVENEARHEAP;\r
+ seglength = length / 16; // now in paragraphs\r
+ segstart = FP_SEG(start)+(FP_OFF(start)+15)/16;\r
+ MML_UseSpace (segstart,seglength);\r
+ mminfo.nearheap = length;\r
+\r
+//\r
+// get all available far conventional memory segments\r
+//\r
+//---- length=farcoreleft();\r
+ length=_memmax();\r
+ start = farheap = _fmalloc(length);\r
+ length -= 16-(FP_OFF(start)&15);\r
+ length -= SAVEFARHEAP;\r
+ seglength = length / 16; // now in paragraphs\r
+ segstart = FP_SEG(start)+(FP_OFF(start)+15)/16;\r
+ MML_UseSpace (segstart,seglength);\r
+ mminfo.farheap = length;\r
+ mminfo.mainmem = mminfo.nearheap + mminfo.farheap;\r
+\r
+\r
+//\r
+// detect EMS and allocate up to 64K at page frame\r
+//\r
+ mminfo.EMSmem = 0;\r
+ for (i = 1;i < __argc;i++)\r
+ {\r
+ if ( US_CheckParm(__argv[i],ParmStringsexmm) == 0)\r
+ goto emsskip; // param NOEMS\r
+ }\r
+\r
+ if (MML_CheckForEMS())\r
+ {\r
+ //printf("EMS1\n");\r
+ MML_SetupEMS(); // allocate space\r
+ //printf("EMS2\n");\r
+ MML_UseSpace (EMSpageframe,EMSpagesmapped*0x400);\r
+ //printf("EMS3\n");\r
+ MM_MapEMS(); // map in used pages\r
+ //printf("EMS4\n");\r
+ mminfo.EMSmem = EMSpagesmapped*0x4000l;\r
+ }\r
+\r
+//\r
+// detect XMS and get upper memory blocks\r
+//\r
+emsskip:\r
+ mminfo.XMSmem = 0;\r
+ for (i = 1;i < __argc;i++)\r
+ {\r
+ if ( US_CheckParm(__argv[i],ParmStringsexmm) == 0)\r
+ goto xmsskip; // param NOXMS\r
+ }\r
+\r
+ if (MML_CheckForXMS())\r
+ {\r
+// printf("XMS!\n");\r
+ MML_SetupXMS(); // allocate as many UMBs as possible\r
+ }\r
+\r
+//\r
+// allocate the misc buffer\r
+//\r
+xmsskip:\r
+ mmrover = mmhead; // start looking for space after low block\r
+\r
+ MM_GetPtr (&bufferseg,BUFFERSIZE);\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+====================\r
+=\r
+= MM_Shutdown\r
+=\r
+= Frees all conventional, EMS, and XMS allocated\r
+=\r
+====================\r
+*/\r
+\r
+void MM_Shutdown (void)\r
+{\r
+ if (!mminfo.mmstarted)\r
+ return;\r
+\r
+ _ffree (farheap);\r
+ free (nearheap);\r
+ hfree(hugeheap);\r
+ MML_ShutdownEMS ();\r
+ MML_ShutdownXMS ();\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+====================\r
+=\r
+= MM_GetPtr\r
+=\r
+= Allocates an unlocked, unpurgable block\r
+=\r
+====================\r
+*/\r
+\r
+void MM_GetPtr (memptr *baseptr,dword size)\r
+{\r
+ mmblocktype far *scan,far *lastscan,far *endscan\r
+ ,far *purge,far *next;\r
+ int search;\r
+ unsigned needed,startseg;\r
+\r
+ needed = (size+15)/16; // convert size from bytes to paragraphs\r
+\r
+ GETNEWBLOCK; // fill in start and next after a spot is found\r
+ mmnew->length = needed;\r
+ mmnew->useptr = baseptr;\r
+ mmnew->attributes = BASEATTRIBUTES;\r
+\r
+ for (search = 0; search<3; search++)\r
+ {\r
+ //\r
+ // first search: try to allocate right after the rover, then on up\r
+ // second search: search from the head pointer up to the rover\r
+ // third search: compress memory, then scan from start\r
+ if (search == 1 && mmrover == mmhead)\r
+ search++;\r
+\r
+ switch (search)\r
+ {\r
+ case 0:\r
+ lastscan = mmrover;\r
+ scan = mmrover->next;\r
+ endscan = NULL;\r
+ break;\r
+ case 1:\r
+ lastscan = mmhead;\r
+ scan = mmhead->next;\r
+ endscan = mmrover;\r
+ break;\r
+ case 2:\r
+ MM_SortMem ();\r
+ lastscan = mmhead;\r
+ scan = mmhead->next;\r
+ endscan = NULL;\r
+ break;\r
+ }\r
+\r
+ startseg = lastscan->start + lastscan->length;\r
+\r
+ while (scan != endscan)\r
+ {\r
+ if (scan->start - startseg >= needed)\r
+ {\r
+ //\r
+ // got enough space between the end of lastscan and\r
+ // the start of scan, so throw out anything in the middle\r
+ // and allocate the new block\r
+ //\r
+ purge = lastscan->next;\r
+ lastscan->next = mmnew;\r
+ mmnew->start = *(unsigned *)baseptr = startseg;\r
+ mmnew->next = scan;\r
+ while ( purge != scan)\r
+ { // free the purgable block\r
+ next = purge->next;\r
+ FREEBLOCK(purge);\r
+ purge = next; // purge another if not at scan\r
+ }\r
+ mmrover = mmnew;\r
+ return; // good allocation!\r
+ }\r
+\r
+ //\r
+ // if this block is purge level zero or locked, skip past it\r
+ //\r
+ if ( (scan->attributes & LOCKBIT)\r
+ || !(scan->attributes & PURGEBITS) )\r
+ {\r
+ lastscan = scan;\r
+ startseg = lastscan->start + lastscan->length;\r
+ }\r
+\r
+\r
+ scan=scan->next; // look at next line\r
+ }\r
+ }\r
+\r
+ if (mminfo.bombonerror)\r
+ printf(OUT_OF_MEM_MSG,(size-mminfo.nearheap));\r
+ else\r
+ mminfo.mmerror = true;\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+====================\r
+=\r
+= MM_FreePtr\r
+=\r
+= Allocates an unlocked, unpurgable block\r
+=\r
+====================\r
+*/\r
+\r
+void MM_FreePtr (memptr *baseptr)\r
+{\r
+ mmblocktype far *scan,far *last;\r
+\r
+ last = mmhead;\r
+ scan = last->next;\r
+\r
+ if (baseptr == mmrover->useptr) // removed the last allocated block\r
+ mmrover = mmhead;\r
+\r
+ while (scan->useptr != baseptr && scan)\r
+ {\r
+ last = scan;\r
+ scan = scan->next;\r
+ }\r
+\r
+ if (!scan)\r
+ {\r
+ printf("MM_FreePtr: Block not found!");\r
+ return;\r
+ }\r
+\r
+ last->next = scan->next;\r
+\r
+ FREEBLOCK(scan);\r
+}\r
+//==========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= MM_SetPurge\r
+=\r
+= Sets the purge level for a block (locked blocks cannot be made purgable)\r
+=\r
+=====================\r
+*/\r
+\r
+void MM_SetPurge (memptr *baseptr, int purge)\r
+{\r
+ mmblocktype far *start;\r
+\r
+ start = mmrover;\r
+\r
+ do\r
+ {\r
+ if (mmrover->useptr == baseptr)\r
+ break;\r
+\r
+ mmrover = mmrover->next;\r
+\r
+ if (!mmrover)\r
+ mmrover = mmhead;\r
+ else if (mmrover == start)\r
+ {\r
+ printf("MM_SetPurge: Block not found!");\r
+ return;\r
+ }\r
+\r
+ } while (1);\r
+\r
+ mmrover->attributes &= ~PURGEBITS;\r
+ mmrover->attributes |= purge;\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= MM_SetLock\r
+=\r
+= Locks / unlocks the block\r
+=\r
+=====================\r
+*/\r
+\r
+void MM_SetLock (memptr *baseptr, boolean locked)\r
+{\r
+ mmblocktype far *start;\r
+\r
+ start = mmrover;\r
+\r
+ do\r
+ {\r
+ if (mmrover->useptr == baseptr)\r
+ break;\r
+\r
+ mmrover = mmrover->next;\r
+\r
+ if (!mmrover)\r
+ mmrover = mmhead;\r
+ else if (mmrover == start)\r
+ {\r
+ printf("MM_SetLock: Block not found!");\r
+ return;\r
+ }\r
+\r
+ } while (1);\r
+\r
+ mmrover->attributes &= ~LOCKBIT;\r
+ mmrover->attributes |= locked*LOCKBIT;\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= MM_SortMem\r
+=\r
+= Throws out all purgable stuff and compresses movable blocks\r
+=\r
+=====================\r
+*/\r
+\r
+void MM_SortMem (void)\r
+{\r
+ mmblocktype far *scan,far *last,far *next;\r
+ unsigned start,length,source,dest,oldborder;\r
+ int playing;\r
+\r
+ //\r
+ // lock down a currently playing sound\r
+ //\r
+/*++++ playing = SD_SoundPlaying ();\r
+ if (playing)\r
+ {\r
+ switch (SoundMode)\r
+ {\r
+ case sdm_PC:\r
+ playing += STARTPCSOUNDS;\r
+ break;\r
+ case sdm_AdLib:\r
+ playing += STARTADLIBSOUNDS;\r
+ break;\r
+ }\r
+ MM_SetLock(&(memptr)audiosegs[playing],true);\r
+ }\r
+\r
+\r
+ SD_StopSound();*/\r
+// oldborder = bordercolor;\r
+// VW_ColorBorder (15);\r
+\r
+ if (beforesort)\r
+ beforesort();\r
+\r
+ scan = mmhead;\r
+\r
+ last = NULL; // shut up compiler warning\r
+\r
+ while (scan)\r
+ {\r
+ if (scan->attributes & LOCKBIT)\r
+ {\r
+ //\r
+ // block is locked, so try to pile later blocks right after it\r
+ //\r
+ start = scan->start + scan->length;\r
+ }\r
+ else\r
+ {\r
+ if (scan->attributes & PURGEBITS)\r
+ {\r
+ //\r
+ // throw out the purgable block\r
+ //\r
+ next = scan->next;\r
+ FREEBLOCK(scan);\r
+ last->next = next;\r
+ scan = next;\r
+ continue;\r
+ }\r
+ else\r
+ {\r
+ //\r
+ // push the non purgable block on top of the last moved block\r
+ //\r
+ if (scan->start != start)\r
+ {\r
+ length = scan->length;\r
+ source = scan->start;\r
+ dest = start;\r
+ while (length > 0xf00)\r
+ {\r
+ movedata(source,0,dest,0,0xf00*16);\r
+ length -= 0xf00;\r
+ source += 0xf00;\r
+ dest += 0xf00;\r
+ }\r
+ movedata(source,0,dest,0,length*16);\r
+\r
+ scan->start = start;\r
+ *(unsigned *)scan->useptr = start;\r
+ }\r
+ start = scan->start + scan->length;\r
+ }\r
+ }\r
+\r
+ last = scan;\r
+ scan = scan->next; // go to next block\r
+ }\r
+\r
+ mmrover = mmhead;\r
+\r
+ if (aftersort)\r
+ aftersort();\r
+\r
+// VW_ColorBorder (oldborder);\r
+\r
+/*++++ if (playing)\r
+ MM_SetLock(&(memptr)audiosegs[playing],false);*/\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+//****#if 0\r
+/*\r
+=====================\r
+=\r
+= MM_ShowMemory\r
+=\r
+=====================\r
+*/\r
+\r
+void MM_ShowMemory (void)\r
+{\r
+ mmblocktype far *scan;\r
+ unsigned color,temp;//, i;\r
+ long end,owner;\r
+ char scratch[80],str[10];\r
+\r
+//**** VW_SetDefaultColors();\r
+//**** VW_SetLineWidth(40);\r
+//++++mh temp = bufferofs;\r
+//++++mh bufferofs = 0;\r
+//**** VW_SetScreen (0,0);\r
+\r
+ scan = mmhead;\r
+\r
+ end = -1;\r
+\r
+//CA_OpenDebug ();\r
+\r
+ while (scan)\r
+ {\r
+ if (scan->attributes & PURGEBITS)\r
+ color = 5; // dark purple = purgable\r
+ else\r
+ color = 9; // medium blue = non purgable\r
+ if (scan->attributes & LOCKBIT)\r
+ color = 12; // red = locked\r
+ if (scan->start<=end)\r
+ {\r
+ printf("MM_ShowMemory: Memory block order currupted!");\r
+ return;\r
+ }\r
+ end = scan->start+scan->length-1;\r
+//++++ VW_Hlin(scan->start,(unsigned)end,0,color);\r
+//++++ VW_Plot(scan->start,0,15);\r
+ if (scan->next->start > end+1)\r
+//++++ VW_Hlin(end+1,scan->next->start,0,0); // black = free\r
+\r
+//****#if 0\r
+printf("Location:");\r
+printf("%Fp\t", scan->start);\r
+strcpy (scratch,"Size:");\r
+ltoa ((long)scan->length*16,str,10);\r
+strcat (scratch,str);\r
+strcat (scratch,"\tOwner:0x");\r
+owner = (unsigned)scan->useptr;\r
+ultoa (owner,str,16);\r
+strcat (scratch,str);\r
+strcat (scratch,"\n");\r
+//++++write (debughandle,scratch,strlen(scratch));\r
+fprintf(stdout, "%s", scratch);\r
+//****#endif\r
+\r
+ scan = scan->next;\r
+ }\r
+\r
+//CA_CloseDebug ();\r
+\r
+//++++mh IN_Ack();\r
+//**** VW_SetLineWidth(64);\r
+//++++mh bufferofs = temp;\r
+}\r
+//****#endif\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= MM_UnusedMemory\r
+=\r
+= Returns the total free space without purging\r
+=\r
+======================\r
+*/\r
+\r
+dword MM_UnusedMemory (void)\r
+{\r
+ unsigned free;\r
+ mmblocktype far *scan;\r
+\r
+ free = 0;\r
+ scan = mmhead;\r
+\r
+ while (scan->next)\r
+ {\r
+ free += scan->next->start - (scan->start + scan->length);\r
+ scan = scan->next;\r
+ }\r
+\r
+ return free*16l;\r
+}\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= MM_TotalFree\r
+=\r
+= Returns the total free space with purging\r
+=\r
+======================\r
+*/\r
+\r
+dword MM_TotalFree (void)\r
+{\r
+ unsigned free;\r
+ mmblocktype far *scan;\r
+\r
+ free = 0;\r
+ scan = mmhead;\r
+\r
+ while (scan->next)\r
+ {\r
+ if ((scan->attributes&PURGEBITS) && !(scan->attributes&LOCKBIT))\r
+ free += scan->length;\r
+ free += scan->next->start - (scan->start + scan->length);\r
+ scan = scan->next;\r
+ }\r
+\r
+ return free*16l;\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= MM_Report\r
+=\r
+=====================\r
+*/\r
+\r
+void MM_Report(void)\r
+{\r
+ printf("EMM %x available\n", EMSVer);\r
+ printf("totalEMSpages=%u\n", totalEMSpages);\r
+ printf("freeEMSpages=%u\n", freeEMSpages);\r
+ printf("EMSpageframe=%Fp\n", EMSpageframe);\r
+ printf("near=%lu\n", mminfo.nearheap);\r
+ printf("far=%lu\n", mminfo.farheap);\r
+ printf("EMSmem=%lu\n", mminfo.EMSmem);\r
+ printf("XMSmem=%lu\n", mminfo.XMSmem);\r
+ printf("mainmem=%lu\n", mminfo.mainmem);\r
+ printf("UnusedMemory=%lu\n", MM_UnusedMemory());\r
+ printf("TotalFree=%lu\n", MM_TotalFree());\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= MM_EMSVer\r
+=\r
+=====================\r
+\r
+\r
int MM_EMSVer(void)\r
-{
+{\r
int EMSver;\r
- __asm
- {
+ __asm\r
+ {\r
mov ah,EMS_VERSION\r
- int EMS_INT
+ int EMS_INT\r
mov EMSver,ax\r
- }
+ }\r
return(EMSver);\r
-}*/
-
-//==========================================================================
-
-/*
-=====================
-=
-= MM_BombOnError
-=
-=====================
-*/
-
-void MM_BombOnError (boolean bomb)
-{
- bombonerror = bomb;
-}
-
-//==========================================================================
-
-///////////////////////////////////////////////////////////////////////////
-//
-// US_CheckParm() - checks to see if a string matches one of a set of
-// strings. The check is case insensitive. The routine returns the
-// index of the string that matched, or -1 if no matches were found
-//
-///////////////////////////////////////////////////////////////////////////
-int
-US_CheckParm(char *parm,char **strings)
-{
- char cp,cs,
- *p,*s;
- int i;
-
- while (!isalpha(*parm)) // Skip non-alphas
- parm++;
-
- for (i = 0;*strings && **strings;i++)
- {
- for (s = *strings++,p = parm,cs = cp = 0;cs == cp;)
- {
- cs = *s++;
- if (!cs)
- return(i);
- cp = *p++;
-
- if (isupper(cs))
- cs = tolower(cs);
- if (isupper(cp))
- cp = tolower(cp);
- }
- }
- return(-1);
-}
-
+}*/\r
+\r
+//==========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= MM_BombOnError\r
+=\r
+=====================\r
+*/\r
+\r
+void MM_BombOnError (boolean bomb)\r
+{\r
+ mminfo.bombonerror = bomb;\r
+}\r
+\r
+//==========================================================================\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// US_CheckParm() - checks to see if a string matches one of a set of\r
+// strings. The check is case insensitive. The routine returns the\r
+// index of the string that matched, or -1 if no matches were found\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+int\r
+US_CheckParm(char *parm,char **strings)\r
+{\r
+ char cp,cs,\r
+ *p,*s;\r
+ int i;\r
+\r
+ while (!isalpha(*parm)) // Skip non-alphas\r
+ parm++;\r
+\r
+ for (i = 0;*strings && **strings;i++)\r
+ {\r
+ for (s = *strings++,p = parm,cs = cp = 0;cs == cp;)\r
+ {\r
+ cs = *s++;\r
+ if (!cs)\r
+ return(i);\r
+ cp = *p++;\r
+\r
+ if (isupper(cs))\r
+ cs = tolower(cs);\r
+ if (isupper(cp))\r
+ cp = tolower(cp);\r
+ }\r
+ }\r
+ return(-1);\r
+}\r
+\r