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