6 #define SPACEFREE 0x2000 // how much mem to leave alone in farheap
7 #define EXTRASTACKSIZE 0x2000
9 #define LOCKBIT 0x8000 // if set in attributes, block cannot be moved
10 #define PURGEBITS 3 // 0-3 level, 0= unpurgable, 3= purge first
12 #define BASEATTRIBUTES 0 // unlocked, non purgable
14 unsigned totalmem; // total paragraphs available with 64k EMS
15 int EMSpresent,XMSpresent;
25 unsigned start; // in paragraphs
29 } blocks[MAXBLOCKS],tempblock;
31 //==========================================================================
36 void CheckForEMS (void);
37 int FindBlock (memptr *ptr);
38 void RemoveBlock (int block);
39 void InsertBlock (int block);
46 void MMStartup (void);
47 void MMShutdown (void);
49 void MMGetPtr (memptr *baseptr,unsigned size);
50 void MMFreePtr (memptr *baseptr);
51 void MMSetPurge (memptr *baseptr, int purge);
52 void MMSortMem (void);
53 void MMBlockDump (void);
54 unsigned MMUnusedMemory (void);
55 unsigned MMTotalFree (void);
57 //==========================================================================
63 // Routine from p36 of Extending DOS
65 void CheckForEMS (void)
67 char emmname[9] = "EMMXXXX0";
69 asm mov dx,OFFSET emmname
71 asm int 0x21 // try to open EMMXXXX0 device
77 asm int 0x21 // get device info
85 asm int 0x21 // get status
91 asm int 0x21 // close handle
109 //==========================================================================
115 int FindBlock (memptr *ptr)
118 for (i=1;i<numblocks;i++)
119 if (blocks[i].useptr == ptr)
122 Quit ("Memory manager error: Block not found!");
128 // 0 the pointer, close the block array down, and decrement numblocks
130 void RemoveBlock (int block)
132 void far *source, far *dest;
135 *blocks[block].useptr = NULL;
136 if (block!=numblocks-1)
138 source = &blocks[block+1];
139 dest = &blocks[block];
140 length = (numblocks-1-block)*sizeof(blocks[0]);
141 movedata (FP_SEG(source),FP_OFF(source),FP_SEG(dest),FP_OFF(dest),length);
148 // Inserts space in the block array AFTER parameter and increments numblocks
150 void InsertBlock (int block)
152 unsigned source,dest,length;
154 if (block!=numblocks-1)
156 source = ((unsigned)&blocks[numblocks])-2;
157 dest = ((unsigned)&blocks[numblocks+1])-2;
158 length = (numblocks-1-block)*sizeof(blocks[0])/2;
168 if (++numblocks>=MAXBLOCKS)
169 Quit ("Memory manager error: Too many blocks!");
174 // check numblocks<MAXBLOCKS
176 //==========================================================================
183 = Initializes the memory manager and returns the total
184 = allocatable free space.
186 = Grabs all space from turbo with farmalloc
191 void MMStartup (void)
193 unsigned long length;
195 unsigned nearstart,farstart,EMSstart,seg,i;
196 unsigned nearlength,farlength,emslength,xmslength;
199 // get all available near conventional memory
202 start = (void far *)(nearheap = malloc(length-SPACEFREE));
205 // paragraph align it and figure size
207 length -= 16-(FP_OFF(start)&15);
208 length -= EXTRASTACKSIZE;
209 nearlength = length / 16; // now in paragraphs
210 nearstart = FP_SEG(start)+(FP_OFF(start)+15)/16;
213 // get all available far conventional memory
215 length=farcoreleft();
216 start = farheap = farmalloc(length);
219 // paragraph align it and figure size
223 length -= 16-FP_OFF(start);
224 start = (void far *)MK_FP(FP_SEG(start)+1,0);
226 farlength = length / 16; // now in paragraphs
227 farstart = FP_SEG(start);
229 totalmem = nearlength + farlength;
232 // detect EMS and allocate 64K at page frame
238 totalmem += 0x1000; // 64k of EMS
239 MMMapEMS(); // map in used pages
247 // set up locked blocks
251 blocks[numblocks].start = 0;
252 blocks[numblocks].length = nearstart;
253 blocks[numblocks].attributes = LOCKBIT;
257 blocks[numblocks].start = nearstart+nearlength;
258 blocks[numblocks].length = farstart-(nearstart+nearlength);
259 blocks[numblocks].attributes = LOCKBIT;
263 blocks[numblocks].start = farstart+farlength;
264 blocks[numblocks].length = EMSstart-(farstart+farlength);
265 blocks[numblocks].attributes = LOCKBIT;
269 TTLMainMem=16L*MMTotalFree();
272 //==========================================================================
279 = Frees all conventional, EMS, and XMS allocated
284 void MMShutdown (void)
289 // 0 the pointers (if any)
291 for (i=0;i<numblocks-1;i++)
292 *blocks[i].useptr=NULL;
299 //==========================================================================
306 = Maps the 64k of EMS used by memory manager into the page frame
317 //==========================================================================
324 = Allocates an unlocked, unpurgable block
325 = Start looking at the top of memory
329 void MMAllocate(memptr *baseptr,long size)
331 MMGetPtr(baseptr,(unsigned)((size+15)/16));
332 TTLMainMem=16L*MMTotalFree();
335 void MMGetPtr (memptr *baseptr,unsigned size)
341 // try a normal scan, then compress if not found
343 for (try=0;try<2;try++)
345 for (i=0;i<numblocks-1;i++)
347 if (blocks[i].attributes & PURGEBITS )
350 // blocks[i] cannot be written over, so try to allocate the
351 // new block right after it
353 start = blocks[i].start + blocks[i].length;
356 while (blocks[j].start < end)
358 if (!(blocks[j].attributes & PURGEBITS))
361 goto lookmore; // a non purgable block is in the way
366 // purge the blocks in the way
371 // allocate the new block
374 *(unsigned *)baseptr = start;
375 blocks[i+1].start = start;
376 blocks[i+1].length = size;
377 blocks[i+1].useptr = baseptr;
378 blocks[i+1].attributes = BASEATTRIBUTES;
383 // didn't find any space, so compress and try again
390 //MMBlockDump(); // DEBUG
391 Quit ("Memory manager error: Out of memory!");
394 //==========================================================================
397 =====================
401 = Frees up a block and NULL's the pointer
403 =====================
406 void MMFreePtr (memptr *baseptr)
408 RemoveBlock(FindBlock (baseptr));
409 TTLMainMem=16L*MMTotalFree();
413 //==========================================================================
416 =====================
420 = Sets the purge level for a block
422 =====================
425 void MMSetPurge (memptr *baseptr, int purge)
430 block = FindBlock (baseptr);
432 attr = blocks[block].attributes;
433 attr &= 0xffff - PURGEBITS;
434 attr |= purge; // set bits in attributes
435 blocks[block].attributes = attr;
440 =============================================================================
444 =============================================================================
450 void MoveParaBase (unsigned source, unsigned dest, unsigned words)
464 void MoveParaBaseUp (unsigned source, unsigned dest, unsigned words)
481 void MoveParas (unsigned source, unsigned dest, unsigned paragraphs)
486 while (paragraphs>0xfff)
488 MoveParaBase (source,dest,0xfff*8);
493 MoveParaBase (source,dest,paragraphs*8);
500 while (paragraphs>0xfff)
504 MoveParaBaseUp (source,dest,0xfff*8);
509 MoveParaBaseUp (source,dest,paragraphs*8);
516 ======================
520 = Sorts all non locked blocks so lower purge levels are lower in memory
521 = and all free space is at the top
523 ======================
531 // Pushes the block (purgeable) as high in memory as possible
532 // must be BELOW keyblock
533 // If it can't fit above keyblock it will be freed
535 void PushUp (int move)
537 unsigned source,dest,size;
540 size = blocks[move].length;
541 source = blocks[move].start;
543 for (i=numblocks-1;i>keyblock;i--)
546 // if the block can fit under this block, move it
548 dest = blocks[i].start - size;
549 if (blocks[i-1].start+blocks[i-1].length <= dest)
552 // make a copy of block 'move' under block 'i'
555 blocks[i] = blocks[move];
556 blocks[i].start = dest;
557 *(blocks[i].useptr) = (void _seg *)dest; // modify the pointer to the new spot
558 MoveParas (source,dest,size);
564 // erase original position
567 keyblock--; // because a block below it was removed
574 // Push keyblock (unpurgable) as low in memory as possible
578 unsigned source,dest,size,end,lowblock,checkblock,i;
580 size = blocks[keyblock].length;
581 source = blocks[keyblock].start;
584 // find the lowest space it can be moved into
586 for (lowblock = 0;lowblock<keyblock;lowblock++)
587 if (!(blocks[lowblock].attributes & PURGEBITS) ||
588 blocks[lowblock].attributes & LOCKBIT)
591 // found a locked or nonpurgable block below keyblock
593 // see if there is enough space to move block
595 dest = blocks[lowblock].start + blocks[lowblock].length;
599 // see if any of the blocks in the middle can be moved away
601 checkblock = lowblock+1;
602 while (checkblock < keyblock && blocks[checkblock].start<end)
604 if (!(blocks[checkblock].attributes & PURGEBITS) )
605 goto nofit; // can't fit between two locked blocks
607 // push the block up or remove it, in either case dropping
608 // keyblock and changing blocks[checkblock]
617 MoveParas (source,dest,size);
618 blocks[keyblock].start = dest;
619 *(blocks[keyblock].useptr) = (void _seg *)dest; // modify the pointer to the new spot
620 if (lowblock<keyblock-1)
623 // reorder the block records
625 tempblock = blocks[keyblock];
626 for (i=keyblock;i>lowblock+1;i--)
627 blocks[i]=blocks[i-1];
628 blocks[lowblock+1] = tempblock;
631 //MMBlockDump(); // DEBUG
635 nofit:; // keep looking...
645 void MMSortMem (void)
647 unsigned i,source,dest;
656 // non-purgable, unlocked blocks will be pushed low in memory
658 if ( !(blocks[keyblock].attributes & PURGEBITS) &&
659 !(blocks[keyblock].attributes & LOCKBIT) )
662 } while (keyblock<numblocks-1);
665 for (i=numblocks-2;i>0;i--)
668 // push all purgable blocks as high as possible
669 // Currently they are NOT moved around locked blocks!
671 if ( blocks[i].attributes & PURGEBITS )
673 source= blocks[i].start;
674 dest= blocks[i+1].start-blocks[i].length;
677 MoveParas (source,dest,blocks[i].length);
678 blocks[i].start = dest;
679 *(blocks[i].useptr) = (void _seg *)dest; // modify the pointer to the new spot
684 PatchPointers(); // let the main program fix up any
685 // internal references
689 //==========================================================================
692 =======================
698 =======================
701 void MMBlockDump (void)
706 fprintf (stdprn,"-------------\n");
707 for (i=0;i<numblocks;i++)
709 fprintf (stdprn,"Start:%4X\tLength:%4X\tAttr:%4X\tPtr:%p\n"
710 ,blocks[i].start,blocks[i].length,blocks[i].attributes,blocks[i].useptr);
713 free = blocks[i+1].start - (blocks[i].start+blocks[i].length);
715 fprintf (stdprn,"### Free:%X\n",free);
722 //==========================================================================
725 ======================
729 = Returns the total free space without purging
731 ======================
734 unsigned MMUnusedMemory (void)
741 for (i=0;i<numblocks;i++)
744 free += blocks[i+1].start - (blocks[i].start+blocks[i].length);
750 //==========================================================================
754 ======================
758 = Returns the total free space with purging
760 ======================
763 unsigned MMTotalFree (void)
770 for (i=0;i<numblocks;i++)
772 if (blocks[i].attributes & PURGEBITS)
773 free += blocks[i].length;
775 free += blocks[i+1].start - (blocks[i].start+blocks[i].length);
781 //==========================================================================