OSDN Git Service

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