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