]> 4ch.mooo.com Git - 16.git/blob - src/lib/16_mm.c
p16 is being worked on a bunch by me wwww [16_ca needs huge amounts of work and I...
[16.git] / src / lib / 16_mm.c
1 /* Catacomb Apocalypse Source Code\r
2  * Copyright (C) 1993-2014 Flat Rock Software\r
3  *\r
4  * This program is free software; you can redistribute it and/or modify\r
5  * it under the terms of the GNU General Public License as published by\r
6  * the Free Software Foundation; either version 2 of the License, or\r
7  * (at your option) any later version.\r
8  *\r
9  * This program is distributed in the hope that it will be useful,\r
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
12  * GNU General Public License for more details.\r
13  *\r
14  * You should have received a copy of the GNU General Public License along\r
15  * with this program; if not, write to the Free Software Foundation, Inc.,\r
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
17  */\r
18 \r
19 // NEWMM.C\r
20 \r
21 /*\r
22 =============================================================================\r
23 \r
24                         ID software memory manager\r
25                         --------------------------\r
26 \r
27 Primary coder: John Carmack\r
28 \r
29 RELIES ON\r
30 ---------\r
31 Quit (global_game_variables_t *gvar, 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 \r
46 Open Watcom port by sparky4\r
47 \r
48 */\r
49 #include "src/lib/16_mm.h"\r
50 #include "src/lib/16_ca.h"\r
51 #include <malloc.h>\r
52 #pragma hdrstop\r
53 \r
54 #pragma warn -pro\r
55 #pragma warn -use\r
56 \r
57 /*\r
58 =============================================================================\r
59 \r
60                                                  GLOBAL VARIABLES\r
61 \r
62 =============================================================================\r
63 */\r
64 \r
65 void            (* beforesort) (void);\r
66 void            (* aftersort) (void);\r
67 void            (* XMSaddr) (void);             // far pointer to XMS driver\r
68 \r
69 /*\r
70 =============================================================================\r
71 \r
72                                                  LOCAL VARIABLES\r
73 \r
74 =============================================================================\r
75 */\r
76 #ifndef __16_PM__\r
77 static  char *ParmStringsexmm[] = {"noems","noxms",""};\r
78 #endif\r
79 /*\r
80 ======================\r
81 =\r
82 = MML_CheckForEMS\r
83 =\r
84 = Routine from p36 of Extending DOS\r
85 =\r
86 =======================\r
87 */\r
88 \r
89 boolean MML_CheckForEMS(void)\r
90 {\r
91         boolean emmcfems = false;\r
92         word            EMSPageFrame = 0;\r
93         byte    err=0, str[64];\r
94         static char     emmname[] = "EMMXXXX0"; //fix by andrius4669\r
95         __asm {\r
96                 mov     dx,OFFSET emmname       //fix by andrius4669\r
97                 mov     ax,0x3d00\r
98                 int     EMM_INT         // try to open EMMXXXX0 device\r
99                 jc      error\r
100 \r
101                 mov     bx,ax\r
102                 mov     ax,0x4400\r
103 \r
104                 int     EMM_INT         // get device info\r
105                 jc      error\r
106 \r
107                 and     dx,0x80\r
108                 jz      error\r
109 \r
110                 mov     ax,0x4407\r
111 \r
112                 int     EMM_INT         // get status\r
113                 jc      error\r
114                 or      al,al\r
115                 jz      error\r
116 \r
117                 mov     ah,0x3e\r
118                 int     EMM_INT         // close handle\r
119                 jc      error\r
120 \r
121                 //\r
122                 // pageframe check\r
123                 //\r
124                 mov     ah,EMS_GETFRAME\r
125                 int     EMS_INT                 // find the page frame address\r
126                 or      ah,ah\r
127                 jnz     error\r
128                 mov     [EMSPageFrame],bx\r
129 \r
130                 //\r
131                 // EMS is good\r
132                 //\r
133                 mov     emmcfems,1\r
134                 jmp     End\r
135 #ifdef __BORLANDC__\r
136         }\r
137 #endif\r
138                 error:\r
139 #ifdef __BORLANDC__\r
140         __asm {\r
141 #endif\r
142                 //\r
143                 // EMS is bad\r
144                 //\r
145                 mov     err,ah\r
146                 mov     emmcfems,0\r
147 #ifdef __BORLANDC__\r
148         }\r
149 #endif\r
150                 End:\r
151 #ifdef __WATCOMC__\r
152         }\r
153 #endif\r
154 \r
155         //\r
156         // Pageframe switch to determine if there is one!\r
157         //\r
158         if(!EMSPageFrame)\r
159         {\r
160                 emmcfems = false;\r
161 #if defined(__DEBUG_PM__) || defined(__DEBUG_MM__)\r
162                 printf("MML_CheckForEMS: EMS error No Pageframe!\nAddress detected to be %04x\n", EMSPageFrame);\r
163 #endif\r
164         }else   if(!emmcfems)// if there is an error and page frame is not 0000\r
165         {\r
166                 strcpy(str,"MML_CheckForEMS: EMS error ");\r
167                 MM_EMSerr(str, err);\r
168                 printf("%s\n",str);\r
169         }\r
170 \r
171         return(emmcfems);\r
172 }\r
173 \r
174 #ifndef __16_PM__\r
175 /*\r
176 ======================\r
177 =\r
178 = MML_SetupEMS\r
179 =\r
180 =======================\r
181 */\r
182 \r
183 byte MML_SetupEMS(global_game_variables_t *gvar)\r
184 {\r
185         byte    str[160];\r
186         byte    err;\r
187         boolean errorflag=false;\r
188 \r
189         unsigned int EMSVer = 0;\r
190         //byte  EMS_status;\r
191         unsigned        totalEMSpages,freeEMSpages,EMSPageFrame,EMSpagesmapped,EMSHandle;\r
192         totalEMSpages = freeEMSpages = EMSPageFrame = EMSpagesmapped = 0;\r
193 \r
194         __asm {\r
195                 mov     ah,EMS_STATUS\r
196                 int     EMS_INT                                         // make sure EMS hardware is present\r
197                 or      ah,ah\r
198                 //mov   [EMS_status],ah\r
199                 jnz     error\r
200 \r
201                 mov     ah,EMS_VERSION\r
202                 int     EMS_INT\r
203                 or      ah,ah\r
204                 jnz     error\r
205                 mov     [EMSVer],ax                             //      set EMSVer\r
206                 cmp     al,0x32                                         // only work on ems 3.2 or greater\r
207                 jb      error\r
208 \r
209                 mov     ah,EMS_GETFRAME\r
210                 int     EMS_INT                                         // find the page frame address\r
211                 or      ah,ah\r
212                 jnz     error\r
213                 mov     [EMSPageFrame],bx\r
214 \r
215                 mov     ah,EMS_GETPAGES\r
216                 int     EMS_INT                                         // find out how much EMS is there\r
217                 or      ah,ah\r
218                 jnz     error\r
219                 mov     [totalEMSpages],dx\r
220                 mov     [freeEMSpages],bx\r
221                 or      bx,bx\r
222                 jz      noEMS                                           // no EMS at all to allocate\r
223                                                                                         //EXPAND DONG!!!!\r
224                 cmp     [EMSVer],0x40\r
225                 jb      low\r
226                 cmp     bx,[freeEMSpages]\r
227                 jle     getpages\r
228                 mov     bx,[freeEMSpages]\r
229                 jmp     getpages\r
230 #ifdef __BORLANDC__\r
231         }\r
232 #endif\r
233         low:\r
234 #ifdef __BORLANDC__\r
235         __asm {\r
236 #endif\r
237                 cmp     bx,4\r
238                 jle     getpages                                        // there is only 1,2,3,or 4 pages\r
239                 mov     bx,4                                            // we can't use more than 4 pages\r
240 #ifdef __BORLANDC__\r
241         }\r
242 #endif\r
243         getpages:\r
244 #ifdef __BORLANDC__\r
245         __asm {\r
246 #endif\r
247                 mov     [EMSpagesmapped],bx\r
248                 mov     ah,EMS_ALLOCPAGES                       // allocate up to 64k of EMS\r
249                 int     EMS_INT\r
250                 or      ah,ah\r
251                 jnz     error\r
252                 mov     [EMSHandle],dx\r
253                 jmp End\r
254 #ifdef __BORLANDC__\r
255         }\r
256 #endif\r
257         error:\r
258 #ifdef __BORLANDC__\r
259         __asm {\r
260 #endif\r
261                 mov     err,ah\r
262                 mov     errorflag,1\r
263                 jmp End\r
264 #ifdef __BORLANDC__\r
265         }\r
266 #endif\r
267 noEMS:\r
268 End:\r
269 #ifdef __WATCOMC__\r
270         }\r
271 #endif\r
272         if(errorflag==true)\r
273         {\r
274                 strcpy(str,"MM_SetupEMS: EMS error ");\r
275                 MM_EMSerr(str, err);\r
276                 printf("%s\n",str);\r
277                 return err;\r
278         }\r
279         gvar->mm.totalEMSpages=totalEMSpages;\r
280         gvar->mm.freeEMSpages=freeEMSpages;\r
281         gvar->mm.EMSPageFrame=EMSPageFrame;\r
282         gvar->mm.EMSpagesmapped=EMSpagesmapped;\r
283         gvar->mm.EMSHandle=EMSHandle;\r
284         gvar->mm.EMSVer=EMSVer;\r
285         return 0;\r
286 }\r
287 \r
288 \r
289 /*\r
290 ======================\r
291 =\r
292 = MML_ShutdownEMS\r
293 =\r
294 =======================\r
295 */\r
296 \r
297 void MML_ShutdownEMS(global_game_variables_t *gvar)\r
298 {\r
299         boolean errorflag=false;\r
300         unsigned EMSHandle=gvar->mm.EMSHandle;\r
301 \r
302         if(!EMSHandle)\r
303                 return;\r
304         __asm {\r
305                 mov     ah,EMS_FREEPAGES\r
306                 mov     dx,[EMSHandle]\r
307                 int     EMS_INT\r
308                 or      ah,ah\r
309                 jz      ok\r
310                 mov     errorflag,1\r
311 #ifdef __BORLANDC__\r
312         }\r
313 #endif\r
314                 ok:\r
315 #ifdef __WATCOMC__\r
316         }\r
317 #endif\r
318         if(errorflag==true)\r
319                 Quit (gvar, "MML_ShutdownEMS: Error freeing EMS!\n");   //++++ add something\r
320 }\r
321 \r
322 /*\r
323 ====================\r
324 =\r
325 = MM_MapEMS\r
326 =\r
327 = Maps the 64k of EMS used by memory manager into the page frame\r
328 = for general use.  This only needs to be called if you are keeping\r
329 = other things in EMS.\r
330 =\r
331 ====================\r
332 */\r
333 \r
334 byte MM_MapEMS(global_game_variables_t *gvar)\r
335 {\r
336         byte    str[160];\r
337         unsigned        EMSHandle;\r
338         byte err;\r
339         boolean errorflag=false;\r
340         int     i;\r
341         EMSHandle=gvar->mm.EMSHandle;\r
342 \r
343         for (i=0;i<4/*MAPPAGES*/;i++)\r
344         {\r
345                 __asm {\r
346                         mov     ah,EMS_MAPPAGE\r
347                         mov     bx,[i]                  // logical page\r
348                         mov     al,bl                   // physical page\r
349                         mov     dx,[EMSHandle]  // handle\r
350                         int     EMS_INT\r
351                         or      ah,ah\r
352                         jnz     error\r
353                         jmp End\r
354 #ifdef __BORLANDC__\r
355                 }\r
356 #endif\r
357                         error:\r
358 #ifdef __BORLANDC__\r
359                 __asm {\r
360 #endif\r
361                         mov     err,ah\r
362                         mov     errorflag,1\r
363 #ifdef __BORLANDC__\r
364                 }\r
365 #endif\r
366                         End:\r
367 #ifdef __WATCOMC__\r
368                 }\r
369 #endif\r
370                 if(errorflag==true)\r
371                 {\r
372                         strcpy(str,"MM_MapEMS: EMS error ");\r
373                         MM_EMSerr(str, err);\r
374                         printf("%s\n",str);\r
375                         return err;\r
376                 }\r
377         }\r
378         gvar->mmi.EMSmem = (i)*0x4000lu;\r
379         return 0;\r
380 }\r
381 \r
382 byte MM_MapXEMS(global_game_variables_t *gvar)\r
383 {\r
384 //SUB EMS.MapXPages (PhysicalStart, LogicalStart, NumPages, Handle)\r
385 \r
386         //Maps up to 4 logical EMS pages to physical pages in the page frame, where:\r
387         //PhysicalStart = Physical page first logical page is mapped to\r
388         //LogicalStart  = First logical page to map\r
389         //NumPages      = Number of pages to map (1 to 4)\r
390         //Handle        = EMS handle logical pages are allocated to\r
391 \r
392   /*//Create a buffer containing the page information\r
393 //  FOR x = 0 TO NumPages - 1\r
394 //    MapInfo$ = MapInfo$ + MKI$(LogicalStart + x) + MKI$(PhysicalStart + x)\r
395 //  NEXT*/\r
396 \r
397 //  Regs.ax = 0x5000                           //Map the pages in the buffer\r
398 //  Regs.cx = NumPages                         //to the pageframe\r
399 //  Regs.dx = Handle\r
400 //  Regs.ds = VARSEG(MapInfo$)\r
401 //  Regs.si = SADD(MapInfo$)\r
402 //  InterruptX 0x67, Regs, Regs\r
403 //      EMS.Error = (Regs.ax AND 0xFF00&) \ 0x100  //Store the status code\r
404 \r
405 //END SUB\r
406         byte    str[160];\r
407         byte err;\r
408         word    EMSHandle;\r
409         boolean errorflag=false;\r
410         int     i;\r
411         EMSHandle=gvar->mm.EMSHandle;\r
412 \r
413         if(gvar->mm.EMSVer<0x40)\r
414                 return 5;\r
415 \r
416         for (i=0;i<MAPPAGES;i++)\r
417         {\r
418                 __asm {\r
419                         mov     ah,EMS_MAPXPAGE\r
420                         mov     cx,[i]                  // logical page\r
421                         mov     al,bl                   // physical page\r
422                         mov     dx,[EMSHandle]  // handle\r
423                         int     EMS_INT\r
424                         or      ah,ah\r
425                         jnz     error\r
426                         jmp End\r
427 #ifdef __BORLANDC__\r
428                 }\r
429 #endif\r
430                         error:\r
431 #ifdef __BORLANDC__\r
432                 __asm {\r
433 #endif\r
434                         mov     err,ah\r
435                         mov     errorflag,1\r
436 #ifdef __BORLANDC__\r
437                 }\r
438 #endif\r
439                         End:\r
440 #ifdef __WATCOMC__\r
441                 }\r
442 #endif\r
443                 if(errorflag==true)\r
444                 {\r
445                         //strcpy(str,"MM_MapXEMS: EMS error 0x");\r
446                         strcpy(str,"MM_MapXEMS: EMS error ");\r
447                         //itoa(err,str2,16);\r
448                         MM_EMSerr(str, err);\r
449                         printf("%s\n",str);\r
450                         //printf("%s%x\n",str, err);\r
451                         //printf("FACK! %x\n", err);\r
452                         return err;\r
453                 }\r
454         }\r
455         gvar->mmi.EMSmem = (i)*0x4000lu;\r
456         return 0;\r
457 }\r
458 #endif\r
459 //==========================================================================\r
460 \r
461 /*\r
462 ======================\r
463 =\r
464 = MML_CheckForXMS\r
465 =\r
466 = Check for XMM driver\r
467 =\r
468 =======================\r
469 */\r
470 \r
471 boolean MML_CheckForXMS(void)\r
472 {\r
473         //numUMBs = 0;\r
474         boolean errorflag=false;\r
475 \r
476         __asm {\r
477                 mov     ax,0x4300\r
478                 int     0x2f                            // query status of installed diver\r
479                 cmp     al,0x80\r
480                 je      good\r
481                 mov     errorflag,1\r
482 #ifdef __BORLANDC__\r
483         }\r
484 #endif\r
485                 good:\r
486 #ifdef __WATCOMC__\r
487         }\r
488 #endif\r
489         if(errorflag==true) return false;\r
490         else return true;\r
491 }\r
492 \r
493 #ifndef __16_PM__\r
494 /*\r
495 ======================\r
496 =\r
497 = MML_SetupXMS\r
498 =\r
499 = Try to allocate all upper memory block\r
500 =\r
501 =======================\r
502 */\r
503 \r
504 void MML_SetupXMS(global_game_variables_t *gvar)\r
505 {\r
506         word    base,size;\r
507 \r
508 \r
509         __asm {\r
510                 mov     ax,0x4310\r
511                 int     0x2f\r
512                 mov     [WORD PTR XMSaddr],bx\r
513                 mov     [WORD PTR XMSaddr+2],es         // function pointer to XMS driver\r
514         }\r
515 getmemory:\r
516         __asm {\r
517                 mov     ah,XMS_ALLOCUMB\r
518                 mov     dx,0xffff                                       // try for largest block possible\r
519                 //mov     ax,dx                                         // Set available Kbytes.\r
520                 call    [DWORD PTR XMSaddr]\r
521                 or      ax,ax\r
522                 jnz     gotone\r
523 \r
524                 cmp     bl,0xb0                                         // error: smaller UMB is available\r
525                 jne     done;\r
526 \r
527                 mov     ah,XMS_ALLOCUMB\r
528                 call    [DWORD PTR XMSaddr]             // DX holds largest available UMB\r
529                 or      ax,ax\r
530                 jz      done                                            // another error...\r
531 #ifdef __BORLANDC__\r
532         }\r
533 #endif\r
534                 gotone:\r
535 #ifdef __BORLANDC__\r
536         __asm {\r
537 #endif\r
538                 mov     [base],bx\r
539                 mov     [size],dx\r
540 #ifdef __BORLANDC__\r
541         }\r
542 #endif\r
543                 done:\r
544 #ifdef __WATCOMC__\r
545         }\r
546 #endif\r
547 //      printf("base=%u ", base); printf("size=%u\n", size);\r
548         MML_UseSpace(base,size, gvar);\r
549         gvar->mmi.XMSmem += size*16;\r
550         gvar->mm.UMBbase[gvar->mm.numUMBs] = base;\r
551         gvar->mm.numUMBs++;\r
552         if(gvar->mm.numUMBs < MAXUMBS)\r
553                 goto getmemory;\r
554 }\r
555 \r
556 \r
557 /*\r
558 ======================\r
559 =\r
560 = MML_ShutdownXMS\r
561 =\r
562 ======================\r
563 */\r
564 \r
565 void MML_ShutdownXMS(global_game_variables_t *gvar)\r
566 {\r
567         int     i;\r
568         unsigned        base;\r
569 \r
570         for (i=0;i<gvar->mm.numUMBs;i++)\r
571         {\r
572                 base = gvar->mm.UMBbase[i];\r
573                 __asm {\r
574                         mov     ah,XMS_FREEUMB\r
575                         mov     dx,[base]\r
576                         call    [DWORD PTR XMSaddr]\r
577                 }\r
578         }\r
579 }\r
580 #endif\r
581 //==========================================================================\r
582 \r
583 /*\r
584 ======================\r
585 =\r
586 = MML_UseSpace\r
587 =\r
588 = Marks a range of paragraphs as usable by the memory manager\r
589 = This is used to mark space for the near heap, far heap, ems page frame,\r
590 = and upper memory blocks\r
591 =\r
592 ======================\r
593 */\r
594 \r
595 /*\r
596         extra = oldend - (segstart+seglength);\r
597 \r
598         segmlen=extra;\r
599 \r
600         //++++emsver stuff!\r
601         if(segm>1)/// || extra>=0x10000lu)\r
602         //if(extra>0xfffflu)\r
603         {\r
604                 scan->blob=segm;\r
605 \r
606                 //MML_UseSpace(segstart, seglength, gvar);\r
607 \r
608                 printf("MML_UseSpace: Segment spans two blocks!\n");\r
609         //}\r
610         printf("segm=%u         ", segm);\r
611         printf("ex=%lu  ", extra);\r
612         printf("old=%u  ", oldend);\r
613         printf("start+seglen=%lu\n", segstart+seglength);\r
614         printf("segsta=%x       ", segstart);\r
615         printf("len=%lu ", scan->length);\r
616         printf("seglen=%lu      ", seglength);\r
617         printf("segmlen=%lu\n", segmlen);\r
618         }\r
619 //++++todo: linked list of segment!\r
620 */\r
621 void MML_UseSpace(word segstart, dword seglength, global_game_variables_t *gvar)\r
622 {\r
623         mmblocktype far *scan,far *last;\r
624         word    oldend;\r
625         sdword          extra;\r
626         //word segm=1;\r
627 \r
628         scan = last = gvar->mm.mmhead;\r
629         gvar->mm.mmrover = gvar->mm.mmhead;             // reset rover to start of memory\r
630 \r
631 //\r
632 // search for the block that contains the range of segments\r
633 //\r
634         while (scan->start+scan->length < segstart)\r
635         {\r
636                 last = scan;\r
637                 scan = scan->next;\r
638         }\r
639 \r
640 //\r
641 // find out how many blocks it spans!\r
642 //\r
643         /*for(;seglength>=0x10000;seglength-=0xFFFF)\r
644         {\r
645                 //printf("      seglen=%lu\n", segmlen);\r
646                 segm++;\r
647         }*/\r
648 \r
649 //\r
650 // take the given range out of the block\r
651 //\r
652         oldend = scan->start + scan->length;\r
653         extra = oldend - (segstart+((unsigned)seglength));\r
654         if (extra < 0)\r
655         {\r
656                 printf("========================================\n");\r
657                 printf("start=%x        ", scan->start);\r
658                 printf("old=%u  ", oldend);\r
659                 printf("start+seglen=%lu\n", segstart+seglength);\r
660                 printf("segsta=%x       ", segstart);\r
661                 printf("len=%lu ", scan->length);\r
662                 printf("seglen=%lu      ", seglength);\r
663                 printf("\n");\r
664                 printf("MML_UseSpace: Segment spans two blocks! %d\n", extra);\r
665                 printf("========================================\n");\r
666                 //return;\r
667         }\r
668 \r
669         if (segstart == scan->start)\r
670         {\r
671                 last->next = scan->next;                        // unlink block\r
672                 FREEBLOCK(scan);\r
673                 scan = last;\r
674         }\r
675         else\r
676                 scan->length = segstart-scan->start;    // shorten block\r
677 \r
678         if (extra > 0)\r
679         {\r
680                 GETNEWBLOCK;\r
681                 gvar->mm.mmnew->useptr = NULL;\r
682 \r
683                 gvar->mm.mmnew->next = scan->next;\r
684                 scan->next = gvar->mm.mmnew;\r
685                 gvar->mm.mmnew->start = segstart+seglength;\r
686                 gvar->mm.mmnew->length = extra;\r
687                 gvar->mm.mmnew->attributes = LOCKBIT;\r
688         }//else if(segm>0) goto segu;\r
689 \r
690 }\r
691 \r
692 //==========================================================================\r
693 \r
694 /*\r
695 ====================\r
696 =\r
697 = MML_ClearBlock\r
698 =\r
699 = We are out of blocks, so free a purgable block\r
700 =\r
701 ====================\r
702 */\r
703 \r
704 void MML_ClearBlock(global_game_variables_t *gvar)\r
705 {\r
706         mmblocktype far *scan;//,far *last;\r
707 \r
708         scan = gvar->mm.mmhead->next;\r
709 \r
710         while(scan)\r
711         {\r
712                 if(!(scan->attributes&LOCKBIT) && (scan->attributes&PURGEBITS))\r
713                 {\r
714                         MM_FreePtr(scan->useptr, gvar);\r
715                         return;\r
716                 }\r
717                 scan = scan->next;\r
718         }\r
719 \r
720         printf("MM_ClearBlock: No purgable blocks!\n");\r
721 }\r
722 \r
723 \r
724 //==========================================================================\r
725 \r
726 /*\r
727 ===================\r
728 =\r
729 = MM_Startup\r
730 =\r
731 = Grabs all space from turbo with malloc/farmalloc\r
732 = Allocates bufferseg misc buffer\r
733 =\r
734 ===================\r
735 */\r
736 \r
737 void MM_Startup(global_game_variables_t *gvar)\r
738 {\r
739         int i;\r
740         //dword length,seglength;\r
741         dword length; word seglength;\r
742         void far        *start;\r
743         word    segstart;//,endfree;\r
744 \r
745         if(gvar->mm.mmstarted)\r
746                 MM_Shutdown(gvar);\r
747 \r
748         gvar->mm.mmstarted = true;\r
749         gvar->mm.bombonerror = true;\r
750 \r
751 //\r
752 // set up the linked list (everything in the free list;\r
753 //\r
754         gvar->mm.mmhead = NULL;\r
755         gvar->mm.mmfree = &(gvar->mm.mmblocks[0]);\r
756         for(i=0;i<MAXBLOCKS-1;i++)\r
757                 gvar->mm.mmblocks[i].next = &(gvar->mm.mmblocks[i+1]);\r
758         gvar->mm.mmblocks[i].next = NULL;\r
759 \r
760 //\r
761 // locked block of all memory until we punch out free space\r
762 //\r
763         GETNEWBLOCK;\r
764         gvar->mm.mmhead = gvar->mm.mmnew;                               // this will allways be the first node\r
765         gvar->mm.mmnew->start = 0;\r
766         gvar->mm.mmnew->length = 0xffff;\r
767         gvar->mm.mmnew->attributes = LOCKBIT;\r
768         gvar->mm.mmnew->next = NULL;\r
769         gvar->mm.mmrover = gvar->mm.mmhead;\r
770 \r
771 //\r
772 // get all available near conventional memory segments\r
773 //\r
774 #ifdef __WATCOMC__\r
775         _nheapgrow();\r
776 #endif\r
777         length=(word)_memavl();//(word)coreleft();\r
778         //start = gvar->mm.nearheap = _fmalloc(length);\r
779 #ifdef __WATCOMC__\r
780         start = (void __far *)(gvar->mm.nearheap = _nmalloc(length));\r
781 #endif\r
782 #ifdef __BORLANDC__\r
783         start = (void far *)(gvar->mm.nearheap = malloc(length));\r
784 #endif\r
785 \r
786         length -= 16-(FP_OFF(start)&15);\r
787         length -= SAVENEARHEAP;\r
788         seglength = length / 16;                        // now in paragraphs\r
789         segstart = FP_SEG(start)+(FP_OFF(start)+15)/16;\r
790         MML_UseSpace(segstart,seglength, gvar);\r
791         gvar->mmi.nearheap = length;\r
792         //0000printf("near:     start=%Fp       segstart=%x     seglen=%lu      len=%lu\n", start, segstart, (dword)seglength, length);\r
793 \r
794 //\r
795 // get all available far conventional memory segments\r
796 //\r
797 #ifdef __WATCOMC__\r
798         _fheapgrow();\r
799 #endif\r
800 #ifdef __BORLANDC__\r
801 //      printf("farcoreleft()                           %lu\n", farcoreleft());\r
802 //      printf("(farcoreleft()+32)-_FCORELEFT   %d\n", (sword)((farcoreleft()+32)-_FCORELEFT));\r
803 #endif\r
804         length=_FCORELEFT;\r
805         start = gvar->mm.farheap = _fmalloc(length);//start = gvar->mm.farheap = halloc(length, 1);\r
806 \r
807         length -= 16-(FP_OFF(start)&15);\r
808         length -= SAVEFARHEAP;\r
809         seglength = length / 16;                        // now in paragraphs\r
810         segstart = FP_SEG(start)+(FP_OFF(start)+15)/16;\r
811         MML_UseSpace(segstart,seglength, gvar);\r
812         gvar->mmi.farheap = length;\r
813         //0000printf("far:      start=%Fp       segstart=%x     seglen=%lu      len=%lu\n", start, segstart, (dword)seglength, length);\r
814 \r
815         gvar->mmi.mainmem = gvar->mmi.nearheap + gvar->mmi.farheap;\r
816 \r
817 #if !defined(__16_PM__)// && defined(__WATCOMC__)\r
818         if(!dbg_debugpm) {\r
819 //\r
820 // detect EMS and allocate up to 64K at page frame\r
821 //\r
822         gvar->mmi.EMSmem = 0;\r
823 //goto emsskip; //0000\r
824         for(i = 1;i < _argc;i++)\r
825         {\r
826                 if(US_CheckParm(_argv[i],ParmStringsexmm) == 0)\r
827                         goto emsskip;                           // param NOEMS\r
828         }\r
829         if(MML_CheckForEMS())\r
830         {\r
831                 MML_SetupEMS(gvar);                                     // allocate space\r
832                 //16_PM: EMS4! AND EMS 3.2 MASSIVE DATA HANDLMENT!\r
833                 MML_UseSpace(gvar->mm.EMSPageFrame,(MAPPAGES)*0x4000lu, gvar);\r
834                 //if(gvar->pm.emm.EMSVer<0x40)\r
835                         MM_MapEMS(gvar);                                        // map in used pages\r
836                 //else\r
837                         //MM_MapXEMS(gvar);                                     // map in used pages\r
838         }\r
839 \r
840 //\r
841 // detect XMS and get upper memory blocks\r
842 //\r
843 emsskip:\r
844         gvar->mmi.XMSmem = 0;\r
845 goto xmsskip;//0000\r
846         for(i = 1;i < _argc;i++)\r
847         {\r
848                 if(US_CheckParm( _argv[i],ParmStringsexmm) == 0)\r
849                         goto xmsskip;                           // param NOXMS\r
850         }\r
851         if(MML_CheckForXMS())\r
852         {\r
853                 MML_SetupXMS(gvar);                                     // allocate as many UMBs as possible\r
854         }\r
855 \r
856         }\r
857 xmsskip:\r
858 #endif\r
859 //\r
860 // allocate the misc buffer\r
861 //\r
862         gvar->mm.mmrover = gvar->mm.mmhead;             // start looking for space after low block\r
863 \r
864         MM_GetPtr(&(gvar->mm.bufferseg),BUFFERSIZE, gvar);\r
865 }\r
866 \r
867 //==========================================================================\r
868 \r
869 /*\r
870 ====================\r
871 =\r
872 = MM_Shutdown\r
873 =\r
874 = Frees all conventional, EMS, and XMS allocated\r
875 =\r
876 ====================\r
877 */\r
878 \r
879 void MM_Shutdown(global_game_variables_t *gvar)\r
880 {\r
881         if(!(gvar->mm.mmstarted))\r
882                 return;\r
883 \r
884         _ffree(gvar->mm.farheap);//     printf("                far freed\n");\r
885 #ifdef __WATCOMC__\r
886         _nfree(gvar->mm.nearheap);//    printf("                near freed\n");\r
887 #endif\r
888 #ifdef __BORLANDC__\r
889         free(gvar->mm.nearheap);//      printf("                near freed\n");\r
890 #endif\r
891 #ifndef __16_PM__\r
892 #ifdef __DEBUG__\r
893         if(!dbg_debugpm) {\r
894 #endif\r
895         if(MML_CheckForEMS()){ MML_ShutdownEMS(gvar); }//printf("               EMS freed\n"); }\r
896         if(MML_CheckForXMS()){ MML_ShutdownXMS(gvar); }//printf("               XMS freed\n"); }\r
897 #ifdef __DEBUG__\r
898         }\r
899 #endif\r
900 #endif\r
901 }\r
902 \r
903 //==========================================================================\r
904 \r
905 /*\r
906 ====================\r
907 =\r
908 = MM_GetPtr\r
909 =\r
910 = Allocates an unlocked, unpurgable block\r
911 =\r
912 ====================\r
913 */\r
914 \r
915 void MM_GetPtr (memptr *baseptr, dword size, global_game_variables_t *gvar)\r
916 {\r
917         mmblocktype far *scan,far *lastscan,far *endscan\r
918                                                 ,far *purge,far *next;\r
919         int                     search;\r
920         unsigned        needed,startseg;\r
921 \r
922         needed = (size+15)/16;          // convert size from bytes to paragraphs\r
923 \r
924         GETNEWBLOCK;                            // fill in start and next after a spot is found\r
925         gvar->mm.mmnew->length = needed;\r
926         gvar->mm.mmnew->useptr = baseptr;\r
927         //if(gvar->mm.mmnew->useptr==NULL){\r
928 #ifdef __DEBUG_MM__\r
929         if(dbg_debugmm>0){\r
930                 printf("MM_GetPtr\n");\r
931                 //%04x\r
932                 printf("        baseptr=%Fp     ", baseptr); printf("useptr=%Fp\n", gvar->mm.mmnew->useptr);\r
933                 printf("        *baseptr=%Fp    ", *baseptr); printf("*useptr=%Fp\n", *(gvar->mm.mmnew->useptr));\r
934                 printf("        &baseptr=%Fp    ", &baseptr); printf("&useptr=%Fp\n", &(gvar->mm.mmnew->useptr));\r
935         }\r
936 #endif\r
937         //Quit(gvar, "gvar->mm.mmnew->useptr==NULL"); }\r
938         gvar->mm.mmnew->attributes = BASEATTRIBUTES;\r
939 \r
940 //tryagain:\r
941         for (search = 0; search<3; search++)\r
942         {\r
943         //\r
944         // first search:        try to allocate right after the rover, then on up\r
945         // second search:       search from the head pointer up to the rover\r
946         // third search:        compress memory, then scan from start\r
947                 if (search == 1 && gvar->mm.mmrover == gvar->mm.mmhead)\r
948                         search++;\r
949 \r
950                 switch (search)\r
951                 {\r
952                 case 0:\r
953                         lastscan = gvar->mm.mmrover;\r
954                         scan = gvar->mm.mmrover->next;\r
955                         endscan = NULL;\r
956                         break;\r
957                 case 1:\r
958                         lastscan = gvar->mm.mmhead;\r
959                         scan = gvar->mm.mmhead->next;\r
960                         endscan = gvar->mm.mmrover;\r
961                         break;\r
962                 case 2:\r
963                         MM_SortMem (gvar);\r
964                         lastscan = gvar->mm.mmhead;\r
965                         scan = gvar->mm.mmhead->next;\r
966                         endscan = NULL;\r
967                         break;\r
968                 }\r
969 \r
970                 startseg = lastscan->start + lastscan->length;\r
971 \r
972                 while (scan != endscan)\r
973                 {\r
974                         if (scan->start - startseg >= needed)\r
975                         {\r
976                         //\r
977                         // got enough space between the end of lastscan and\r
978                         // the start of scan, so throw out anything in the middle\r
979                         // and allocate the new block\r
980                         //\r
981                                 purge = lastscan->next;\r
982                                 lastscan->next = gvar->mm.mmnew;\r
983                                 gvar->mm.mmnew->start = *(unsigned *)baseptr = startseg;\r
984                                 gvar->mm.mmnew->next = scan;\r
985                                 while ( purge != scan)\r
986                                 {       // free the purgable block\r
987                                         next = purge->next;\r
988                                         FREEBLOCK(purge);\r
989                                         purge = next;           // purge another if not at scan\r
990                                 }\r
991                                 gvar->mm.mmrover = gvar->mm.mmnew;\r
992                                 return; // good allocation!\r
993                         }\r
994 \r
995                         //\r
996                         // if this block is purge level zero or locked, skip past it\r
997                         //\r
998                         if ( (scan->attributes & LOCKBIT)\r
999                                 || !(scan->attributes & PURGEBITS) )\r
1000                         {\r
1001                                 lastscan = scan;\r
1002                                 startseg = lastscan->start + lastscan->length;\r
1003                         }\r
1004 \r
1005 \r
1006                         scan=scan->next;                // look at next line\r
1007                 }\r
1008         }\r
1009 \r
1010         if (gvar->mm.bombonerror)\r
1011         {\r
1012 #ifdef __WATCOMC__\r
1013                 //heapdump();\r
1014 #endif\r
1015                 printf(OUT_OF_MEM_MSG,(size-gvar->mmi.nearheap));\r
1016                 Quit(gvar, "for stability reasons the program will shut down! wwww\n");\r
1017         }\r
1018         else\r
1019                 gvar->mm.mmerror = true;\r
1020 }\r
1021 \r
1022 //==========================================================================\r
1023 \r
1024 /*\r
1025 ====================\r
1026 =\r
1027 = MM_FreePtr\r
1028 =\r
1029 = Deallocates an unlocked, purgable block\r
1030 =\r
1031 ====================\r
1032 */\r
1033 \r
1034 void MM_FreePtr (memptr *baseptr, global_game_variables_t *gvar)\r
1035 {\r
1036         mmblocktype far *scan,far *last;\r
1037 \r
1038         last = gvar->mm.mmhead;\r
1039         scan = last->next;\r
1040 \r
1041         if (baseptr == gvar->mm.mmrover->useptr)        // removed the last allocated block\r
1042                 gvar->mm.mmrover = gvar->mm.mmhead;\r
1043 \r
1044         while(scan->useptr != baseptr && scan)\r
1045         {\r
1046                 last = scan;\r
1047                 scan = scan->next;\r
1048         }\r
1049 \r
1050         if(!scan)\r
1051                 Quit (gvar, "MM_FreePtr: Block not found!");\r
1052 \r
1053         last->next = scan->next;\r
1054 \r
1055         FREEBLOCK(scan);\r
1056 }\r
1057 //==========================================================================\r
1058 \r
1059 /*\r
1060 =====================\r
1061 =\r
1062 = MM_SetPurge\r
1063 =\r
1064 = Sets the purge level for a block (locked blocks cannot be made purgable)\r
1065 =\r
1066 =====================\r
1067 */\r
1068 \r
1069 void MM_SetPurge (memptr *baseptr, int purge, global_game_variables_t *gvar)\r
1070 {\r
1071         mmblocktype far *start;\r
1072 \r
1073         start = gvar->mm.mmrover;\r
1074 \r
1075         do\r
1076         {\r
1077                 if (gvar->mm.mmrover->useptr == baseptr)\r
1078                         break;\r
1079 \r
1080                 gvar->mm.mmrover = gvar->mm.mmrover->next;\r
1081 \r
1082                 if (!gvar->mm.mmrover)\r
1083                         gvar->mm.mmrover = gvar->mm.mmhead;\r
1084                 else if (gvar->mm.mmrover == start)\r
1085                         Quit (gvar, "MM_SetPurge: Block not found!");\r
1086 \r
1087         } while(1);\r
1088 \r
1089         gvar->mm.mmrover->attributes &= ~PURGEBITS;\r
1090         gvar->mm.mmrover->attributes |= purge;\r
1091 }\r
1092 \r
1093 //==========================================================================\r
1094 \r
1095 /*\r
1096 =====================\r
1097 =\r
1098 = MM_SetLock\r
1099 =\r
1100 = Locks / unlocks the block\r
1101 =\r
1102 =====================\r
1103 */\r
1104 \r
1105 void MM_SetLock (memptr *baseptr, boolean locked, global_game_variables_t *gvar)\r
1106 {\r
1107         mmblocktype far *start;\r
1108 \r
1109         start = gvar->mm.mmrover;\r
1110 \r
1111         do\r
1112         {\r
1113                 if (gvar->mm.mmrover->useptr == baseptr)\r
1114                         break;\r
1115 \r
1116                 gvar->mm.mmrover = gvar->mm.mmrover->next;\r
1117 \r
1118                 if (!gvar->mm.mmrover)\r
1119                         gvar->mm.mmrover = gvar->mm.mmhead;\r
1120                 else if (gvar->mm.mmrover == start)\r
1121                         Quit (gvar, "MM_SetLock: Block not found!");\r
1122 \r
1123         } while(1);\r
1124 \r
1125         gvar->mm.mmrover->attributes &= ~LOCKBIT;\r
1126         gvar->mm.mmrover->attributes |= locked*LOCKBIT;\r
1127 }\r
1128 \r
1129 //==========================================================================\r
1130 \r
1131 /*\r
1132 =====================\r
1133 =\r
1134 = MM_SortMem\r
1135 =\r
1136 = Throws out all purgable stuff and compresses movable blocks\r
1137 =\r
1138 =====================\r
1139 */\r
1140 \r
1141 void MM_SortMem (global_game_variables_t *gvar)\r
1142 {\r
1143         mmblocktype far *scan,far *last,far *next;\r
1144         unsigned        start,length,source,dest,oldborder;\r
1145         //++++int                       playing;\r
1146 \r
1147         //\r
1148         // lock down a currently playing sound\r
1149         //\r
1150 /*++++  playing = SD_SoundPlaying ();\r
1151         if(playing)\r
1152         {\r
1153                 switch (SoundMode)\r
1154                 {\r
1155                 case sdm_PC:\r
1156                         playing += STARTPCSOUNDS;\r
1157                         break;\r
1158                 case sdm_AdLib:\r
1159                         playing += STARTADLIBSOUNDS;\r
1160                         break;\r
1161                 }\r
1162                 MM_SetLock((memptr *)&audiosegs[playing],true);\r
1163         }\r
1164 \r
1165 \r
1166         SD_StopSound();*/\r
1167         oldborder = gvar->video.bordercolor;\r
1168         gvar->video.bordercolor = modexPalOverscan(15);\r
1169 \r
1170         if(beforesort)\r
1171                 beforesort();\r
1172 \r
1173         scan = gvar->mm.mmhead;\r
1174 \r
1175         last = NULL;            // shut up compiler warning\r
1176 \r
1177         while(scan)\r
1178         {\r
1179                 if(scan->attributes & LOCKBIT)\r
1180                 {\r
1181                 //\r
1182                 // block is locked, so try to pile later blocks right after it\r
1183                 //\r
1184                         start = scan->start + scan->length;\r
1185                 }\r
1186                 else\r
1187                 {\r
1188                         if(scan->attributes & PURGEBITS)\r
1189                         {\r
1190                         //\r
1191                         // throw out the purgable block\r
1192                         //\r
1193                                 next = scan->next;\r
1194                                 FREEBLOCK(scan); //MM_FreeBlock(scan, gvar);\r
1195                                 last->next = next;\r
1196                                 scan = next;\r
1197                                 continue;\r
1198                         }\r
1199                         else\r
1200                         {\r
1201                         //\r
1202                         // push the non purgable block on top of the last moved block\r
1203                         //\r
1204                                 if(scan->start != start)\r
1205                                 {\r
1206                                         length = scan->length;\r
1207                                         source = scan->start;\r
1208                                         dest = start;\r
1209                                         while(length > 0xf00)\r
1210                                         {\r
1211                                                 movedata(source,0,dest,0,0xf00*16);\r
1212                                                 length -= 0xf00;\r
1213                                                 source += 0xf00;\r
1214                                                 dest += 0xf00;\r
1215                                         }\r
1216                                         movedata(source,0,dest,0,length*16);\r
1217 \r
1218                                         scan->start = start;\r
1219                                         *(unsigned *)scan->useptr = start;\r
1220                                 }\r
1221                                 start = scan->start + scan->length;\r
1222                         }\r
1223                 }\r
1224 \r
1225                 last = scan;\r
1226                 scan = scan->next;              // go to next block\r
1227         }\r
1228 \r
1229         gvar->mm.mmrover = gvar->mm.mmhead;\r
1230 \r
1231         if(aftersort)\r
1232                 aftersort();\r
1233 \r
1234         VL_ColorBorder (oldborder, &gvar->video);\r
1235 \r
1236 /*++++  if(playing)\r
1237                 MM_SetLock((memptr *)&audiosegs[playing],false);*/\r
1238 }\r
1239 \r
1240 //==========================================================================\r
1241 \r
1242 /*\r
1243 =====================\r
1244 =\r
1245 = MM_ShowMemory\r
1246 =\r
1247 =====================\r
1248 */\r
1249 \r
1250 //#define MMSMSORTNEWTYPE\r
1251 #define MMSHOWMEMOFFSET 0//(gvar->video.page[0].dx+(gvar->video.page[0].dy*gvar->video.page[0].stridew))\r
1252 \r
1253 void MM_ShowMemory (global_game_variables_t *gvar)\r
1254 {\r
1255         mmblocktype far *scan;\r
1256         unsigned color,temp,x,y         ,w;//,bofstemp;\r
1257         sdword  end,owner;\r
1258         byte    scratch[160],scratch0[4096],str[16];\r
1259 \r
1260 //--    VL_SetLineWidth(40, gvar);\r
1261         //temp = gvar->video.ofs.bufferofs;\r
1262         //gvar->video.ofs.bufferofs = gvar->video.ofs.displayofs;\r
1263         temp = BDOFSCONV gvar->video.BOFS+MMSHOWMEMOFFSET;\r
1264         gvar->video.BOFS = gvar->video.DOFS;\r
1265         scan = gvar->mm.mmhead;\r
1266 \r
1267         end = -1; w = 0;\r
1268 \r
1269         CA_OpenDebug (gvar);\r
1270         while (scan)\r
1271         {\r
1272                 strcpy(scratch, AARESET);\r
1273                 if(scan->attributes & PURGEBITS)\r
1274                 {\r
1275                         color = 6;              // dark purple = purgable\r
1276                         strcpy(scratch0, AAMAGENTA);            // dark purple = purgable\r
1277                 }else{\r
1278                         color = 2;              // medium blue = non purgable\r
1279                         strcpy(scratch0, AABLUE);               // medium blue = non purgable\r
1280                 }\r
1281                 if(scan->attributes & LOCKBIT)\r
1282                 {\r
1283                         color = 1;              // red = locked\r
1284                         strcpy(scratch0, AARED);                // red = locked\r
1285                 }\r
1286                 if(scan->start<=end)\r
1287                 {\r
1288                         printf("\nend==%d\n\n", end);\r
1289                         strcat(scratch, "MM_ShowMemory: Memory block order currupted!\n");\r
1290                         strcat(scratch, "End's Size: ");\r
1291                         ultoa (end,str,10);\r
1292                         strcat (scratch,str);\r
1293                         strcat(scratch, "\nscan->start's Size: ");\r
1294                         ultoa (scan->start,str,10);\r
1295                         strcat (scratch,str);\r
1296                         write(gvar->handle.debughandle,scratch,strlen(scratch));\r
1297                         Quit (gvar, "MM_ShowMemory: Memory block order currupted!");\r
1298                 }\r
1299 #ifdef MMSMSORTNEWTYPE\r
1300                 end = scan->start+(scan->length)-1;\r
1301 #else\r
1302                 end = scan->length-1;\r
1303 #endif\r
1304                 if(!gvar->video.page[0].width) gvar->video.page[0].width = 352;\r
1305                 y = scan->start/gvar->video.page[0].width;\r
1306                 x = scan->start%gvar->video.page[0].width;\r
1307                 VW_Hlin(x,x+end,y,color,gvar);\r
1308                 VL_Plot(x,y,15,gvar);\r
1309                 for(w=(scan->start)/80;w<=end/80;w++)\r
1310                 {\r
1311                         //printf("+     %u      %lu\n", w, scan->length);\r
1312                         strcat(scratch0, "+");\r
1313                 }\r
1314                 //++==++==optional\r
1315                 strcat(scratch0, AARESET); strcat(scratch0, AAGREY); strcat(scratch0,"_");\r
1316 #ifdef MMSMSORTNEWTYPE\r
1317                 if (scan->next && scan->next->start > end+1)\r
1318 #else\r
1319                 if (scan->next && scan->next->start >= end+1)\r
1320 #endif\r
1321                 {\r
1322                         VW_Hlin(x+end+1,x+(scan->next->start-scan->start),y,3,gvar);    // black = free//now green\r
1323                         strcat(scratch0, AARESET);\r
1324 //++==++==optional                      strcat(scratch0, "\n");\r
1325                         strcat(scratch0,AAGREEN);\r
1326                         for(w=(end+1)/80;w<=((scan->next->start-scan->start)/80);w++)\r
1327                         {\r
1328                                 //printf("0     %x      %u      %lu\n", scan->next->start, w, scan->length);\r
1329                                 strcat(scratch0,"0");\r
1330                         }\r
1331                         //printf("==================\n");\r
1332                         //printf("w=%u  start=%04x      next=%04x       end=%lu\n", w/80, scan->start, (scan->next->start), end+1);\r
1333                         //printf("==================\n");\r
1334                         strcat(scratch0, "\n");\r
1335                 }\r
1336 #if 0\r
1337                 else {//if(scan->next->start <= scan->start){\r
1338                         scan->next->start=scan->start+0x1000;\r
1339                         strcat(scratch0, AARESET);\r
1340                         strcat(scratch0, "\n");\r
1341                         strcat(scratch0,AAGREEN);\r
1342                         for(w=(end+1);w<=(0x1000/80);w++)\r
1343                         {\r
1344                                 //printf("0     %x      %x      %u\n", scan->start, w);\r
1345                                 strcat(scratch0,"0");\r
1346                         }\r
1347                         printf("================\n");\r
1348                         printf("w=%x    start=%x        next=%x end=%u\n", w, scan->start, (scan->next->start), end+1);\r
1349                         printf("================\n");\r
1350                         getch();\r
1351                 }\r
1352 #endif\r
1353                 strcat(scratch0, AARESET);\r
1354                 //strcat(scratch0,"\n");\r
1355                 strcat(scratch,"Seg:");\r
1356                 ultoa (scan->start,str,16);\r
1357                 strcat (scratch,str);\r
1358 //              strcat(scratch, AABLACK); strcat(scratch,"\t"); strcat(scratch, AARESET);\r
1359                 strcat (scratch,"\tSize:");\r
1360                 ultoa ((unsigned)scan->length,str,10);\r
1361                 strcat (scratch,str);\r
1362 //              strcat(scratch, AABLACK); strcat(scratch,"\t"); strcat(scratch, AARESET);\r
1363                 strcat (scratch,"\tOwner:0x");\r
1364                 owner = (unsigned)scan->useptr;\r
1365                 ultoa (owner,str,16);\r
1366                 strcat (scratch,str);\r
1367                 strcat (scratch,"\n");\r
1368                 write(gvar->handle.debughandle,scratch,strlen(scratch));\r
1369                 write(gvar->handle.debughandle,scratch0,strlen(scratch0));\r
1370 //fprintf(stdout, "%s", scratch);\r
1371 \r
1372                 scan = scan->next;\r
1373         }\r
1374 \r
1375         CA_CloseDebug (gvar);\r
1376 \r
1377         IN_Ack(gvar);\r
1378 \r
1379         gvar->video.BOFS = (byte __far *)temp;\r
1380 }\r
1381 \r
1382 //==========================================================================\r
1383 \r
1384 /*\r
1385 =====================\r
1386 =\r
1387 = MM_DumpData\r
1388 =\r
1389 =====================\r
1390 */\r
1391 \r
1392 void MM_DumpData (global_game_variables_t *gvar)\r
1393 {\r
1394         mmblocktype far *scan,far *best;\r
1395         long    lowest,oldlowest;\r
1396         unsigned        owner;\r
1397         char    lock,purge;\r
1398         FILE    *dumpfile;\r
1399 \r
1400 #ifdef __WATCOMC__\r
1401         _nfree(gvar->mm.nearheap);\r
1402 #endif\r
1403 #ifdef __BORLANDC__\r
1404         free(gvar->mm.nearheap);\r
1405 #endif\r
1406 #ifdef __BORLANDC__\r
1407                 dumpfile = fopen ("mmdump.16b","w");\r
1408 #endif\r
1409 #ifdef __WATCOMC__\r
1410                 dumpfile = fopen ("mmdump.16w","w");\r
1411 #endif\r
1412         if (!dumpfile){\r
1413                 printf("MM_DumpData: Couldn't open MMDUMP.16!\n");\r
1414                 return;\r
1415         }\r
1416 \r
1417         lowest = -1;\r
1418         do\r
1419         {\r
1420                 oldlowest = lowest;\r
1421                 lowest = 0xffff;\r
1422 \r
1423                 scan = gvar->mm.mmhead;\r
1424                 while (scan)\r
1425                 {\r
1426                         owner = (unsigned)scan->useptr;\r
1427 \r
1428                         if (owner && owner<lowest && owner > oldlowest)\r
1429                         {\r
1430                                 best = scan;\r
1431                                 lowest = owner;\r
1432                         }\r
1433 \r
1434                         scan = scan->next;\r
1435                 }\r
1436 \r
1437                 if (lowest != 0xffff)\r
1438                 {\r
1439                         if (best->attributes & PURGEBITS)\r
1440                                 purge = 'P';\r
1441                         else\r
1442                                 purge = '-';\r
1443                         if (best->attributes & LOCKBIT)\r
1444                                 lock = 'L';\r
1445                         else\r
1446                                 lock = '-';\r
1447                         fprintf (dumpfile,"0x%p (%c%c) = %u\n"\r
1448                         ,(unsigned)lowest,lock,purge,best->length);\r
1449                 }\r
1450 \r
1451         } while (lowest != 0xffff);\r
1452 \r
1453         fclose(dumpfile);\r
1454         printf("MMDUMP.16 created.\n");\r
1455 }\r
1456 \r
1457 //==========================================================================\r
1458 \r
1459 \r
1460 /*\r
1461 ======================\r
1462 =\r
1463 = MM_UnusedMemory\r
1464 =\r
1465 = Returns the total free space without purging\r
1466 =\r
1467 ======================\r
1468 */\r
1469 \r
1470 dword MM_UnusedMemory (global_game_variables_t *gvar)\r
1471 {\r
1472         unsigned free;\r
1473         mmblocktype far *scan;\r
1474 \r
1475         free = 0;\r
1476         scan = gvar->mm.mmhead;\r
1477 \r
1478         while(scan->next)\r
1479         {\r
1480                 free += scan->next->start - (scan->start + scan->length);\r
1481                 scan = scan->next;\r
1482         }\r
1483 \r
1484         return free*16lu;\r
1485 }\r
1486 \r
1487 //==========================================================================\r
1488 \r
1489 \r
1490 /*\r
1491 ======================\r
1492 =\r
1493 = MM_TotalFree\r
1494 =\r
1495 = Returns the total free space with purging\r
1496 =\r
1497 ======================\r
1498 */\r
1499 \r
1500 dword MM_TotalFree (global_game_variables_t *gvar)\r
1501 {\r
1502         unsigned free;\r
1503         mmblocktype far *scan;\r
1504 \r
1505         free = 0;\r
1506         scan = gvar->mm.mmhead;\r
1507 \r
1508         while(scan->next)\r
1509         {\r
1510                 if((scan->attributes&PURGEBITS) && !(scan->attributes&LOCKBIT))\r
1511                         free += scan->length;\r
1512                 free += scan->next->start - (scan->start + scan->length);\r
1513                 scan = scan->next;\r
1514         }\r
1515 \r
1516         return free*16lu;\r
1517 }\r
1518 \r
1519 //==========================================================================\r
1520 \r
1521 /*\r
1522 =====================\r
1523 =\r
1524 = MM_Report\r
1525 =\r
1526 =====================\r
1527 */\r
1528 \r
1529 void MM_Report_(global_game_variables_t *gvar)\r
1530 {\r
1531         printf("========================================\n");\r
1532         printf("                MM_Report_\n");\r
1533         printf("========================================\n");\r
1534         if(MML_CheckForEMS())\r
1535         {\r
1536                 printf("        %cLIMEMS        %u\n", 0xC9, gvar->pm.emm.EMSPresent);\r
1537                 printf("        %c%cEMM v%x.%x available\n", 0xC7, 0xC4, gvar->pm.emm.EMSVer>>4,gvar->pm.emm.EMSVer&0x0F);\r
1538                 printf("        %c%ctotalEMSpages:      %u      ", 0xC7, 0xC4, gvar->pm.emm.totalEMSpages); printf("freeEMSpages:       %u\n", gvar->pm.emm.freeEMSpages);\r
1539                 printf("        %c%cEMSPageFrame:       %04x\n", 0xC7, 0xC4, gvar->pm.emm.EMSPageFrame);\r
1540                 printf("        %c%cEMSmem:     %lu or %luk\n", 0xD3, 0xC4, gvar->mmi.EMSmem, gvar->mmi.EMSmem/1204);\r
1541         }\r
1542         if(MML_CheckForXMS())\r
1543         {\r
1544                 printf("        %cXMS   %u\n", 0xC9, gvar->pm.xmm.XMSPresent);\r
1545                 printf("        %c%cXMS v%x.%x available\n", 0xC7, 0xC4, XMSVer>>8,XMSVer&0x0F);\r
1546                 printf("        %c%cXMSDriver:  %Fp\n", 0xC7, 0xC4, XMSDriver);\r
1547                 printf("        %c%cXMSHandle:  %04x\n", 0xC7, 0xC4, gvar->pm.xmm.XMSHandle);\r
1548                 printf("        %c%cXMSmem:     %lu or %lukb\n", 0xD3, 0xC4, gvar->mmi.XMSmem, gvar->mmi.XMSmem/1024);\r
1549         }\r
1550         printf("        %cConv. %u\n", 0xC9, gvar->pm.mm.MainPresent); DebugMemory_(gvar, 0);\r
1551         //printf("mainmem:      %lu\n", gvar->mmi.mainmem);\r
1552         //printf("Total convmem:        %lu     ", gvar->mmi.mainmem); printf("TotalFree:       %lu     ", MM_TotalFree(gvar)+gvar->mmi.EMSmem+gvar->mmi.XMSmem+gvar->mmi.XMSmem); printf("TotalUsed:   %lu\n", gvar->mmi.mainmem);\r
1553         //printf("                      UnusedMemory:   %lu\n", MM_UnusedMemory(gvar));\r
1554         printf("nearheap:       %lu             ", gvar->mmi.nearheap); printf("farheap:        %lu\n", gvar->mmi.farheap);\r
1555 }\r
1556 \r
1557 //==========================================================================\r
1558 \r
1559 /*\r
1560 =====================\r
1561 =\r
1562 = MM_EMSerr\r
1563 =\r
1564 =====================\r
1565 */\r
1566 \r
1567 void MM_EMSerr(byte *stri, byte err)\r
1568 {\r
1569         //Returns a text string describing the error code in EMS.Error.\r
1570         switch(err)\r
1571         {\r
1572                 case 0x0:\r
1573                         strcat(stri, "successful");\r
1574                 break;\r
1575                 case 0x80:\r
1576                         strcat(stri, "internal error");\r
1577                 break;\r
1578                 case 0x81:\r
1579                         strcat(stri, "hardware malfunction");\r
1580                 break;\r
1581                 case 0x82:\r
1582                         strcat(stri, "busy .. retry later");\r
1583                 break;\r
1584                 case 0x83:\r
1585                         strcat(stri, "invalid handle");\r
1586                 break;\r
1587                 case 0x84:\r
1588                         strcat(stri, "undefined function requested by application");\r
1589                 break;\r
1590                 case 0x85:\r
1591                         strcat(stri, "no more handles available");\r
1592                 break;\r
1593                 case 0x86:\r
1594                         strcat(stri, "error in save or restore of mapping context");\r
1595                 break;\r
1596                 case 0x87:\r
1597                         strcat(stri, "insufficient memory pages in system");\r
1598                 break;\r
1599                 case 0x88:\r
1600                         strcat(stri, "insufficient memory pages available");\r
1601                 break;\r
1602                 case 0x89:\r
1603                         strcat(stri, "zero pages requested");\r
1604                 break;\r
1605                 case 0x8A:\r
1606                         strcat(stri, "invalid logical page number encountered");\r
1607                 break;\r
1608                 case 0x8B:\r
1609                         strcat(stri, "invalid physical page number encountered");\r
1610                 break;\r
1611                 case 0x8C:\r
1612                         strcat(stri, "page-mapping hardware state save area is full");\r
1613                 break;\r
1614                 case 0x8D:\r
1615                         strcat(stri, "save of mapping context failed");\r
1616                 break;\r
1617                 case 0x8E:\r
1618                         strcat(stri, "restore of mapping context failed");\r
1619                 break;\r
1620                 case 0x8F:\r
1621                         strcat(stri, "undefined subfunction");\r
1622                 break;\r
1623                 case 0x90:\r
1624                         strcat(stri, "undefined attribute type");\r
1625                 break;\r
1626                 case 0x91:\r
1627                         strcat(stri, "feature not supported");\r
1628                 break;\r
1629                 case 0x92:\r
1630                         strcat(stri, "successful, but a portion of the source region has been overwritten");\r
1631                 break;\r
1632                 case 0x93:\r
1633                         strcat(stri, "length of source or destination region exceeds length of region allocated to either source or destination handle");\r
1634                 break;\r
1635                 case 0x94:\r
1636                         strcat(stri, "conventional and expanded memory regions overlap");\r
1637                 break;\r
1638                 case 0x95:\r
1639                         strcat(stri, "offset within logical page exceeds size of logical page");\r
1640                 break;\r
1641                 case 0x96:\r
1642                         strcat(stri, "region length exceeds 1 MB");\r
1643                 break;\r
1644                 case 0x97:\r
1645                         strcat(stri, "source and destination EMS regions have same handle and overlap");\r
1646                 break;\r
1647                 case 0x98:\r
1648                         strcat(stri, "memory source or destination type undefined");\r
1649                 break;\r
1650                 case 0x9A:\r
1651                         strcat(stri, "specified alternate map register or DMA register set not supported");\r
1652                 break;\r
1653                 case 0x9B:\r
1654                         strcat(stri, "all alternate map register or DMA register sets currently allocated");\r
1655                 break;\r
1656                 case 0x9C:\r
1657                         strcat(stri, "alternate map register or DMA register sets not supported");\r
1658                 break;\r
1659                 case 0x9D:\r
1660                         strcat(stri, "undefined or unallocated alternate map register or DMA register set");\r
1661                 break;\r
1662                 case 0x9E:\r
1663                         strcat(stri, "dedicated DMA channels not supported");\r
1664                 break;\r
1665                 case 0x9F:\r
1666                         strcat(stri, "specified dedicated DMA channel not supported");\r
1667                 break;\r
1668                 case 0xA0:\r
1669                         strcat(stri, "no such handle name");\r
1670                 break;\r
1671                 case 0xA1:\r
1672                         strcat(stri, "a handle found had no name, or duplicate handle name");\r
1673                 break;\r
1674                 case 0xA2:\r
1675                         strcat(stri, "attempted to wrap around 1M conventional address space");\r
1676                 break;\r
1677                 case 0xA3:\r
1678                         strcat(stri, "source array corrupted");\r
1679                 break;\r
1680                 case 0xA4:\r
1681                         strcat(stri, "operating system denied access");\r
1682                 break;\r
1683                 default:\r
1684                         strcat(stri, "undefined error");\r
1685         }\r
1686 }\r
1687 \r
1688 //==========================================================================\r
1689 \r
1690 /*\r
1691 =====================\r
1692 =\r
1693 = MM_BombOnError\r
1694 =\r
1695 =====================\r
1696 */\r
1697 \r
1698 void MM_BombOnError (boolean bomb, global_game_variables_t *gvar)\r
1699 {\r
1700         gvar->mm.bombonerror = bomb;\r
1701 }\r
1702 \r
1703 #if 0\r
1704 void MM_GetNewBlock(global_game_variables_t *gvar)\r
1705 {\r
1706         if(!gvar->mm.mmfree)\r
1707                 MML_ClearBlock(gvar);\r
1708         gvar->mm.mmnew=gvar->mm.mmfree;\r
1709         gvar->mm.mmfree=gvar->mm.mmfree->next;\r
1710         if(!(gvar->mm.mmnew=gvar->mm.mmfree))\r
1711         {\r
1712                 printf("MM_GETNEWBLOCK: No free blocks!\n");\r
1713                 return;\r
1714         }\r
1715         gvar->mm.mmfree=gvar->mm.mmfree->next;\r
1716 }\r
1717 \r
1718 void MM_FreeBlock(mmblocktype *x, global_game_variables_t *gvar)\r
1719 {\r
1720         x->useptr=NULL;\r
1721         x->next=gvar->mm.mmfree;\r
1722         gvar->mm.mmfree=x;\r
1723 }\r
1724 #endif\r
1725 \r
1726 void xms_call(byte v, global_game_variables_t *gvar)\r
1727 {\r
1728         dword XMSDriver = gvar->pm.xmm.XMSDriver;\r
1729         __asm {\r
1730                 mov     ah,[v]\r
1731                 call [DWORD PTR XMSDriver]\r
1732         }\r
1733 }\r
1734 \r
1735 /*void MM_seguin(void)\r
1736 {\r
1737         __asm {\r
1738                 push    ds\r
1739                 mov     ax,ds\r
1740                 inc             ax\r
1741                 mov     ds,ax\r
1742         }\r
1743 }\r
1744 \r
1745 void MM_segude(void)\r
1746 {\r
1747         __asm {\r
1748                 pop ds\r
1749         }\r
1750 }*/\r
1751 \r
1752 /*\r
1753 pull data from far and put it into ds var\r
1754 mov ax,es:si\r
1755 mov x,ax\r
1756 */\r
1757 /*\r
1758 ss stack segment\r
1759 sp top of stack\r
1760 bp bottem of stack\r
1761 */\r