]> 4ch.mooo.com Git - 16.git/blob - 16/ted5/MEMMGR.C
ted5 added
[16.git] / 16 / ted5 / MEMMGR.C
1 #include "ted5.h"
2 #pragma hdrstop
3
4 #define EMSINT          0x67
5
6 #define SPACEFREE       0x2000  // how much mem to leave alone in farheap
7 #define EXTRASTACKSIZE  0x2000
8 #define MAXBLOCKS       1000
9 #define LOCKBIT         0x8000  // if set in attributes, block cannot be moved
10 #define PURGEBITS       3       // 0-3 level, 0= unpurgable, 3= purge first
11
12 #define BASEATTRIBUTES  0       // unlocked, non purgable
13
14 unsigned totalmem;              // total paragraphs available with 64k EMS
15 int     EMSpresent,XMSpresent;
16
17
18 long TTLMainMem;
19
20 void far *farheap;
21 void *nearheap;
22
23 int     numblocks;
24 struct {
25          unsigned start;        // in paragraphs
26          unsigned length;
27          unsigned attributes;
28          memptr *useptr;
29        } blocks[MAXBLOCKS],tempblock;
30
31 //==========================================================================
32
33 //
34 // local prototypes
35 //
36 void CheckForEMS (void);
37 int FindBlock (memptr *ptr);
38 void RemoveBlock (int block);
39 void InsertBlock (int block);
40
41
42 //
43 // public prototypes
44 //
45
46 void MMStartup (void);
47 void MMShutdown (void);
48 void MMMapEMS (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);
56
57 //==========================================================================
58
59
60 //
61 // CheckForEMS
62 //
63 // Routine from p36 of Extending DOS
64 //
65 void CheckForEMS (void)
66 {
67   char  emmname[9] = "EMMXXXX0";
68
69 asm     mov     dx,OFFSET emmname
70 asm     mov     ax,0x3d00
71 asm     int     0x21            // try to open EMMXXXX0 device
72 asm     jc      error
73
74 asm     mov     bx,ax
75 asm     mov     ax,0x4400
76
77 asm     int     0x21            // get device info
78 asm     jc      error
79
80 asm     and     dx,0x80
81 asm     jz      error
82
83 asm     mov     ax,0x4407
84
85 asm     int     0x21            // get status
86 asm     jc      error
87 asm     or      al,al
88 asm     jz      error
89
90 asm     mov     ah,0x3e
91 asm     int     0x21            // close handle
92 asm     jc      error
93
94 //
95 // EMS is good
96 //
97
98
99   return;
100
101 error:
102 //
103 // EMS is bad
104 //
105   EMSpresent = 0;
106
107 }
108
109 //==========================================================================
110
111
112 //
113 // FindBlock
114 //
115 int FindBlock (memptr *ptr)
116 {
117   int i;
118   for (i=1;i<numblocks;i++)
119     if (blocks[i].useptr == ptr)
120       return i;
121
122   Quit ("Memory manager error: Block not found!");
123   return -1;
124 }
125
126 //
127 // RemoveBlock
128 // 0 the pointer, close the block array down, and decrement numblocks
129 //
130 void RemoveBlock (int block)
131 {
132   void far *source, far *dest;
133   unsigned length;
134
135   *blocks[block].useptr = NULL;
136   if (block!=numblocks-1)
137   {
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);
142   }
143   numblocks--;
144 }
145
146 //
147 // InsertBlock
148 // Inserts space in the block array AFTER parameter and increments numblocks
149 //
150 void InsertBlock (int block)
151 {
152   unsigned source,dest,length;
153
154   if (block!=numblocks-1)
155   {
156     source = ((unsigned)&blocks[numblocks])-2;
157     dest = ((unsigned)&blocks[numblocks+1])-2;
158     length = (numblocks-1-block)*sizeof(blocks[0])/2;
159 asm     mov     cx,length
160 asm     mov     si,source
161 asm     mov     di,dest
162 asm     mov     ax,ds
163 asm     mov     es,ax
164 asm     std
165 asm     rep     movsw
166 asm     cld
167   }
168   if (++numblocks>=MAXBLOCKS)
169     Quit ("Memory manager error: Too many blocks!");
170 }
171
172
173
174 // check numblocks<MAXBLOCKS
175
176 //==========================================================================
177
178 /*
179 ===================
180 =
181 = MMStartup
182 =
183 = Initializes the memory manager and returns the total
184 = allocatable free space.
185 =
186 = Grabs all space from turbo with farmalloc
187 =
188 ===================
189 */
190
191 void MMStartup (void)
192 {
193   unsigned long length;
194   void far *start;
195   unsigned nearstart,farstart,EMSstart,seg,i;
196   unsigned nearlength,farlength,emslength,xmslength;
197
198 //
199 // get all available near conventional memory
200 //
201   length=coreleft();
202   start = (void far *)(nearheap = malloc(length-SPACEFREE));
203
204 //
205 // paragraph align it and figure size
206 //
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;
211
212 //
213 // get all available far conventional memory
214 //
215   length=farcoreleft();
216   start = farheap = farmalloc(length);
217
218 //
219 // paragraph align it and figure size
220 //
221   if (FP_OFF(start))
222   {
223     length -= 16-FP_OFF(start);
224     start = (void far *)MK_FP(FP_SEG(start)+1,0);
225   }
226   farlength = length / 16;                      // now in paragraphs
227   farstart = FP_SEG(start);
228
229   totalmem = nearlength + farlength;
230
231 //
232 // detect EMS and allocate 64K at page frame
233 //
234   CheckForEMS();
235   if (EMSpresent)
236   {
237     EMSstart = 0xffff;
238     totalmem += 0x1000;                         // 64k of EMS
239     MMMapEMS();                                 // map in used pages
240   }
241   else
242   {
243     EMSstart = 0xffff;
244   }
245
246 //
247 // set up locked blocks
248 //
249   numblocks = 0;
250
251   blocks[numblocks].start = 0;
252   blocks[numblocks].length = nearstart;
253   blocks[numblocks].attributes = LOCKBIT;
254
255   numblocks++;
256
257   blocks[numblocks].start = nearstart+nearlength;
258   blocks[numblocks].length = farstart-(nearstart+nearlength);
259   blocks[numblocks].attributes = LOCKBIT;
260
261   numblocks++;
262
263   blocks[numblocks].start = farstart+farlength;
264   blocks[numblocks].length = EMSstart-(farstart+farlength);
265   blocks[numblocks].attributes = LOCKBIT;
266
267   numblocks++;
268
269   TTLMainMem=16L*MMTotalFree();
270 }
271
272 //==========================================================================
273
274 /*
275 ====================
276 =
277 = MMShutdown
278 =
279 = Frees all conventional, EMS, and XMS allocated
280 =
281 ====================
282 */
283
284 void MMShutdown (void)
285 {
286  int i;
287
288  //
289  // 0 the pointers (if any)
290  //
291   for (i=0;i<numblocks-1;i++)
292     *blocks[i].useptr=NULL;
293
294   farfree (farheap);
295   free (nearheap);
296
297 }
298
299 //==========================================================================
300
301 /*
302 ====================
303 =
304 = MMMapEMS
305 =
306 = Maps the 64k of EMS used by memory manager into the page frame
307 = for general use.
308 =
309 ====================
310 */
311
312 void MMMapEMS (void)
313 {
314
315 }
316
317 //==========================================================================
318
319 /*
320 ====================
321 =
322 = MMGetPtr
323 =
324 = Allocates an unlocked, unpurgable block
325 = Start looking at the top of memory
326 =
327 ====================
328 */
329 void MMAllocate(memptr *baseptr,long size)
330 {
331  MMGetPtr(baseptr,(unsigned)((size+15)/16));
332  TTLMainMem=16L*MMTotalFree();
333 }
334
335 void MMGetPtr (memptr *baseptr,unsigned size)
336 {
337   int i,j,k,try;
338   unsigned start,end;
339
340   //
341   // try a normal scan, then compress if not found
342   //
343   for (try=0;try<2;try++)
344   {
345     for (i=0;i<numblocks-1;i++)
346     {
347       if (blocks[i].attributes & PURGEBITS )
348         continue;
349       //
350       // blocks[i] cannot be written over, so try to allocate the
351       // new block right after it
352       //
353       start = blocks[i].start + blocks[i].length;
354       end = start + size;
355       j=i+1;
356       while (blocks[j].start < end)
357       {
358         if (!(blocks[j].attributes & PURGEBITS))
359         {
360           i = j-1;
361           goto lookmore;                // a non purgable block is in the way
362         }
363         j++;
364       }
365       //
366       // purge the blocks in the way
367       //
368       for (k=i+1;k<j;j--)
369         RemoveBlock(k);
370       //
371       // allocate the new block
372       //
373       InsertBlock(i);
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;
379       return;
380 lookmore:;
381     }
382     //
383     // didn't find any space, so compress and try again
384     //
385     if (try==0)
386       MMSortMem();
387   }
388
389 //puts("");
390 //MMBlockDump();        // DEBUG
391   Quit ("Memory manager error: Out of memory!");
392 }
393
394 //==========================================================================
395
396 /*
397 =====================
398 =
399 = MMFreePtr
400 =
401 = Frees up a block and NULL's the pointer
402 =
403 =====================
404 */
405
406 void MMFreePtr (memptr *baseptr)
407 {
408  RemoveBlock(FindBlock (baseptr));
409  TTLMainMem=16L*MMTotalFree();
410 }
411
412
413 //==========================================================================
414
415 /*
416 =====================
417 =
418 = MMSetPurge
419 =
420 = Sets the purge level for a block
421 =
422 =====================
423 */
424
425 void MMSetPurge (memptr *baseptr, int purge)
426 {
427   int block;
428   unsigned attr;
429
430   block = FindBlock (baseptr);
431
432   attr = blocks[block].attributes;
433   attr &= 0xffff - PURGEBITS;
434   attr |= purge;                // set bits in attributes
435   blocks[block].attributes = attr;
436 }
437
438
439 /*
440 =============================================================================
441
442                             MMSortMem
443
444 =============================================================================
445 */
446
447 //
448 // MoveParas
449 //
450 void MoveParaBase (unsigned source, unsigned dest, unsigned words)
451 {
452 asm     mov     cx,words
453 asm     xor     si,si
454 asm     xor     di,di
455 asm     mov     ax,source
456 asm     mov     bx,dest
457 asm     mov     ds,source
458 asm     mov     es,dest
459 asm     rep     movsw
460 asm     mov     ax,ss
461 asm     mov     ds,ax
462 }
463
464 void MoveParaBaseUp (unsigned source, unsigned dest, unsigned words)
465 {
466 asm     mov     cx,words
467 asm     mov     si,cx
468 asm     dec     si
469 asm     shl     si,1
470 asm     mov     di,si
471 asm     mov     ax,source
472 asm     mov     bx,dest
473 asm     mov     ds,source
474 asm     mov     es,dest
475 asm     rep     movsw
476 asm     mov     ax,ss
477 asm     mov     ds,ax
478 }
479
480
481 void MoveParas (unsigned source, unsigned dest, unsigned paragraphs)
482 {
483   if (source>dest)
484   {
485 asm     cld
486     while (paragraphs>0xfff)
487     {
488       MoveParaBase (source,dest,0xfff*8);
489       source += 0xfff*8;
490       dest += 0xfff*8;
491       paragraphs -= 0xfff;
492     }
493     MoveParaBase (source,dest,paragraphs*8);
494   }
495   else
496   {
497 asm     std
498     source+=paragraphs;
499     dest+=paragraphs;
500     while (paragraphs>0xfff)
501     {
502       source-=0xfff;
503       dest-=0xfff;
504       MoveParaBaseUp (source,dest,0xfff*8);
505       paragraphs -= 0xfff;
506     }
507     source-=paragraphs;
508     dest-=paragraphs;
509     MoveParaBaseUp (source,dest,paragraphs*8);
510 asm     cld
511   }
512 }
513
514
515 /*
516 ======================
517 =
518 = MMSortMem
519 =
520 = Sorts all non locked blocks so lower purge levels are lower in memory
521 = and all free space is at the top
522 =
523 ======================
524 */
525
526 int keyblock;
527
528 //
529 // PushUp
530 //
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
534 //
535 void PushUp (int move)
536 {
537   unsigned source,dest,size;
538   int i;
539
540   size = blocks[move].length;
541   source = blocks[move].start;
542
543   for (i=numblocks-1;i>keyblock;i--)
544   {
545   //
546   // if the block can fit under this block, move it
547   //
548     dest = blocks[i].start - size;
549     if (blocks[i-1].start+blocks[i-1].length <= dest)
550     {
551     //
552     // make a copy of block 'move' under block 'i'
553     //
554       InsertBlock (i-1);
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);
559       break;
560     }
561   }
562
563   //
564   // erase original position
565   //
566   RemoveBlock (move);
567   keyblock--;           // because a block below it was removed
568 }
569
570
571 //
572 // PushDown
573 //
574 // Push keyblock (unpurgable) as low in memory as possible
575 //
576 void PushDown (void)
577 {
578   unsigned source,dest,size,end,lowblock,checkblock,i;
579
580   size = blocks[keyblock].length;
581   source = blocks[keyblock].start;
582
583 //
584 // find the lowest space it can be moved into
585 //
586   for (lowblock = 0;lowblock<keyblock;lowblock++)
587     if (!(blocks[lowblock].attributes & PURGEBITS) ||
588         blocks[lowblock].attributes & LOCKBIT)
589     {
590     //
591     // found a locked or nonpurgable block below keyblock
592     //
593     // see if there is enough space to move block
594     //
595       dest = blocks[lowblock].start + blocks[lowblock].length;
596       end = dest+size;
597
598     //
599     // see if any of the blocks in the middle can be moved away
600     //
601       checkblock = lowblock+1;
602       while (checkblock < keyblock && blocks[checkblock].start<end)
603       {
604         if (!(blocks[checkblock].attributes & PURGEBITS) )
605           goto nofit;   // can't fit between two locked blocks
606         //
607         // push the block up or remove it, in either case dropping
608         // keyblock and changing blocks[checkblock]
609         //
610         PushUp (checkblock);
611       }
612 //
613 // move it!
614 //
615       if (dest != source)
616       {
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)
621         {
622         //
623         // reorder the block records
624         //
625           tempblock = blocks[keyblock];
626           for (i=keyblock;i>lowblock+1;i--)
627             blocks[i]=blocks[i-1];
628           blocks[lowblock+1] = tempblock;
629         }
630
631 //MMBlockDump();        // DEBUG
632       }
633       return;
634
635  nofit:;                // keep looking...
636
637     }
638 }
639
640
641 //
642 // MMSortMem
643 //
644
645 void MMSortMem (void)
646 {
647   unsigned i,source,dest;
648
649   keyblock = 0;
650
651   do
652   {
653     keyblock++;
654
655     //
656     // non-purgable, unlocked blocks will be pushed low in memory
657     //
658     if ( !(blocks[keyblock].attributes & PURGEBITS) &&
659          !(blocks[keyblock].attributes & LOCKBIT) )
660       PushDown ();
661
662   } while (keyblock<numblocks-1);
663
664
665   for (i=numblocks-2;i>0;i--)
666   {
667     //
668     // push all purgable blocks as high as possible
669     // Currently they are NOT moved around locked blocks!
670     //
671     if ( blocks[i].attributes & PURGEBITS )
672     {
673       source= blocks[i].start;
674       dest= blocks[i+1].start-blocks[i].length;
675       if (source!=dest)
676       {
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
680       }
681     }
682   }
683
684   PatchPointers();              // let the main program fix up any
685                                 // internal references
686 }
687
688
689 //==========================================================================
690
691 /*
692 =======================
693 =
694 = MMBlockDump
695 =
696 = Dewbug tool
697 =
698 =======================
699 */
700
701 void MMBlockDump (void)
702 {
703   int i;
704   unsigned free;
705
706   fprintf (stdprn,"-------------\n");
707   for (i=0;i<numblocks;i++)
708   {
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);
711     if (i<numblocks-1)
712     {
713       free = blocks[i+1].start - (blocks[i].start+blocks[i].length);
714       if (free)
715         fprintf (stdprn,"### Free:%X\n",free);
716     }
717   }
718   puts("");
719 }
720
721
722 //==========================================================================
723
724 /*
725 ======================
726 =
727 = MMUnusedMemory
728 =
729 = Returns the total free space without purging
730 =
731 ======================
732 */
733
734 unsigned MMUnusedMemory (void)
735 {
736   int i;
737   unsigned free;
738
739   free = 0;
740
741   for (i=0;i<numblocks;i++)
742   {
743     if (i<numblocks-1)
744       free += blocks[i+1].start - (blocks[i].start+blocks[i].length);
745   }
746
747   return free;
748 }
749
750 //==========================================================================
751
752
753 /*
754 ======================
755 =
756 = MMTotalFree
757 =
758 = Returns the total free space with purging
759 =
760 ======================
761 */
762
763 unsigned MMTotalFree (void)
764 {
765   int i;
766   unsigned free;
767
768   free = 0;
769
770   for (i=0;i<numblocks;i++)
771   {
772     if (blocks[i].attributes & PURGEBITS)
773       free += blocks[i].length;
774     if (i<numblocks-1)
775       free += blocks[i+1].start - (blocks[i].start+blocks[i].length);
776   }
777
778   return free;
779 }
780
781 //==========================================================================