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 #ifdef __WATCOMC__\r
1261 //#define MMSMPANVID\r
1262 #define MMSMSCANINFO\r
1263 #endif\r
1264 \r
1265 void MM_ShowMemory (global_game_variables_t *gvar)\r
1266 {\r
1267         mmblocktype far *scan;\r
1268         unsigned color,temp,x,y         ,w,q,width;\r
1269         sdword  end,owner;\r
1270         byte            scratch[160],scratch0[4096],str[16];\r
1271         mmshowmemoryinfo_t scaninfo[MAXBLOCKS];\r
1272 \r
1273         if(!gvar->video.page[0].width) gvar->video.page[0].sw = gvar->video.page[0].width = 320;        //to prevent division by 0\r
1274 //--    VL_SetLineWidth(40, gvar);\r
1275         //temp = gvar->video.ofs.bufferofs;\r
1276         //gvar->video.ofs.bufferofs = gvar->video.ofs.displayofs;\r
1277         temp = BDOFSCONV gvar->video.BOFS;\r
1278         gvar->video.BOFS = gvar->video.DOFS;\r
1279         scan = gvar->mm.mmhead;\r
1280 \r
1281         end = -1; w = 0;\r
1282 \r
1283         width = gvar->video.page[0].width; q = 0;\r
1284 \r
1285         CA_OpenDebug (gvar);\r
1286         while (scan)\r
1287         {\r
1288                 scaninfo[q].scan = scan;\r
1289                 strcpy(scratch, AARESET);\r
1290                 if(scan->attributes & PURGEBITS)\r
1291                 {\r
1292                         color = 6;              // dark purple = purgable\r
1293                         strcpy(scratch0, AAMAGENTA);            // dark purple = purgable\r
1294                 }else{\r
1295                         color = 2;              // medium blue = non purgable\r
1296                         strcpy(scratch0, AABLUE);               // medium blue = non purgable\r
1297                 }\r
1298                 if(scan->attributes & LOCKBIT)\r
1299                 {\r
1300                         color = 1;              // red = locked\r
1301                         strcpy(scratch0, AARED);                // red = locked\r
1302                 }\r
1303                 if (scan->start<=end)\r
1304                 {\r
1305                         printf("\nend==%d\n\n", end);\r
1306                         strcat(scratch, "MM_ShowMemory: Memory block order currupted!\n");\r
1307                         strcat(scratch, "End's Size: ");\r
1308                         ultoa (end,str,10);\r
1309                         strcat (scratch,str);\r
1310                         strcat(scratch, "\nscan->start's Size: ");\r
1311                         ultoa (scan->start,str,10);\r
1312                         strcat (scratch,str);\r
1313                         write(gvar->handle.debughandle,scratch,strlen(scratch));\r
1314                         Quit (gvar, "MM_ShowMemory: Memory block order currupted!");\r
1315                 }\r
1316                 end = scan->length-1;\r
1317                 y = scan->start/width;\r
1318                 x = scan->start%width;\r
1319                 scaninfo[q].x = x;\r
1320                 scaninfo[q].y = y;\r
1321                 VW_Hlin(x,x+end,y,color,gvar);\r
1322                 VL_Plot(x,y,5,gvar);\r
1323                 for(w=(scan->start)/80;w<=end/80;w++)\r
1324                 {\r
1325 //printf("+     %u      %lu\n", w, scan->length);\r
1326                         strcat(scratch0, "+");\r
1327                 }\r
1328                 //++==++==optional\r
1329                 strcat(scratch0, AARESET); strcat(scratch0, AAGREY); strcat(scratch0,"_");\r
1330 \r
1331                 if (scan->next && scan->next->start > end+1)\r
1332                 {\r
1333                         VW_Hlin(x+end+1,x+(scan->next->start-scan->start),y,3,gvar);    // black = free//now green\r
1334                         strcat(scratch0, AARESET);\r
1335 //++==++==optional                      strcat(scratch0, "\n");\r
1336                         strcat(scratch0,AAGREEN);\r
1337                         for(w=(end+1)/80;w<=((scan->next->start-scan->start)/80);w++)\r
1338                         {\r
1339 //printf("0     %x      %u      %lu\n", scan->next->start, w, scan->length);\r
1340                                 strcat(scratch0,"0");\r
1341                         }\r
1342                         //printf("==================\n");\r
1343                         //printf("w=%u  start=%04x      next=%04x       end=%lu\n", w/80, scan->start, (scan->next->start), end+1);\r
1344                         //printf("==================\n");\r
1345                         strcat(scratch0, "\n");\r
1346                 }\r
1347 #if 0\r
1348                 else {//if(scan->next->start <= scan->start){\r
1349                         scan->next->start=scan->start+0x1000;\r
1350                         strcat(scratch0, AARESET);\r
1351                         strcat(scratch0, "\n");\r
1352                         strcat(scratch0,AAGREEN);\r
1353                         for(w=(end+1);w<=(0x1000/80);w++)\r
1354                         {\r
1355                                 //printf("0     %x      %x      %u\n", scan->start, w);\r
1356                                 strcat(scratch0,"0");\r
1357                         }\r
1358                         printf("================\n");\r
1359                         printf("w=%x    start=%x        next=%x end=%u\n", w, scan->start, (scan->next->start), end+1);\r
1360                         printf("================\n");\r
1361                         getch();\r
1362                 }\r
1363 #endif\r
1364                 strcat(scratch0, AARESET);\r
1365                 //strcat(scratch0,"\n");\r
1366                 strcat(scratch,"Seg:");\r
1367                 ultoa (scan->start,str,16);\r
1368                 strcat (scratch,str);\r
1369 //              strcat(scratch, AABLACK); strcat(scratch,"\t"); strcat(scratch, AARESET);\r
1370                 strcat (scratch,"\tSize:");\r
1371                 ultoa ((unsigned)scan->length,str,10);\r
1372                 strcat (scratch,str);\r
1373 //              strcat(scratch, AABLACK); strcat(scratch,"\t"); strcat(scratch, AARESET);\r
1374                 strcat (scratch,"\tOwner:0x");\r
1375                 owner = (unsigned)scan->useptr;\r
1376                 ultoa (owner,str,16);\r
1377                 strcat (scratch,str);\r
1378                 strcat (scratch,"\n");\r
1379                 write(gvar->handle.debughandle,scratch,strlen(scratch));\r
1380                 write(gvar->handle.debughandle,scratch0,strlen(scratch0));\r
1381 //fprintf(stdout, "%s", scratch);\r
1382 \r
1383                 scan = scan->next;\r
1384                 q++;\r
1385 //if(color!=6) IN_Ack(gvar);\r
1386         }\r
1387 \r
1388         CA_CloseDebug (gvar);\r
1389 \r
1390 #ifdef MMSMPANVID\r
1391         {\r
1392                 int dx,dy,odx,ody;\r
1393                 odx = gvar->video.page[0].dx;\r
1394                 ody = gvar->video.page[0].dy;\r
1395                 dx = dy = 0;\r
1396                 while(!gvar->in.inst->Keyboard[sc_Escape])\r
1397                 {\r
1398                         if(gvar->in.inst->Keyboard[sc_UpArrow])\r
1399                         {\r
1400                                 if(dy>0)\r
1401                                         dy--;\r
1402                         }\r
1403                         else if(gvar->in.inst->Keyboard[sc_DownArrow])\r
1404                         {\r
1405                                 if(dy<gvar->video.page[0].height-gvar->video.page[0].sh)\r
1406                                         dy++;\r
1407                         }\r
1408                         if(gvar->in.inst->Keyboard[sc_LeftArrow])\r
1409                         {\r
1410                                 if(dx>0)\r
1411                                         dx--;\r
1412                         }\r
1413                         else if(gvar->in.inst->Keyboard[sc_RightArrow])\r
1414                         {\r
1415                                 if(dx<gvar->video.page[0].width-gvar->video.page[0].sw)\r
1416                                         dx++;\r
1417                         }\r
1418 \r
1419                         modexPanPage(&gvar->video.page[0], dx, dy);\r
1420                         VL_ShowPage(&gvar->video.page[0], 1, 1);\r
1421                 }\r
1422 \r
1423                 gvar->video.page[0].dx = odx;\r
1424                 gvar->video.page[0].dy = ody;\r
1425         }\r
1426 #endif\r
1427 #ifdef MMSMSCANINFO\r
1428         {\r
1429                 unsigned                maxq = q;\r
1430                 boolean                 done;\r
1431                 ScanCode                scancode;\r
1432                 int xpos,ypos;\r
1433                 word qq, ccolor = 3;\r
1434                 IN_Ack(gvar);\r
1435 //              VL_ClearVideo (8);\r
1436                 for (qq = 0,done = false;!done;)\r
1437                 {\r
1438                         if(scaninfo[qq].scan->attributes & PURGEBITS)\r
1439                         {\r
1440                                 ccolor = 6;             // dark purple = purgable\r
1441                         }else{\r
1442                                 ccolor = 2;             // medium blue = non purgable\r
1443                         }\r
1444                         if(scaninfo[qq].scan->attributes & LOCKBIT)\r
1445                         {\r
1446                                 ccolor = 1;             // red = locked\r
1447                         }\r
1448                         end = scaninfo[qq].scan->length-1;\r
1449 /*typedef struct mmblockstruct{\r
1450         word    start,length;\r
1451         unsigned        attributes;\r
1452         memptr          *useptr;        // pointer to the segment start\r
1453         struct mmblockstruct far *next;\r
1454 } mmblocktype;*/\r
1455                         //modexprint(page, x, y, t, tlsw, color, bgcolor, vidsw, const byte *str);\r
1456 #define MMSMPRINTMEMINFO modexprint(&(gvar->video.page[0]), xpos, ypos, 1, 0, ccolor, 8, gvar->video.VL_Started, global_temp_status_text); ypos+=8;\r
1457                         VL_ShowPage(&gvar->video.page[0], 1, 0);\r
1458                         if(!gvar->video.VL_Started) clrscr(); else\r
1459                         {\r
1460                                 modexClearRegion(&gvar->video.page[0], 0, 0, gvar->video.page[0].width, gvar->video.page[0].height, 8);\r
1461                         }\r
1462                         sprintf(global_temp_status_text, "block #%04u", qq); MMSMPRINTMEMINFO\r
1463 //                      sprintf(global_temp_status_text, "%Fp", scaninfo[qq].scan->useptr); MMSMPRINTMEMINFO\r
1464                         sprintf(global_temp_status_text, "%04x", (unsigned)scaninfo[qq].scan->useptr); MMSMPRINTMEMINFO\r
1465                         sprintf(global_temp_status_text, "size: %05u", (unsigned)scaninfo[qq].scan->length); MMSMPRINTMEMINFO\r
1466                         if (scaninfo[qq].scan->next && scaninfo[qq].scan->next->start > end+1)\r
1467                         {\r
1468                                 sprintf(global_temp_status_text, "free: %05u", (unsigned)(scaninfo[qq].scan->next->start-scaninfo[qq].scan->start)); MMSMPRINTMEMINFO\r
1469                         }\r
1470                         y = ypos;//scaninfo[qq].scan->start/width;\r
1471                         x = xpos;//scaninfo[qq].scan->start%width;\r
1472                         VW_Hlin(x,x+end,y,ccolor,gvar);\r
1473                         VL_Plot(x,y,5,gvar);\r
1474                         if (scaninfo[qq].scan->next && scaninfo[qq].scan->next->start > end+1)\r
1475                                 VW_Hlin(x+end+1,x+(scaninfo[qq].scan->next->start-scaninfo[qq].scan->start),y,3,gvar);  // black = free//now green\r
1476 \r
1477                         //if (scan->next && scan->next->start > end+1) free\r
1478                         xpos = 16;\r
1479                         ypos = 16;//(gvar->video.page[0].sh-(32));//8*4\r
1480                         while (!(scancode = gvar->in.inst->LastScan)){}\r
1481 \r
1482                         IN_ClearKey(scancode);\r
1483                         switch (scancode)\r
1484                         {\r
1485                                 case sc_LeftArrow:\r
1486                                         if(qq>0) qq--;\r
1487                                         else    qq = maxq;\r
1488                                 break;\r
1489                                 case sc_RightArrow:\r
1490                                         if(qq<maxq) qq++;\r
1491                                         else qq = 0;\r
1492                                 break;\r
1493                                 case sc_Escape:\r
1494                                         done = true;\r
1495                                 break;\r
1496                         }\r
1497                 }\r
1498         }\r
1499 #endif\r
1500 \r
1501         IN_Ack(gvar);\r
1502 \r
1503         gvar->video.BOFS = (byte __far *)temp;\r
1504 }\r
1505 \r
1506 //==========================================================================\r
1507 \r
1508 /*\r
1509 =====================\r
1510 =\r
1511 = MM_DumpData\r
1512 =\r
1513 =====================\r
1514 */\r
1515 \r
1516 void MM_DumpData (global_game_variables_t *gvar)\r
1517 {\r
1518         mmblocktype far *scan,far *best;\r
1519         long    lowest,oldlowest;\r
1520         unsigned        owner;\r
1521         char    lock,purge;\r
1522         FILE    *dumpfile;\r
1523 \r
1524 #ifdef __WATCOMC__\r
1525         _nfree(gvar->mm.nearheap);\r
1526 #endif\r
1527 #ifdef __BORLANDC__\r
1528         free(gvar->mm.nearheap);\r
1529 #endif\r
1530 #ifdef __BORLANDC__\r
1531                 dumpfile = fopen ("mmdump.16b","w");\r
1532 #endif\r
1533 #ifdef __WATCOMC__\r
1534                 dumpfile = fopen ("mmdump.16w","w");\r
1535 #endif\r
1536         if (!dumpfile){\r
1537                 printf("MM_DumpData: Couldn't open MMDUMP.16!\n");\r
1538                 return;\r
1539         }\r
1540 \r
1541         lowest = -1;\r
1542         do\r
1543         {\r
1544                 oldlowest = lowest;\r
1545                 lowest = 0xffff;\r
1546 \r
1547                 scan = gvar->mm.mmhead;\r
1548                 while (scan)\r
1549                 {\r
1550                         owner = (unsigned)scan->useptr;\r
1551 \r
1552                         if (owner && owner<lowest && owner > oldlowest)\r
1553                         {\r
1554                                 best = scan;\r
1555                                 lowest = owner;\r
1556                         }\r
1557 \r
1558                         scan = scan->next;\r
1559                 }\r
1560 \r
1561                 if (lowest != 0xffff)\r
1562                 {\r
1563                         if (best->attributes & PURGEBITS)\r
1564                                 purge = 'P';\r
1565                         else\r
1566                                 purge = '-';\r
1567                         if (best->attributes & LOCKBIT)\r
1568                                 lock = 'L';\r
1569                         else\r
1570                                 lock = '-';\r
1571                         fprintf (dumpfile,"0x%p (%c%c) = %u\n"\r
1572                         ,(unsigned)lowest,lock,purge,best->length);\r
1573                 }\r
1574 \r
1575         } while (lowest != 0xffff);\r
1576 \r
1577         fclose(dumpfile);\r
1578         printf("MMDUMP.16 created.\n");\r
1579 }\r
1580 \r
1581 //==========================================================================\r
1582 \r
1583 \r
1584 /*\r
1585 ======================\r
1586 =\r
1587 = MM_UnusedMemory\r
1588 =\r
1589 = Returns the total free space without purging\r
1590 =\r
1591 ======================\r
1592 */\r
1593 \r
1594 dword MM_UnusedMemory (global_game_variables_t *gvar)\r
1595 {\r
1596         unsigned free;\r
1597         mmblocktype far *scan;\r
1598 \r
1599         free = 0;\r
1600         scan = gvar->mm.mmhead;\r
1601 \r
1602         while(scan->next)\r
1603         {\r
1604                 free += scan->next->start - (scan->start + scan->length);\r
1605                 scan = scan->next;\r
1606         }\r
1607 \r
1608         return free*16lu;\r
1609 }\r
1610 \r
1611 //==========================================================================\r
1612 \r
1613 \r
1614 /*\r
1615 ======================\r
1616 =\r
1617 = MM_TotalFree\r
1618 =\r
1619 = Returns the total free space with purging\r
1620 =\r
1621 ======================\r
1622 */\r
1623 \r
1624 dword MM_TotalFree (global_game_variables_t *gvar)\r
1625 {\r
1626         unsigned free;\r
1627         mmblocktype far *scan;\r
1628 \r
1629         free = 0;\r
1630         scan = gvar->mm.mmhead;\r
1631 \r
1632         while(scan->next)\r
1633         {\r
1634                 if((scan->attributes&PURGEBITS) && !(scan->attributes&LOCKBIT))\r
1635                         free += scan->length;\r
1636                 free += scan->next->start - (scan->start + scan->length);\r
1637                 scan = scan->next;\r
1638         }\r
1639 \r
1640         return free*16lu;\r
1641 }\r
1642 \r
1643 //==========================================================================\r
1644 \r
1645 /*\r
1646 =====================\r
1647 =\r
1648 = MM_Report\r
1649 =\r
1650 =====================\r
1651 */\r
1652 \r
1653 void MM_Report_ (global_game_variables_t *gvar)\r
1654 {\r
1655         printf("========================================\n");\r
1656         printf("                MM_Report_\n");\r
1657         printf("========================================\n");\r
1658         if(MML_CheckForEMS())\r
1659         {\r
1660                 printf("        %cLIMEMS        %u\n", 0xC9, gvar->pm.emm.EMSPresent);\r
1661                 printf("        %c%cEMM v%x.%x available\n", 0xC7, 0xC4, gvar->pm.emm.EMSVer>>4,gvar->pm.emm.EMSVer&0x0F);\r
1662                 printf("        %c%ctotalEMSpages:      %u      ", 0xC7, 0xC4, gvar->pm.emm.totalEMSpages); printf("freeEMSpages:       %u\n", gvar->pm.emm.freeEMSpages);\r
1663                 printf("        %c%cEMSPageFrame:       %04x\n", 0xC7, 0xC4, gvar->pm.emm.EMSPageFrame);\r
1664                 printf("        %c%cEMSmem:     %lu\n", 0xD3, 0xC4, gvar->mmi.EMSmem);\r
1665         }\r
1666         if(MML_CheckForXMS())\r
1667         {\r
1668                 printf("        %cXMS   %u\n", 0xC9, gvar->pm.xmm.XMSPresent);\r
1669                 printf("        %c%cXMS v%x.%x available\n", 0xC7, 0xC4, XMSVer>>8,XMSVer&0x0F);\r
1670                 printf("        %c%cXMSDriver:  %Fp\n", 0xC7, 0xC4, XMSDriver);\r
1671                 printf("        %c%cXMSHandle:  %04x\n", 0xC7, 0xC4, gvar->pm.xmm.XMSHandle);\r
1672                 printf("        %c%cXMSmem:     %lu\n", 0xD3, 0xC4, gvar->mmi.XMSmem);\r
1673         }\r
1674         printf("        %cConv. %u\n", 0xC9, gvar->pm.mm.MainPresent); DebugMemory_(gvar, 0);\r
1675         //printf("mainmem:      %lu\n", gvar->mmi.mainmem);\r
1676         //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
1677         //printf("                      UnusedMemory:   %lu\n", MM_UnusedMemory(gvar));\r
1678         printf("nearheap:       %lu             ", gvar->mmi.nearheap); printf("farheap:        %lu\n", gvar->mmi.farheap);\r
1679 }\r
1680 \r
1681 //==========================================================================\r
1682 \r
1683 /*\r
1684 =====================\r
1685 =\r
1686 = MM_EMSerr\r
1687 =\r
1688 =====================\r
1689 */\r
1690 \r
1691 void MM_EMSerr(byte *stri, byte err)\r
1692 {\r
1693         //Returns a text string describing the error code in EMS.Error.\r
1694         switch(err)\r
1695         {\r
1696                 case 0x0:\r
1697                         strcat(stri, "successful");\r
1698                 break;\r
1699                 case 0x80:\r
1700                         strcat(stri, "internal error");\r
1701                 break;\r
1702                 case 0x81:\r
1703                         strcat(stri, "hardware malfunction");\r
1704                 break;\r
1705                 case 0x82:\r
1706                         strcat(stri, "busy .. retry later");\r
1707                 break;\r
1708                 case 0x83:\r
1709                         strcat(stri, "invalid handle");\r
1710                 break;\r
1711                 case 0x84:\r
1712                         strcat(stri, "undefined function requested by application");\r
1713                 break;\r
1714                 case 0x85:\r
1715                         strcat(stri, "no more handles available");\r
1716                 break;\r
1717                 case 0x86:\r
1718                         strcat(stri, "error in save or restore of mapping context");\r
1719                 break;\r
1720                 case 0x87:\r
1721                         strcat(stri, "insufficient memory pages in system");\r
1722                 break;\r
1723                 case 0x88:\r
1724                         strcat(stri, "insufficient memory pages available");\r
1725                 break;\r
1726                 case 0x89:\r
1727                         strcat(stri, "zero pages requested");\r
1728                 break;\r
1729                 case 0x8A:\r
1730                         strcat(stri, "invalid logical page number encountered");\r
1731                 break;\r
1732                 case 0x8B:\r
1733                         strcat(stri, "invalid physical page number encountered");\r
1734                 break;\r
1735                 case 0x8C:\r
1736                         strcat(stri, "page-mapping hardware state save area is full");\r
1737                 break;\r
1738                 case 0x8D:\r
1739                         strcat(stri, "save of mapping context failed");\r
1740                 break;\r
1741                 case 0x8E:\r
1742                         strcat(stri, "restore of mapping context failed");\r
1743                 break;\r
1744                 case 0x8F:\r
1745                         strcat(stri, "undefined subfunction");\r
1746                 break;\r
1747                 case 0x90:\r
1748                         strcat(stri, "undefined attribute type");\r
1749                 break;\r
1750                 case 0x91:\r
1751                         strcat(stri, "feature not supported");\r
1752                 break;\r
1753                 case 0x92:\r
1754                         strcat(stri, "successful, but a portion of the source region has been overwritten");\r
1755                 break;\r
1756                 case 0x93:\r
1757                         strcat(stri, "length of source or destination region exceeds length of region allocated to either source or destination handle");\r
1758                 break;\r
1759                 case 0x94:\r
1760                         strcat(stri, "conventional and expanded memory regions overlap");\r
1761                 break;\r
1762                 case 0x95:\r
1763                         strcat(stri, "offset within logical page exceeds size of logical page");\r
1764                 break;\r
1765                 case 0x96:\r
1766                         strcat(stri, "region length exceeds 1 MB");\r
1767                 break;\r
1768                 case 0x97:\r
1769                         strcat(stri, "source and destination EMS regions have same handle and overlap");\r
1770                 break;\r
1771                 case 0x98:\r
1772                         strcat(stri, "memory source or destination type undefined");\r
1773                 break;\r
1774                 case 0x9A:\r
1775                         strcat(stri, "specified alternate map register or DMA register set not supported");\r
1776                 break;\r
1777                 case 0x9B:\r
1778                         strcat(stri, "all alternate map register or DMA register sets currently allocated");\r
1779                 break;\r
1780                 case 0x9C:\r
1781                         strcat(stri, "alternate map register or DMA register sets not supported");\r
1782                 break;\r
1783                 case 0x9D:\r
1784                         strcat(stri, "undefined or unallocated alternate map register or DMA register set");\r
1785                 break;\r
1786                 case 0x9E:\r
1787                         strcat(stri, "dedicated DMA channels not supported");\r
1788                 break;\r
1789                 case 0x9F:\r
1790                         strcat(stri, "specified dedicated DMA channel not supported");\r
1791                 break;\r
1792                 case 0xA0:\r
1793                         strcat(stri, "no such handle name");\r
1794                 break;\r
1795                 case 0xA1:\r
1796                         strcat(stri, "a handle found had no name, or duplicate handle name");\r
1797                 break;\r
1798                 case 0xA2:\r
1799                         strcat(stri, "attempted to wrap around 1M conventional address space");\r
1800                 break;\r
1801                 case 0xA3:\r
1802                         strcat(stri, "source array corrupted");\r
1803                 break;\r
1804                 case 0xA4:\r
1805                         strcat(stri, "operating system denied access");\r
1806                 break;\r
1807                 default:\r
1808                         strcat(stri, "undefined error");\r
1809         }\r
1810 }\r
1811 \r
1812 //==========================================================================\r
1813 \r
1814 /*\r
1815 =====================\r
1816 =\r
1817 = MM_BombOnError\r
1818 =\r
1819 =====================\r
1820 */\r
1821 \r
1822 void MM_BombOnError (boolean bomb, global_game_variables_t *gvar)\r
1823 {\r
1824         gvar->mm.bombonerror = bomb;\r
1825 }\r
1826 \r
1827 #if 0\r
1828 void MM_GetNewBlock(global_game_variables_t *gvar)\r
1829 {\r
1830         if(!gvar->mm.mmfree)\r
1831                 MML_ClearBlock(gvar);\r
1832         gvar->mm.mmnew=gvar->mm.mmfree;\r
1833         gvar->mm.mmfree=gvar->mm.mmfree->next;\r
1834         if(!(gvar->mm.mmnew=gvar->mm.mmfree))\r
1835         {\r
1836                 printf("MM_GETNEWBLOCK: No free blocks!\n");\r
1837                 return;\r
1838         }\r
1839         gvar->mm.mmfree=gvar->mm.mmfree->next;\r
1840 }\r
1841 \r
1842 void MM_FreeBlock(mmblocktype *x, global_game_variables_t *gvar)\r
1843 {\r
1844         x->useptr=NULL;\r
1845         x->next=gvar->mm.mmfree;\r
1846         gvar->mm.mmfree=x;\r
1847 }\r
1848 #endif\r
1849 \r
1850 void xms_call(byte v, global_game_variables_t *gvar)\r
1851 {\r
1852         dword XMSDriver = gvar->pm.xmm.XMSDriver;\r
1853         __asm {\r
1854                 mov     ah,[v]\r
1855                 call [DWORD PTR XMSDriver]\r
1856         }\r
1857 }\r
1858 \r
1859 /*void MM_seguin(void)\r
1860 {\r
1861         __asm {\r
1862                 push    ds\r
1863                 mov     ax,ds\r
1864                 inc             ax\r
1865                 mov     ds,ax\r
1866         }\r
1867 }\r
1868 \r
1869 void MM_segude(void)\r
1870 {\r
1871         __asm {\r
1872                 pop ds\r
1873         }\r
1874 }*/\r
1875 \r
1876 /*\r
1877 pull data from far and put it into ds var\r
1878 mov ax,es:si\r
1879 mov x,ax\r
1880 */\r
1881 /*\r
1882 ss stack segment\r
1883 sp top of stack\r
1884 bp bottem of stack\r
1885 */\r