From 1dbd79f535c2617caefe848842199988dbedc12f Mon Sep 17 00:00:00 2001 From: sparky4 Date: Thu, 22 Sep 2016 14:44:04 -0500 Subject: [PATCH] reverted to older ver of 16_mm because of bugs --- 16/16_mm.c | 1802 ++++++++++++++++++++++ DEBUG.16B | 16 +- DEBUG.16W | 16 +- HEAP.16W | 86 +- MMDUMP.16B | Bin 75 -> 75 bytes MMDUMP.16W | Bin 22 -> 66 bytes bcexmm.exe | Bin 83827 -> 83128 bytes bcexmm.prj | Bin 7812 -> 6566 bytes src/exmmtest.c | 8 +- src/lib/16_head.h | 3 +- src/lib/16_mm.c | 3625 ++++++++++++++++++++++---------------------- src/lib/16_mm.h | 5 +- src/lib/16_pm.c | 25 +- src/lib/16_pm.h | 2 +- src/lib/length | 4 + src/lib/next | 0 src/lib/typdefst.h | 1 + 17 files changed, 3697 insertions(+), 1896 deletions(-) create mode 100755 16/16_mm.c create mode 100755 src/lib/length create mode 100755 src/lib/next diff --git a/16/16_mm.c b/16/16_mm.c new file mode 100755 index 00000000..9f10fd39 --- /dev/null +++ b/16/16_mm.c @@ -0,0 +1,1802 @@ +/* Catacomb Apocalypse 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 + +============================================================================= +*/ +/* + +Open Watcom port by sparky4 + +*/ +#include "src/lib/16_mm.h" +#include "src/lib/16_ca.h" +#pragma hdrstop + +#pragma warn -pro +#pragma warn -use + +/* +============================================================================= + + GLOBAL VARIABLES + +============================================================================= +*/ + +void (* beforesort) (void); +void (* aftersort) (void); +void (* XMSaddr) (void); // far pointer to XMS driver + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + +/* +====================== += += MML_CheckForEMS += += Routine from p36 of Extending DOS += +======================= +*/ + +boolean MML_CheckForEMS(void) +{ + boolean emmcfems; + static char emmname[] = "EMMXXXX0"; //fix by andrius4669 + __asm { + mov dx,OFFSET 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 +#ifdef __BORLANDC__ + } +#endif + error: +#ifdef __BORLANDC__ + __asm { +#endif + // + // EMS is bad + // + mov emmcfems,0 +#ifdef __BORLANDC__ + } +#endif + End: +#ifdef __WATCOMC__ + } +#endif + return(emmcfems); +} + + +/* +====================== += += MML_SetupEMS += +======================= +*/ + +byte MML_SetupEMS(global_game_variables_t *gvar) +{ + byte str[160]; + byte err; + boolean errorflag=false; + + unsigned int EMSVer = 0; + //byte EMS_status; + unsigned totalEMSpages,freeEMSpages,EMSPageFrame,EMSpagesmapped,EMSHandle; + totalEMSpages = freeEMSpages = EMSPageFrame = EMSpagesmapped = 0; + + __asm { + mov ah,EMS_STATUS + int EMS_INT // make sure EMS hardware is present + or ah,ah + //mov [EMS_status],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 + //EXPAND DONG!!!! + cmp [EMSVer],0x40 + jb low + cmp bx,[freeEMSpages] + jle getpages + mov bx,[freeEMSpages] + jmp getpages +#ifdef __BORLANDC__ + } +#endif + low: +#ifdef __BORLANDC__ + __asm { +#endif + 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 +#ifdef __BORLANDC__ + } +#endif + getpages: +#ifdef __BORLANDC__ + __asm { +#endif + 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 +#ifdef __BORLANDC__ + } +#endif + error: +#ifdef __BORLANDC__ + __asm { +#endif + mov err,ah + mov errorflag,1 + jmp End +#ifdef __BORLANDC__ + } +#endif +noEMS: +End: +#ifdef __WATCOMC__ + } +#endif + if(errorflag==true) + { + strcpy(str,"MM_SetupEMS: EMS error "); + MM_EMSerr(str, err); + printf("%s\n",str); + return err; + } + gvar->pm.emm.totalEMSpages=totalEMSpages; + gvar->pm.emm.freeEMSpages=freeEMSpages; + gvar->pm.emm.EMSPageFrame=EMSPageFrame; + gvar->pm.emm.EMSpagesmapped=EMSpagesmapped; + gvar->pm.emm.EMSHandle=EMSHandle; + gvar->pm.emm.EMSVer=EMSVer; + return 0; +} + + +/* +====================== += += MML_ShutdownEMS += +======================= +*/ + +void MML_ShutdownEMS(global_game_variables_t *gvar) +{ + boolean errorflag=false; + unsigned EMSHandle=gvar->pm.emm.EMSHandle; + + if(!EMSHandle) + return; + __asm { + mov ah,EMS_FREEPAGES + mov dx,[EMSHandle] + int EMS_INT + or ah,ah + jz ok + mov errorflag,1 +#ifdef __BORLANDC__ + } +#endif + ok: +#ifdef __WATCOMC__ + } +#endif + if(errorflag==true) + Quit("MML_ShutdownEMS: Error freeing EMS!\n"); //++++ 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. += +==================== +*/ + +byte MM_MapEMS(global_game_variables_t *gvar) +{ + byte str[160]; + unsigned EMSHandle; + byte err; + boolean errorflag=false; + int i; + EMSHandle=gvar->pm.emm.EMSHandle; + + for (i=0;i<4/*MAPPAGES*/;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 +#ifdef __BORLANDC__ + } +#endif + error: +#ifdef __BORLANDC__ + __asm { +#endif + mov err,ah + mov errorflag,1 +#ifdef __BORLANDC__ + } +#endif + End: +#ifdef __WATCOMC__ + } +#endif + if(errorflag==true) + { + strcpy(str,"MM_MapEMS: EMS error "); + MM_EMSerr(str, err); + printf("%s\n",str); + return err; + } + } + gvar->mmi.EMSmem = (i)*0x4000lu; + //printf(" gvar->mmi.EMSmem=%lu\n", gvar->mmi.EMSmem); + return 0; +} + +byte MM_MapXEMS(global_game_variables_t *gvar) +{ +//SUB EMS.MapXPages (PhysicalStart, LogicalStart, NumPages, Handle) + + //Maps up to 4 logical EMS pages to physical pages in the page frame, where: + //PhysicalStart = Physical page first logical page is mapped to + //LogicalStart = First logical page to map + //NumPages = Number of pages to map (1 to 4) + //Handle = EMS handle logical pages are allocated to + + /*//Create a buffer containing the page information +// FOR x = 0 TO NumPages - 1 +// MapInfo$ = MapInfo$ + MKI$(LogicalStart + x) + MKI$(PhysicalStart + x) +// NEXT*/ + +// Regs.ax = 0x5000 //Map the pages in the buffer +// Regs.cx = NumPages //to the pageframe +// Regs.dx = Handle +// Regs.ds = VARSEG(MapInfo$) +// Regs.si = SADD(MapInfo$) +// InterruptX 0x67, Regs, Regs +// EMS.Error = (Regs.ax AND 0xFF00&) \ 0x100 //Store the status code + +//END SUB + byte str[160]; + byte err; + word EMSHandle; + boolean errorflag=false; + int i; + EMSHandle=gvar->pm.emm.EMSHandle; + + if(gvar->pm.emm.EMSVer<0x40) + return 5; + + for (i=0;immi.EMSmem = (i)*0x4000lu; + return 0; +} + +//========================================================================== + +/* +====================== += += MML_CheckForXMS += += Check for XMM driver += +======================= +*/ + +boolean MML_CheckForXMS(global_game_variables_t *gvar) +{ + boolean errorflag=false; + gvar->mm.numUMBs = 0; + + __asm { + mov ax,0x4300 + int 0x2f // query status of installed diver + cmp al,0x80 + je good + mov errorflag,1 +#ifdef __BORLANDC__ + } +#endif + good: +#ifdef __WATCOMC__ + } +#endif + if(errorflag==true) return false; + else return true; +} + + +/* +====================== += += MML_SetupXMS += += Try to allocate all upper memory block += +======================= +*/ + +void MML_SetupXMS(global_game_variables_t *gvar) +{ + word 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 + //mov ax,dx // Set available Kbytes. + 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... +#ifdef __BORLANDC__ + } +#endif + gotone: +#ifdef __BORLANDC__ + __asm { +#endif + mov [base],bx + mov [size],dx +#ifdef __BORLANDC__ + } +#endif + done: +#ifdef __WATCOMC__ + } +#endif +// printf("base=%u ", base); printf("size=%u\n", size); + MML_UseSpace(base,size, gvar); + gvar->mmi.XMSmem += size*16; + gvar->mm.UMBbase[gvar->mm.numUMBs] = base; + gvar->mm.numUMBs++; + if(gvar->mm.numUMBs < MAXUMBS) + goto getmemory; +} + + +/* +====================== += += MML_ShutdownXMS += +====================== +*/ + +void MML_ShutdownXMS(global_game_variables_t *gvar) +{ + int i; + unsigned base; + + for (i=0;imm.numUMBs;i++) + { + base = gvar->mm.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(word segstart, dword seglength, global_game_variables_t *gvar) +{ + //huge mmblocktype huge *scan,huge *last; + word segm=1; + word oldend; + dword segmlen; + dword extra; + + scan = last = gvar->mm.mmhead; + gvar->mm.mmrover = gvar->mm.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); + + segmlen=extra; + + //++++emsver stuff! + if(segm>1)/// || extra>=0x10000lu) + //if(extra>0xfffflu) + { + scan->blob=segm; + + //MML_UseSpace(segstart, seglength, gvar); + + printf("MML_UseSpace: Segment spans two blocks!\n"); + //} + printf("segm=%u ", segm); + printf("ex=%lu ", extra); + printf("old=%u ", oldend); + printf("start+seglen=%lu\n", segstart+seglength); + printf("segsta=%x ", segstart); + printf("len=%lu ", scan->length); + printf("seglen=%lu ", seglength); + printf("segmlen=%lu\n", segmlen); + } +//++++todo: linked list of segment! + 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; + gvar->mm.mmnew->useptr = NULL; + + gvar->mm.mmnew->next = scan->next; + scan->next = gvar->mm.mmnew; + gvar->mm.mmnew->start = segstart+seglength; + gvar->mm.mmnew->length = extra; + gvar->mm.mmnew->attributes = LOCKBIT; + }//else if(segm>0) goto segu; + +}*/ +void MML_UseSpace(word segstart, dword seglength, global_game_variables_t *gvar) +{ + mmblocktype far *scan,far *last; + word oldend; + sdword extra; + //word segm=1; + + scan = last = gvar->mm.mmhead; + gvar->mm.mmrover = gvar->mm.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; + } + +// +// find out how many blocks it spans! +// + /*for(;seglength>=0x10000;seglength-=0xFFFF) + { + //printf(" seglen=%lu\n", segmlen); + segm++; + }*/ + +// +// take the given range out of the block +// + oldend = scan->start + scan->length; + extra = oldend - (segstart+((unsigned)seglength)); + if (extra < 0) + { + printf("========================================\n"); + printf("start=%x ", scan->start); + printf("old=%u ", oldend); + printf("start+seglen=%lu\n", segstart+seglength); + printf("segsta=%x ", segstart); + printf("len=%lu ", scan->length); + printf("seglen=%lu ", seglength); + printf("\n"); + printf("MML_UseSpace: Segment spans two blocks! %d\n", extra); + printf("========================================\n"); + //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; + gvar->mm.mmnew->useptr = NULL; + + gvar->mm.mmnew->next = scan->next; + scan->next = gvar->mm.mmnew; + gvar->mm.mmnew->start = segstart+seglength; + gvar->mm.mmnew->length = extra; + gvar->mm.mmnew->attributes = LOCKBIT; + } + +} + +//========================================================================== + +/* +==================== += += MML_ClearBlock += += We are out of blocks, so free a purgable block += +==================== +*/ + +void MML_ClearBlock(global_game_variables_t *gvar) +{ + //huge mmblocktype huge *scan,huge *last; + mmblocktype far *scan,far *last; + + scan = gvar->mm.mmhead->next; + + while(scan) + { + if(!(scan->attributes&LOCKBIT) && (scan->attributes&PURGEBITS)) + { + MM_FreePtr(scan->useptr, gvar); + return; + } + scan = scan->next; + } + + printf("MM_ClearBlock: No purgable blocks!\n"); +} + + +//========================================================================== + +/* +=================== += += MM_Startup += += Grabs all space from turbo with malloc/farmalloc += Allocates bufferseg misc buffer += +=================== +*/ + +void MM_Startup(global_game_variables_t *gvar) +{ + int i; + //dword length,seglength; + dword length; + //huge void huge *start; + void far *start; + word segstart,seglength,endfree; + //memptr *peeonself; + + if(gvar->mm.mmstarted) + MM_Shutdown(gvar); + + + gvar->mm.mmstarted = true; + gvar->mm.bombonerror = true; +// +// set up the linked list (everything in the free list; +// + gvar->mm.mmhead = NULL; + gvar->mm.mmfree = &(gvar->mm.mmblocks[0]); + for(i=0;imm.mmblocks[i].next = &(gvar->mm.mmblocks[i+1]); + } + gvar->mm.mmblocks[i].next = NULL; + +// +// locked block of all memory until we punch out free space +// + GETNEWBLOCK; + gvar->mm.mmhead = gvar->mm.mmnew; // this will allways be the first node + gvar->mm.mmnew->start = 0; + gvar->mm.mmnew->length = 0xffff; + gvar->mm.mmnew->attributes = LOCKBIT; + gvar->mm.mmnew->next = NULL; + //gvar->mm.mmnew->useptr = peeonself; + gvar->mm.mmrover = gvar->mm.mmhead; + + //printf(" %x\n", peeonself); + //printf(" %x\n", *peeonself); +// +// get all available near conventional memory segments +// +#ifdef __WATCOMC__ + _nheapgrow(); + length=(dword)_memavl();//(dword)GetFreeSize(); + //huge start = (void huge *)(gvar->mm.nearheap = _nmalloc(length)); + start = (void far *)(gvar->mm.nearheap = _nmalloc(length)); +#endif +#ifdef __BORLANDC__ + length=coreleft(); + //huge start = (void huge *)(gvar->mm.nearheap = malloc(length)); + start = (void far *)(gvar->mm.nearheap = malloc(length)); + printf("Borland C unique function\n"); + printf(" coreleft() %lu\n", coreleft()); +#endif + 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, gvar); + gvar->mmi.nearheap = length; + //printf("start=%Fp segstart=%x seglen=%lu len=%lu\n", start, segstart, seglength, length); + +// +// get all available far conventional memory segments +// + //printf("_FARCORELEFT %lu\n", _FCORELEFT); +#ifdef __WATCOMC__ + _fheapgrow(); +#endif +#ifdef __BORLANDC__ + printf(" farcoreleft() %lu\n", farcoreleft()); + printf(" (farcoreleft()+32)-_FCORELEFT %d\n", (sword)((farcoreleft()+32)-_FCORELEFT)); +#endif + length=_FCORELEFT;//_fcoreleft();//(dword)GetFarFreeSize();//0xffffUL*4UL; + start = gvar->mm.farheap = _fmalloc(length); + //start = gvar->mm.farheap = halloc(length, 1); + 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, gvar); + gvar->mmi.farheap = length; + gvar->mmi.mainmem = gvar->mmi.nearheap + gvar->mmi.farheap; + //printf("start=%Fp segstart=%x seglen=%lu len=%lu\n", start, segstart, seglength, length); + +#ifdef __DEBUG_PM__ +goto xmsskip; //INFO: 16_PM dose this job better +#endif + +// +// detect EMS and allocate up to 64K at page frame +// + gvar->mmi.EMSmem = 0; +//goto emsskip; //0000 + if(MML_CheckForEMS()) + { + MML_SetupEMS(gvar); // allocate space + //TODO: EMS4! AND EMS 3.2 MASSIVE DATA HANDLMENT! + MML_UseSpace(gvar->pm.emm.EMSPageFrame,(MAPPAGES)*0x4000lu, gvar); + //if(gvar->pm.emm.EMSVer<0x40) + MM_MapEMS(gvar); // map in used pages + //else + //MM_MapXEMS(gvar); // map in used pages + } + +// +// detect XMS and get upper memory blocks +// +//emsskip: + gvar->mmi.XMSmem = 0; +goto xmsskip;//0000 + if(MML_CheckForXMS(gvar)) + { + MML_SetupXMS(gvar); // allocate as many UMBs as possible + } + +// +// allocate the misc buffer +// +xmsskip: + gvar->mm.mmrover = gvar->mm.mmhead; // start looking for space after low block + + MM_GetPtr(&(gvar->mm.bufferseg),BUFFERSIZE, gvar); +} + +//========================================================================== + +/* +==================== += += MM_Shutdown += += Frees all conventional, EMS, and XMS allocated += +==================== +*/ + +void MM_Shutdown(global_game_variables_t *gvar) +{ + if(!(gvar->mm.mmstarted)) + return; + + _ffree(gvar->mm.farheap);// printf(" far freed\n"); +#ifdef __WATCOMC__ + _nfree(gvar->mm.nearheap);// printf(" near freed\n"); +#endif +#ifdef __BORLANDC__ + free(gvar->mm.nearheap);// printf(" near freed\n"); +#endif +#ifndef __DEBUG_PM__ + if(MML_CheckForEMS()){ MML_ShutdownEMS(gvar); }//printf(" EMS freed\n"); } + if(MML_CheckForXMS(gvar)){ MML_ShutdownXMS(gvar); }//printf(" XMS freed\n"); } //INFO: 16_PM dose this job better +#endif +} + +//========================================================================== + +/* +==================== += += MM_GetPtr += += Allocates an unlocked, unpurgable block += +==================== +*/ + +void MM_GetPtr (memptr *baseptr, dword size, global_game_variables_t *gvar) +{ + //huge mmblocktype huge *scan,huge *lastscan,huge *endscan,huge *purge,huge *next; + 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 + gvar->mm.mmnew->length = needed; + gvar->mm.mmnew->useptr = baseptr; + //if(gvar->mm.mmnew->useptr==NULL){ +#ifdef __DEBUG__ + printf(" MM_GetPtr\n"); + printf(" baseptr=%04x ", baseptr); printf("useptr=%04x\n", gvar->mm.mmnew->useptr); + printf(" *baseptr=%04x ", *baseptr); printf("*useptr=%04x\n", *(gvar->mm.mmnew->useptr)); + printf(" *baseptr=%Fp ", *baseptr); printf("*useptr=%Fp\n", *(gvar->mm.mmnew->useptr)); +#endif + //exit(-5); } + gvar->mm.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 && gvar->mm.mmrover == gvar->mm.mmhead) + search++; + + switch (search) + { + case 0: + lastscan = gvar->mm.mmrover; + scan = gvar->mm.mmrover->next; + endscan = NULL; + break; + case 1: + lastscan = gvar->mm.mmhead; + scan = gvar->mm.mmhead->next; + endscan = gvar->mm.mmrover; + break; + case 2: + MM_SortMem (gvar); + lastscan = gvar->mm.mmhead; + scan = gvar->mm.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 = gvar->mm.mmnew; + gvar->mm.mmnew->start = *(unsigned *)baseptr = startseg; + gvar->mm.mmnew->next = scan; + while ( purge != scan) + { // free the purgable block + next = purge->next; + FREEBLOCK(purge); + purge = next; // purge another if not at scan + } + gvar->mm.mmrover = gvar->mm.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 (gvar->mm.bombonerror) + { +#ifdef __WATCOMC__ + //heapdump(); +#endif + printf(OUT_OF_MEM_MSG,(size-gvar->mmi.nearheap)); + printf("for stability reasons the program will shut down! wwww\n"); + MM_Shutdown(gvar); + exit(-1); + } + else + gvar->mm.mmerror = true; +} + +//========================================================================== + +/* +==================== += += MM_FreePtr += += Allocates an unlocked, unpurgable block += +==================== +*/ + +void MM_FreePtr(memptr *baseptr, global_game_variables_t *gvar) +{ + //huge mmblocktype huge *scan,huge *last; + mmblocktype far *scan,far *last; + + last = gvar->mm.mmhead; + scan = last->next; + + if(baseptr == gvar->mm.mmrover->useptr) // removed the last allocated block + gvar->mm.mmrover = gvar->mm.mmhead; + + while(scan->useptr != baseptr && scan) + { + last = scan; + scan = scan->next; + } + + if(!scan) + { + printf("MM_FreePtr: Block not found!\n"); + 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, global_game_variables_t *gvar) +{ + //huge mmblocktype huge *start; + mmblocktype far *start; + + start = gvar->mm.mmrover; + + do + { + if(gvar->mm.mmrover->useptr == baseptr) + break; + + gvar->mm.mmrover = gvar->mm.mmrover->next; + + if(!gvar->mm.mmrover) + gvar->mm.mmrover = gvar->mm.mmhead; + else if(gvar->mm.mmrover == start) + { +#ifdef __DEBUG_PM__ + printf("\nstart->useptr gvar->mm.mmhead->useptr\n"); + printf(" %Fp %Fp\n", start->useptr, gvar->mm.mmhead->useptr); + printf("& %Fp %Fp\n", &(start->useptr), &(gvar->mm.mmhead->useptr)); + printf("baseptr gvar->mm.mmrover->useptr\n"); + printf(" %Fp %Fp\n", baseptr, gvar->mm.mmrover->useptr); + printf("& %Fp %Fp\n", &(baseptr), &(gvar->mm.mmrover->useptr)); + printf("* %Fp %Fp\n", *(baseptr), *(gvar->mm.mmrover->useptr)); + printf("start gvar->mm.mmrover gvar->mm.mmrover->next\n"); + printf(" %Fp %Fp %Fp\n", start, gvar->mm.mmrover, gvar->mm.mmrover->next); + printf("& %Fp %Fp %Fp\n", &start, &gvar->mm.mmrover, gvar->mm.mmrover->next); + getch(); + MM_ShowMemory(gvar); + MM_DumpData(gvar); + MM_Report_(gvar); + getch(); +#endif + Quit("MM_SetPurge: Block not found!"); + return; + } + + } while(1); + + gvar->mm.mmrover->attributes &= ~PURGEBITS; + gvar->mm.mmrover->attributes |= purge; +} + +//========================================================================== + +/* +===================== += += MM_SetLock += += Locks / unlocks the block += +===================== +*/ + +void MM_SetLock(memptr *baseptr, boolean locked, global_game_variables_t *gvar) +{ + //huge mmblocktype huge *start; + mmblocktype far *start; + + start = gvar->mm.mmrover; + + do + { + if(gvar->mm.mmrover->useptr == baseptr) + break; + + gvar->mm.mmrover = gvar->mm.mmrover->next; + + if(!gvar->mm.mmrover) + gvar->mm.mmrover = gvar->mm.mmhead; + else if(gvar->mm.mmrover == start) + { + Quit("MM_SetLock: Block not found!"); + //return; + } + + } while(1); + + gvar->mm.mmrover->attributes &= ~LOCKBIT; + gvar->mm.mmrover->attributes |= locked*LOCKBIT; +} + +//========================================================================== + +/* +===================== += += MM_SortMem += += Throws out all purgable stuff and compresses movable blocks += +===================== +*/ + +void MM_SortMem(global_game_variables_t *gvar) +{ + //huge mmblocktype huge *scan,huge *last,huge *next; + 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 = gvar->mm.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); + //MM_FreeBlock(scan, gvar); + 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 + } + + gvar->mm.mmrover = gvar->mm.mmhead; + + if(aftersort) + aftersort(); + +// VW_ColorBorder (oldborder); + +/*++++ if(playing) + MM_SetLock(&(memptr)audiosegs[playing],false);*/ +} + +//========================================================================== + +/* +===================== += += MM_ShowMemory += +===================== +*/ + +void MM_ShowMemory(global_game_variables_t *gvar) +{ + //huge mmblocktype huge *scan; + mmblocktype far *scan; + word temp; + sdword end,owner; + //word chx,chy; + word w; + //dword wwww; + byte scratch[160],scratch0[4096],scratch1[160],str[16]; + //byte d = '#'; +//**** VW_SetDefaultColors(); +//**** VW_SetLineWidth(40); +//++++mh temp = bufferofs; +//++++mh bufferofs = 0; +//**** VW_SetScreen (0,0); + scan = gvar->mm.mmhead; + end = -1; + + CA_OpenDebug (gvar); + w=0; + while(scan) + { + strcpy(scratch, AARESET); + if(scan->attributes & PURGEBITS) + strcpy(scratch0, AAMAGENTA); // dark purple = purgable + else + strcpy(scratch0, AABLUE); // medium blue = non purgable + if(scan->attributes & LOCKBIT) + strcpy(scratch0, AARED); // red = locked + if(scan->start<=end) + { + printf("\nend==%d\n\n", end); + strcat(scratch, "MM_ShowMemory: Memory block order currupted!\n"); + strcat(scratch, "End's Size: "); + ultoa (end,str,10); + strcat (scratch,str); + strcat(scratch, "\nscan->start's Size: "); + ultoa (scan->start,str,10); + strcat (scratch,str); + write(gvar->handle.debughandle,scratch,strlen(scratch)); + //modexprint(&page, chx, chy, 1, 0, 24, "\nMM_ShowMemory: Memory block order currupted!\n"); + break; + } + end = scan->start+(scan->length)-1; +//++++ chy = scan->start/320; +//++++ chx = scan->start%320; + //modexhlin(page, scan->start, (unsigned)end, chy, color); + //for(chx=scan->start;chx+4>=(word)end;chx+=4) + //{ +//++++ modexClearRegion(page, chx, chy, 4, 4, color); + //} +//++++ VW_Hlin(scan->start,(unsigned)end,0,color); + for(w=(scan->start)/80;w<=end/80;w++) + { + //printf("+ %u %lu\n", w, scan->length); + strcat(scratch0, "+"); + } + //++==++==optional strcat(scratch0, AARESET); strcat(scratch0, AAGREY); strcat(scratch0,"_"); +//++++ VW_Plot(scan->start,0,15); +//++++ modexClearRegion(page, chx, chy, 4, 4, 15); +//++++ VW_Hlin(end+1,scan->next->start,0,0); // black = free + + //wwww=(dword)(scan->next->start)-(dword)scan->start; + //wwww=(dword)scan->start+(dword)(scan->next->start); + if (scan->next && scan->next->start >= end+1) + { + strcat(scratch0, AARESET); + //++==++==optional strcat(scratch0, "\n"); + strcat(scratch0,AAGREEN); + for(w=(end+1)/80;w<=((scan->next->start-scan->start)/80);w++) + //for(w=(wwww)/80;w<=((end+1)/80);w++) + //for(w=(end+1)/80;w<=((wwww)/80);w++) + { + //printf("0 %x %u %lu\n", scan->next->start, w, scan->length); + strcat(scratch0,"0"); + } + //printf("==================\n"); + //printf("w=%u wwww=%lu start=%04x next=%04x end=%lu\n", w/80, wwww/80, scan->start, (scan->next->start), end+1); + //printf("==================\n"); + strcat(scratch0, "\n"); + //getch(); + }/*else {//if(scan->next->start <= scan->start){ + scan->next->start=scan->start+0x1000; + wwww=(dword)(scan->next->start)-(dword)scan->start; + strcat(scratch0, AARESET); + strcat(scratch0, "\n"); + strcat(scratch0,AAGREEN); + for(w=(end+1);w<=(0x1000/80);w++) + { + //printf("0 %x %x %u\n", scan->start, w); + strcat(scratch0,"0"); + } + printf("================\n"); + printf("w=%x start=%x next=%x end=%u %lu\n", w, scan->start, (scan->next->start), end+1, wwww); + printf("================\n"); + getch(); + }*/ + strcat(scratch0, AARESET); + //strcat(scratch0,"\n"); + //for(chx=scan->next->start;chx+4>=(word)end+1;chx+=4) + //{ +// chx+=scan->next->start; +// modexClearRegion(page, chx, chy, 4, 4, 2); + //} + //modexhlin(page, end+1,scan->next->start, chy, 0); +/* y = scan->start/320; + x = scan->start%320; + VW_Hlin(x,x+end,y,color); + VW_Plot(x,y,15);*/ +//++++ VW_Hlin(x+end+1,x+(scan->next->start-scan->start),y,0); // black = free + strcat(scratch,"Seg:"); + ultoa (scan->start,str,16); + strcat (scratch,str); + strcat (scratch,"\tSize:"); + ultoa ((unsigned)scan->length,str,10); + strcat (scratch,str); + strcat (scratch,"\tOwner:0x"); + owner = (unsigned)scan->useptr; + ultoa (owner,str,16); + strcat (scratch,str); + strcat (scratch,"\n"); + write(gvar->handle.debughandle,scratch,strlen(scratch)); + write(gvar->handle.debughandle,scratch0,strlen(scratch0)); +//modexprint(page, chx, chy, 1, 0, 24, &scratch); +//++++chy+=4; +//fprintf(stdout, "%s", scratch); + + scan = scan->next; + } + /*strcpy(scratch1, AARESET); + strcat(scratch1, "========================================\n"); + strcat(scratch1, "near= "); + ultoa (*(gvar->mm.nearheap),str,10); + strcat (scratch1,str); + strcat(scratch1, " far= "); + ultoa (*(gvar->mm.farheap),str,10); + strcat (scratch1,str); + strcat(scratch1, "\n"); + //strcat(scratch1, "&near= %Fp ", &(gvar->mm.nearheap)); + //strcat(scratch1, "&far= %Fp", &(gvar->mm.farheap)); + //strcat(scratch1, "\n"); + strcat(scratch1, "========================================\n"); + write(gvar->handle.debughandle,scratch1,strlen(scratch1));*/ + + + CA_CloseDebug (gvar); + +//++++mh IN_Ack(); +//**** VW_SetLineWidth(64); +//++++mh bufferofs = temp; +} + +//========================================================================== + +/* +===================== += += MM_DumpData += +===================== +*/ + +void MM_DumpData(global_game_variables_t *gvar) +{ + //huge mmblocktype huge *scan,huge *best; + mmblocktype far *scan,far *best; + long lowest,oldlowest; + word owner; + byte lock,purge; + FILE *dumpfile; + + free(gvar->mm.nearheap); +#ifdef __BORLANDC__ + dumpfile = fopen ("mmdump.16b","w"); +#endif +#ifdef __WATCOMC__ + dumpfile = fopen ("mmdump.16w","w"); +#endif + if (!dumpfile){ + printf("MM_DumpData: Couldn't open MMDUMP.16!\n"); + return; + } + + lowest = -1; + do + { + oldlowest = lowest; + lowest = 0xffff; + + scan = gvar->mm.mmhead; + while (scan) + { + owner = (unsigned)scan->useptr; + + if (owner && owner oldlowest) + { + best = scan; + lowest = owner; + } + + scan = scan->next; + } + + if (lowest != 0xffff) + { + if (best->attributes & PURGEBITS) + purge = 'P'; + else + purge = '-'; + if (best->attributes & LOCKBIT) + lock = 'L'; + else + lock = '-'; + fprintf (dumpfile,"0x%p (%c%c) = %u\n" + ,(unsigned)lowest,lock,purge,best->length); + } + + } while (lowest != 0xffff); + + fclose(dumpfile); + printf("MMDUMP.16 created.\n"); +} + +//========================================================================== + + +/* +====================== += += MM_UnusedMemory += += Returns the total free space without purging += +====================== +*/ + +dword MM_UnusedMemory(global_game_variables_t *gvar) +{ + dword free; + //huge mmblocktype huge *scan; + mmblocktype far *scan; + + free = 0; + scan = gvar->mm.mmhead; + + while(scan->next) + { + free += scan->next->start - (scan->start + scan->length); + scan = scan->next; + } + + return free*16lu; +// return free; +} + +//========================================================================== + + +/* +====================== += += MM_TotalFree += += Returns the total free space with purging += +====================== +*/ + +dword MM_TotalFree(global_game_variables_t *gvar) +{ + dword free; + //huge mmblocktype huge *scan; + mmblocktype far *scan; + + free = 0; + scan = gvar->mm.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*16lu; +// return free; +} + +//========================================================================== + +/* +===================== += += MM_Report += +===================== +*/ + +void MM_Report_(global_game_variables_t *gvar) +{ + printf("========================================\n"); + printf(" MM_Report\n"); + printf("========================================\n"); + if(MML_CheckForEMS()) + { + printf(" LIMEMS\n"); + printf(" EMM v%x.%x available\n", gvar->pm.emm.EMSVer>>4,gvar->pm.emm.EMSVer&0x0F); + printf(" totalEMSpages: %u ", gvar->pm.emm.totalEMSpages); printf("freeEMSpages: %u\n", gvar->pm.emm.freeEMSpages); + printf(" EMSPageFrame: %x\n", gvar->pm.emm.EMSPageFrame); + } + if(MML_CheckForXMS(gvar)) + { + printf(" XMS\n"); + printf(" XMSaddr: %X\n", *XMSaddr); + } + printf("near: %lu ", gvar->mmi.nearheap); printf("far: %lu\n", gvar->mmi.farheap); if(MML_CheckForEMS()) + printf("EMSmem: %lu ", gvar->mmi.EMSmem); if(MML_CheckForXMS(gvar)) printf("XMSmem: %lu", gvar->mmi.XMSmem); printf("\n"); + //printf("mainmem: %lu\n", gvar->mmi.mainmem); + printf("Total convmem: %lu ", gvar->mmi.mainmem); printf("TotalFree: %lu ", MM_TotalFree(gvar)); printf("TotalUsed: %lu\n", gvar->mmi.mainmem+gvar->mmi.EMSmem+gvar->mmi.XMSmem+gvar->mmi.XMSmem); + printf(" UnusedMemory: %lu\n", MM_UnusedMemory(gvar)); +} + +//========================================================================== + +/* +===================== += += MM_EMSerr += +===================== +*/ + +void MM_EMSerr(byte *stri, byte err) +{ + //Returns a text string describing the error code in EMS.Error. + switch(err) + { + case 0x0: + strcat(stri, "successful"); + break; + case 0x80: + strcat(stri, "internal error"); + break; + case 0x81: + strcat(stri, "hardware malfunction"); + break; + case 0x82: + strcat(stri, "busy .. retry later"); + break; + case 0x83: + strcat(stri, "invalid handle"); + break; + case 0x84: + strcat(stri, "undefined function requested by application"); + break; + case 0x85: + strcat(stri, "no more handles available"); + break; + case 0x86: + strcat(stri, "error in save or restore of mapping context"); + break; + case 0x87: + strcat(stri, "insufficient memory pages in system"); + break; + case 0x88: + strcat(stri, "insufficient memory pages available"); + break; + case 0x89: + strcat(stri, "zero pages requested"); + break; + case 0x8A: + strcat(stri, "invalid logical page number encountered"); + break; + case 0x8B: + strcat(stri, "invalid physical page number encountered"); + break; + case 0x8C: + strcat(stri, "page-mapping hardware state save area is full"); + break; + case 0x8D: + strcat(stri, "save of mapping context failed"); + break; + case 0x8E: + strcat(stri, "restore of mapping context failed"); + break; + case 0x8F: + strcat(stri, "undefined subfunction"); + break; + case 0x90: + strcat(stri, "undefined attribute type"); + break; + case 0x91: + strcat(stri, "feature not supported"); + break; + case 0x92: + strcat(stri, "successful, but a portion of the source region has been overwritten"); + break; + case 0x93: + strcat(stri, "length of source or destination region exceeds length of region allocated to either source or destination handle"); + break; + case 0x94: + strcat(stri, "conventional and expanded memory regions overlap"); + break; + case 0x95: + strcat(stri, "offset within logical page exceeds size of logical page"); + break; + case 0x96: + strcat(stri, "region length exceeds 1 MB"); + break; + case 0x97: + strcat(stri, "source and destination EMS regions have same handle and overlap"); + break; + case 0x98: + strcat(stri, "memory source or destination type undefined"); + break; + case 0x9A: + strcat(stri, "specified alternate map register or DMA register set not supported"); + break; + case 0x9B: + strcat(stri, "all alternate map register or DMA register sets currently allocated"); + break; + case 0x9C: + strcat(stri, "alternate map register or DMA register sets not supported"); + break; + case 0x9D: + strcat(stri, "undefined or unallocated alternate map register or DMA register set"); + break; + case 0x9E: + strcat(stri, "dedicated DMA channels not supported"); + break; + case 0x9F: + strcat(stri, "specified dedicated DMA channel not supported"); + break; + case 0xA0: + strcat(stri, "no such handle name"); + break; + case 0xA1: + strcat(stri, "a handle found had no name, or duplicate handle name"); + break; + case 0xA2: + strcat(stri, "attempted to wrap around 1M conventional address space"); + break; + case 0xA3: + strcat(stri, "source array corrupted"); + break; + case 0xA4: + strcat(stri, "operating system denied access"); + break; + default: + strcat(stri, "undefined error"); + } +} + +//========================================================================== + +/* +===================== += += MM_BombOnError += +===================== +*/ + +void MM_BombOnError(boolean bomb, global_game_variables_t *gvar) +{ + gvar->mm.bombonerror = bomb; +} + +/*void MM_GetNewBlock(global_game_variables_t *gvar) +{ + if(!gvar->mm.mmfree) + MML_ClearBlock(gvar); + gvar->mm.mmnew=gvar->mm.mmfree; + gvar->mm.mmfree=gvar->mm.mmfree->next; + if(!(gvar->mm.mmnew=gvar->mm.mmfree)) + { + printf("MM_GETNEWBLOCK: No free blocks!\n"); + return; + } + gvar->mm.mmfree=gvar->mm.mmfree->next; +} + +void MM_FreeBlock(mmblocktype *x, global_game_variables_t *gvar) +{ + x->useptr=NULL; + x->next=gvar->mm.mmfree; + gvar->mm.mmfree=x; +}*/ + +/*void MM_seguin(void) +{ + __asm { + push ds + mov ax,ds + inc ax + mov ds,ax + } +} + +void MM_segude(void) +{ + __asm { + pop ds + } +}*/ + +/* +pull data from far and put it into ds var +mov ax,es:si +mov x,ax +*/ +/* +ss stack segment +sp top of stack +bp bottem of stack +*/ diff --git a/DEBUG.16B b/DEBUG.16B index 97df5039..f5605e85 100755 --- a/DEBUG.16B +++ b/DEBUG.16B @@ -1,12 +1,10 @@ -Seg:0 Size:3016 Owner:0x2065 -++++++++++++++++++++++++++++++++++++++0 -Seg:bc8 Size:256 Owner:0xcf79 +Seg:0 Size:3547 Owner:0x696c ++++++++++++++++++++++++++++++++++++++++++++++0 +Seg:ddb Size:256 Owner:0xcf85 ++++ -Seg:cc8 Size:273 Owner:0xfde -+++++0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +Seg:edb Size:273 Owner:0xfde +++++0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 Seg:9fde Size:28706 Owner:0x0  -Seg:9ffe Size:16386 Owner:0x0 -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -Seg:e000 Size:8191 Owner:0x0 -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ \ No newline at end of file +Seg:9ffe Size:24577 Owner:0x0 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ \ No newline at end of file diff --git a/DEBUG.16W b/DEBUG.16W index e42fdf08..7e2f4f13 100755 --- a/DEBUG.16W +++ b/DEBUG.16W @@ -1,8 +1,12 @@ -Seg:0 Size:8601 Owner:0x0 +Seg:0 Size:8567 Owner:0xfc7e ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++0 -Seg:2199 Size:256 Owner:0x5424 +Seg:2177 Size:256 Owner:0x5428 ++++ -Seg:280e Size:44 Owner:0x0 -+0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -Seg:b83a Size:18373 Owner:0x0 -+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ \ No newline at end of file +Seg:2277 Size:17 Owner:0x9480 ++ +Seg:27eb Size:44 Owner:0x0 +++0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +Seg:b817 Size:10217 Owner:0x0 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +Seg:e000 Size:8191 Owner:0x0 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ \ No newline at end of file diff --git a/HEAP.16W b/HEAP.16W index 11a19e83..c5de931a 100755 --- a/HEAP.16W +++ b/HEAP.16W @@ -1,71 +1,47 @@ == default == - FREE block at 2e330016 of size 18 - USED block at 2e330028 of size 136 - USED block at 2e3300b0 of size 50 - USED block at 2e3300e2 of size 50 - USED block at 2e330114 of size 50 - USED block at 2e330146 of size 50 - USED block at 2e330178 of size 50 - USED block at 2e3301aa of size 50 - USED block at 2e3301dc of size 50 - USED block at 2e33020e of size 50 - USED block at 2e330240 of size 50 - USED block at 2e330272 of size 50 - USED block at 2e3302a4 of size 50 - USED block at 2e3302d6 of size 50 - USED block at 2e330308 of size 50 - FREE block at 2e33033a of size 14 - USED block at 2e330348 of size 20 - FREE block at 2e33035c of size 7328 + USED block at 280d0016 of size 66 + USED block at 280d0058 of size 66 + FREE block at 280d009a of size 18 + USED block at 280d00ac of size 136 + USED block at 280d0134 of size 20 + FREE block at 280d0148 of size 7860 OK - end of heap == near == - USED block at 1e32a466 of size 12 - USED block at 1e32a472 of size 330 - USED block at 1e32a5bc of size 52 - USED block at 1e32a5f0 of size 20 - USED block at 1e32a604 of size 20 - USED block at 1e32a618 of size 20 - USED block at 1e32a62c of size 20 - USED block at 1e32a640 of size 20 - USED block at 1e32a654 of size 22952 + USED block at 180c94b6 of size 12 + USED block at 180c94c2 of size 332 + USED block at 180c960e of size 52 + USED block at 180c9642 of size 20 + USED block at 180c9656 of size 20 + USED block at 180c966a of size 20 + USED block at 180c967e of size 20 + USED block at 180c9692 of size 20 + USED block at 180c96a6 of size 26966 OK - end of heap == far == - USED block at 2e330016 of size 18 - USED block at 2e330028 of size 136 - USED block at 2e3300b0 of size 50 - USED block at 2e3300e2 of size 50 - USED block at 2e330114 of size 50 - USED block at 2e330146 of size 50 - USED block at 2e330178 of size 50 - USED block at 2e3301aa of size 50 - USED block at 2e3301dc of size 50 - USED block at 2e33020e of size 50 - USED block at 2e330240 of size 50 - USED block at 2e330272 of size 50 - USED block at 2e3302a4 of size 50 - USED block at 2e3302d6 of size 50 - USED block at 2e330308 of size 50 - USED block at 2e33033a of size 14 - USED block at 2e330348 of size 20 - USED block at 2e33035c of size 7328 + USED block at 280d0016 of size 66 + USED block at 280d0058 of size 66 + USED block at 280d009a of size 18 + USED block at 280d00ac of size 136 + USED block at 280d0134 of size 20 + USED block at 280d0148 of size 7860 OK - end of heap Memory Type Total Used Free ---------------- -------- -------- -------- -Default 8166 806 7360 -Near 23446 494 22952 -Far 8166 806 7360 +Default 8166 288 7878 +Near 27462 496 26966 +Far 8166 288 7878 ---------------- -------- -------- -------- -coreleft = 22950 -farcoreleft = 21944 -GetFreeSize = 64548 -GetNearFreeSize = 22952 -GetFarFreeSize = 64548 -memavl = 22950 -stackavail = 11203 +coreleft = 26964 +farcoreleft = 51072 +GetFreeSize = 24128 +GetNearFreeSize = 26966 +GetFarFreeSize = 24128 +memavl = 26964 +stackavail = 11268 diff --git a/MMDUMP.16B b/MMDUMP.16B index 5bad126273a3882136631318e8e68b81cdb942a7..b9dba4098a7462b56b9604a128c8017cdd85933e 100755 GIT binary patch literal 75 zcmXr0FfcH3u`+OTaaGXJ71UI)RWPzNH09+o07{rRTbWs!IRhnbqe=jEIJ;Sx0wov_ F5&%-f4*UQB literal 75 zcmXr0FfcH3u`+OTaaGXJ71UI)RWLF!FyQ4f07{rRTNxRcnF1wFph^IBIJ=o!0wov_ F5&%ds4zK_K diff --git a/MMDUMP.16W b/MMDUMP.16W index 86d239b00841ce04466efae3ed916a82d1f0cd6a..023a748e760120c2b35dd5d05d472d69bb9208e8 100755 GIT binary patch literal 66 zcmXr0FfcGmu`)F=vQW^_WzbZxRWRV?GJuF$nphYBMFo*WO_HtBlFd_rqUBIg0KR$+ AMF0Q* literal 22 dcmXr0FfcGmu`)F=GEvabWzbZxRWRV?0suDL1PTBE diff --git a/bcexmm.exe b/bcexmm.exe index 88bb916e0afed6d8df51f7e676ee5833b5fe2f42..ebfd740ed727432e13bf8452aa20e4eceeb46292 100755 GIT binary patch delta 37095 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ð6zDEh< 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 LOjew)JF7nc12`#o diff --git a/src/exmmtest.c b/src/exmmtest.c index aa21497e..a1e0391f 100755 --- a/src/exmmtest.c +++ b/src/exmmtest.c @@ -97,9 +97,11 @@ main(int argc, char *argv[]) } //printf("main()=%Fp start MM\n", *argv[0]); MM_Startup(&gvar); +#ifdef __DEBUG_PM__ PM_Startup(&gvar); - PM_CheckMainMem(&gvar); + //PM_CheckMainMem(&gvar); PM_UnlockMainMem(&gvar); +#endif CA_Startup(&gvar); // printf(" done!\n"); PRINTBB; @@ -144,8 +146,12 @@ for(w=0;w<2;w++) #ifdef FILEREAD } #endif + printf("bakapee1=%s\n", bakapee1); + printf("bakapee2=%s\n", bakapee2); MM_FreePtr(&bigbuffer, &gvar); +#ifdef __DEBUG_PM__ PM_Shutdown(&gvar); +#endif CA_Shutdown(&gvar); MM_Shutdown(&gvar); free(bakapee1); free(bakapee2); diff --git a/src/lib/16_head.h b/src/lib/16_head.h index 0155c81e..ec7db9f8 100755 --- a/src/lib/16_head.h +++ b/src/lib/16_head.h @@ -152,7 +152,7 @@ static word far* clockw= (word far*) 0x046C; /* 18.2hz clock */ extern int profilehandle,debughandle; //make it into game global #define __DEBUG__ -#define __DEBUG_PM__ +//0000#define __DEBUG_PM__ #define nil ((void *)0) #ifdef __BORLANDC__ @@ -199,7 +199,6 @@ int US_CheckParm(char *parm,char **strings); #ifdef __BORLANDC__ void Quit (char *error); #endif -void XMS_CALL(byte v, global_game_variables_t *gvar); byte dirchar(byte in); #endif/*_LIBHEAD_H_*/ diff --git a/src/lib/16_mm.c b/src/lib/16_mm.c index 5f5b6444..9eb93c67 100755 --- a/src/lib/16_mm.c +++ b/src/lib/16_mm.c @@ -1,1808 +1,1817 @@ -/* Catacomb Apocalypse 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 - -============================================================================= -*/ -/* - -Open Watcom port by sparky4 - -*/ -#include "src/lib/16_mm.h" -#include "src/lib/16_ca.h" -#pragma hdrstop - -#pragma warn -pro -#pragma warn -use - -/* -============================================================================= - - GLOBAL VARIABLES - -============================================================================= -*/ - -void (* beforesort) (void); -void (* aftersort) (void); -void (* XMSaddr) (void); // far pointer to XMS driver - -/* -============================================================================= - - LOCAL VARIABLES - -============================================================================= -*/ - -/* -====================== -= -= MML_CheckForEMS -= -= Routine from p36 of Extending DOS -= -======================= -*/ - -boolean MML_CheckForEMS(void) -{ - boolean emmcfems; - static char emmname[] = "EMMXXXX0"; //fix by andrius4669 - __asm { - mov dx,OFFSET 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 -#ifdef __BORLANDC__ - } -#endif - error: -#ifdef __BORLANDC__ - __asm { -#endif - // - // EMS is bad - // - mov emmcfems,0 -#ifdef __BORLANDC__ - } -#endif - End: -#ifdef __WATCOMC__ - } -#endif - return(emmcfems); -} - - -/* -====================== -= -= MML_SetupEMS -= -======================= -*/ - -byte MML_SetupEMS(global_game_variables_t *gvar) -{ - byte str[160]; - byte err; - boolean errorflag=false; - - unsigned int EMSVer = 0; - //byte EMS_status; - unsigned totalEMSpages,freeEMSpages,EMSPageFrame,EMSpagesmapped,EMSHandle; - totalEMSpages = freeEMSpages = EMSPageFrame = EMSpagesmapped = 0; - - __asm { - mov ah,EMS_STATUS - int EMS_INT // make sure EMS hardware is present - or ah,ah - //mov [EMS_status],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 - //EXPAND DONG!!!! - cmp [EMSVer],0x40 - jb low - cmp bx,[freeEMSpages] - jle getpages - mov bx,[freeEMSpages] - jmp getpages -#ifdef __BORLANDC__ - } -#endif - low: -#ifdef __BORLANDC__ - __asm { -#endif - 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 -#ifdef __BORLANDC__ - } -#endif - getpages: -#ifdef __BORLANDC__ - __asm { -#endif - 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 -#ifdef __BORLANDC__ - } -#endif - error: -#ifdef __BORLANDC__ - __asm { -#endif - mov err,ah - mov errorflag,1 - jmp End -#ifdef __BORLANDC__ - } -#endif -noEMS: -End: -#ifdef __WATCOMC__ - } -#endif - if(errorflag==true) - { - strcpy(str,"MM_SetupEMS: EMS error "); - MM_EMSerr(str, err); - printf("%s\n",str); - return err; - } - gvar->pm.emm.totalEMSpages=totalEMSpages; - gvar->pm.emm.freeEMSpages=freeEMSpages; - gvar->pm.emm.EMSPageFrame=EMSPageFrame; - gvar->pm.emm.EMSpagesmapped=EMSpagesmapped; - gvar->pm.emm.EMSHandle=EMSHandle; - gvar->pm.emm.EMSVer=EMSVer; - return 0; -} - - -/* -====================== -= -= MML_ShutdownEMS -= -======================= -*/ - -void MML_ShutdownEMS(global_game_variables_t *gvar) -{ - boolean errorflag=false; - unsigned EMSHandle=gvar->pm.emm.EMSHandle; - - if(!EMSHandle) - return; - __asm { - mov ah,EMS_FREEPAGES - mov dx,[EMSHandle] - int EMS_INT - or ah,ah - jz ok - mov errorflag,1 -#ifdef __BORLANDC__ - } -#endif - ok: -#ifdef __WATCOMC__ - } -#endif - if(errorflag==true) - Quit("MML_ShutdownEMS: Error freeing EMS!\n"); //++++ 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. -= -==================== -*/ - -byte MM_MapEMS(global_game_variables_t *gvar) -{ - byte str[160]; - unsigned EMSHandle; - byte err; - boolean errorflag=false; - int i; - EMSHandle=gvar->pm.emm.EMSHandle; - - for (i=0;i<4/*MAPPAGES*/;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 -#ifdef __BORLANDC__ - } -#endif - error: -#ifdef __BORLANDC__ - __asm { -#endif - mov err,ah - mov errorflag,1 -#ifdef __BORLANDC__ - } -#endif - End: -#ifdef __WATCOMC__ - } -#endif - if(errorflag==true) - { - strcpy(str,"MM_MapEMS: EMS error "); - MM_EMSerr(str, err); - printf("%s\n",str); - return err; - } - } - gvar->mmi.EMSmem = (i)*0x4000lu; - //printf(" gvar->mmi.EMSmem=%lu\n", gvar->mmi.EMSmem); - return 0; -} - -byte MM_MapXEMS(global_game_variables_t *gvar) -{ -//SUB EMS.MapXPages (PhysicalStart, LogicalStart, NumPages, Handle) - - //Maps up to 4 logical EMS pages to physical pages in the page frame, where: - //PhysicalStart = Physical page first logical page is mapped to - //LogicalStart = First logical page to map - //NumPages = Number of pages to map (1 to 4) - //Handle = EMS handle logical pages are allocated to - - /*//Create a buffer containing the page information -// FOR x = 0 TO NumPages - 1 -// MapInfo$ = MapInfo$ + MKI$(LogicalStart + x) + MKI$(PhysicalStart + x) -// NEXT*/ - -// Regs.ax = 0x5000 //Map the pages in the buffer -// Regs.cx = NumPages //to the pageframe -// Regs.dx = Handle -// Regs.ds = VARSEG(MapInfo$) -// Regs.si = SADD(MapInfo$) -// InterruptX 0x67, Regs, Regs -// EMS.Error = (Regs.ax AND 0xFF00&) \ 0x100 //Store the status code - -//END SUB - byte str[160]; - byte err; - word EMSHandle; - boolean errorflag=false; - int i; - EMSHandle=gvar->pm.emm.EMSHandle; - - if(gvar->pm.emm.EMSVer<0x40) - return 5; - - for (i=0;immi.EMSmem = (i)*0x4000lu; - return 0; -} - -//========================================================================== - -/* -====================== -= -= MML_CheckForXMS -= -= Check for XMM driver -= -======================= -*/ - -boolean MML_CheckForXMS(global_game_variables_t *gvar) -{ - boolean errorflag=false; - gvar->mm.numUMBs = 0; - - __asm { - mov ax,0x4300 - int 0x2f // query status of installed diver - cmp al,0x80 - je good - mov errorflag,1 -#ifdef __BORLANDC__ - } -#endif - good: -#ifdef __WATCOMC__ - } -#endif - if(errorflag==true) return false; - else return true; -} - - -/* -====================== -= -= MML_SetupXMS -= -= Try to allocate all upper memory block -= -======================= -*/ - -void MML_SetupXMS(global_game_variables_t *gvar) -{ - word 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 - //mov ax,dx // Set available Kbytes. - 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... -#ifdef __BORLANDC__ - } -#endif - gotone: -#ifdef __BORLANDC__ - __asm { -#endif - mov [base],bx - mov [size],dx -#ifdef __BORLANDC__ - } -#endif - done: -#ifdef __WATCOMC__ - } -#endif -// printf("base=%u ", base); printf("size=%u\n", size); - MML_UseSpace(base,size, gvar); - gvar->mmi.XMSmem += size*16; - gvar->mm.UMBbase[gvar->mm.numUMBs] = base; - gvar->mm.numUMBs++; - if(gvar->mm.numUMBs < MAXUMBS) - goto getmemory; -} - - -/* -====================== -= -= MML_ShutdownXMS -= -====================== -*/ - -void MML_ShutdownXMS(global_game_variables_t *gvar) -{ - int i; - unsigned base; - - for (i=0;imm.numUMBs;i++) - { - base = gvar->mm.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(word segstart, dword seglength, global_game_variables_t *gvar) -{ - //huge mmblocktype huge *scan,huge *last; - word segm=1; - word oldend; - dword segmlen; - dword extra; - - scan = last = gvar->mm.mmhead; - gvar->mm.mmrover = gvar->mm.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); - - segmlen=extra; - - //++++emsver stuff! - if(segm>1)/// || extra>=0x10000lu) - //if(extra>0xfffflu) - { - scan->blob=segm; - - //MML_UseSpace(segstart, seglength, gvar); - - printf("MML_UseSpace: Segment spans two blocks!\n"); - //} - printf("segm=%u ", segm); - printf("ex=%lu ", extra); - printf("old=%u ", oldend); - printf("start+seglen=%lu\n", segstart+seglength); - printf("segsta=%x ", segstart); - printf("len=%lu ", scan->length); - printf("seglen=%lu ", seglength); - printf("segmlen=%lu\n", segmlen); - } -//++++todo: linked list of segment! - 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; - gvar->mm.mmnew->useptr = NULL; - - gvar->mm.mmnew->next = scan->next; - scan->next = gvar->mm.mmnew; - gvar->mm.mmnew->start = segstart+seglength; - gvar->mm.mmnew->length = extra; - gvar->mm.mmnew->attributes = LOCKBIT; - }//else if(segm>0) goto segu; - -}*/ -void MML_UseSpace(word segstart, dword seglength, global_game_variables_t *gvar) -{ - mmblocktype far *scan,far *last; - word oldend; - sdword extra; - //word segm=1; - - scan = last = gvar->mm.mmhead; - gvar->mm.mmrover = gvar->mm.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; - } - -// -// find out how many blocks it spans! -// - /*for(;seglength>=0x10000;seglength-=0xFFFF) - { - //printf(" seglen=%lu\n", segmlen); - segm++; - }*/ - -// -// take the given range out of the block -// - oldend = scan->start + scan->length; - extra = oldend - (segstart+((unsigned)seglength)); - if (extra < 0) - { - printf("========================================\n"); - printf("start=%x ", scan->start); - printf("old=%u ", oldend); - printf("start+seglen=%lu\n", segstart+seglength); - printf("segsta=%x ", segstart); - printf("len=%lu ", scan->length); - printf("seglen=%lu ", seglength); - printf("\n"); - printf("MML_UseSpace: Segment spans two blocks! %d\n", extra); - printf("========================================\n"); - //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; - gvar->mm.mmnew->useptr = NULL; - - gvar->mm.mmnew->next = scan->next; - scan->next = gvar->mm.mmnew; - gvar->mm.mmnew->start = segstart+seglength; - gvar->mm.mmnew->length = extra; - gvar->mm.mmnew->attributes = LOCKBIT; - } - -} - -//========================================================================== - -/* -==================== -= -= MML_ClearBlock -= -= We are out of blocks, so free a purgable block -= -==================== -*/ - -void MML_ClearBlock(global_game_variables_t *gvar) -{ - //huge mmblocktype huge *scan,huge *last; - mmblocktype far *scan,far *last; - - scan = gvar->mm.mmhead->next; - - while(scan) - { - if(!(scan->attributes&LOCKBIT) && (scan->attributes&PURGEBITS)) - { - MM_FreePtr(scan->useptr, gvar); - return; - } - scan = scan->next; - } - - printf("MM_ClearBlock: No purgable blocks!\n"); -} - - -//========================================================================== - -/* -=================== -= -= MM_Startup -= -= Grabs all space from turbo with malloc/farmalloc -= Allocates bufferseg misc buffer -= -=================== -*/ - -void MM_Startup(global_game_variables_t *gvar) -{ - int i; - //dword length,seglength; - dword length; - //huge void huge *start; - void far *start; - word segstart,seglength,endfree; - //memptr *peeonself; - - if(gvar->mm.mmstarted) - MM_Shutdown(gvar); - - - gvar->mm.mmstarted = true; - gvar->mm.bombonerror = true; -// -// set up the linked list (everything in the free list; -// - gvar->mm.mmhead = NULL; - gvar->mm.mmfree = &(gvar->mm.mmblocks[0]); - for(i=0;imm.mmblocks[i].next = &(gvar->mm.mmblocks[i+1]); - } - gvar->mm.mmblocks[i].next = NULL; - -// -// locked block of all memory until we punch out free space -// - GETNEWBLOCK; - gvar->mm.mmhead = gvar->mm.mmnew; // this will allways be the first node - gvar->mm.mmnew->start = 0; - gvar->mm.mmnew->length = 0xffff; - gvar->mm.mmnew->attributes = LOCKBIT; - gvar->mm.mmnew->next = NULL; - //gvar->mm.mmnew->useptr = peeonself; - gvar->mm.mmrover = gvar->mm.mmhead; - - //printf(" %x\n", peeonself); - //printf(" %x\n", *peeonself); -// -// get all available near conventional memory segments -// -#ifdef __WATCOMC__ - _nheapgrow(); - length=(dword)_memavl();//(dword)GetFreeSize(); - //huge start = (void huge *)(gvar->mm.nearheap = _nmalloc(length)); - start = (void far *)(gvar->mm.nearheap = _nmalloc(length)); -#endif -#ifdef __BORLANDC__ - length=coreleft(); - //huge start = (void huge *)(gvar->mm.nearheap = malloc(length)); - start = (void far *)(gvar->mm.nearheap = malloc(length)); - printf("Borland C unique function\n"); - printf(" coreleft() %lu\n", coreleft()); -#endif - 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, gvar); - gvar->mmi.nearheap = length; - //printf("start=%Fp segstart=%x seglen=%lu len=%lu\n", start, segstart, seglength, length); - -// -// get all available far conventional memory segments -// - //printf("_FARCORELEFT %lu\n", _FCORELEFT); -#ifdef __WATCOMC__ - _fheapgrow(); -#endif -#ifdef __BORLANDC__ - printf(" farcoreleft() %lu\n", farcoreleft()); - printf(" (farcoreleft()+32)-_FCORELEFT %d\n", (sword)((farcoreleft()+32)-_FCORELEFT)); -#endif - length=_FCORELEFT;//_fcoreleft();//(dword)GetFarFreeSize();//0xffffUL*4UL; - start = gvar->mm.farheap = _fmalloc(length); - //start = gvar->mm.farheap = halloc(length, 1); - 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, gvar); - gvar->mmi.farheap = length; - gvar->mmi.mainmem = gvar->mmi.nearheap + gvar->mmi.farheap; - //printf("start=%Fp segstart=%x seglen=%lu len=%lu\n", start, segstart, seglength, length); - -goto xmsskip; //INFO: 16_PM dose this job better - -// -// detect EMS and allocate up to 64K at page frame -// - gvar->mmi.EMSmem = 0; -//goto emsskip; //0000 - if(MML_CheckForEMS()) - { - MML_SetupEMS(gvar); // allocate space - //TODO: EMS4! AND EMS 3.2 MASSIVE DATA HANDLMENT! - MML_UseSpace(gvar->pm.emm.EMSPageFrame,(MAPPAGES)*0x4000lu, gvar); - //if(gvar->pm.emm.EMSVer<0x40) - MM_MapEMS(gvar); // map in used pages - //else - //MM_MapXEMS(gvar); // map in used pages - } - -// -// detect XMS and get upper memory blocks -// -//emsskip: - gvar->mmi.XMSmem = 0; -//goto xmsskip;//0000 - if(MML_CheckForXMS(gvar)) - { - MML_SetupXMS(gvar); // allocate as many UMBs as possible - } - -// -// allocate the misc buffer -// -xmsskip: - gvar->mm.mmrover = gvar->mm.mmhead; // start looking for space after low block - - MM_GetPtr(&(gvar->mm.bufferseg),BUFFERSIZE, gvar); -} - -//========================================================================== - -/* -==================== -= -= MM_Shutdown -= -= Frees all conventional, EMS, and XMS allocated -= -==================== -*/ - -void MM_Shutdown(global_game_variables_t *gvar) -{ - if(!(gvar->mm.mmstarted)) - return; - - _ffree(gvar->mm.farheap);// printf(" far freed\n"); -#ifdef __WATCOMC__ - _nfree(gvar->mm.nearheap);// printf(" near freed\n"); -#endif -#ifdef __BORLANDC__ - free(gvar->mm.nearheap);// printf(" near freed\n"); -#endif - if(MML_CheckForEMS()){ MML_ShutdownEMS(gvar); }//printf(" EMS freed\n"); } - if(MML_CheckForXMS(gvar)){ MML_ShutdownXMS(gvar); }//printf(" XMS freed\n"); } -} - -//========================================================================== - -/* -==================== -= -= MM_GetPtr -= -= Allocates an unlocked, unpurgable block -= -==================== -*/ - -void MM_GetPtr (memptr *baseptr, dword size, global_game_variables_t *gvar) -{ - //huge mmblocktype huge *scan,huge *lastscan,huge *endscan,huge *purge,huge *next; - 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 - gvar->mm.mmnew->length = needed; - gvar->mm.mmnew->useptr = baseptr; - //if(gvar->mm.mmnew->useptr==NULL){ -#ifdef __DEBUG__ - printf(" MM_GetPtr\n"); - printf(" baseptr=%04x ", baseptr); printf("useptr=%04x\n", gvar->mm.mmnew->useptr); - printf(" *baseptr=%04x ", *baseptr); printf("*useptr=%04x\n", *(gvar->mm.mmnew->useptr)); - printf(" *baseptr=%Fp ", *baseptr); printf("*useptr=%Fp\n", *(gvar->mm.mmnew->useptr)); -#endif - //exit(-5); } - gvar->mm.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 && gvar->mm.mmrover == gvar->mm.mmhead) - search++; - - switch (search) - { - case 0: - lastscan = gvar->mm.mmrover; - scan = gvar->mm.mmrover->next; - endscan = NULL; - break; - case 1: - lastscan = gvar->mm.mmhead; - scan = gvar->mm.mmhead->next; - endscan = gvar->mm.mmrover; - break; - case 2: - MM_SortMem (gvar); - lastscan = gvar->mm.mmhead; - scan = gvar->mm.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 = gvar->mm.mmnew; - gvar->mm.mmnew->start = *(unsigned *)baseptr = startseg; - gvar->mm.mmnew->next = scan; - while ( purge != scan) - { // free the purgable block - next = purge->next; - FREEBLOCK(purge); - purge = next; // purge another if not at scan - } - gvar->mm.mmrover = gvar->mm.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 (gvar->mm.bombonerror) - { -#ifdef __WATCOMC__ - //heapdump(); -#endif - printf(OUT_OF_MEM_MSG,(size-gvar->mmi.nearheap)); - printf("for stability reasons the program will shut down! wwww\n"); - MM_Shutdown(gvar); - exit(-1); - } - else - gvar->mm.mmerror = true; -} - -//========================================================================== - -/* -==================== -= -= MM_FreePtr -= -= Allocates an unlocked, unpurgable block -= -==================== -*/ - -void MM_FreePtr(memptr *baseptr, global_game_variables_t *gvar) -{ - //huge mmblocktype huge *scan,huge *last; - mmblocktype far *scan,far *last; - - last = gvar->mm.mmhead; - scan = last->next; - - if(baseptr == gvar->mm.mmrover->useptr) // removed the last allocated block - gvar->mm.mmrover = gvar->mm.mmhead; - - while(scan->useptr != baseptr && scan) - { - last = scan; - scan = scan->next; - } - - if(!scan) - { - printf("MM_FreePtr: Block not found!\n"); - 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, global_game_variables_t *gvar) -{ - mmblocktype huge *start; - //mmblocktype far *start; - - start = gvar->mm.mmrover; - - do - { - if(gvar->mm.mmrover->useptr == baseptr) - break; - - gvar->mm.mmrover = gvar->mm.mmrover->next; - - if(!gvar->mm.mmrover) - gvar->mm.mmrover = gvar->mm.mmhead; - else if(gvar->mm.mmrover == start) - { -#ifdef __DEBUG_PM__ - printf("\n\nstart->useptr gvar->mm.mmhead->useptr\n"); - printf(" %Fp %Fp\n", start->useptr, gvar->mm.mmhead->useptr); - printf("& %Fp %Fp\n", &(start->useptr), &(gvar->mm.mmhead->useptr)); - printf("baseptr gvar->mm.mmrover->useptr\n"); - printf(" %Fp %Fp\n", baseptr, gvar->mm.mmrover->useptr); - printf("& %Fp %Fp\n", &(baseptr), &(gvar->mm.mmrover->useptr)); - printf("* %Fp %Fp\n", *(baseptr), *(gvar->mm.mmrover->useptr)); - printf("start gvar->mm.mmrover gvar->mm.mmrover->next\n"); - printf(" %Fp %Fp %Fp\n", start, gvar->mm.mmrover, gvar->mm.mmrover->next); - printf("& %Fp %Fp %Fp\n", &start, &gvar->mm.mmrover, gvar->mm.mmrover->next); - getch(); - MM_ShowMemory(gvar); - MM_DumpData(gvar); - MM_Report_(gvar); - getch(); -#endif - Quit("MM_SetPurge: Block not found!"); - return; - } - - } while(1); - - gvar->mm.mmrover->attributes &= ~PURGEBITS; - gvar->mm.mmrover->attributes |= purge; -} - -//========================================================================== - -/* -===================== -= -= MM_SetLock -= -= Locks / unlocks the block -= -===================== -*/ - -void MM_SetLock(memptr *baseptr, boolean locked, global_game_variables_t *gvar) -{ - //huge mmblocktype huge *start; - mmblocktype far *start; - - start = gvar->mm.mmrover; - - do - { - if(gvar->mm.mmrover->useptr == baseptr) - break; - - gvar->mm.mmrover = gvar->mm.mmrover->next; - - if(!gvar->mm.mmrover) - gvar->mm.mmrover = gvar->mm.mmhead; - else if(gvar->mm.mmrover == start) - { - Quit("MM_SetLock: Block not found!"); - //return; - } - - } while(1); - - gvar->mm.mmrover->attributes &= ~LOCKBIT; - gvar->mm.mmrover->attributes |= locked*LOCKBIT; -} - -//========================================================================== - -/* -===================== -= -= MM_SortMem -= -= Throws out all purgable stuff and compresses movable blocks -= -===================== -*/ - -void MM_SortMem(global_game_variables_t *gvar) -{ - //huge mmblocktype huge *scan,huge *last,huge *next; - 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 = gvar->mm.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); - //MM_FreeBlock(scan, gvar); - 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 - } - - gvar->mm.mmrover = gvar->mm.mmhead; - - if(aftersort) - aftersort(); - -// VW_ColorBorder (oldborder); - -/*++++ if(playing) - MM_SetLock(&(memptr)audiosegs[playing],false);*/ -} - -//========================================================================== - -/* -===================== -= -= MM_ShowMemory -= -===================== -*/ - -void MM_ShowMemory(global_game_variables_t *gvar) -{ - //huge mmblocktype huge *scan; - mmblocktype far *scan; - word temp; - sdword end,owner; - //word chx,chy; - word w; - //dword wwww; - byte scratch[160],scratch0[4096],scratch1[160],str[16]; - //byte d = '#'; -//**** VW_SetDefaultColors(); -//**** VW_SetLineWidth(40); -//++++mh temp = bufferofs; -//++++mh bufferofs = 0; -//**** VW_SetScreen (0,0); - scan = gvar->mm.mmhead; - end = -1; - - CA_OpenDebug (gvar); - w=0; - while(scan) - { - strcpy(scratch, AARESET); - if(scan->attributes & PURGEBITS) - strcpy(scratch0, AAMAGENTA); // dark purple = purgable - else - strcpy(scratch0, AABLUE); // medium blue = non purgable - if(scan->attributes & LOCKBIT) - strcpy(scratch0, AARED); // red = locked - if(scan->start<=end) - { - printf("\nend==%d\n\n", end); - strcat(scratch, "MM_ShowMemory: Memory block order currupted!\n"); - strcat(scratch, "End's Size: "); - ultoa (end,str,10); - strcat (scratch,str); - strcat(scratch, "\nscan->start's Size: "); - ultoa (scan->start,str,10); - strcat (scratch,str); - write(gvar->handle.debughandle,scratch,strlen(scratch)); - //modexprint(&page, chx, chy, 1, 0, 24, "\nMM_ShowMemory: Memory block order currupted!\n"); - break; - } - end = scan->start+(scan->length)-1; -//++++ chy = scan->start/320; -//++++ chx = scan->start%320; - //modexhlin(page, scan->start, (unsigned)end, chy, color); - //for(chx=scan->start;chx+4>=(word)end;chx+=4) - //{ -//++++ modexClearRegion(page, chx, chy, 4, 4, color); - //} -//++++ VW_Hlin(scan->start,(unsigned)end,0,color); - for(w=(scan->start)/80;w<=end/80;w++) - { - //printf("+ %u %lu\n", w, scan->length); - strcat(scratch0, "+"); - } - //++==++==optional strcat(scratch0, AARESET); strcat(scratch0, AAGREY); strcat(scratch0,"_"); -//++++ VW_Plot(scan->start,0,15); -//++++ modexClearRegion(page, chx, chy, 4, 4, 15); -//++++ VW_Hlin(end+1,scan->next->start,0,0); // black = free - - //wwww=(dword)(scan->next->start)-(dword)scan->start; - //wwww=(dword)scan->start+(dword)(scan->next->start); - if (scan->next && scan->next->start >= end+1) - { - strcat(scratch0, AARESET); - //++==++==optional strcat(scratch0, "\n"); - strcat(scratch0,AAGREEN); - for(w=(end+1)/80;w<=((scan->next->start-scan->start)/80);w++) - //for(w=(wwww)/80;w<=((end+1)/80);w++) - //for(w=(end+1)/80;w<=((wwww)/80);w++) - { - //printf("0 %x %u %lu\n", scan->next->start, w, scan->length); - strcat(scratch0,"0"); - } - //printf("==================\n"); - //printf("w=%u wwww=%lu start=%04x next=%04x end=%lu\n", w/80, wwww/80, scan->start, (scan->next->start), end+1); - //printf("==================\n"); - strcat(scratch0, "\n"); - //getch(); - }/*else {//if(scan->next->start <= scan->start){ - scan->next->start=scan->start+0x1000; - wwww=(dword)(scan->next->start)-(dword)scan->start; - strcat(scratch0, AARESET); - strcat(scratch0, "\n"); - strcat(scratch0,AAGREEN); - for(w=(end+1);w<=(0x1000/80);w++) - { - //printf("0 %x %x %u\n", scan->start, w); - strcat(scratch0,"0"); - } - printf("================\n"); - printf("w=%x start=%x next=%x end=%u %lu\n", w, scan->start, (scan->next->start), end+1, wwww); - printf("================\n"); - getch(); - }*/ - strcat(scratch0, AARESET); - //strcat(scratch0,"\n"); - //for(chx=scan->next->start;chx+4>=(word)end+1;chx+=4) - //{ -// chx+=scan->next->start; -// modexClearRegion(page, chx, chy, 4, 4, 2); - //} - //modexhlin(page, end+1,scan->next->start, chy, 0); -/* y = scan->start/320; - x = scan->start%320; - VW_Hlin(x,x+end,y,color); - VW_Plot(x,y,15);*/ -//++++ VW_Hlin(x+end+1,x+(scan->next->start-scan->start),y,0); // black = free - strcat(scratch,"Seg:"); - ultoa (scan->start,str,16); - strcat (scratch,str); - strcat (scratch,"\tSize:"); - ultoa ((unsigned)scan->length,str,10); - strcat (scratch,str); - strcat (scratch,"\tOwner:0x"); - owner = (unsigned)scan->useptr; - ultoa (owner,str,16); - strcat (scratch,str); - strcat (scratch,"\n"); - write(gvar->handle.debughandle,scratch,strlen(scratch)); - write(gvar->handle.debughandle,scratch0,strlen(scratch0)); -//modexprint(page, chx, chy, 1, 0, 24, &scratch); -//++++chy+=4; -//fprintf(stdout, "%s", scratch); - - scan = scan->next; - } - /*strcpy(scratch1, AARESET); - strcat(scratch1, "========================================\n"); - strcat(scratch1, "near= "); - ultoa (*(gvar->mm.nearheap),str,10); - strcat (scratch1,str); - strcat(scratch1, " far= "); - ultoa (*(gvar->mm.farheap),str,10); - strcat (scratch1,str); - strcat(scratch1, "\n"); - //strcat(scratch1, "&near= %Fp ", &(gvar->mm.nearheap)); - //strcat(scratch1, "&far= %Fp", &(gvar->mm.farheap)); - //strcat(scratch1, "\n"); - strcat(scratch1, "========================================\n"); - write(gvar->handle.debughandle,scratch1,strlen(scratch1));*/ - - - CA_CloseDebug (gvar); - -//++++mh IN_Ack(); -//**** VW_SetLineWidth(64); -//++++mh bufferofs = temp; -} - -//========================================================================== - -/* -===================== -= -= MM_DumpData -= -===================== -*/ - -void MM_DumpData(global_game_variables_t *gvar) -{ - //huge mmblocktype huge *scan,huge *best; - mmblocktype far *scan,far *best; - long lowest,oldlowest; - word owner; - byte lock,purge; - FILE *dumpfile; - - free(gvar->mm.nearheap); -#ifdef __BORLANDC__ - dumpfile = fopen ("mmdump.16b","w"); -#endif -#ifdef __WATCOMC__ - dumpfile = fopen ("mmdump.16w","w"); -#endif - if (!dumpfile){ - printf("MM_DumpData: Couldn't open MMDUMP.16!\n"); - return; - } - - lowest = -1; - do - { - oldlowest = lowest; - lowest = 0xffff; - - scan = gvar->mm.mmhead; - while (scan) - { - owner = (unsigned)scan->useptr; - - if (owner && owner oldlowest) - { - best = scan; - lowest = owner; - } - - scan = scan->next; - } - - if (lowest != 0xffff) - { - if (best->attributes & PURGEBITS) - purge = 'P'; - else - purge = '-'; - if (best->attributes & LOCKBIT) - lock = 'L'; - else - lock = '-'; - fprintf (dumpfile,"0x%p (%c%c) = %u\n" - ,(unsigned)lowest,lock,purge,best->length); - } - - } while (lowest != 0xffff); - - fclose(dumpfile); - printf("MMDUMP.16 created.\n"); -} - -//========================================================================== - - -/* -====================== -= -= MM_UnusedMemory -= -= Returns the total free space without purging -= -====================== -*/ - -dword MM_UnusedMemory(global_game_variables_t *gvar) -{ - dword free; - //huge mmblocktype huge *scan; - mmblocktype far *scan; - - free = 0; - scan = gvar->mm.mmhead; - - while(scan->next) - { - free += scan->next->start - (scan->start + scan->length); - scan = scan->next; - } - - return free*16lu; -// return free; -} - -//========================================================================== - - -/* -====================== -= -= MM_TotalFree -= -= Returns the total free space with purging -= -====================== -*/ - -dword MM_TotalFree(global_game_variables_t *gvar) -{ - dword free; - //huge mmblocktype huge *scan; - mmblocktype far *scan; - - free = 0; - scan = gvar->mm.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*16lu; -// return free; -} - -//========================================================================== - -/* -===================== -= -= MM_Report -= -===================== -*/ - -void MM_Report_(global_game_variables_t *gvar) -{ - printf("========================================\n"); - printf(" MM_Report\n"); - printf("========================================\n"); - if(MML_CheckForEMS()) - { - printf(" LIMEMS\n"); - printf(" EMM v%x.%x available\n", gvar->pm.emm.EMSVer>>4,gvar->pm.emm.EMSVer&0x0F); - printf(" totalEMSpages: %u ", gvar->pm.emm.totalEMSpages); printf("freeEMSpages: %u\n", gvar->pm.emm.freeEMSpages); - printf(" EMSPageFrame: %x\n", gvar->pm.emm.EMSPageFrame); - } - if(MML_CheckForXMS(gvar)) - { - printf(" XMS\n"); - printf(" XMSaddr: %X\n", *XMSaddr); - } - printf("near: %lu ", gvar->mmi.nearheap); printf("far: %lu\n", gvar->mmi.farheap); if(MML_CheckForEMS()) - printf("EMSmem: %lu ", gvar->mmi.EMSmem); if(MML_CheckForXMS(gvar)) printf("XMSmem: %lu", gvar->mmi.XMSmem); printf("\n"); - //printf("mainmem: %lu\n", gvar->mmi.mainmem); - printf("Total convmem: %lu ", gvar->mmi.mainmem); printf("TotalFree: %lu ", MM_TotalFree(gvar)); printf("TotalUsed: %lu\n", gvar->mmi.mainmem+gvar->mmi.EMSmem+gvar->mmi.XMSmem+gvar->mmi.XMSmem); - printf(" UnusedMemory: %lu\n", MM_UnusedMemory(gvar)); -} - -//========================================================================== - -/* -===================== -= -= MM_EMSerr -= -===================== -*/ - -void MM_EMSerr(byte *stri, byte err) -{ - //Returns a text string describing the error code in EMS.Error. - switch(err) - { - case 0x0: - strcat(stri, "successful"); - break; - case 0x80: - strcat(stri, "internal error"); - break; - case 0x81: - strcat(stri, "hardware malfunction"); - break; - case 0x82: - strcat(stri, "busy .. retry later"); - break; - case 0x83: - strcat(stri, "invalid handle"); - break; - case 0x84: - strcat(stri, "undefined function requested by application"); - break; - case 0x85: - strcat(stri, "no more handles available"); - break; - case 0x86: - strcat(stri, "error in save or restore of mapping context"); - break; - case 0x87: - strcat(stri, "insufficient memory pages in system"); - break; - case 0x88: - strcat(stri, "insufficient memory pages available"); - break; - case 0x89: - strcat(stri, "zero pages requested"); - break; - case 0x8A: - strcat(stri, "invalid logical page number encountered"); - break; - case 0x8B: - strcat(stri, "invalid physical page number encountered"); - break; - case 0x8C: - strcat(stri, "page-mapping hardware state save area is full"); - break; - case 0x8D: - strcat(stri, "save of mapping context failed"); - break; - case 0x8E: - strcat(stri, "restore of mapping context failed"); - break; - case 0x8F: - strcat(stri, "undefined subfunction"); - break; - case 0x90: - strcat(stri, "undefined attribute type"); - break; - case 0x91: - strcat(stri, "feature not supported"); - break; - case 0x92: - strcat(stri, "successful, but a portion of the source region has been overwritten"); - break; - case 0x93: - strcat(stri, "length of source or destination region exceeds length of region allocated to either source or destination handle"); - break; - case 0x94: - strcat(stri, "conventional and expanded memory regions overlap"); - break; - case 0x95: - strcat(stri, "offset within logical page exceeds size of logical page"); - break; - case 0x96: - strcat(stri, "region length exceeds 1 MB"); - break; - case 0x97: - strcat(stri, "source and destination EMS regions have same handle and overlap"); - break; - case 0x98: - strcat(stri, "memory source or destination type undefined"); - break; - case 0x9A: - strcat(stri, "specified alternate map register or DMA register set not supported"); - break; - case 0x9B: - strcat(stri, "all alternate map register or DMA register sets currently allocated"); - break; - case 0x9C: - strcat(stri, "alternate map register or DMA register sets not supported"); - break; - case 0x9D: - strcat(stri, "undefined or unallocated alternate map register or DMA register set"); - break; - case 0x9E: - strcat(stri, "dedicated DMA channels not supported"); - break; - case 0x9F: - strcat(stri, "specified dedicated DMA channel not supported"); - break; - case 0xA0: - strcat(stri, "no such handle name"); - break; - case 0xA1: - strcat(stri, "a handle found had no name, or duplicate handle name"); - break; - case 0xA2: - strcat(stri, "attempted to wrap around 1M conventional address space"); - break; - case 0xA3: - strcat(stri, "source array corrupted"); - break; - case 0xA4: - strcat(stri, "operating system denied access"); - break; - default: - strcat(stri, "undefined error"); - } -} - -//========================================================================== - -/* -===================== -= -= MM_BombOnError -= -===================== -*/ - -void MM_BombOnError(boolean bomb, global_game_variables_t *gvar) -{ - gvar->mm.bombonerror = bomb; -} - -/*void MM_GetNewBlock(global_game_variables_t *gvar) -{ - if(!gvar->mm.mmfree) - MML_ClearBlock(gvar); - gvar->mm.mmnew=gvar->mm.mmfree; - gvar->mm.mmfree=gvar->mm.mmfree->next; - if(!(gvar->mm.mmnew=gvar->mm.mmfree)) - { - printf("MM_GETNEWBLOCK: No free blocks!\n"); - return; - } - gvar->mm.mmfree=gvar->mm.mmfree->next; -} - -void MM_FreeBlock(mmblocktype *x, global_game_variables_t *gvar) -{ - x->useptr=NULL; - x->next=gvar->mm.mmfree; - gvar->mm.mmfree=x; -}*/ - -void XMS_CALL(byte v, global_game_variables_t *gvar) -{ - XMSD; - //XMSDriver=gvar->pm.xmm.XMSDriver; - __asm { - mov v,ah - call [WORD PTR XMSDriver] - } -} - -/*void MM_seguin(void) -{ - __asm { - push ds - mov ax,ds - inc ax - mov ds,ax - } -} - -void MM_segude(void) -{ - __asm { - pop ds - } -}*/ - -/* -pull data from far and put it into ds var -mov ax,es:si -mov x,ax -*/ -/* -ss stack segment -sp top of stack -bp bottem of stack -*/ +/* Catacomb Apocalypse 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 + +============================================================================= +*/ +/* + +Open Watcom port by sparky4 + +*/ +#include "src/lib/16_mm.h" +#include "src/lib/16_ca.h" +#pragma hdrstop + +#pragma warn -pro +#pragma warn -use + +/* +============================================================================= + + GLOBAL VARIABLES + +============================================================================= +*/ + +void (* beforesort) (void); +void (* aftersort) (void); +void (* XMSaddr) (void); // far pointer to XMS driver + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + +static char *ParmStringsexmm[] = {"noems","noxms",""}; + +/* +====================== += += MML_CheckForEMS += += Routine from p36 of Extending DOS += +======================= +*/ + +boolean MML_CheckForEMS(void) +{ + boolean emmcfems; + static char emmname[] = "EMMXXXX0"; //fix by andrius4669 + __asm { + mov dx,OFFSET 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 +#ifdef __BORLANDC__ + } +#endif + error: +#ifdef __BORLANDC__ + __asm { +#endif + // + // EMS is bad + // + mov emmcfems,0 +#ifdef __BORLANDC__ + } +#endif + End: +#ifdef __WATCOMC__ + } +#endif + return(emmcfems); +} + + +/* +====================== += += MML_SetupEMS += +======================= +*/ + +byte MML_SetupEMS(global_game_variables_t *gvar) +{ + byte str[160]; + byte err; + boolean errorflag=false; + + unsigned int EMSVer = 0; + //byte EMS_status; + unsigned totalEMSpages,freeEMSpages,EMSpageframe,EMSpagesmapped,EMShandle; + totalEMSpages = freeEMSpages = EMSpageframe = EMSpagesmapped = 0; + + __asm { + mov ah,EMS_STATUS + int EMS_INT // make sure EMS hardware is present + or ah,ah + //mov [EMS_status],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 + //EXPAND DONG!!!! + cmp [EMSVer],0x40 + jb low + cmp bx,[freeEMSpages] + jle getpages + mov bx,[freeEMSpages] + jmp getpages +#ifdef __BORLANDC__ + } +#endif + low: +#ifdef __BORLANDC__ + __asm { +#endif + 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 +#ifdef __BORLANDC__ + } +#endif + getpages: +#ifdef __BORLANDC__ + __asm { +#endif + 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 +#ifdef __BORLANDC__ + } +#endif + error: +#ifdef __BORLANDC__ + __asm { +#endif + mov err,ah + mov errorflag,1 + jmp End +#ifdef __BORLANDC__ + } +#endif +noEMS: +End: +#ifdef __WATCOMC__ + } +#endif + if(errorflag==true) + { + strcpy(str,"MM_SetupEMS: EMS error "); + MM_EMSerr(str, err); + printf("%s\n",str); + return err; + } + gvar->mm.totalEMSpages=totalEMSpages; + gvar->mm.freeEMSpages=freeEMSpages; + gvar->mm.EMSpageframe=EMSpageframe; + gvar->mm.EMSpagesmapped=EMSpagesmapped; + gvar->mm.EMShandle=EMShandle; + gvar->mm.EMSVer=EMSVer; + return 0; +} + + +/* +====================== += += MML_ShutdownEMS += +======================= +*/ + +void MML_ShutdownEMS(global_game_variables_t *gvar) +{ + boolean errorflag=false; + unsigned EMShandle=gvar->mm.EMShandle; + + if(!EMShandle) + return; + __asm { + mov ah,EMS_FREEPAGES + mov dx,[EMShandle] + int EMS_INT + or ah,ah + jz ok + mov errorflag,1 +#ifdef __BORLANDC__ + } +#endif + ok: +#ifdef __WATCOMC__ + } +#endif + if(errorflag==true) + Quit("MML_ShutdownEMS: Error freeing EMS!\n"); //++++ 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. += +==================== +*/ + +byte MM_MapEMS(global_game_variables_t *gvar) +{ + byte str[160]; + unsigned EMShandle; + byte err; + boolean errorflag=false; + int i; + EMShandle=gvar->mm.EMShandle; + + for (i=0;i<4/*MAPPAGES*/;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 +#ifdef __BORLANDC__ + } +#endif + error: +#ifdef __BORLANDC__ + __asm { +#endif + mov err,ah + mov errorflag,1 +#ifdef __BORLANDC__ + } +#endif + End: +#ifdef __WATCOMC__ + } +#endif + if(errorflag==true) + { + strcpy(str,"MM_MapEMS: EMS error "); + MM_EMSerr(str, err); + printf("%s\n",str); + return err; + } + } + gvar->mmi.EMSmem = (i)*0x4000lu; + //printf(" gvar->mmi.EMSmem=%lu\n", gvar->mmi.EMSmem); + return 0; +} + +byte MM_MapXEMS(global_game_variables_t *gvar) +{ +//SUB EMS.MapXPages (PhysicalStart, LogicalStart, NumPages, Handle) + + //Maps up to 4 logical EMS pages to physical pages in the page frame, where: + //PhysicalStart = Physical page first logical page is mapped to + //LogicalStart = First logical page to map + //NumPages = Number of pages to map (1 to 4) + //Handle = EMS handle logical pages are allocated to + + /*//Create a buffer containing the page information +// FOR x = 0 TO NumPages - 1 +// MapInfo$ = MapInfo$ + MKI$(LogicalStart + x) + MKI$(PhysicalStart + x) +// NEXT*/ + +// Regs.ax = 0x5000 //Map the pages in the buffer +// Regs.cx = NumPages //to the pageframe +// Regs.dx = Handle +// Regs.ds = VARSEG(MapInfo$) +// Regs.si = SADD(MapInfo$) +// InterruptX 0x67, Regs, Regs +// EMS.Error = (Regs.ax AND 0xFF00&) \ 0x100 //Store the status code + +//END SUB + byte str[160]; + byte err; + word EMShandle; + boolean errorflag=false; + int i; + EMShandle=gvar->mm.EMShandle; + + if(gvar->mm.EMSVer<0x40) + return 5; + + for (i=0;immi.EMSmem = (i)*0x4000lu; + return 0; +} + +//========================================================================== + +/* +====================== += += MML_CheckForXMS += += Check for XMM driver += +======================= +*/ + +boolean MML_CheckForXMS(global_game_variables_t *gvar) +{ + boolean errorflag=false; + gvar->mm.numUMBs = 0; + + __asm { + mov ax,0x4300 + int 0x2f // query status of installed diver + cmp al,0x80 + je good + mov errorflag,1 +#ifdef __BORLANDC__ + } +#endif + good: +#ifdef __WATCOMC__ + } +#endif + if(errorflag==true) return false; + else return true; +} + + +/* +====================== += += MML_SetupXMS += += Try to allocate all upper memory block += +======================= +*/ + +void MML_SetupXMS(global_game_variables_t *gvar) +{ + word 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 + //mov ax,dx // Set available Kbytes. + 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... +#ifdef __BORLANDC__ + } +#endif + gotone: +#ifdef __BORLANDC__ + __asm { +#endif + mov [base],bx + mov [size],dx +#ifdef __BORLANDC__ + } +#endif + done: +#ifdef __WATCOMC__ + } +#endif +// printf("base=%u ", base); printf("size=%u\n", size); + MML_UseSpace(base,size, gvar); + gvar->mmi.XMSmem += size*16; + gvar->mm.UMBbase[gvar->mm.numUMBs] = base; + gvar->mm.numUMBs++; + if(gvar->mm.numUMBs < MAXUMBS) + goto getmemory; +} + + +/* +====================== += += MML_ShutdownXMS += +====================== +*/ + +void MML_ShutdownXMS(global_game_variables_t *gvar) +{ + int i; + unsigned base; + + for (i=0;imm.numUMBs;i++) + { + base = gvar->mm.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(word segstart, dword seglength, global_game_variables_t *gvar) +{ + //huge mmblocktype huge *scan,huge *last; + word segm=1; + word oldend; + dword segmlen; + dword extra; + + scan = last = gvar->mm.mmhead; + gvar->mm.mmrover = gvar->mm.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); + + segmlen=extra; + + //++++emsver stuff! + if(segm>1)/// || extra>=0x10000lu) + //if(extra>0xfffflu) + { + scan->blob=segm; + + //MML_UseSpace(segstart, seglength, gvar); + + printf("MML_UseSpace: Segment spans two blocks!\n"); + //} + printf("segm=%u ", segm); + printf("ex=%lu ", extra); + printf("old=%u ", oldend); + printf("start+seglen=%lu\n", segstart+seglength); + printf("segsta=%x ", segstart); + printf("len=%lu ", scan->length); + printf("seglen=%lu ", seglength); + printf("segmlen=%lu\n", segmlen); + } +//++++todo: linked list of segment! + 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; + gvar->mm.mmnew->useptr = NULL; + + gvar->mm.mmnew->next = scan->next; + scan->next = gvar->mm.mmnew; + gvar->mm.mmnew->start = segstart+seglength; + gvar->mm.mmnew->length = extra; + gvar->mm.mmnew->attributes = LOCKBIT; + }//else if(segm>0) goto segu; + +}*/ +void MML_UseSpace(word segstart, dword seglength, global_game_variables_t *gvar) +{ + mmblocktype far *scan,far *last; + word oldend; + sdword extra; + //word segm=1; + + scan = last = gvar->mm.mmhead; + gvar->mm.mmrover = gvar->mm.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; + } + +// +// find out how many blocks it spans! +// + /*for(;seglength>=0x10000;seglength-=0xFFFF) + { + //printf(" seglen=%lu\n", segmlen); + segm++; + }*/ + +// +// take the given range out of the block +// + oldend = scan->start + scan->length; + extra = oldend - (segstart+((unsigned)seglength)); + if (extra < 0) + { + printf("========================================\n"); + printf("start=%x ", scan->start); + printf("old=%u ", oldend); + printf("start+seglen=%lu\n", segstart+seglength); + printf("segsta=%x ", segstart); + printf("len=%lu ", scan->length); + printf("seglen=%lu ", seglength); + printf("\n"); + printf("MML_UseSpace: Segment spans two blocks! %d\n", extra); + printf("========================================\n"); + //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; + gvar->mm.mmnew->useptr = NULL; + + gvar->mm.mmnew->next = scan->next; + scan->next = gvar->mm.mmnew; + gvar->mm.mmnew->start = segstart+seglength; + gvar->mm.mmnew->length = extra; + gvar->mm.mmnew->attributes = LOCKBIT; + } + +} + +//========================================================================== + +/* +==================== += += MML_ClearBlock += += We are out of blocks, so free a purgable block += +==================== +*/ + +void MML_ClearBlock(global_game_variables_t *gvar) +{ + //huge mmblocktype huge *scan,huge *last; + mmblocktype far *scan,far *last; + + scan = gvar->mm.mmhead->next; + + while(scan) + { + if(!(scan->attributes&LOCKBIT) && (scan->attributes&PURGEBITS)) + { + MM_FreePtr(scan->useptr, gvar); + return; + } + scan = scan->next; + } + + printf("MM_ClearBlock: No purgable blocks!\n"); +} + + +//========================================================================== + +/* +=================== += += MM_Startup += += Grabs all space from turbo with malloc/farmalloc += Allocates bufferseg misc buffer += +=================== +*/ + +void MM_Startup(global_game_variables_t *gvar) +{ + int i; + //dword length,seglength; + dword length; word seglength; + //huge void huge *start; + void far *start; + word segstart;//,endfree; + //memptr *peeonself; + + if(gvar->mm.mmstarted) + MM_Shutdown(gvar); + + gvar->mm.mmstarted = true; + gvar->mm.bombonerror = true; + +// +// set up the linked list (everything in the free list; +// + gvar->mm.mmhead = NULL; + gvar->mm.mmfree = &(gvar->mm.mmblocks[0]); + for(i=0;imm.mmblocks[i].next = &(gvar->mm.mmblocks[i+1]); + } + gvar->mm.mmblocks[i].next = NULL; + +// +// locked block of all memory until we punch out free space +// + GETNEWBLOCK; + gvar->mm.mmhead = gvar->mm.mmnew; // this will allways be the first node + gvar->mm.mmnew->start = 0; + gvar->mm.mmnew->length = 0xffff; + gvar->mm.mmnew->attributes = LOCKBIT; + gvar->mm.mmnew->next = NULL; + //gvar->mm.mmnew->useptr = peeonself; + gvar->mm.mmrover = gvar->mm.mmhead; + + //printf(" %x\n", peeonself); + //printf(" %x\n", *peeonself); +// +// get all available near conventional memory segments +// +#ifdef __WATCOMC__ + _nheapgrow(); + length=(dword)_memavl();//(dword)GetFreeSize(); + //huge start = (void huge *)(gvar->mm.nearheap = _nmalloc(length)); + start = (void far *)(gvar->mm.nearheap = _nmalloc(length)); +#endif +#ifdef __BORLANDC__ + length=coreleft(); + //huge start = (void huge *)(gvar->mm.nearheap = malloc(length)); + start = (void far *)(gvar->mm.nearheap = malloc(length)); +#endif + 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, gvar); + gvar->mmi.nearheap = length; + //printf("start=%Fp segstart=%x seglen=%lu len=%lu\n", start, segstart, seglength, length); + +// +// get all available far conventional memory segments +// + //printf("_FARCORELEFT %lu\n", _FCORELEFT); +#ifdef __WATCOMC__ + _fheapgrow(); +#endif +#ifdef __BORLANDC__ + printf("farcoreleft() %lu\n", farcoreleft()); + printf("(farcoreleft()+32)-_FCORELEFT %d\n", (sword)((farcoreleft()+32)-_FCORELEFT)); +#endif + length=_FCORELEFT;//_fcoreleft();//(dword)GetFarFreeSize();//0xffffUL*4UL; + start = gvar->mm.farheap = _fmalloc(length); + //start = gvar->mm.farheap = halloc(length, 1); + 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, gvar); + gvar->mmi.farheap = length; + //printf("start=%Fp segstart=%x seglen=%lu len=%lu\n", start, segstart, seglength, length); + + gvar->mmi.mainmem = gvar->mmi.nearheap + gvar->mmi.farheap; + +// +// detect EMS and allocate up to 64K at page frame +// + gvar->mmi.EMSmem = 0; +//goto emsskip; //0000 + for(i = 1;i < +#ifdef __WATCOMC__ + __argc +#endif +#ifdef __BORLANDC__ + _argc +#endif + ;i++) + { + if(US_CheckParm( +#ifdef __WATCOMC__ + __argv[i] +#endif +#ifdef __BORLANDC__ + _argv[i] +#endif + ,ParmStringsexmm) == 0) + goto emsskip; // param NOEMS + } + if(MML_CheckForEMS()) + { + MML_SetupEMS(gvar); // allocate space + //TODO: EMS4! AND EMS 3.2 MASSIVE DATA HANDLMENT! + MML_UseSpace(gvar->mm.EMSpageframe,(MAPPAGES)*0x4000lu, gvar); + //if(gvar->pm.emm.EMSVer<0x40) + MM_MapEMS(gvar); // map in used pages + //else + //MM_MapXEMS(gvar); // map in used pages + } + +// +// detect XMS and get upper memory blocks +// +emsskip: + gvar->mmi.XMSmem = 0; +goto xmsskip;//0000 + for(i = 1;i < +#ifdef __WATCOMC__ + __argc +#endif +#ifdef __BORLANDC__ + _argc +#endif + ;i++) + { + if(US_CheckParm( +#ifdef __WATCOMC__ + __argv[i] +#endif +#ifdef __BORLANDC__ + _argv[i] +#endif + ,ParmStringsexmm) == 0) + goto xmsskip; // param NOXMS + } + if(MML_CheckForXMS(gvar)) + { + MML_SetupXMS(gvar); // allocate as many UMBs as possible + } + +// +// allocate the misc buffer +// +xmsskip: + gvar->mm.mmrover = gvar->mm.mmhead; // start looking for space after low block + + MM_GetPtr(&(gvar->mm.bufferseg),BUFFERSIZE, gvar); +} + +//========================================================================== + +/* +==================== += += MM_Shutdown += += Frees all conventional, EMS, and XMS allocated += +==================== +*/ + +void MM_Shutdown(global_game_variables_t *gvar) +{ + if(!(gvar->mm.mmstarted)) + return; + + _ffree(gvar->mm.farheap);// printf(" far freed\n"); +#ifdef __WATCOMC__ + _nfree(gvar->mm.nearheap);// printf(" near freed\n"); +#endif +#ifdef __BORLANDC__ + free(gvar->mm.nearheap);// printf(" near freed\n"); +#endif + if(MML_CheckForEMS()){ MML_ShutdownEMS(gvar); }//printf(" EMS freed\n"); } + if(MML_CheckForXMS(gvar)){ MML_ShutdownXMS(gvar); }//printf(" XMS freed\n"); } +} + +//========================================================================== + +/* +==================== += += MM_GetPtr += += Allocates an unlocked, unpurgable block += +==================== +*/ + +void MM_GetPtr (memptr *baseptr, dword size, global_game_variables_t *gvar) +{ + //huge mmblocktype huge *scan,huge *lastscan,huge *endscan,huge *purge,huge *next; + 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 + gvar->mm.mmnew->length = needed; + gvar->mm.mmnew->useptr = baseptr; + //if(gvar->mm.mmnew->useptr==NULL){ +#ifdef __DEBUG__ + printf("baseptr=%04x ", baseptr); printf("useptr=%04x\n", gvar->mm.mmnew->useptr); + printf("*baseptr=%04x ", *baseptr); printf("*useptr=%04x\n", *(gvar->mm.mmnew->useptr)); + printf("*baseptr=%Fp ", *baseptr); printf("*useptr=%Fp\n", *(gvar->mm.mmnew->useptr)); +#endif + //exit(-5); } + gvar->mm.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 && gvar->mm.mmrover == gvar->mm.mmhead) + search++; + + switch (search) + { + case 0: + lastscan = gvar->mm.mmrover; + scan = gvar->mm.mmrover->next; + endscan = NULL; + break; + case 1: + lastscan = gvar->mm.mmhead; + scan = gvar->mm.mmhead->next; + endscan = gvar->mm.mmrover; + break; + case 2: + MM_SortMem (gvar); + lastscan = gvar->mm.mmhead; + scan = gvar->mm.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 = gvar->mm.mmnew; + gvar->mm.mmnew->start = *(unsigned *)baseptr = startseg; + gvar->mm.mmnew->next = scan; + while ( purge != scan) + { // free the purgable block + next = purge->next; + FREEBLOCK(purge); + purge = next; // purge another if not at scan + } + gvar->mm.mmrover = gvar->mm.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 (gvar->mm.bombonerror) + { +#ifdef __WATCOMC__ + //heapdump(); +#endif + printf(OUT_OF_MEM_MSG,(size-gvar->mmi.nearheap)); + printf("for stability reasons the program will shut down! wwww\n"); + MM_Shutdown(gvar); + exit(-1); + } + else + gvar->mm.mmerror = true; +} + +//========================================================================== + +/* +==================== += += MM_FreePtr += += Allocates an unlocked, unpurgable block += +==================== +*/ + +void MM_FreePtr(memptr *baseptr, global_game_variables_t *gvar) +{ + //huge mmblocktype huge *scan,huge *last; + mmblocktype far *scan,far *last; + + last = gvar->mm.mmhead; + scan = last->next; + + if(baseptr == gvar->mm.mmrover->useptr) // removed the last allocated block + gvar->mm.mmrover = gvar->mm.mmhead; + + while(scan->useptr != baseptr && scan) + { + last = scan; + scan = scan->next; + } + + if(!scan) + { + printf("MM_FreePtr: Block not found!\n"); + 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, global_game_variables_t *gvar) +{ + //huge mmblocktype huge *start; + mmblocktype far *start; + + start = gvar->mm.mmrover; + + do + { + if(gvar->mm.mmrover->useptr == baseptr) + break; + + gvar->mm.mmrover = gvar->mm.mmrover->next; + + if(!gvar->mm.mmrover) + gvar->mm.mmrover = gvar->mm.mmhead; + else if(gvar->mm.mmrover == start) + { + Quit("MM_SetPurge: Block not found!"); + //return; + } + + } while(1); + + gvar->mm.mmrover->attributes &= ~PURGEBITS; + gvar->mm.mmrover->attributes |= purge; +} + +//========================================================================== + +/* +===================== += += MM_SetLock += += Locks / unlocks the block += +===================== +*/ + +void MM_SetLock(memptr *baseptr, boolean locked, global_game_variables_t *gvar) +{ + //huge mmblocktype huge *start; + mmblocktype far *start; + + start = gvar->mm.mmrover; + + do + { + if(gvar->mm.mmrover->useptr == baseptr) + break; + + gvar->mm.mmrover = gvar->mm.mmrover->next; + + if(!gvar->mm.mmrover) + gvar->mm.mmrover = gvar->mm.mmhead; + else if(gvar->mm.mmrover == start) + { + Quit("MM_SetLock: Block not found!"); + //return; + } + + } while(1); + + gvar->mm.mmrover->attributes &= ~LOCKBIT; + gvar->mm.mmrover->attributes |= locked*LOCKBIT; +} + +//========================================================================== + +/* +===================== += += MM_SortMem += += Throws out all purgable stuff and compresses movable blocks += +===================== +*/ + +void MM_SortMem(global_game_variables_t *gvar) +{ + //huge mmblocktype huge *scan,huge *last,huge *next; + 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 = gvar->mm.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); + //MM_FreeBlock(scan, gvar); + 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 + } + + gvar->mm.mmrover = gvar->mm.mmhead; + + if(aftersort) + aftersort(); + +// VW_ColorBorder (oldborder); + +/*++++ if(playing) + MM_SetLock(&(memptr)audiosegs[playing],false);*/ +} + +//========================================================================== + +/* +===================== += += MM_ShowMemory += +===================== +*/ + +void MM_ShowMemory(global_game_variables_t *gvar) +{ + //huge mmblocktype huge *scan; + mmblocktype far *scan; + word temp; + sdword end,owner; + //word chx,chy; + word w; + //dword wwww; + byte scratch[160],scratch0[4096],scratch1[160],str[16]; + //byte d = '#'; +//**** VW_SetDefaultColors(); +//**** VW_SetLineWidth(40); +//++++mh temp = bufferofs; +//++++mh bufferofs = 0; +//**** VW_SetScreen (0,0); + scan = gvar->mm.mmhead; + end = -1; + + CA_OpenDebug (gvar); + w=0; + while(scan) + { + strcpy(scratch, AARESET); + if(scan->attributes & PURGEBITS) + strcpy(scratch0, AAMAGENTA); // dark purple = purgable + else + strcpy(scratch0, AABLUE); // medium blue = non purgable + if(scan->attributes & LOCKBIT) + strcpy(scratch0, AARED); // red = locked + if(scan->start<=end) + { + printf("\nend==%d\n\n", end); + strcat(scratch, "MM_ShowMemory: Memory block order currupted!\n"); + strcat(scratch, "End's Size: "); + ultoa (end,str,10); + strcat (scratch,str); + strcat(scratch, "\nscan->start's Size: "); + ultoa (scan->start,str,10); + strcat (scratch,str); + write(gvar->handle.debughandle,scratch,strlen(scratch)); + //modexprint(&page, chx, chy, 1, 0, 24, "\nMM_ShowMemory: Memory block order currupted!\n"); + break; + } + end = scan->start+(scan->length)-1; +//++++ chy = scan->start/320; +//++++ chx = scan->start%320; + //modexhlin(page, scan->start, (unsigned)end, chy, color); + //for(chx=scan->start;chx+4>=(word)end;chx+=4) + //{ +//++++ modexClearRegion(page, chx, chy, 4, 4, color); + //} +//++++ VW_Hlin(scan->start,(unsigned)end,0,color); + for(w=(scan->start)/80;w<=end/80;w++) + { + //printf("+ %u %lu\n", w, scan->length); + strcat(scratch0, "+"); + } + //++==++==optional strcat(scratch0, AARESET); strcat(scratch0, AAGREY); strcat(scratch0,"_"); +//++++ VW_Plot(scan->start,0,15); +//++++ modexClearRegion(page, chx, chy, 4, 4, 15); +//++++ VW_Hlin(end+1,scan->next->start,0,0); // black = free + + //wwww=(dword)(scan->next->start)-(dword)scan->start; + //wwww=(dword)scan->start+(dword)(scan->next->start); + if (scan->next && scan->next->start >= end+1) + { + strcat(scratch0, AARESET); + //++==++==optional strcat(scratch0, "\n"); + strcat(scratch0,AAGREEN); + for(w=(end+1)/80;w<=((scan->next->start-scan->start)/80);w++) + //for(w=(wwww)/80;w<=((end+1)/80);w++) + //for(w=(end+1)/80;w<=((wwww)/80);w++) + { + //printf("0 %x %u %lu\n", scan->next->start, w, scan->length); + strcat(scratch0,"0"); + } + //printf("==================\n"); + //printf("w=%u wwww=%lu start=%04x next=%04x end=%lu\n", w/80, wwww/80, scan->start, (scan->next->start), end+1); + //printf("==================\n"); + strcat(scratch0, "\n"); + //getch(); + }/*else {//if(scan->next->start <= scan->start){ + scan->next->start=scan->start+0x1000; + wwww=(dword)(scan->next->start)-(dword)scan->start; + strcat(scratch0, AARESET); + strcat(scratch0, "\n"); + strcat(scratch0,AAGREEN); + for(w=(end+1);w<=(0x1000/80);w++) + { + //printf("0 %x %x %u\n", scan->start, w); + strcat(scratch0,"0"); + } + printf("================\n"); + printf("w=%x start=%x next=%x end=%u %lu\n", w, scan->start, (scan->next->start), end+1, wwww); + printf("================\n"); + getch(); + }*/ + strcat(scratch0, AARESET); + //strcat(scratch0,"\n"); + //for(chx=scan->next->start;chx+4>=(word)end+1;chx+=4) + //{ +// chx+=scan->next->start; +// modexClearRegion(page, chx, chy, 4, 4, 2); + //} + //modexhlin(page, end+1,scan->next->start, chy, 0); +/* y = scan->start/320; + x = scan->start%320; + VW_Hlin(x,x+end,y,color); + VW_Plot(x,y,15);*/ +//++++ VW_Hlin(x+end+1,x+(scan->next->start-scan->start),y,0); // black = free + strcat(scratch,"Seg:"); + ultoa (scan->start,str,16); + strcat (scratch,str); + strcat (scratch,"\tSize:"); + ultoa ((unsigned)scan->length,str,10); + strcat (scratch,str); + strcat (scratch,"\tOwner:0x"); + owner = (unsigned)scan->useptr; + ultoa (owner,str,16); + strcat (scratch,str); + strcat (scratch,"\n"); + write(gvar->handle.debughandle,scratch,strlen(scratch)); + write(gvar->handle.debughandle,scratch0,strlen(scratch0)); +//modexprint(page, chx, chy, 1, 0, 24, &scratch); +//++++chy+=4; +//fprintf(stdout, "%s", scratch); + + scan = scan->next; + } + /*strcpy(scratch1, AARESET); + strcat(scratch1, "========================================\n"); + strcat(scratch1, "near= "); + ultoa (*(gvar->mm.nearheap),str,10); + strcat (scratch1,str); + strcat(scratch1, " far= "); + ultoa (*(gvar->mm.farheap),str,10); + strcat (scratch1,str); + strcat(scratch1, "\n"); + //strcat(scratch1, "&near= %Fp ", &(gvar->mm.nearheap)); + //strcat(scratch1, "&far= %Fp", &(gvar->mm.farheap)); + //strcat(scratch1, "\n"); + strcat(scratch1, "========================================\n"); + write(gvar->handle.debughandle,scratch1,strlen(scratch1));*/ + + + CA_CloseDebug (gvar); + +//++++mh IN_Ack(); +//**** VW_SetLineWidth(64); +//++++mh bufferofs = temp; +} + +//========================================================================== + +/* +===================== += += MM_DumpData += +===================== +*/ + +void MM_DumpData(global_game_variables_t *gvar) +{ + //huge mmblocktype huge *scan,huge *best; + mmblocktype far *scan,far *best; + long lowest,oldlowest; + word owner; + byte lock,purge; + FILE *dumpfile; + + free(gvar->mm.nearheap); +#ifdef __BORLANDC__ + dumpfile = fopen ("mmdump.16b","w"); +#endif +#ifdef __WATCOMC__ + dumpfile = fopen ("mmdump.16w","w"); +#endif + if (!dumpfile){ + printf("MM_DumpData: Couldn't open MMDUMP.16!\n"); + return; + } + + lowest = -1; + do + { + oldlowest = lowest; + lowest = 0xffff; + + scan = gvar->mm.mmhead; + while (scan) + { + owner = (unsigned)scan->useptr; + + if (owner && owner oldlowest) + { + best = scan; + lowest = owner; + } + + scan = scan->next; + } + + if (lowest != 0xffff) + { + if (best->attributes & PURGEBITS) + purge = 'P'; + else + purge = '-'; + if (best->attributes & LOCKBIT) + lock = 'L'; + else + lock = '-'; + fprintf (dumpfile,"0x%p (%c%c) = %u\n" + ,(unsigned)lowest,lock,purge,best->length); + } + + } while (lowest != 0xffff); + + fclose(dumpfile); + printf("MMDUMP.16 created.\n"); +} + +//========================================================================== + + +/* +====================== += += MM_UnusedMemory += += Returns the total free space without purging += +====================== +*/ + +dword MM_UnusedMemory(global_game_variables_t *gvar) +{ + dword free; + //huge mmblocktype huge *scan; + mmblocktype far *scan; + + free = 0; + scan = gvar->mm.mmhead; + + while(scan->next) + { + free += scan->next->start - (scan->start + scan->length); + scan = scan->next; + } + + return free*16lu; +// return free; +} + +//========================================================================== + + +/* +====================== += += MM_TotalFree += += Returns the total free space with purging += +====================== +*/ + +dword MM_TotalFree(global_game_variables_t *gvar) +{ + dword free; + //huge mmblocktype huge *scan; + mmblocktype far *scan; + + free = 0; + scan = gvar->mm.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*16lu; +// return free; +} + +//========================================================================== + +/* +===================== += += MM_Report += +===================== +*/ + +void MM_Report_(global_game_variables_t *gvar) +{ + printf("========================================\n"); + printf(" MM_Report\n"); + printf("========================================\n"); + if(MML_CheckForEMS()) + { + printf(" LIMEMS\n"); + printf(" EMM v%x.%x available\n", gvar->mm.EMSVer>>4,gvar->mm.EMSVer&0x0F); + printf(" totalEMSpages: %u ", gvar->mm.totalEMSpages); printf("freeEMSpages: %u\n", gvar->mm.freeEMSpages); + printf(" EMSpageframe: %x\n", gvar->mm.EMSpageframe); + } + if(MML_CheckForXMS(gvar)) + { + printf(" XMS\n"); + printf(" XMSaddr: %X\n", *XMSaddr); + } + printf("near: %lu ", gvar->mmi.nearheap); printf("far: %lu\n", gvar->mmi.farheap); if(MML_CheckForEMS()) + printf("EMSmem: %lu ", gvar->mmi.EMSmem); if(MML_CheckForXMS(gvar)) printf("XMSmem: %lu", gvar->mmi.XMSmem); printf("\n"); + //printf("mainmem: %lu\n", gvar->mmi.mainmem); + printf("Total convmem: %lu ", gvar->mmi.mainmem); printf("TotalFree: %lu ", MM_TotalFree(gvar)); printf("TotalUsed: %lu\n", gvar->mmi.mainmem+gvar->mmi.EMSmem+gvar->mmi.XMSmem+gvar->mmi.XMSmem); + printf(" UnusedMemory: %lu\n", MM_UnusedMemory(gvar)); +} + +//========================================================================== + +/* +===================== += += MM_EMSerr += +===================== +*/ + +void MM_EMSerr(byte *stri, byte err) +{ + //Returns a text string describing the error code in EMS.Error. + switch(err) + { + case 0x0: + strcat(stri, "successful"); + break; + case 0x80: + strcat(stri, "internal error"); + break; + case 0x81: + strcat(stri, "hardware malfunction"); + break; + case 0x82: + strcat(stri, "busy .. retry later"); + break; + case 0x83: + strcat(stri, "invalid handle"); + break; + case 0x84: + strcat(stri, "undefined function requested by application"); + break; + case 0x85: + strcat(stri, "no more handles available"); + break; + case 0x86: + strcat(stri, "error in save or restore of mapping context"); + break; + case 0x87: + strcat(stri, "insufficient memory pages in system"); + break; + case 0x88: + strcat(stri, "insufficient memory pages available"); + break; + case 0x89: + strcat(stri, "zero pages requested"); + break; + case 0x8A: + strcat(stri, "invalid logical page number encountered"); + break; + case 0x8B: + strcat(stri, "invalid physical page number encountered"); + break; + case 0x8C: + strcat(stri, "page-mapping hardware state save area is full"); + break; + case 0x8D: + strcat(stri, "save of mapping context failed"); + break; + case 0x8E: + strcat(stri, "restore of mapping context failed"); + break; + case 0x8F: + strcat(stri, "undefined subfunction"); + break; + case 0x90: + strcat(stri, "undefined attribute type"); + break; + case 0x91: + strcat(stri, "feature not supported"); + break; + case 0x92: + strcat(stri, "successful, but a portion of the source region has been overwritten"); + break; + case 0x93: + strcat(stri, "length of source or destination region exceeds length of region allocated to either source or destination handle"); + break; + case 0x94: + strcat(stri, "conventional and expanded memory regions overlap"); + break; + case 0x95: + strcat(stri, "offset within logical page exceeds size of logical page"); + break; + case 0x96: + strcat(stri, "region length exceeds 1 MB"); + break; + case 0x97: + strcat(stri, "source and destination EMS regions have same handle and overlap"); + break; + case 0x98: + strcat(stri, "memory source or destination type undefined"); + break; + case 0x9A: + strcat(stri, "specified alternate map register or DMA register set not supported"); + break; + case 0x9B: + strcat(stri, "all alternate map register or DMA register sets currently allocated"); + break; + case 0x9C: + strcat(stri, "alternate map register or DMA register sets not supported"); + break; + case 0x9D: + strcat(stri, "undefined or unallocated alternate map register or DMA register set"); + break; + case 0x9E: + strcat(stri, "dedicated DMA channels not supported"); + break; + case 0x9F: + strcat(stri, "specified dedicated DMA channel not supported"); + break; + case 0xA0: + strcat(stri, "no such handle name"); + break; + case 0xA1: + strcat(stri, "a handle found had no name, or duplicate handle name"); + break; + case 0xA2: + strcat(stri, "attempted to wrap around 1M conventional address space"); + break; + case 0xA3: + strcat(stri, "source array corrupted"); + break; + case 0xA4: + strcat(stri, "operating system denied access"); + break; + default: + strcat(stri, "undefined error"); + } +} + +//========================================================================== + +/* +===================== += += MM_BombOnError += +===================== +*/ + +void MM_BombOnError(boolean bomb, global_game_variables_t *gvar) +{ + gvar->mm.bombonerror = bomb; +} + +/*void MM_GetNewBlock(global_game_variables_t *gvar) +{ + if(!gvar->mm.mmfree) + MML_ClearBlock(gvar); + gvar->mm.mmnew=gvar->mm.mmfree; + gvar->mm.mmfree=gvar->mm.mmfree->next; + if(!(gvar->mm.mmnew=gvar->mm.mmfree)) + { + printf("MM_GETNEWBLOCK: No free blocks!\n"); + return; + } + gvar->mm.mmfree=gvar->mm.mmfree->next; +} + +void MM_FreeBlock(mmblocktype *x, global_game_variables_t *gvar) +{ + x->useptr=NULL; + x->next=gvar->mm.mmfree; + gvar->mm.mmfree=x; +}*/ + +/*void MM_seguin(void) +{ + __asm { + push ds + mov ax,ds + inc ax + mov ds,ax + } +} + +void MM_segude(void) +{ + __asm { + pop ds + } +}*/ + +/* +pull data from far and put it into ds var +mov ax,es:si +mov x,ax +*/ +/* +ss stack segment +sp top of stack +bp bottem of stack +*/ diff --git a/src/lib/16_mm.h b/src/lib/16_mm.h index d351abfa..1a448a2a 100755 --- a/src/lib/16_mm.h +++ b/src/lib/16_mm.h @@ -66,7 +66,9 @@ //-------- #define XMS_INT 0x2f -#define XMSD dword XMSDriver=gvar->pm.xmm.XMSDriver; +#define XMS_CALL(v) _AH = (v);\ + __asm call [WORD PTR XMSDriver] +/*__asm { //mov (v),ah*/ #define XMS_VERSION 0x00 @@ -205,7 +207,6 @@ void MM_Report_(global_game_variables_t *gvar); void MM_BombOnError(boolean bomb, global_game_variables_t *gvar); //void MM_GetNewBlock(mminfo_t *mm); //void MM_FreeBlock(mmblocktype *x, mminfo_t *mm); -void XMS_CALL(byte v, global_game_variables_t *gvar); //========================================================================== diff --git a/src/lib/16_pm.c b/src/lib/16_pm.c index 139b72c8..e699fcbf 100755 --- a/src/lib/16_pm.c +++ b/src/lib/16_pm.c @@ -44,9 +44,9 @@ // XMS specific variables boolean gvar->pm.xmm.XMSPresent; - word gvar->pm.xmm.XMSAvail,gvar->pm.xmm.XMSPagesAvail,gvar->pm.xmm.XMSHandle; - dword XMSDriver; - int gvar->pm.xmm.XMSProtectPage = -1; + word gvar->pm.xmm.XMSAvail,gvar->pm.xmm.XMSPagesAvail,gvar->pm.xmm.XMSHandle;*/ + word XMSDriver; +/* int gvar->pm.xmm.XMSProtectPage = -1; // File specific variables char gvar->pm.fi.PageFileName[13] = {"VSWAP."}; @@ -293,7 +293,7 @@ PML_ShutdownEMS(global_game_variables_t *gvar) boolean PML_StartupXMS(global_game_variables_t *gvar) { - XMSD; + //XMSD; gvar->pm.xmm.XMSPresent = false; // Assume failure gvar->pm.xmm.XMSAvail = 0; @@ -310,7 +310,7 @@ PML_StartupXMS(global_game_variables_t *gvar) mov [WORD PTR XMSDriver+2],es // function pointer to XMS driver } - XMS_CALL(XMS_QUERYFREE, gvar); // Find out how much XMS is available + XMS_CALL(XMS_QUERYFREE); // Find out how much XMS is available gvar->pm.xmm.XMSAvail = _AX; if (!_AX) // AJR: bugfix 10/8/92 goto error; @@ -320,7 +320,7 @@ PML_StartupXMS(global_game_variables_t *gvar) goto error; _DX = gvar->pm.xmm.XMSAvail; - XMS_CALL(XMS_ALLOC, gvar); // And do the allocation + XMS_CALL(XMS_ALLOC); // And do the allocation gvar->pm.xmm.XMSHandle = _DX; if (!_AX) // AJR: bugfix 10/8/92 @@ -344,7 +344,7 @@ void PML_XMSCopy(boolean toxms,byte far *addr,word xmspage,word length, global_game_variables_t *gvar) { #ifdef __WATCOMC__ - XMSD; + //XMSD; #endif dword xoffset; struct @@ -374,7 +374,7 @@ PML_XMSCopy(boolean toxms,byte far *addr,word xmspage,word length, global_game_v push si } _SI = (word)© - XMS_CALL(XMS_MOVE, gvar); + XMS_CALL(XMS_MOVE); __asm { pop si } @@ -416,11 +416,11 @@ PML_CopyFromXMS(byte far *target,int sourcepage,word length, global_game_variabl void PML_ShutdownXMS(global_game_variables_t *gvar) { - XMSD; + //XMSD; if (gvar->pm.xmm.XMSPresent) { _DX = gvar->pm.xmm.XMSHandle; - XMS_CALL(XMS_FREE, gvar); + XMS_CALL(XMS_FREE); if (_BL) { Quit("PML_ShutdownXMS: Error freeing XMS"); @@ -1277,6 +1277,9 @@ PM_Reset(global_game_variables_t *gvar) gvar->pm.PMPanicMode = false; + gvar->pm.fi.PageFile = -1; + gvar->pm.xmm.XMSProtectPage = -1; + // Initialize page list for (i = 0,page = gvar->pm.PMPages;i < gvar->pm.PMNumBlocks;i++,page++) { @@ -1300,8 +1303,6 @@ PM_Startup(global_game_variables_t *gvar) return; strcat(&(gvar->pm.fi.PageFileName), "VSWAP."); - gvar->pm.fi.PageFile = -1; - gvar->pm.xmm.XMSProtectPage = -1; nomain = noems = noxms = false; for (i = 1;i < diff --git a/src/lib/16_pm.h b/src/lib/16_pm.h index 85135d91..b9d801e1 100755 --- a/src/lib/16_pm.h +++ b/src/lib/16_pm.h @@ -110,5 +110,5 @@ extern void PM_Startup(global_game_variables_t *gvar), extern memptr PM_GetPageAddress(int pagenum, global_game_variables_t *gvar), PM_GetPage(int pagenum, global_game_variables_t *gvar); // Use this one to cache page -void PM_SetMainMemPurge(int level, global_game_variables_t *gvar); +//void PM_SetMainMemPurge(int level, global_game_variables_t *gvar); #endif diff --git a/src/lib/length b/src/lib/length new file mode 100755 index 00000000..ff49ecdf --- /dev/null +++ b/src/lib/length @@ -0,0 +1,4 @@ + total used free shared buffers cached +Mem: 7879884 7039184 840700 199796 367668 4095452 +-/+ buffers/cache: 2576064 5303820 +Swap: 2097148 0 2097148 diff --git a/src/lib/next b/src/lib/next new file mode 100755 index 00000000..e69de29b diff --git a/src/lib/typdefst.h b/src/lib/typdefst.h index 4d031f9e..d069b92f 100755 --- a/src/lib/typdefst.h +++ b/src/lib/typdefst.h @@ -171,6 +171,7 @@ typedef struct #endif //byte EMS_status; word numUMBs,UMBbase[MAXUMBS]; + word totalEMSpages, freeEMSpages, EMSpagesmapped, EMShandle, EMSpageframe,EMSVer; //dword numUMBs,UMBbase[MAXUMBS]; //huge mmblocktype huge mmblocks[MAXBLOCKS],huge *mmhead,huge *mmfree,huge *mmrover,huge *mmnew; mmblocktype far mmblocks[MAXBLOCKS],far *mmhead,far *mmfree,far *mmrover,far *mmnew; -- 2.39.2