]> 4ch.mooo.com Git - 16.git/blob - src/lib/16_mm.c
started to work on mm libery~
[16.git] / src / lib / 16_mm.c
1 /* Catacomb Armageddon 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 void 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);\r
218         }\r
219 }\r
220 \r
221 \r
222 /*\r
223 ======================\r
224 =\r
225 = MML_ShutdownEMS\r
226 =\r
227 =======================\r
228 */\r
229 \r
230 void MML_ShutdownEMS (void)\r
231 {\r
232         boolean errorflag=false;\r
233         if (!EMShandle)\r
234                 return;\r
235         __asm\r
236         {\r
237                 mov     ah,EMS_FREEPAGES\r
238                 mov     dx,[EMShandle]\r
239                 int     EMS_INT\r
240                 or      ah,ah\r
241                 jz      ok\r
242                 mov     errorflag,1\r
243                 ok:\r
244         }\r
245         if(errorflag==true) printf("MML_ShutdownEMS: Error freeing EMS!");      //++++ add something\r
246 }\r
247 \r
248 /*\r
249 ====================\r
250 =\r
251 = MM_MapEMS\r
252 =\r
253 = Maps the 64k of EMS used by memory manager into the page frame\r
254 = for general use.  This only needs to be called if you are keeping\r
255 = other things in EMS.\r
256 =\r
257 ====================\r
258 */\r
259 \r
260 void MM_MapEMS (void)\r
261 {\r
262         char    str[80],str2[10];\r
263         unsigned        err;\r
264         boolean errorflag=false;\r
265         int     i;\r
266         union REGS CPURegs;\r
267 \r
268         for (i=0;i<EMSpagesmapped;i++)\r
269         {\r
270                 __asm\r
271                 {\r
272                         mov     ah,EMS_MAPPAGE\r
273                         mov     bx,[i]                  // logical page\r
274                         mov     al,bl                   // physical page\r
275                         mov     dx,[EMShandle]  // handle\r
276                         int     EMS_INT\r
277                         or      ah,ah\r
278                         jnz     error\r
279                         jmp End\r
280                         error:\r
281                         mov     errorflag,1\r
282                         End:\r
283                 }\r
284                 if(errorflag==true)\r
285                 {\r
286                         err = CPURegs.h.ah;\r
287                         strcpy(str,"MM_MapEMS: EMS error 0x");\r
288                         itoa(err,str2,16);\r
289                         strcpy(str,str2);\r
290                         printf("%s\n",str);\r
291                 }\r
292         }\r
293         return;\r
294 }\r
295 \r
296 //==========================================================================\r
297 \r
298 /*\r
299 ======================\r
300 =\r
301 = MML_CheckForXMS\r
302 =\r
303 = Check for XMM driver\r
304 =\r
305 =======================\r
306 */\r
307 \r
308 boolean MML_CheckForXMS (void)\r
309 {\r
310         boolean errorflag=false;\r
311         numUMBs = 0;\r
312 \r
313         __asm\r
314         {\r
315                 mov     ax,0x4300\r
316                 int     0x2f                            // query status of installed diver\r
317                 cmp     al,0x80\r
318                 je      good\r
319                 mov     errorflag,1\r
320                 good:\r
321         }\r
322         if(errorflag==true) return false;\r
323         else return true;\r
324 }\r
325 \r
326 \r
327 /*\r
328 ======================\r
329 =\r
330 = MML_SetupXMS\r
331 =\r
332 = Try to allocate all upper memory block\r
333 =\r
334 =======================\r
335 */\r
336 \r
337 void MML_SetupXMS (void)\r
338 {\r
339         unsigned        base,size;\r
340 \r
341         __asm\r
342         {\r
343                 mov     ax,0x4310\r
344                 int     0x2f\r
345                 mov     [WORD PTR XMSaddr],bx\r
346                 mov     [WORD PTR XMSaddr+2],es         // function pointer to XMS driver\r
347         }\r
348 getmemory:\r
349         __asm\r
350         {\r
351                 mov     ah,XMS_ALLOCUMB\r
352                 mov     dx,0xffff                                       // try for largest block possible\r
353                 call    [DWORD PTR XMSaddr]\r
354                 or      ax,ax\r
355                 jnz     gotone\r
356 \r
357                 cmp     bl,0xb0                                         // error: smaller UMB is available\r
358                 jne     done;\r
359 \r
360                 mov     ah,XMS_ALLOCUMB\r
361                 call    [DWORD PTR XMSaddr]             // DX holds largest available UMB\r
362                 or      ax,ax\r
363                 jz      done                                            // another error...\r
364 \r
365 gotone:\r
366                 mov     [base],bx\r
367                 mov     [size],dx\r
368 done:\r
369         }\r
370         MML_UseSpace (base,size);\r
371         mminfo.XMSmem += size*16;\r
372         UMBbase[numUMBs] = base;\r
373         numUMBs++;\r
374         if (numUMBs < MAXUMBS)\r
375                 goto getmemory;\r
376 }\r
377 \r
378 \r
379 /*\r
380 ======================\r
381 =\r
382 = MML_ShutdownXMS\r
383 =\r
384 ======================\r
385 */\r
386 \r
387 void MML_ShutdownXMS (void)\r
388 {\r
389         int     i;\r
390         unsigned        base;\r
391 \r
392         for (i=0;i<numUMBs;i++)\r
393         {\r
394                 base = UMBbase[i];\r
395                 __asm\r
396                 {\r
397                         mov     ah,XMS_FREEUMB\r
398                         mov     dx,[base]\r
399                         call    [DWORD PTR XMSaddr]\r
400                 }\r
401         }\r
402 }\r
403 \r
404 //==========================================================================\r
405 \r
406 /*\r
407 ======================\r
408 =\r
409 = MML_UseSpace\r
410 =\r
411 = Marks a range of paragraphs as usable by the memory manager\r
412 = This is used to mark space for the near heap, far heap, ems page frame,\r
413 = and upper memory blocks\r
414 =\r
415 ======================\r
416 */\r
417 \r
418 void MML_UseSpace (unsigned segstart, unsigned seglength)\r
419 {\r
420         mmblocktype far *scan,far *last;\r
421         unsigned        oldend;\r
422         long            extra;\r
423 \r
424         scan = last = mmhead;\r
425         mmrover = mmhead;               // reset rover to start of memory\r
426 \r
427 //\r
428 // search for the block that contains the range of segments\r
429 //\r
430         while (scan->start+scan->length < segstart)\r
431         {\r
432                 last = scan;\r
433                 scan = scan->next;\r
434         }\r
435 \r
436 //\r
437 // take the given range out of the block\r
438 //\r
439         oldend = scan->start + scan->length;\r
440         extra = oldend - (segstart+seglength);\r
441         if (extra < 0)\r
442         {\r
443                 printf("MML_UseSpace: Segment spans two blocks!");\r
444                 return;\r
445         }\r
446 \r
447 \r
448         if (segstart == scan->start)\r
449         {\r
450                 last->next = scan->next;                        // unlink block\r
451                 FREEBLOCK(scan);\r
452                 scan = last;\r
453         }\r
454         else\r
455                 scan->length = segstart-scan->start;    // shorten block\r
456 \r
457         if (extra > 0)\r
458         {\r
459                 GETNEWBLOCK;\r
460                 mmnew->next = scan->next;\r
461                 scan->next = mmnew;\r
462                 mmnew->start = segstart+seglength;\r
463                 mmnew->length = extra;\r
464                 mmnew->attributes = LOCKBIT;\r
465         }\r
466 \r
467 }\r
468 \r
469 //==========================================================================\r
470 \r
471 /*\r
472 ====================\r
473 =\r
474 = MML_ClearBlock\r
475 =\r
476 = We are out of blocks, so free a purgable block\r
477 =\r
478 ====================\r
479 */\r
480 \r
481 void MML_ClearBlock (void)\r
482 {\r
483         mmblocktype far *scan,far *last;\r
484 \r
485         scan = mmhead->next;\r
486 \r
487         while (scan)\r
488         {\r
489                 if (!(scan->attributes&LOCKBIT) && (scan->attributes&PURGEBITS) )\r
490                 {\r
491                         MM_FreePtr(scan->useptr);\r
492                         return;\r
493                 }\r
494                 scan = scan->next;\r
495         }\r
496 \r
497         printf("MM_ClearBlock: No purgable blocks!");\r
498 }\r
499 \r
500 \r
501 //==========================================================================\r
502 \r
503 /*\r
504 ===================\r
505 =\r
506 = MM_Startup\r
507 =\r
508 = Grabs all space from turbo with malloc/farmalloc\r
509 = Allocates bufferseg misc buffer\r
510 =\r
511 ===================\r
512 */\r
513 \r
514 void MM_Startup (void)\r
515 {\r
516         int i;\r
517         dword length;\r
518         void far        *start;\r
519         unsigned        segstart,seglength,endfree;\r
520 \r
521         if (mminfo.mmstarted)\r
522                 MM_Shutdown ();\r
523 \r
524 \r
525         mminfo.mmstarted = true;\r
526         mminfo.bombonerror = true;\r
527 //\r
528 // set up the linked list (everything in the free list;\r
529 //\r
530         mmhead = NULL;\r
531         mmfree = &mmblocks[0];\r
532         for (i=0;i<MAXBLOCKS-1;i++)\r
533                 mmblocks[i].next = &mmblocks[i+1];\r
534         mmblocks[i].next = NULL;\r
535 \r
536 //\r
537 // locked block of all memory until we punch out free space\r
538 //\r
539         GETNEWBLOCK;\r
540         mmhead = mmnew;                         // this will allways be the first node\r
541         mmnew->start = 0;\r
542         mmnew->length = 0xffff;\r
543         mmnew->attributes = LOCKBIT;\r
544         mmnew->next = NULL;\r
545         mmrover = mmhead;\r
546 \r
547 \r
548 //\r
549 // get all available near conventional memory segments\r
550 //\r
551 //----  length=coreleft();\r
552         _nheapgrow();\r
553         length=_memavl();\r
554         start = (void far *)(nearheap = malloc(length));\r
555 \r
556         length -= 16-(FP_OFF(start)&15);\r
557         length -= SAVENEARHEAP;\r
558         seglength = length / 16;                        // now in paragraphs\r
559         segstart = FP_SEG(start)+(FP_OFF(start)+15)/16;\r
560         MML_UseSpace (segstart,seglength);\r
561         mminfo.nearheap = length;\r
562 \r
563 //\r
564 // get all available far conventional memory segments\r
565 //\r
566 //----  length=farcoreleft();\r
567         _fheapgrow();\r
568         length=_memavl();\r
569         start = farheap = _fmalloc(length);\r
570         length -= 16-(FP_OFF(start)&15);\r
571         length -= SAVEFARHEAP;\r
572         seglength = length / 16;                        // now in paragraphs\r
573         segstart = FP_SEG(start)+(FP_OFF(start)+15)/16;\r
574         MML_UseSpace (segstart,seglength);\r
575         mminfo.farheap = length;\r
576         mminfo.mainmem = mminfo.nearheap + mminfo.farheap;\r
577 \r
578 \r
579 //\r
580 // detect EMS and allocate up to 64K at page frame\r
581 //\r
582         mminfo.EMSmem = 0;\r
583         for (i = 1;i < __argc;i++)\r
584         {\r
585                 if ( US_CheckParm(__argv[i],ParmStringsexmm) == 0)\r
586                         goto emsskip;                           // param NOEMS\r
587         }\r
588 \r
589         if (MML_CheckForEMS())\r
590         {\r
591                 //printf("EMS1\n");\r
592                 MML_SetupEMS();                                 // allocate space\r
593                 //printf("EMS2\n");\r
594                 MML_UseSpace (EMSpageframe,EMSpagesmapped*0x400);\r
595                 //printf("EMS3\n");\r
596                 MM_MapEMS();                                    // map in used pages\r
597                 //printf("EMS4\n");\r
598                 mminfo.EMSmem = EMSpagesmapped*0x4000l;\r
599         }\r
600 \r
601 //\r
602 // detect XMS and get upper memory blocks\r
603 //\r
604 emsskip:\r
605         mminfo.XMSmem = 0;\r
606         for (i = 1;i < __argc;i++)\r
607         {\r
608                 if ( US_CheckParm(__argv[i],ParmStringsexmm) == 0)\r
609                         goto xmsskip;                           // param NOXMS\r
610         }\r
611 \r
612         if (MML_CheckForXMS())\r
613         {\r
614 //              printf("XMS!\n");\r
615 //++++          MML_SetupXMS();                                 // allocate as many UMBs as possible\r
616         }\r
617 \r
618 //\r
619 // allocate the misc buffer\r
620 //\r
621 xmsskip:\r
622         mmrover = mmhead;               // start looking for space after low block\r
623 \r
624         MM_GetPtr (&bufferseg,BUFFERSIZE);\r
625 }\r
626 \r
627 //==========================================================================\r
628 \r
629 /*\r
630 ====================\r
631 =\r
632 = MM_Shutdown\r
633 =\r
634 = Frees all conventional, EMS, and XMS allocated\r
635 =\r
636 ====================\r
637 */\r
638 \r
639 void MM_Shutdown (void)\r
640 {\r
641   if (!mminfo.mmstarted)\r
642         return;\r
643 \r
644   _ffree (farheap);
645   printf("far freed\n");\r
646   free (nearheap);
647   printf("near freed\n");\r
648   //hfree(hugeheap);
649   printf("huge freed\n");\r
650   MML_ShutdownEMS ();
651   printf("EMS freed\n");\r
652 //++++  MML_ShutdownXMS ();
653   printf("XMS freed\n");\r
654 }\r
655 \r
656 //==========================================================================\r
657 \r
658 /*\r
659 ====================\r
660 =\r
661 = MM_GetPtr\r
662 =\r
663 = Allocates an unlocked, unpurgable block\r
664 =\r
665 ====================\r
666 */\r
667 \r
668 void MM_GetPtr (memptr *baseptr,dword size)\r
669 {\r
670         mmblocktype far *scan,far *lastscan,far *endscan\r
671                                 ,far *purge,far *next;\r
672         int                     search;\r
673         unsigned        needed,startseg;\r
674 \r
675         needed = (size+15)/16;          // convert size from bytes to paragraphs\r
676 \r
677         GETNEWBLOCK;                            // fill in start and next after a spot is found\r
678         mmnew->length = needed;\r
679         mmnew->useptr = baseptr;\r
680         mmnew->attributes = BASEATTRIBUTES;\r
681 \r
682         for (search = 0; search<3; search++)\r
683         {\r
684         //\r
685         // first search:        try to allocate right after the rover, then on up\r
686         // second search:       search from the head pointer up to the rover\r
687         // third search:        compress memory, then scan from start\r
688                 if (search == 1 && mmrover == mmhead)\r
689                         search++;\r
690 \r
691                 switch (search)\r
692                 {\r
693                 case 0:\r
694                         lastscan = mmrover;\r
695                         scan = mmrover->next;\r
696                         endscan = NULL;\r
697                         break;\r
698                 case 1:\r
699                         lastscan = mmhead;\r
700                         scan = mmhead->next;\r
701                         endscan = mmrover;\r
702                         break;\r
703                 case 2:\r
704                         MM_SortMem ();\r
705                         lastscan = mmhead;\r
706                         scan = mmhead->next;\r
707                         endscan = NULL;\r
708                         break;\r
709                 }\r
710 \r
711                 startseg = lastscan->start + lastscan->length;\r
712 \r
713                 while (scan != endscan)\r
714                 {\r
715                         if (scan->start - startseg >= needed)\r
716                         {\r
717                         //\r
718                         // got enough space between the end of lastscan and\r
719                         // the start of scan, so throw out anything in the middle\r
720                         // and allocate the new block\r
721                         //\r
722                                 purge = lastscan->next;\r
723                                 lastscan->next = mmnew;\r
724                                 mmnew->start = *(unsigned *)baseptr = startseg;\r
725                                 mmnew->next = scan;\r
726                                 while ( purge != scan)\r
727                                 {       // free the purgable block\r
728                                         next = purge->next;\r
729                                         FREEBLOCK(purge);\r
730                                         purge = next;           // purge another if not at scan\r
731                                 }\r
732                                 mmrover = mmnew;\r
733                                 return; // good allocation!\r
734                         }\r
735 \r
736                         //\r
737                         // if this block is purge level zero or locked, skip past it\r
738                         //\r
739                         if ( (scan->attributes & LOCKBIT)\r
740                                 || !(scan->attributes & PURGEBITS) )\r
741                         {\r
742                                 lastscan = scan;\r
743                                 startseg = lastscan->start + lastscan->length;\r
744                         }\r
745 \r
746 \r
747                         scan=scan->next;                // look at next line\r
748                 }\r
749         }\r
750 \r
751         if (mminfo.bombonerror)\r
752                 printf(OUT_OF_MEM_MSG,(size-mminfo.nearheap));\r
753         else\r
754                 mminfo.mmerror = true;\r
755 }\r
756 \r
757 //==========================================================================\r
758 \r
759 /*\r
760 ====================\r
761 =\r
762 = MM_FreePtr\r
763 =\r
764 = Allocates an unlocked, unpurgable block\r
765 =\r
766 ====================\r
767 */\r
768 \r
769 void MM_FreePtr (memptr *baseptr)\r
770 {\r
771         mmblocktype far *scan,far *last;\r
772 \r
773         last = mmhead;\r
774         scan = last->next;\r
775 \r
776         if (baseptr == mmrover->useptr) // removed the last allocated block\r
777                 mmrover = mmhead;\r
778 \r
779         while (scan->useptr != baseptr && scan)\r
780         {\r
781                 last = scan;\r
782                 scan = scan->next;\r
783         }\r
784 \r
785         if (!scan)\r
786         {\r
787                 printf("MM_FreePtr: Block not found!");\r
788                 return;\r
789         }\r
790 \r
791         last->next = scan->next;\r
792 \r
793         FREEBLOCK(scan);\r
794 }\r
795 //==========================================================================\r
796 \r
797 /*\r
798 =====================\r
799 =\r
800 = MM_SetPurge\r
801 =\r
802 = Sets the purge level for a block (locked blocks cannot be made purgable)\r
803 =\r
804 =====================\r
805 */\r
806 \r
807 void MM_SetPurge (memptr *baseptr, int purge)\r
808 {\r
809         mmblocktype far *start;\r
810 \r
811         start = mmrover;\r
812 \r
813         do\r
814         {\r
815                 if (mmrover->useptr == baseptr)\r
816                         break;\r
817 \r
818                 mmrover = mmrover->next;\r
819 \r
820                 if (!mmrover)\r
821                         mmrover = mmhead;\r
822                 else if (mmrover == start)\r
823                 {\r
824                         printf("MM_SetPurge: Block not found!");\r
825                         return;\r
826                 }\r
827 \r
828         } while (1);\r
829 \r
830         mmrover->attributes &= ~PURGEBITS;\r
831         mmrover->attributes |= purge;\r
832 }\r
833 \r
834 //==========================================================================\r
835 \r
836 /*\r
837 =====================\r
838 =\r
839 = MM_SetLock\r
840 =\r
841 = Locks / unlocks the block\r
842 =\r
843 =====================\r
844 */\r
845 \r
846 void MM_SetLock (memptr *baseptr, boolean locked)\r
847 {\r
848         mmblocktype far *start;\r
849 \r
850         start = mmrover;\r
851 \r
852         do\r
853         {\r
854                 if (mmrover->useptr == baseptr)\r
855                         break;\r
856 \r
857                 mmrover = mmrover->next;\r
858 \r
859                 if (!mmrover)\r
860                         mmrover = mmhead;\r
861                 else if (mmrover == start)\r
862                 {\r
863                         printf("MM_SetLock: Block not found!");\r
864                         return;\r
865                 }\r
866 \r
867         } while (1);\r
868 \r
869         mmrover->attributes &= ~LOCKBIT;\r
870         mmrover->attributes |= locked*LOCKBIT;\r
871 }\r
872 \r
873 //==========================================================================\r
874 \r
875 /*\r
876 =====================\r
877 =\r
878 = MM_SortMem\r
879 =\r
880 = Throws out all purgable stuff and compresses movable blocks\r
881 =\r
882 =====================\r
883 */\r
884 \r
885 void MM_SortMem (void)\r
886 {\r
887         mmblocktype far *scan,far *last,far *next;\r
888         unsigned        start,length,source,dest,oldborder;\r
889         int                     playing;\r
890 \r
891         //\r
892         // lock down a currently playing sound\r
893         //\r
894 /*++++  playing = SD_SoundPlaying ();\r
895         if (playing)\r
896         {\r
897                 switch (SoundMode)\r
898                 {\r
899                 case sdm_PC:\r
900                         playing += STARTPCSOUNDS;\r
901                         break;\r
902                 case sdm_AdLib:\r
903                         playing += STARTADLIBSOUNDS;\r
904                         break;\r
905                 }\r
906                 MM_SetLock(&(memptr)audiosegs[playing],true);\r
907         }\r
908 \r
909 \r
910         SD_StopSound();*/\r
911 //      oldborder = bordercolor;\r
912 //      VW_ColorBorder (15);\r
913 \r
914         if (beforesort)\r
915                 beforesort();\r
916 \r
917         scan = mmhead;\r
918 \r
919         last = NULL;            // shut up compiler warning\r
920 \r
921         while (scan)\r
922         {\r
923                 if (scan->attributes & LOCKBIT)\r
924                 {\r
925                 //\r
926                 // block is locked, so try to pile later blocks right after it\r
927                 //\r
928                         start = scan->start + scan->length;\r
929                 }\r
930                 else\r
931                 {\r
932                         if (scan->attributes & PURGEBITS)\r
933                         {\r
934                         //\r
935                         // throw out the purgable block\r
936                         //\r
937                                 next = scan->next;\r
938                                 FREEBLOCK(scan);\r
939                                 last->next = next;\r
940                                 scan = next;\r
941                                 continue;\r
942                         }\r
943                         else\r
944                         {\r
945                         //\r
946                         // push the non purgable block on top of the last moved block\r
947                         //\r
948                                 if (scan->start != start)\r
949                                 {\r
950                                         length = scan->length;\r
951                                         source = scan->start;\r
952                                         dest = start;\r
953                                         while (length > 0xf00)\r
954                                         {\r
955                                                 movedata(source,0,dest,0,0xf00*16);\r
956                                                 length -= 0xf00;\r
957                                                 source += 0xf00;\r
958                                                 dest += 0xf00;\r
959                                         }\r
960                                         movedata(source,0,dest,0,length*16);\r
961 \r
962                                         scan->start = start;\r
963                                         *(unsigned *)scan->useptr = start;\r
964                                 }\r
965                                 start = scan->start + scan->length;\r
966                         }\r
967                 }\r
968 \r
969                 last = scan;\r
970                 scan = scan->next;              // go to next block\r
971         }\r
972 \r
973         mmrover = mmhead;\r
974 \r
975         if (aftersort)\r
976                 aftersort();\r
977 \r
978 //      VW_ColorBorder (oldborder);\r
979 \r
980 /*++++  if (playing)\r
981                 MM_SetLock(&(memptr)audiosegs[playing],false);*/\r
982 }\r
983 \r
984 \r
985 //==========================================================================\r
986 \r
987 //****#if 0\r
988 /*\r
989 =====================\r
990 =\r
991 = MM_ShowMemory\r
992 =\r
993 =====================\r
994 */\r
995 \r
996 void MM_ShowMemory (void)\r
997 {\r
998         mmblocktype far *scan;\r
999         unsigned color,temp;//, i;\r
1000         long    end,owner;\r
1001         char    scratch[80],str[10];\r
1002 \r
1003 //****  VW_SetDefaultColors();\r
1004 //****  VW_SetLineWidth(40);\r
1005 //++++mh        temp = bufferofs;\r
1006 //++++mh        bufferofs = 0;\r
1007 //****  VW_SetScreen (0,0);\r
1008 \r
1009         scan = mmhead;\r
1010 \r
1011         end = -1;\r
1012 \r
1013 //CA_OpenDebug ();\r
1014 \r
1015         while (scan)\r
1016         {\r
1017                 if (scan->attributes & PURGEBITS)\r
1018                         color = 5;              // dark purple = purgable\r
1019                 else\r
1020                         color = 9;              // medium blue = non purgable\r
1021                 if (scan->attributes & LOCKBIT)\r
1022                         color = 12;             // red = locked\r
1023                 if (scan->start<=end)\r
1024                 {\r
1025                         printf("MM_ShowMemory: Memory block order currupted!");\r
1026                         return;\r
1027                 }\r
1028                 end = scan->start+scan->length-1;\r
1029 //++++          VW_Hlin(scan->start,(unsigned)end,0,color);\r
1030 //++++          VW_Plot(scan->start,0,15);\r
1031                 if (scan->next->start > end+1)\r
1032 //++++                  VW_Hlin(end+1,scan->next->start,0,0);   // black = free\r
1033 \r
1034 //****#if 0\r
1035 printf("Location:");\r
1036 printf("%Fp\t", scan->start);\r
1037 strcpy (scratch,"Size:");\r
1038 ltoa ((long)scan->length*16,str,10);\r
1039 strcat (scratch,str);\r
1040 strcat (scratch,"\tOwner:0x");\r
1041 owner = (unsigned)scan->useptr;\r
1042 ultoa (owner,str,16);\r
1043 strcat (scratch,str);\r
1044 strcat (scratch,"\n");\r
1045 //++++write (debughandle,scratch,strlen(scratch));\r
1046 fprintf(stdout, "%s", scratch);\r
1047 //****#endif\r
1048 \r
1049                 scan = scan->next;\r
1050         }\r
1051 \r
1052 //CA_CloseDebug ();\r
1053 \r
1054 //++++mh        IN_Ack();\r
1055 //****  VW_SetLineWidth(64);\r
1056 //++++mh        bufferofs = temp;\r
1057 }\r
1058 //****#endif\r
1059 \r
1060 //==========================================================================\r
1061 \r
1062 \r
1063 /*\r
1064 ======================\r
1065 =\r
1066 = MM_UnusedMemory\r
1067 =\r
1068 = Returns the total free space without purging\r
1069 =\r
1070 ======================\r
1071 */\r
1072 \r
1073 dword MM_UnusedMemory (void)\r
1074 {\r
1075         unsigned free;\r
1076         mmblocktype far *scan;\r
1077 \r
1078         free = 0;\r
1079         scan = mmhead;\r
1080 \r
1081         while (scan->next)\r
1082         {\r
1083                 free += scan->next->start - (scan->start + scan->length);\r
1084                 scan = scan->next;\r
1085         }\r
1086 \r
1087 //      return free*16l;\r
1088         return free;\r
1089 }\r
1090 \r
1091 //==========================================================================\r
1092 \r
1093 \r
1094 /*\r
1095 ======================\r
1096 =\r
1097 = MM_TotalFree\r
1098 =\r
1099 = Returns the total free space with purging\r
1100 =\r
1101 ======================\r
1102 */\r
1103 \r
1104 dword MM_TotalFree (void)\r
1105 {\r
1106         unsigned free;\r
1107         mmblocktype far *scan;\r
1108 \r
1109         free = 0;\r
1110         scan = mmhead;\r
1111 \r
1112         while (scan->next)\r
1113         {\r
1114                 if ((scan->attributes&PURGEBITS) && !(scan->attributes&LOCKBIT))\r
1115                         free += scan->length;\r
1116                 free += scan->next->start - (scan->start + scan->length);\r
1117                 scan = scan->next;\r
1118         }\r
1119 \r
1120 //      return free*16l;\r
1121         return free;\r
1122 }\r
1123 \r
1124 //==========================================================================\r
1125 \r
1126 /*\r
1127 =====================\r
1128 =\r
1129 = MM_Report\r
1130 =\r
1131 =====================\r
1132 */\r
1133 \r
1134 void MM_Report(void)\r
1135 {\r
1136         printf("EMM %x available\n", EMSVer);\r
1137         printf("totalEMSpages=%u\n", totalEMSpages);\r
1138         printf("freeEMSpages=%u\n", freeEMSpages);\r
1139         printf("EMSpageframe=%Fp\n", EMSpageframe);\r
1140         printf("near=%lu\n", mminfo.nearheap);\r
1141         printf("far=%lu\n", mminfo.farheap);\r
1142         printf("EMSmem=%lu\n", mminfo.EMSmem);\r
1143         printf("XMSmem=%lu\n", mminfo.XMSmem);\r
1144         printf("mainmem=%lu\n", mminfo.mainmem);\r
1145         printf("UnusedMemory=%lu\n", MM_UnusedMemory());\r
1146         printf("TotalFree=%lu\n", MM_TotalFree());\r
1147 //      printf("\n");\r
1148 //      printf("UnusedMemory=%lu kb\n", MM_UnusedMemory()/10248);\r
1149 //      printf("TotalFree=%lu kb\n", MM_TotalFree()/10248);\r
1150 }\r
1151 \r
1152 //==========================================================================\r
1153 \r
1154 /*\r
1155 =====================\r
1156 =\r
1157 = MM_EMSVer\r
1158 =\r
1159 =====================\r
1160 \r
1161 \r
1162 int MM_EMSVer(void)\r
1163 {\r
1164         int EMSver;\r
1165         __asm\r
1166         {\r
1167                 mov             ah,EMS_VERSION\r
1168                 int             EMS_INT\r
1169                 mov             EMSver,ax\r
1170         }\r
1171         return(EMSver);\r
1172 }*/\r
1173 \r
1174 //==========================================================================\r
1175 \r
1176 /*\r
1177 =====================\r
1178 =\r
1179 = MM_BombOnError\r
1180 =\r
1181 =====================\r
1182 */\r
1183 \r
1184 void MM_BombOnError (boolean bomb)\r
1185 {\r
1186         mminfo.bombonerror = bomb;\r
1187 }\r
1188 \r
1189 //==========================================================================\r
1190 \r
1191 ///////////////////////////////////////////////////////////////////////////\r
1192 //\r
1193 //      US_CheckParm() - checks to see if a string matches one of a set of\r
1194 //              strings. The check is case insensitive. The routine returns the\r
1195 //              index of the string that matched, or -1 if no matches were found\r
1196 //\r
1197 ///////////////////////////////////////////////////////////////////////////\r
1198 int\r
1199 US_CheckParm(char *parm,char **strings)\r
1200 {\r
1201         char    cp,cs,\r
1202                         *p,*s;\r
1203         int             i;\r
1204 \r
1205         while (!isalpha(*parm)) // Skip non-alphas\r
1206                 parm++;\r
1207 \r
1208         for (i = 0;*strings && **strings;i++)\r
1209         {\r
1210                 for (s = *strings++,p = parm,cs = cp = 0;cs == cp;)\r
1211                 {\r
1212                         cs = *s++;\r
1213                         if (!cs)\r
1214                                 return(i);\r
1215                         cp = *p++;\r
1216 \r
1217                         if (isupper(cs))\r
1218                                 cs = tolower(cs);\r
1219                         if (isupper(cp))\r
1220                                 cp = tolower(cp);\r
1221                 }\r
1222         }\r
1223         return(-1);\r
1224 }\r