]> 4ch.mooo.com Git - 16.git/blob - src/lib/16_mm.c
111b696de77ef4715f84b59ae84e3f93d2253bc5
[16.git] / src / lib / 16_mm.c
1 /* Catacomb Apocalypse Source Code\r
2  * Copyright (C) 1993-2014 Flat Rock Software\r
3  *\r
4  * This program is free software; you can redistribute it and/or modify\r
5  * it under the terms of the GNU General Public License as published by\r
6  * the Free Software Foundation; either version 2 of the License, or\r
7  * (at your option) any later version.\r
8  *\r
9  * This program is distributed in the hope that it will be useful,\r
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
12  * GNU General Public License for more details.\r
13  *\r
14  * You should have received a copy of the GNU General Public License along\r
15  * with this program; if not, write to the Free Software Foundation, Inc.,\r
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
17  */\r
18 \r
19 // NEWMM.C\r
20 \r
21 /*\r
22 =============================================================================\r
23 \r
24                         ID software memory manager\r
25                         --------------------------\r
26 \r
27 Primary coder: John Carmack\r
28 \r
29 RELIES ON\r
30 ---------\r
31 Quit (char *error) function\r
32 \r
33 \r
34 WORK TO DO\r
35 ----------\r
36 MM_SizePtr to change the size of a given pointer\r
37 \r
38 Multiple purge levels utilized\r
39 \r
40 EMS / XMS unmanaged routines\r
41 \r
42 =============================================================================\r
43 */\r
44 \r
45 #include "src/lib/16_mm.h"\r
46
47 /*\r
48 =============================================================================\r
49 \r
50                                                  GLOBAL VARIABLES\r
51 \r
52 =============================================================================\r
53 */\r
54 \r
55 mminfotype      mminfo;\r
56 memptr          bufferseg;\r
57 boolean         mmerror;\r
58 \r
59 void            (* beforesort) (void);\r
60 void            (* aftersort) (void);\r
61 \r
62 /*\r
63 =============================================================================\r
64 \r
65                                                  LOCAL VARIABLES\r
66 \r
67 =============================================================================\r
68 */\r
69 \r
70 boolean         mmstarted;\r
71 \r
72 void far        *farheap;\r
73 void            *nearheap;\r
74 \r
75 mmblocktype     far mmblocks[MAXBLOCKS]\r
76                         ,far *mmhead,far *mmfree,far *mmrover,far *mmnew;\r
77 \r
78 boolean         bombonerror;\r
79 \r
80 unsigned        totalEMSpages,freeEMSpages,EMSpageframe,EMSpagesmapped,EMShandle;
81 unsigned int EMSVer;\r
82 \r
83 void            (* XMSaddr) (void);             // far pointer to XMS driver\r
84 \r
85 unsigned        numUMBs,UMBbase[MAXUMBS];
86
87 static  char *ParmStringsexmm[] = {"noems","noxms",""};
88 \r
89 /*\r
90 ======================\r
91 =\r
92 = MML_CheckForEMS\r
93 =\r
94 = Routine from p36 of Extending DOS\r
95 =\r
96 =======================\r
97 */\r
98 \r
99 boolean MML_CheckForEMS (void)\r
100 {\r
101         boolean emmcfems;\r
102         char    emmname[] = "EMMXXXX0";\r
103 //              mov     dx,OFFSET emmname\r
104         __asm {\r
105                 LEA     DX, emmname     //fix by andrius4669\r
106                 mov     ax,0x3d00\r
107                 int     0x21            // try to open EMMXXXX0 device\r
108                 jc      error\r
109 \r
110                 mov     bx,ax\r
111                 mov     ax,0x4400\r
112 \r
113                 int     0x21            // get device info\r
114                 jc      error\r
115 \r
116                 and     dx,0x80\r
117                 jz      error\r
118 \r
119                 mov     ax,0x4407\r
120 \r
121                 int     0x21            // get status\r
122                 jc      error\r
123                 or      al,al\r
124                 jz      error\r
125 \r
126                 mov     ah,0x3e\r
127                 int     0x21            // close handle\r
128                 jc      error\r
129                 //\r
130                 // EMS is good\r
131                 //\r
132                 mov     emmcfems,1\r
133                 jmp End\r
134                 error:\r
135                 //\r
136                 // EMS is bad\r
137                 //\r
138                 mov     emmcfems,0\r
139                 End:\r
140         }\r
141         return(emmcfems);\r
142 }\r
143 \r
144 \r
145 /*\r
146 ======================\r
147 =\r
148 = MML_SetupEMS\r
149 =\r
150 =======================\r
151 */\r
152 \r
153 unsigned MML_SetupEMS (void)\r
154 {\r
155         char    str[80],str2[10];\r
156         unsigned        err;\r
157         boolean errorflag=false;\r
158         union REGS CPURegs;\r
159 \r
160         EMSVer = 0;\r
161         totalEMSpages = freeEMSpages = EMSpageframe = EMSpagesmapped = 0;\r
162 \r
163         __asm\r
164                 {\r
165                 mov     ah,EMS_STATUS\r
166                 int     EMS_INT                                         // make sure EMS hardware is present\r
167                 or      ah,ah\r
168                 jnz     error\r
169 \r
170                 mov     ah,EMS_VERSION\r
171                 int     EMS_INT\r
172                 or      ah,ah\r
173                 jnz     error\r
174                 mov     [EMSVer],ax                             //      set EMSVer\r
175                 cmp     al,0x32                                         // only work on ems 3.2 or greater\r
176                 jb      error\r
177 \r
178                 mov     ah,EMS_GETFRAME\r
179                 int     EMS_INT                                         // find the page frame address\r
180                 or      ah,ah\r
181                 jnz     error\r
182                 mov     [EMSpageframe],bx\r
183 \r
184                 mov     ah,EMS_GETPAGES\r
185                 int     EMS_INT                                         // find out how much EMS is there\r
186                 or      ah,ah\r
187                 jnz     error\r
188                 mov     [totalEMSpages],dx\r
189                 mov     [freeEMSpages],bx\r
190                 or      bx,bx\r
191                 jz      noEMS                                           // no EMS at all to allocate\r
192 \r
193                 cmp     bx,4\r
194                 jle     getpages                                        // there is only 1,2,3,or 4 pages\r
195                 mov     bx,4                                            // we can't use more than 4 pages\r
196 \r
197 getpages:\r
198                 mov     [EMSpagesmapped],bx\r
199                 mov     ah,EMS_ALLOCPAGES                       // allocate up to 64k of EMS\r
200                 int     EMS_INT\r
201                 or      ah,ah\r
202                 jnz     error\r
203                 mov     [EMShandle],dx\r
204                 jmp End\r
205 error:\r
206                 mov     errorflag,1\r
207                 jmp End\r
208 noEMS:\r
209 End:\r
210         }\r
211         if(errorflag==true)\r
212         {\r
213                 err = CPURegs.h.ah;\r
214                 strcpy(str,"MML_SetupEMS: EMS error 0x");\r
215                 itoa(err,str2,16);\r
216                 strcpy(str,str2);\r
217                 printf("%s\n",str);
218                 return err;\r
219         }
220         return 0;\r
221 }\r
222 \r
223 \r
224 /*\r
225 ======================\r
226 =\r
227 = MML_ShutdownEMS\r
228 =\r
229 =======================\r
230 */\r
231 \r
232 void MML_ShutdownEMS (void)\r
233 {\r
234         boolean errorflag=false;\r
235         if (!EMShandle)\r
236                 return;\r
237         __asm\r
238         {\r
239                 mov     ah,EMS_FREEPAGES\r
240                 mov     dx,[EMShandle]\r
241                 int     EMS_INT\r
242                 or      ah,ah\r
243                 jz      ok\r
244                 mov     errorflag,1\r
245                 ok:\r
246         }\r
247         if(errorflag==true) printf("MML_ShutdownEMS: Error freeing EMS!");      //++++ add something\r
248 }\r
249 \r
250 /*\r
251 ====================\r
252 =\r
253 = MM_MapEMS\r
254 =\r
255 = Maps the 64k of EMS used by memory manager into the page frame\r
256 = for general use.  This only needs to be called if you are keeping\r
257 = other things in EMS.\r
258 =\r
259 ====================\r
260 */\r
261 \r
262 unsigned MM_MapEMS (void)\r
263 {\r
264         char    str[80],str2[10];\r
265         unsigned        err;\r
266         boolean errorflag=false;\r
267         int     i;\r
268         union REGS CPURegs;\r
269 \r
270         for (i=0;i<EMSpagesmapped;i++)\r
271         {\r
272                 __asm\r
273                 {\r
274                         mov     ah,EMS_MAPPAGE\r
275                         mov     bx,[i]                  // logical page\r
276                         mov     al,bl                   // physical page\r
277                         mov     dx,[EMShandle]  // handle\r
278                         int     EMS_INT\r
279                         or      ah,ah\r
280                         jnz     error\r
281                         jmp End\r
282                         error:\r
283                         mov     errorflag,1\r
284                         End:\r
285                 }\r
286                 if(errorflag==true)\r
287                 {\r
288                         err = CPURegs.h.ah;\r
289                         strcpy(str,"MM_MapEMS: EMS error 0x");\r
290                         itoa(err,str2,16);\r
291                         strcpy(str,str2);\r
292                         printf("%s\n",str);
293                         return err;\r
294                 }\r
295         }\r
296         return 0;\r
297 }\r
298 \r
299 //==========================================================================\r
300 \r
301 /*\r
302 ======================\r
303 =\r
304 = MML_CheckForXMS\r
305 =\r
306 = Check for XMM driver\r
307 =\r
308 =======================\r
309 */\r
310 \r
311 boolean MML_CheckForXMS (void)\r
312 {\r
313         boolean errorflag=false;\r
314         numUMBs = 0;\r
315 \r
316         __asm\r
317         {\r
318                 mov     ax,0x4300\r
319                 int     0x2f                            // query status of installed diver\r
320                 cmp     al,0x80\r
321                 je      good\r
322                 mov     errorflag,1\r
323                 good:\r
324         }\r
325         if(errorflag==true) return false;\r
326         else return true;\r
327 }\r
328 \r
329 \r
330 /*\r
331 ======================\r
332 =\r
333 = MML_SetupXMS\r
334 =\r
335 = Try to allocate all upper memory block\r
336 =\r
337 =======================\r
338 */\r
339 \r
340 void MML_SetupXMS (void)\r
341 {\r
342         unsigned        base,size;\r
343 \r
344         __asm\r
345         {\r
346                 mov     ax,0x4310\r
347                 int     0x2f\r
348                 mov     [WORD PTR XMSaddr],bx\r
349                 mov     [WORD PTR XMSaddr+2],es         // function pointer to XMS driver\r
350         }\r
351 getmemory:\r
352         __asm\r
353         {\r
354                 mov     ah,XMS_ALLOCUMB\r
355                 mov     dx,0xffff                                       // try for largest block possible\r
356                 call    [DWORD PTR XMSaddr]\r
357                 or      ax,ax\r
358                 jnz     gotone\r
359 \r
360                 cmp     bl,0xb0                                         // error: smaller UMB is available\r
361                 jne     done;\r
362 \r
363                 mov     ah,XMS_ALLOCUMB\r
364                 call    [DWORD PTR XMSaddr]             // DX holds largest available UMB\r
365                 or      ax,ax\r
366                 jz      done                                            // another error...\r
367 \r
368 gotone:\r
369                 mov     [base],bx\r
370                 mov     [size],dx\r
371 done:\r
372         }\r
373         MML_UseSpace (base,size);\r
374         mminfo.XMSmem += size*16;\r
375         UMBbase[numUMBs] = base;\r
376         numUMBs++;\r
377         if (numUMBs < MAXUMBS)\r
378                 goto getmemory;\r
379 }\r
380 \r
381 \r
382 /*\r
383 ======================\r
384 =\r
385 = MML_ShutdownXMS\r
386 =\r
387 ======================\r
388 */\r
389 \r
390 void MML_ShutdownXMS (void)\r
391 {\r
392         int     i;\r
393         unsigned        base;\r
394 \r
395         for (i=0;i<numUMBs;i++)\r
396         {\r
397                 base = UMBbase[i];\r
398                 __asm\r
399                 {\r
400                         mov     ah,XMS_FREEUMB\r
401                         mov     dx,[base]\r
402                         call    [DWORD PTR XMSaddr]\r
403                 }\r
404         }\r
405 }\r
406 \r
407 //==========================================================================\r
408 \r
409 /*\r
410 ======================\r
411 =\r
412 = MML_UseSpace\r
413 =\r
414 = Marks a range of paragraphs as usable by the memory manager\r
415 = This is used to mark space for the near heap, far heap, ems page frame,\r
416 = and upper memory blocks\r
417 =\r
418 ======================\r
419 */\r
420 \r
421 void MML_UseSpace (unsigned segstart, unsigned seglength)\r
422 {\r
423         mmblocktype far *scan,far *last;\r
424         unsigned        oldend;\r
425         long            extra;\r
426 \r
427         scan = last = mmhead;\r
428         mmrover = mmhead;               // reset rover to start of memory\r
429 \r
430 //\r
431 // search for the block that contains the range of segments\r
432 //\r
433         while (scan->start+scan->length < segstart)\r
434         {\r
435                 last = scan;\r
436                 scan = scan->next;\r
437         }\r
438 \r
439 //\r
440 // take the given range out of the block\r
441 //\r
442         oldend = scan->start + scan->length;\r
443         extra = oldend - (segstart+seglength);\r
444         if (extra < 0)\r
445         {\r
446                 printf("MML_UseSpace: Segment spans two blocks!");\r
447                 return;\r
448         }\r
449 \r
450 \r
451         if (segstart == scan->start)\r
452         {\r
453                 last->next = scan->next;                        // unlink block\r
454                 FREEBLOCK(scan);\r
455                 scan = last;\r
456         }\r
457         else\r
458                 scan->length = segstart-scan->start;    // shorten block\r
459 \r
460         if (extra > 0)\r
461         {\r
462                 GETNEWBLOCK;\r
463                 mmnew->next = scan->next;\r
464                 scan->next = mmnew;\r
465                 mmnew->start = segstart+seglength;\r
466                 mmnew->length = extra;\r
467                 mmnew->attributes = LOCKBIT;\r
468         }\r
469 \r
470 }\r
471 \r
472 //==========================================================================\r
473 \r
474 /*\r
475 ====================\r
476 =\r
477 = MML_ClearBlock\r
478 =\r
479 = We are out of blocks, so free a purgable block\r
480 =\r
481 ====================\r
482 */\r
483 \r
484 void MML_ClearBlock (void)\r
485 {\r
486         mmblocktype far *scan,far *last;\r
487 \r
488         scan = mmhead->next;\r
489 \r
490         while (scan)\r
491         {\r
492                 if (!(scan->attributes&LOCKBIT) && (scan->attributes&PURGEBITS) )\r
493                 {\r
494                         MM_FreePtr(scan->useptr);\r
495                         return;\r
496                 }\r
497                 scan = scan->next;\r
498         }\r
499 \r
500         printf("MM_ClearBlock: No purgable blocks!");\r
501 }\r
502 \r
503 \r
504 //==========================================================================\r
505 \r
506 /*\r
507 ===================\r
508 =\r
509 = MM_Startup\r
510 =\r
511 = Grabs all space from turbo with malloc/farmalloc\r
512 = Allocates bufferseg misc buffer\r
513 =\r
514 ===================\r
515 */\r
516 \r
517 void MM_Startup (void)\r
518 {\r
519         int i;\r
520         dword length;\r
521         void far        *start;\r
522         unsigned        segstart,seglength,endfree;\r
523 \r
524         if (mminfo.mmstarted)\r
525                 MM_Shutdown ();\r
526 \r
527 \r
528         mminfo.mmstarted = true;\r
529         mminfo.bombonerror = true;\r
530 //\r
531 // set up the linked list (everything in the free list;\r
532 //\r
533         mmhead = NULL;\r
534         mmfree = &mmblocks[0];\r
535         for (i=0;i<MAXBLOCKS-1;i++)\r
536                 mmblocks[i].next = &mmblocks[i+1];\r
537         mmblocks[i].next = NULL;\r
538 \r
539 //\r
540 // locked block of all memory until we punch out free space\r
541 //\r
542         GETNEWBLOCK;\r
543         mmhead = mmnew;                         // this will allways be the first node\r
544         mmnew->start = 0;\r
545         mmnew->length = 0xffff;\r
546         mmnew->attributes = LOCKBIT;\r
547         mmnew->next = NULL;\r
548         mmrover = mmhead;\r
549 \r
550 \r
551 //\r
552 // get all available near conventional memory segments\r
553 //\r
554 //----  length=coreleft();\r
555         _nheapgrow();\r
556         length=_memavl();\r
557         start = (void far *)(nearheap = malloc(length));\r
558 \r
559         length -= 16-(FP_OFF(start)&15);\r
560         length -= SAVENEARHEAP;\r
561         seglength = length / 16;                        // now in paragraphs\r
562         segstart = FP_SEG(start)+(FP_OFF(start)+15)/16;\r
563         MML_UseSpace (segstart,seglength);\r
564         mminfo.nearheap = length;\r
565 \r
566 //\r
567 // get all available far conventional memory segments\r
568 //\r
569 //----  length=farcoreleft();\r
570         _fheapgrow();\r
571         length=_memavl();\r
572         start = farheap = _fmalloc(length);\r
573         length -= 16-(FP_OFF(start)&15);\r
574         length -= SAVEFARHEAP;\r
575         seglength = length / 16;                        // now in paragraphs\r
576         segstart = FP_SEG(start)+(FP_OFF(start)+15)/16;\r
577         MML_UseSpace (segstart,seglength);\r
578         mminfo.farheap = length;\r
579         mminfo.mainmem = mminfo.nearheap + mminfo.farheap;\r
580 \r
581 \r
582 //\r
583 // detect EMS and allocate up to 64K at page frame\r
584 //\r
585         mminfo.EMSmem = 0;\r
586         for (i = 1;i < __argc;i++)\r
587         {\r
588                 if ( US_CheckParm(__argv[i],ParmStringsexmm) == 0)\r
589                         goto emsskip;                           // param NOEMS\r
590         }\r
591 \r
592         if (MML_CheckForEMS())\r
593         {\r
594                 //printf("EMS1\n");\r
595                 MML_SetupEMS();                                 // allocate space\r
596                 //printf("EMS2\n");\r
597                 MML_UseSpace (EMSpageframe,EMSpagesmapped*0x400);\r
598                 //printf("EMS3\n");\r
599                 MM_MapEMS();                                    // map in used pages\r
600                 //printf("EMS4\n");\r
601                 mminfo.EMSmem = EMSpagesmapped*0x4000l;\r
602         }\r
603 \r
604 //\r
605 // detect XMS and get upper memory blocks\r
606 //\r
607 emsskip:\r
608         mminfo.XMSmem = 0;\r
609         for (i = 1;i < __argc;i++)\r
610         {\r
611                 if ( US_CheckParm(__argv[i],ParmStringsexmm) == 0)\r
612                         goto xmsskip;                           // param NOXMS\r
613         }\r
614 \r
615         if (MML_CheckForXMS())\r
616         {\r
617 //              printf("XMS!\n");\r
618 //++++          MML_SetupXMS();                                 // allocate as many UMBs as possible\r
619         }\r
620 \r
621 //\r
622 // allocate the misc buffer\r
623 //\r
624 xmsskip:\r
625         mmrover = mmhead;               // start looking for space after low block\r
626 \r
627         MM_GetPtr (&bufferseg,BUFFERSIZE);\r
628 }\r
629 \r
630 //==========================================================================\r
631 \r
632 /*\r
633 ====================\r
634 =\r
635 = MM_Shutdown\r
636 =\r
637 = Frees all conventional, EMS, and XMS allocated\r
638 =\r
639 ====================\r
640 */\r
641 \r
642 void MM_Shutdown (void)\r
643 {\r
644   if (!mminfo.mmstarted)\r
645         return;\r
646 \r
647   _ffree (farheap);
648   printf("far freed\n");\r
649   free (nearheap);
650   printf("near freed\n");\r
651   //hfree(hugeheap);
652   printf("huge freed\n");\r
653   MML_ShutdownEMS ();
654   printf("EMS freed\n");\r
655 //++++  MML_ShutdownXMS ();
656   printf("XMS freed\n");\r
657 }\r
658 \r
659 //==========================================================================\r
660 \r
661 /*\r
662 ====================\r
663 =\r
664 = MM_GetPtr\r
665 =\r
666 = Allocates an unlocked, unpurgable block\r
667 =\r
668 ====================\r
669 */\r
670 \r
671 void MM_GetPtr (memptr *baseptr,dword size)\r
672 {\r
673         mmblocktype far *scan,far *lastscan,far *endscan\r
674                                 ,far *purge,far *next;\r
675         int                     search;\r
676         unsigned        needed,startseg;\r
677 \r
678         needed = (size+15)/16;          // convert size from bytes to paragraphs\r
679 \r
680         GETNEWBLOCK;                            // fill in start and next after a spot is found\r
681         mmnew->length = needed;\r
682         mmnew->useptr = baseptr;\r
683         mmnew->attributes = BASEATTRIBUTES;\r
684 \r
685         for (search = 0; search<3; search++)\r
686         {\r
687         //\r
688         // first search:        try to allocate right after the rover, then on up\r
689         // second search:       search from the head pointer up to the rover\r
690         // third search:        compress memory, then scan from start\r
691                 if (search == 1 && mmrover == mmhead)\r
692                         search++;\r
693 \r
694                 switch (search)\r
695                 {\r
696                 case 0:\r
697                         lastscan = mmrover;\r
698                         scan = mmrover->next;\r
699                         endscan = NULL;\r
700                         break;\r
701                 case 1:\r
702                         lastscan = mmhead;\r
703                         scan = mmhead->next;\r
704                         endscan = mmrover;\r
705                         break;\r
706                 case 2:\r
707                         MM_SortMem ();\r
708                         lastscan = mmhead;\r
709                         scan = mmhead->next;\r
710                         endscan = NULL;\r
711                         break;\r
712                 }\r
713 \r
714                 startseg = lastscan->start + lastscan->length;\r
715 \r
716                 while (scan != endscan)\r
717                 {\r
718                         if (scan->start - startseg >= needed)\r
719                         {\r
720                         //\r
721                         // got enough space between the end of lastscan and\r
722                         // the start of scan, so throw out anything in the middle\r
723                         // and allocate the new block\r
724                         //\r
725                                 purge = lastscan->next;\r
726                                 lastscan->next = mmnew;\r
727                                 mmnew->start = *(unsigned *)baseptr = startseg;\r
728                                 mmnew->next = scan;\r
729                                 while ( purge != scan)\r
730                                 {       // free the purgable block\r
731                                         next = purge->next;\r
732                                         FREEBLOCK(purge);\r
733                                         purge = next;           // purge another if not at scan\r
734                                 }\r
735                                 mmrover = mmnew;\r
736                                 return; // good allocation!\r
737                         }\r
738 \r
739                         //\r
740                         // if this block is purge level zero or locked, skip past it\r
741                         //\r
742                         if ( (scan->attributes & LOCKBIT)\r
743                                 || !(scan->attributes & PURGEBITS) )\r
744                         {\r
745                                 lastscan = scan;\r
746                                 startseg = lastscan->start + lastscan->length;\r
747                         }\r
748 \r
749 \r
750                         scan=scan->next;                // look at next line\r
751                 }\r
752         }\r
753 \r
754         if (mminfo.bombonerror)\r
755                 printf(OUT_OF_MEM_MSG,(size-mminfo.nearheap));\r
756         else\r
757                 mminfo.mmerror = true;\r
758 }\r
759 \r
760 //==========================================================================\r
761 \r
762 /*\r
763 ====================\r
764 =\r
765 = MM_FreePtr\r
766 =\r
767 = Allocates an unlocked, unpurgable block\r
768 =\r
769 ====================\r
770 */\r
771 \r
772 void MM_FreePtr (memptr *baseptr)\r
773 {\r
774         mmblocktype far *scan,far *last;\r
775 \r
776         last = mmhead;\r
777         scan = last->next;\r
778 \r
779         if (baseptr == mmrover->useptr) // removed the last allocated block\r
780                 mmrover = mmhead;\r
781 \r
782         while (scan->useptr != baseptr && scan)\r
783         {\r
784                 last = scan;\r
785                 scan = scan->next;\r
786         }\r
787 \r
788         if (!scan)\r
789         {\r
790                 printf("MM_FreePtr: Block not found!");\r
791                 return;\r
792         }\r
793 \r
794         last->next = scan->next;\r
795 \r
796         FREEBLOCK(scan);\r
797 }\r
798 //==========================================================================\r
799 \r
800 /*\r
801 =====================\r
802 =\r
803 = MM_SetPurge\r
804 =\r
805 = Sets the purge level for a block (locked blocks cannot be made purgable)\r
806 =\r
807 =====================\r
808 */\r
809 \r
810 void MM_SetPurge (memptr *baseptr, int purge)\r
811 {\r
812         mmblocktype far *start;\r
813 \r
814         start = mmrover;\r
815 \r
816         do\r
817         {\r
818                 if (mmrover->useptr == baseptr)\r
819                         break;\r
820 \r
821                 mmrover = mmrover->next;\r
822 \r
823                 if (!mmrover)\r
824                         mmrover = mmhead;\r
825                 else if (mmrover == start)\r
826                 {\r
827                         printf("MM_SetPurge: Block not found!");\r
828                         return;\r
829                 }\r
830 \r
831         } while (1);\r
832 \r
833         mmrover->attributes &= ~PURGEBITS;\r
834         mmrover->attributes |= purge;\r
835 }\r
836 \r
837 //==========================================================================\r
838 \r
839 /*\r
840 =====================\r
841 =\r
842 = MM_SetLock\r
843 =\r
844 = Locks / unlocks the block\r
845 =\r
846 =====================\r
847 */\r
848 \r
849 void MM_SetLock (memptr *baseptr, boolean locked)\r
850 {\r
851         mmblocktype far *start;\r
852 \r
853         start = mmrover;\r
854 \r
855         do\r
856         {\r
857                 if (mmrover->useptr == baseptr)\r
858                         break;\r
859 \r
860                 mmrover = mmrover->next;\r
861 \r
862                 if (!mmrover)\r
863                         mmrover = mmhead;\r
864                 else if (mmrover == start)\r
865                 {\r
866                         printf("MM_SetLock: Block not found!");\r
867                         return;\r
868                 }\r
869 \r
870         } while (1);\r
871 \r
872         mmrover->attributes &= ~LOCKBIT;\r
873         mmrover->attributes |= locked*LOCKBIT;\r
874 }\r
875 \r
876 //==========================================================================\r
877 \r
878 /*\r
879 =====================\r
880 =\r
881 = MM_SortMem\r
882 =\r
883 = Throws out all purgable stuff and compresses movable blocks\r
884 =\r
885 =====================\r
886 */\r
887 \r
888 void MM_SortMem (void)\r
889 {\r
890         mmblocktype far *scan,far *last,far *next;\r
891         unsigned        start,length,source,dest,oldborder;\r
892         int                     playing;\r
893 \r
894         //\r
895         // lock down a currently playing sound\r
896         //\r
897 /*++++  playing = SD_SoundPlaying ();\r
898         if (playing)\r
899         {\r
900                 switch (SoundMode)\r
901                 {\r
902                 case sdm_PC:\r
903                         playing += STARTPCSOUNDS;\r
904                         break;\r
905                 case sdm_AdLib:\r
906                         playing += STARTADLIBSOUNDS;\r
907                         break;\r
908                 }\r
909                 MM_SetLock(&(memptr)audiosegs[playing],true);\r
910         }\r
911 \r
912 \r
913         SD_StopSound();*/\r
914 //      oldborder = bordercolor;\r
915 //      VW_ColorBorder (15);\r
916 \r
917         if (beforesort)\r
918                 beforesort();\r
919 \r
920         scan = mmhead;\r
921 \r
922         last = NULL;            // shut up compiler warning\r
923 \r
924         while (scan)\r
925         {\r
926                 if (scan->attributes & LOCKBIT)\r
927                 {\r
928                 //\r
929                 // block is locked, so try to pile later blocks right after it\r
930                 //\r
931                         start = scan->start + scan->length;\r
932                 }\r
933                 else\r
934                 {\r
935                         if (scan->attributes & PURGEBITS)\r
936                         {\r
937                         //\r
938                         // throw out the purgable block\r
939                         //\r
940                                 next = scan->next;\r
941                                 FREEBLOCK(scan);\r
942                                 last->next = next;\r
943                                 scan = next;\r
944                                 continue;\r
945                         }\r
946                         else\r
947                         {\r
948                         //\r
949                         // push the non purgable block on top of the last moved block\r
950                         //\r
951                                 if (scan->start != start)\r
952                                 {\r
953                                         length = scan->length;\r
954                                         source = scan->start;\r
955                                         dest = start;\r
956                                         while (length > 0xf00)\r
957                                         {\r
958                                                 movedata(source,0,dest,0,0xf00*16);\r
959                                                 length -= 0xf00;\r
960                                                 source += 0xf00;\r
961                                                 dest += 0xf00;\r
962                                         }\r
963                                         movedata(source,0,dest,0,length*16);\r
964 \r
965                                         scan->start = start;\r
966                                         *(unsigned *)scan->useptr = start;\r
967                                 }\r
968                                 start = scan->start + scan->length;\r
969                         }\r
970                 }\r
971 \r
972                 last = scan;\r
973                 scan = scan->next;              // go to next block\r
974         }\r
975 \r
976         mmrover = mmhead;\r
977 \r
978         if (aftersort)\r
979                 aftersort();\r
980 \r
981 //      VW_ColorBorder (oldborder);\r
982 \r
983 /*++++  if (playing)\r
984                 MM_SetLock(&(memptr)audiosegs[playing],false);*/\r
985 }\r
986 \r
987 \r
988 //==========================================================================\r
989 \r
990 //****#if 0\r
991 /*\r
992 =====================\r
993 =\r
994 = MM_ShowMemory\r
995 =\r
996 =====================\r
997 */\r
998 \r
999 void MM_ShowMemory (void)\r
1000 {\r
1001         mmblocktype far *scan;\r
1002         unsigned color,temp;//, i;\r
1003         long    end,owner;\r
1004         char    scratch[80],str[10];\r
1005 \r
1006 //****  VW_SetDefaultColors();\r
1007 //****  VW_SetLineWidth(40);\r
1008 //++++mh        temp = bufferofs;\r
1009 //++++mh        bufferofs = 0;\r
1010 //****  VW_SetScreen (0,0);\r
1011 \r
1012         scan = mmhead;\r
1013 \r
1014         end = -1;\r
1015 \r
1016 //CA_OpenDebug ();\r
1017 \r
1018         while (scan)\r
1019         {\r
1020                 if (scan->attributes & PURGEBITS)\r
1021                         color = 5;              // dark purple = purgable\r
1022                 else\r
1023                         color = 9;              // medium blue = non purgable\r
1024                 if (scan->attributes & LOCKBIT)\r
1025                         color = 12;             // red = locked\r
1026                 if (scan->start<=end)\r
1027                 {\r
1028                         printf("MM_ShowMemory: Memory block order currupted!");\r
1029                         return;\r
1030                 }\r
1031                 end = scan->start+scan->length-1;\r
1032 //++++          VW_Hlin(scan->start,(unsigned)end,0,color);\r
1033 //++++          VW_Plot(scan->start,0,15);\r
1034                 if (scan->next->start > end+1)\r
1035 //++++                  VW_Hlin(end+1,scan->next->start,0,0);   // black = free\r
1036 \r
1037 //****#if 0\r
1038 printf("Location:");\r
1039 printf("%Fp\t", scan->start);\r
1040 strcpy (scratch,"Size:");\r
1041 ltoa ((long)scan->length*16,str,10);\r
1042 strcat (scratch,str);\r
1043 strcat (scratch,"\tOwner:0x");\r
1044 owner = (unsigned)scan->useptr;\r
1045 ultoa (owner,str,16);\r
1046 strcat (scratch,str);\r
1047 strcat (scratch,"\n");\r
1048 //++++write (debughandle,scratch,strlen(scratch));\r
1049 fprintf(stdout, "%s", scratch);\r
1050 //****#endif\r
1051 \r
1052                 scan = scan->next;\r
1053         }\r
1054 \r
1055 //CA_CloseDebug ();\r
1056 \r
1057 //++++mh        IN_Ack();\r
1058 //****  VW_SetLineWidth(64);\r
1059 //++++mh        bufferofs = temp;\r
1060 }\r
1061 //****#endif\r
1062 \r
1063 //==========================================================================\r
1064 \r
1065 \r
1066 /*\r
1067 ======================\r
1068 =\r
1069 = MM_UnusedMemory\r
1070 =\r
1071 = Returns the total free space without purging\r
1072 =\r
1073 ======================\r
1074 */\r
1075 \r
1076 dword MM_UnusedMemory (void)\r
1077 {\r
1078         unsigned free;\r
1079         mmblocktype far *scan;\r
1080 \r
1081         free = 0;\r
1082         scan = mmhead;\r
1083 \r
1084         while (scan->next)\r
1085         {\r
1086                 free += scan->next->start - (scan->start + scan->length);\r
1087                 scan = scan->next;\r
1088         }\r
1089 \r
1090         return free*16l;\r
1091 //      return free;\r
1092 }\r
1093 \r
1094 //==========================================================================\r
1095 \r
1096 \r
1097 /*\r
1098 ======================\r
1099 =\r
1100 = MM_TotalFree\r
1101 =\r
1102 = Returns the total free space with purging\r
1103 =\r
1104 ======================\r
1105 */\r
1106 \r
1107 dword MM_TotalFree (void)\r
1108 {\r
1109         unsigned free;\r
1110         mmblocktype far *scan;\r
1111 \r
1112         free = 0;\r
1113         scan = mmhead;\r
1114 \r
1115         while (scan->next)\r
1116         {\r
1117                 if ((scan->attributes&PURGEBITS) && !(scan->attributes&LOCKBIT))\r
1118                         free += scan->length;\r
1119                 free += scan->next->start - (scan->start + scan->length);\r
1120                 scan = scan->next;\r
1121         }\r
1122 \r
1123         return free*16l;\r
1124 //      return free;\r
1125 }\r
1126 \r
1127 //==========================================================================\r
1128 \r
1129 /*\r
1130 =====================\r
1131 =\r
1132 = MM_Report\r
1133 =\r
1134 =====================\r
1135 */\r
1136 \r
1137 void MM_Report(void)\r
1138 {\r
1139         printf("EMM %x available\n", EMSVer);\r
1140         printf("totalEMSpages=%u\n", totalEMSpages);\r
1141         printf("freeEMSpages=%u\n", freeEMSpages);\r
1142         printf("EMSpageframe=%Fp\n", EMSpageframe);\r
1143         printf("near=%lu\n", mminfo.nearheap);\r
1144         printf("far=%lu\n", mminfo.farheap);\r
1145         printf("EMSmem=%lu\n", mminfo.EMSmem);\r
1146         printf("XMSmem=%lu\n", mminfo.XMSmem);\r
1147         printf("mainmem=%lu\n", mminfo.mainmem);\r
1148         printf("UnusedMemory=%lu\n", MM_UnusedMemory());\r
1149         printf("TotalFree=%lu\n", MM_TotalFree());\r
1150 //      printf("\n");\r
1151 //      printf("UnusedMemory=%lu kb\n", MM_UnusedMemory()/10248);\r
1152 //      printf("TotalFree=%lu kb\n", MM_TotalFree()/10248);\r
1153 }\r
1154 \r
1155 //==========================================================================\r
1156 \r
1157 /*\r
1158 =====================\r
1159 =\r
1160 = MM_EMSVer\r
1161 =\r
1162 =====================\r
1163 \r
1164 \r
1165 int MM_EMSVer(void)\r
1166 {\r
1167         int EMSver;\r
1168         __asm\r
1169         {\r
1170                 mov             ah,EMS_VERSION\r
1171                 int             EMS_INT\r
1172                 mov             EMSver,ax\r
1173         }\r
1174         return(EMSver);\r
1175 }*/\r
1176 \r
1177 //==========================================================================\r
1178 \r
1179 /*\r
1180 =====================\r
1181 =\r
1182 = MM_BombOnError\r
1183 =\r
1184 =====================\r
1185 */\r
1186 \r
1187 void MM_BombOnError (boolean bomb)\r
1188 {\r
1189         mminfo.bombonerror = bomb;\r
1190 }\r