OSDN Git Service

16_ca needs huge amounts of work and I should remember what needs to be done soon...
[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         printf("MM_GetPtr\n");\r
940         if(dbg_debugmm>0){\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         printf("        size is %lu\n", size);\r
947 #endif\r
948         //Quit(gvar, "gvar->mm.mmnew->useptr==NULL"); }\r
949         gvar->mm.mmnew->attributes = BASEATTRIBUTES;\r
950 \r
951 //tryagain:\r
952         for (search = 0; search<3; search++)\r
953         {\r
954         //\r
955         // first search:        try to allocate right after the rover, then on up\r
956         // second search:       search from the head pointer up to the rover\r
957         // third search:        compress memory, then scan from start\r
958                 if (search == 1 && gvar->mm.mmrover == gvar->mm.mmhead)\r
959                         search++;\r
960 \r
961                 switch (search)\r
962                 {\r
963                 case 0:\r
964                         lastscan = gvar->mm.mmrover;\r
965                         scan = gvar->mm.mmrover->next;\r
966                         endscan = NULL;\r
967                         break;\r
968                 case 1:\r
969                         lastscan = gvar->mm.mmhead;\r
970                         scan = gvar->mm.mmhead->next;\r
971                         endscan = gvar->mm.mmrover;\r
972                         break;\r
973                 case 2:\r
974                         MM_SortMem (gvar);\r
975                         lastscan = gvar->mm.mmhead;\r
976                         scan = gvar->mm.mmhead->next;\r
977                         endscan = NULL;\r
978                         break;\r
979                 }\r
980 \r
981                 startseg = lastscan->start + lastscan->length;\r
982 \r
983                 while (scan != endscan)\r
984                 {\r
985                         if (scan->start - startseg >= needed)\r
986                         {\r
987                         //\r
988                         // got enough space between the end of lastscan and\r
989                         // the start of scan, so throw out anything in the middle\r
990                         // and allocate the new block\r
991                         //\r
992                                 purge = lastscan->next;\r
993                                 lastscan->next = gvar->mm.mmnew;\r
994                                 gvar->mm.mmnew->start = *(unsigned *)baseptr = startseg;\r
995                                 gvar->mm.mmnew->next = scan;\r
996                                 while ( purge != scan)\r
997                                 {       // free the purgable block\r
998                                         next = purge->next;\r
999                                         FREEBLOCK(purge);\r
1000                                         purge = next;           // purge another if not at scan\r
1001                                 }\r
1002                                 gvar->mm.mmrover = gvar->mm.mmnew;\r
1003                                 return; // good allocation!\r
1004                         }\r
1005 \r
1006                         //\r
1007                         // if this block is purge level zero or locked, skip past it\r
1008                         //\r
1009                         if ( (scan->attributes & LOCKBIT)\r
1010                                 || !(scan->attributes & PURGEBITS) )\r
1011                         {\r
1012                                 lastscan = scan;\r
1013                                 startseg = lastscan->start + lastscan->length;\r
1014                         }\r
1015 \r
1016 \r
1017                         scan=scan->next;                // look at next line\r
1018                 }\r
1019         }\r
1020 \r
1021         if (gvar->mm.bombonerror)\r
1022         {\r
1023 #ifdef __WATCOMC__\r
1024                 //heapdump();\r
1025 #endif\r
1026                 printf(OUT_OF_MEM_MSG,(size-gvar->mmi.nearheap));\r
1027                 Quit(gvar, "for stability reasons the program will shut down! wwww\n");\r
1028         }\r
1029         else\r
1030                 gvar->mm.mmerror = true;\r
1031 }\r
1032 \r
1033 //==========================================================================\r
1034 \r
1035 /*\r
1036 ====================\r
1037 =\r
1038 = MM_FreePtr\r
1039 =\r
1040 = Deallocates an unlocked, purgable block\r
1041 =\r
1042 ====================\r
1043 */\r
1044 \r
1045 void MM_FreePtr (memptr *baseptr, global_game_variables_t *gvar)\r
1046 {\r
1047         mmblocktype far *scan,far *last;\r
1048 \r
1049         last = gvar->mm.mmhead;\r
1050         scan = last->next;\r
1051 \r
1052         if (baseptr == gvar->mm.mmrover->useptr)        // removed the last allocated block\r
1053                 gvar->mm.mmrover = gvar->mm.mmhead;\r
1054 \r
1055         while(scan->useptr != baseptr && scan)\r
1056         {\r
1057                 last = scan;\r
1058                 scan = scan->next;\r
1059         }\r
1060 \r
1061         if(!scan)\r
1062                 Quit (gvar, "MM_FreePtr: Block not found!");\r
1063 \r
1064         last->next = scan->next;\r
1065 \r
1066         FREEBLOCK(scan);\r
1067 }\r
1068 //==========================================================================\r
1069 \r
1070 /*\r
1071 =====================\r
1072 =\r
1073 = MM_SetPurge\r
1074 =\r
1075 = Sets the purge level for a block (locked blocks cannot be made purgable)\r
1076 =\r
1077 =====================\r
1078 */\r
1079 \r
1080 void MM_SetPurge (memptr *baseptr, int purge, global_game_variables_t *gvar)\r
1081 {\r
1082         mmblocktype far *start;\r
1083 \r
1084         start = gvar->mm.mmrover;\r
1085 \r
1086         do\r
1087         {\r
1088                 if (gvar->mm.mmrover->useptr == baseptr)\r
1089                         break;\r
1090 \r
1091                 gvar->mm.mmrover = gvar->mm.mmrover->next;\r
1092 \r
1093                 if (!gvar->mm.mmrover)\r
1094                         gvar->mm.mmrover = gvar->mm.mmhead;\r
1095                 else if (gvar->mm.mmrover == start)\r
1096                         Quit (gvar, "MM_SetPurge: Block not found!");\r
1097 \r
1098         } while(1);\r
1099 \r
1100         gvar->mm.mmrover->attributes &= ~PURGEBITS;\r
1101         gvar->mm.mmrover->attributes |= purge;\r
1102 }\r
1103 \r
1104 //==========================================================================\r
1105 \r
1106 /*\r
1107 =====================\r
1108 =\r
1109 = MM_SetLock\r
1110 =\r
1111 = Locks / unlocks the block\r
1112 =\r
1113 =====================\r
1114 */\r
1115 \r
1116 void MM_SetLock (memptr *baseptr, boolean locked, global_game_variables_t *gvar)\r
1117 {\r
1118         mmblocktype far *start;\r
1119 \r
1120         start = gvar->mm.mmrover;\r
1121 \r
1122         do\r
1123         {\r
1124                 if (gvar->mm.mmrover->useptr == baseptr)\r
1125                         break;\r
1126 \r
1127                 gvar->mm.mmrover = gvar->mm.mmrover->next;\r
1128 \r
1129                 if (!gvar->mm.mmrover)\r
1130                         gvar->mm.mmrover = gvar->mm.mmhead;\r
1131                 else if (gvar->mm.mmrover == start)\r
1132                         Quit (gvar, "MM_SetLock: Block not found!");\r
1133 \r
1134         } while(1);\r
1135 \r
1136         gvar->mm.mmrover->attributes &= ~LOCKBIT;\r
1137         gvar->mm.mmrover->attributes |= locked*LOCKBIT;\r
1138 }\r
1139 \r
1140 //==========================================================================\r
1141 \r
1142 /*\r
1143 =====================\r
1144 =\r
1145 = MM_SortMem\r
1146 =\r
1147 = Throws out all purgable stuff and compresses movable blocks\r
1148 =\r
1149 =====================\r
1150 */\r
1151 \r
1152 void MM_SortMem (global_game_variables_t *gvar)\r
1153 {\r
1154         mmblocktype far *scan,far *last,far *next;\r
1155         unsigned        start,length,source,dest,oldborder;\r
1156         //++++int                       playing;\r
1157 \r
1158         //\r
1159         // lock down a currently playing sound\r
1160         //\r
1161 /*++++  playing = SD_SoundPlaying ();\r
1162         if(playing)\r
1163         {\r
1164                 switch (SoundMode)\r
1165                 {\r
1166                 case sdm_PC:\r
1167                         playing += STARTPCSOUNDS;\r
1168                         break;\r
1169                 case sdm_AdLib:\r
1170                         playing += STARTADLIBSOUNDS;\r
1171                         break;\r
1172                 }\r
1173                 MM_SetLock((memptr *)&audiosegs[playing],true);\r
1174         }\r
1175 \r
1176 \r
1177         SD_StopSound();*/\r
1178         oldborder = gvar->video.bordercolor;\r
1179         gvar->video.bordercolor = modexPalOverscan(15);\r
1180 \r
1181         if(beforesort)\r
1182                 beforesort();\r
1183 \r
1184         scan = gvar->mm.mmhead;\r
1185 \r
1186         last = NULL;            // shut up compiler warning\r
1187 \r
1188         while(scan)\r
1189         {\r
1190                 if(scan->attributes & LOCKBIT)\r
1191                 {\r
1192                 //\r
1193                 // block is locked, so try to pile later blocks right after it\r
1194                 //\r
1195                         start = scan->start + scan->length;\r
1196                 }\r
1197                 else\r
1198                 {\r
1199                         if(scan->attributes & PURGEBITS)\r
1200                         {\r
1201                         //\r
1202                         // throw out the purgable block\r
1203                         //\r
1204                                 next = scan->next;\r
1205                                 FREEBLOCK(scan); //MM_FreeBlock(scan, gvar);\r
1206                                 last->next = next;\r
1207                                 scan = next;\r
1208                                 continue;\r
1209                         }\r
1210                         else\r
1211                         {\r
1212                         //\r
1213                         // push the non purgable block on top of the last moved block\r
1214                         //\r
1215                                 if(scan->start != start)\r
1216                                 {\r
1217                                         length = scan->length;\r
1218                                         source = scan->start;\r
1219                                         dest = start;\r
1220                                         while(length > 0xf00)\r
1221                                         {\r
1222                                                 movedata(source,0,dest,0,0xf00*16);\r
1223                                                 length -= 0xf00;\r
1224                                                 source += 0xf00;\r
1225                                                 dest += 0xf00;\r
1226                                         }\r
1227                                         movedata(source,0,dest,0,length*16);\r
1228 \r
1229                                         scan->start = start;\r
1230                                         *(unsigned *)scan->useptr = start;\r
1231                                 }\r
1232                                 start = scan->start + scan->length;\r
1233                         }\r
1234                 }\r
1235 \r
1236                 last = scan;\r
1237                 scan = scan->next;              // go to next block\r
1238         }\r
1239 \r
1240         gvar->mm.mmrover = gvar->mm.mmhead;\r
1241 \r
1242         if(aftersort)\r
1243                 aftersort();\r
1244 \r
1245         VL_ColorBorder (oldborder, &gvar->video);\r
1246 \r
1247 /*++++  if(playing)\r
1248                 MM_SetLock((memptr *)&audiosegs[playing],false);*/\r
1249 }\r
1250 \r
1251 //==========================================================================\r
1252 \r
1253 /*\r
1254 =====================\r
1255 =\r
1256 = MM_ShowMemory\r
1257 =\r
1258 =====================\r
1259 */\r
1260 \r
1261 #ifdef __WATCOMC__\r
1262 //#define MMSMPANVID\r
1263 #define MMSMSCANINFO\r
1264 #endif\r
1265 \r
1266 void MM_ShowMemory (global_game_variables_t *gvar)\r
1267 {\r
1268         mmblocktype far *scan;\r
1269         unsigned color,temp,x,y         ,w,q,width;\r
1270         sdword  end,owner;\r
1271         byte            scratch[160],scratch0[4096],str[16];\r
1272         mmshowmemoryinfo_t scaninfo[MAXBLOCKS];\r
1273 \r
1274         if(!gvar->video.page[0].width) gvar->video.page[0].sw = gvar->video.page[0].width = 320;        //to prevent division by 0\r
1275 //--    VL_SetLineWidth(40, gvar);\r
1276         //temp = gvar->video.ofs.bufferofs;\r
1277         //gvar->video.ofs.bufferofs = gvar->video.ofs.displayofs;\r
1278         temp = BDOFSCONV gvar->video.BOFS;\r
1279         gvar->video.BOFS = gvar->video.DOFS;\r
1280         scan = gvar->mm.mmhead;\r
1281 \r
1282         end = -1; w = 0;\r
1283 \r
1284         width = gvar->video.page[0].width; q = 0;\r
1285 \r
1286         CA_OpenDebug (gvar);\r
1287         while (scan)\r
1288         {\r
1289                 scaninfo[q].scan = scan;\r
1290                 strcpy(scratch, AARESET);\r
1291                 if(scan->attributes & PURGEBITS)\r
1292                 {\r
1293                         color = 6;              // dark purple = purgable\r
1294                         strcpy(scratch0, AAMAGENTA);            // dark purple = purgable\r
1295                 }else{\r
1296                         color = 2;              // medium blue = non purgable\r
1297                         strcpy(scratch0, AABLUE);               // medium blue = non purgable\r
1298                 }\r
1299                 if(scan->attributes & LOCKBIT)\r
1300                 {\r
1301                         color = 1;              // red = locked\r
1302                         strcpy(scratch0, AARED);                // red = locked\r
1303                 }\r
1304                 if (scan->start<=end)\r
1305                 {\r
1306                         printf("\nend==%d\n\n", end);\r
1307                         strcat(scratch, "MM_ShowMemory: Memory block order currupted!\n");\r
1308                         strcat(scratch, "End's Size: ");\r
1309                         ultoa (end,str,10);\r
1310                         strcat (scratch,str);\r
1311                         strcat(scratch, "\nscan->start's Size: ");\r
1312                         ultoa (scan->start,str,10);\r
1313                         strcat (scratch,str);\r
1314                         write(gvar->handle.debughandle,scratch,strlen(scratch));\r
1315                         Quit (gvar, "MM_ShowMemory: Memory block order currupted!");\r
1316                 }\r
1317                 end = scan->length-1;\r
1318                 y = scan->start/width;\r
1319                 x = scan->start%width;\r
1320                 scaninfo[q].x = x;\r
1321                 scaninfo[q].y = y;\r
1322                 VW_Hlin(x,x+end,y,color,gvar);\r
1323                 VL_Plot(x,y,5,gvar);\r
1324 //++==++==optional                      strcat(scratch0, AARESET); strcat(scratch0, AAGREY); strcat(scratch0,"_");\r
1325                 for(w=(scan->start)/80;w<=end/80;w++)\r
1326                 {\r
1327 //printf("+     %u      %lu\n", w, scan->length);\r
1328                         strcat(scratch0, "+");\r
1329                 }\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                 byte scratch1[4];\r
1430                 unsigned                maxq = q;\r
1431                 boolean                 done;\r
1432                 ScanCode                scancode;\r
1433                 int xpos,ypos;\r
1434                 word qq, ccolor = 3;\r
1435                 IN_Ack(gvar);\r
1436 //              VL_ClearVideo (8);\r
1437                 for (qq = 0,done = false;!done;)\r
1438                 {\r
1439                         if(scaninfo[qq].scan->attributes & PURGEBITS)\r
1440                         {\r
1441                                 ccolor = 6;             // dark purple = purgable\r
1442                                 strcpy(scratch1, AAMAGENTA);            // dark purple = purgable\r
1443                                 //printf("%s", AAMAGENTA);\r
1444                         }else{\r
1445                                 ccolor = 2;             // medium blue = non purgable\r
1446                                 strcpy(scratch1, AABLUE);               // medium blue = non purgable\r
1447                                 //printf("%s", AABLUE);\r
1448                         }\r
1449                         if(scaninfo[qq].scan->attributes & LOCKBIT)\r
1450                         {\r
1451                                 ccolor = 1;             // red = locked\r
1452                                 strcpy(scratch1, AARED);                // red = locked\r
1453                                 //printf("%s", AARED);\r
1454                         }\r
1455                         end = scaninfo[qq].scan->length-1;\r
1456 /*typedef struct mmblockstruct{\r
1457         word    start,length;\r
1458         unsigned        attributes;\r
1459         memptr          *useptr;        // pointer to the segment start\r
1460         struct mmblockstruct far *next;\r
1461 } mmblocktype;*/\r
1462                         //modexprint(page, x, y, t, tlsw, color, bgcolor, vidsw, const byte *str);\r
1463 #define MMSMPRINTMEMINFO modexprint(&(gvar->video.page[0]), xpos, ypos, 1, 0, ccolor, 8, gvar->video.VL_Started, global_temp_status_text); ypos+=8;\r
1464                         if(!gvar->video.VL_Started) clrscr(); else\r
1465                         {\r
1466                                 VL_ShowPage(&gvar->video.page[0], 1, 0);\r
1467                                 modexClearRegion(&gvar->video.page[0], 0, 0, gvar->video.page[0].width, gvar->video.page[0].height, 8);\r
1468                         }\r
1469                         sprintf(global_temp_status_text, "block #%04u", qq); MMSMPRINTMEMINFO\r
1470 //                      sprintf(global_temp_status_text, "%Fp", scaninfo[qq].scan->useptr); MMSMPRINTMEMINFO\r
1471                         sprintf(global_temp_status_text, "%04x", (unsigned)scaninfo[qq].scan->useptr); MMSMPRINTMEMINFO\r
1472                         sprintf(global_temp_status_text, "size: %05u", (unsigned)scaninfo[qq].scan->length); MMSMPRINTMEMINFO\r
1473                         if (scaninfo[qq].scan->next && scaninfo[qq].scan->next->start > end+1)\r
1474                         {\r
1475                                 sprintf(global_temp_status_text, "free: %05u", (unsigned)(scaninfo[qq].scan->next->start-scaninfo[qq].scan->start)); MMSMPRINTMEMINFO\r
1476                         }\r
1477                         if(gvar->video.VL_Started)\r
1478                         {\r
1479                                 y = ypos;//scaninfo[qq].scan->start/width;\r
1480                                 x = xpos;//scaninfo[qq].scan->start%width;\r
1481                                 VW_Hlin(x,x+end,y,ccolor,gvar);\r
1482                                 VL_Plot(x,y,5,gvar);\r
1483                         }\r
1484                         else\r
1485                         {\r
1486                                 printf("%s", scratch1);\r
1487                                 printf("%s", AAGREY); printf("_");\r
1488                                 for(w=(scaninfo[qq].scan->start)/80;w<=end/80;w++)\r
1489                                 {\r
1490                                         //strcat(scratch1, "+");\r
1491                                         printf("+");\r
1492                                 }\r
1493                         }\r
1494 \r
1495 \r
1496                                 if (scaninfo[qq].scan->next && scaninfo[qq].scan->next->start > end+1) if(!gvar->video.VL_Started)\r
1497                                 {\r
1498                                         //strcat(scratch1, AARESET);\r
1499                                         printf("%s", AARESET);\r
1500                                         //strcat(scratch1,AAGREEN);\r
1501                                         printf("%s", AAGREEN);\r
1502                                         for(w=(end+1)/80;w<=((scaninfo[qq].scan->next->start-scaninfo[qq].scan->start)/80);w++)\r
1503                                         {\r
1504                                                 //strcat(scratch1,"0");\r
1505                                                 printf("0");\r
1506                                         }\r
1507                                 }else VW_Hlin(x+end+1,x+(scaninfo[qq].scan->next->start-scaninfo[qq].scan->start),y,3,gvar);    // black = free//now green\r
1508 \r
1509 \r
1510                         if(gvar->video.VL_Started)\r
1511                         {\r
1512                                 //if (scan->next && scan->next->start > end+1) free\r
1513                                 xpos = 16;\r
1514                                 ypos = 16;//(gvar->video.page[0].sh-(32));//8*4\r
1515                         }\r
1516                         else\r
1517                         {\r
1518                                 //printf("%s\n", scratch1);\r
1519                                 printf("%s", AARESET);\r
1520                                 printf("\n");\r
1521                         }\r
1522                         while (!(scancode = gvar->in.inst->LastScan)){}\r
1523 \r
1524                         IN_ClearKey(scancode);\r
1525                         switch (scancode)\r
1526                         {\r
1527                                 case sc_LeftArrow:\r
1528                                         if(qq>0) qq--;\r
1529                                         else    qq = maxq;\r
1530                                 break;\r
1531                                 case sc_RightArrow:\r
1532                                         if(qq<maxq) qq++;\r
1533                                         else qq = 0;\r
1534                                 break;\r
1535                                 case sc_Escape:\r
1536                                         done = true;\r
1537                                 break;\r
1538                         }\r
1539                 }\r
1540         }\r
1541 #endif\r
1542 \r
1543         if(gvar->video.VL_Started) IN_Ack(gvar);\r
1544 \r
1545         gvar->video.BOFS = (byte __far *)temp;\r
1546 }\r
1547 \r
1548 //==========================================================================\r
1549 \r
1550 /*\r
1551 =====================\r
1552 =\r
1553 = MM_DumpData\r
1554 =\r
1555 =====================\r
1556 */\r
1557 \r
1558 void MM_DumpData (global_game_variables_t *gvar)\r
1559 {\r
1560         mmblocktype far *scan,far *best;\r
1561         long    lowest,oldlowest;\r
1562         unsigned        owner;\r
1563         char    lock,purge;\r
1564         FILE    *dumpfile;\r
1565 \r
1566 #ifdef __WATCOMC__\r
1567         _nfree(gvar->mm.nearheap);\r
1568 #endif\r
1569 #ifdef __BORLANDC__\r
1570         free(gvar->mm.nearheap);\r
1571 #endif\r
1572 #ifdef __BORLANDC__\r
1573                 dumpfile = fopen ("mmdump.16b","w");\r
1574 #endif\r
1575 #ifdef __WATCOMC__\r
1576                 dumpfile = fopen ("mmdump.16w","w");\r
1577 #endif\r
1578         if (!dumpfile){\r
1579                 printf("MM_DumpData: Couldn't open MMDUMP.16!\n");\r
1580                 return;\r
1581         }\r
1582 \r
1583         lowest = -1;\r
1584         do\r
1585         {\r
1586                 oldlowest = lowest;\r
1587                 lowest = 0xffff;\r
1588 \r
1589                 scan = gvar->mm.mmhead;\r
1590                 while (scan)\r
1591                 {\r
1592                         owner = (unsigned)scan->useptr;\r
1593 \r
1594                         if (owner && owner<lowest && owner > oldlowest)\r
1595                         {\r
1596                                 best = scan;\r
1597                                 lowest = owner;\r
1598                         }\r
1599 \r
1600                         scan = scan->next;\r
1601                 }\r
1602 \r
1603                 if (lowest != 0xffff)\r
1604                 {\r
1605                         if (best->attributes & PURGEBITS)\r
1606                                 purge = 'P';\r
1607                         else\r
1608                                 purge = '-';\r
1609                         if (best->attributes & LOCKBIT)\r
1610                                 lock = 'L';\r
1611                         else\r
1612                                 lock = '-';\r
1613                         fprintf (dumpfile,"0x%p (%c%c) = %u\n"\r
1614                         ,(unsigned)lowest,lock,purge,best->length);\r
1615                 }\r
1616 \r
1617         } while (lowest != 0xffff);\r
1618 \r
1619         fclose(dumpfile);\r
1620         printf("MMDUMP.16 created.\n");\r
1621 }\r
1622 \r
1623 //==========================================================================\r
1624 \r
1625 \r
1626 /*\r
1627 ======================\r
1628 =\r
1629 = MM_UnusedMemory\r
1630 =\r
1631 = Returns the total free space without purging\r
1632 =\r
1633 ======================\r
1634 */\r
1635 \r
1636 dword MM_UnusedMemory (global_game_variables_t *gvar)\r
1637 {\r
1638         unsigned free;\r
1639         mmblocktype far *scan;\r
1640 \r
1641         free = 0;\r
1642         scan = gvar->mm.mmhead;\r
1643 \r
1644         while(scan->next)\r
1645         {\r
1646                 free += scan->next->start - (scan->start + scan->length);\r
1647                 scan = scan->next;\r
1648         }\r
1649 \r
1650         return free*16lu;\r
1651 }\r
1652 \r
1653 //==========================================================================\r
1654 \r
1655 \r
1656 /*\r
1657 ======================\r
1658 =\r
1659 = MM_TotalFree\r
1660 =\r
1661 = Returns the total free space with purging\r
1662 =\r
1663 ======================\r
1664 */\r
1665 \r
1666 dword MM_TotalFree (global_game_variables_t *gvar)\r
1667 {\r
1668         unsigned free;\r
1669         mmblocktype far *scan;\r
1670 \r
1671         free = 0;\r
1672         scan = gvar->mm.mmhead;\r
1673 \r
1674         while(scan->next)\r
1675         {\r
1676                 if((scan->attributes&PURGEBITS) && !(scan->attributes&LOCKBIT))\r
1677                         free += scan->length;\r
1678                 free += scan->next->start - (scan->start + scan->length);\r
1679                 scan = scan->next;\r
1680         }\r
1681 \r
1682         return free*16lu;\r
1683 }\r
1684 \r
1685 //==========================================================================\r
1686 \r
1687 /*\r
1688 =====================\r
1689 =\r
1690 = MM_Report\r
1691 =\r
1692 =====================\r
1693 */\r
1694 \r
1695 void MM_Report_ (global_game_variables_t *gvar)\r
1696 {\r
1697         printf("========================================\n");\r
1698         printf("                MM_Report_\n");\r
1699         printf("========================================\n");\r
1700         if(MML_CheckForEMS())\r
1701         {\r
1702                 printf("        %cLIMEMS        %u\n", 0xC9, gvar->pm.emm.EMSPresent);\r
1703                 printf("        %c%cEMM v%x.%x available\n", 0xC7, 0xC4, gvar->pm.emm.EMSVer>>4,gvar->pm.emm.EMSVer&0x0F);\r
1704                 printf("        %c%ctotalEMSpages:      %u      ", 0xC7, 0xC4, gvar->pm.emm.totalEMSpages); printf("freeEMSpages:       %u\n", gvar->pm.emm.freeEMSpages);\r
1705                 printf("        %c%cEMSPageFrame:       %04x\n", 0xC7, 0xC4, gvar->pm.emm.EMSPageFrame);\r
1706                 printf("        %c%cEMSmem:     %lu\n", 0xD3, 0xC4, gvar->mmi.EMSmem);\r
1707         }\r
1708         if(MML_CheckForXMS())\r
1709         {\r
1710                 printf("        %cXMS   %u\n", 0xC9, gvar->pm.xmm.XMSPresent);\r
1711                 printf("        %c%cXMS v%x.%x available\n", 0xC7, 0xC4, XMSVer>>8,XMSVer&0x0F);\r
1712                 printf("        %c%cXMSDriver:  %Fp\n", 0xC7, 0xC4, XMSDriver);\r
1713                 printf("        %c%cXMSHandle:  %04x\n", 0xC7, 0xC4, gvar->pm.xmm.XMSHandle);\r
1714                 printf("        %c%cXMSmem:     %lu\n", 0xD3, 0xC4, gvar->mmi.XMSmem);\r
1715         }\r
1716         printf("        %cConv. %u\n", 0xC9, gvar->pm.mm.MainPresent); DebugMemory_(gvar, 0);\r
1717         //printf("mainmem:      %lu\n", gvar->mmi.mainmem);\r
1718         //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
1719         //printf("                      UnusedMemory:   %lu\n", MM_UnusedMemory(gvar));\r
1720         printf("nearheap:       %lu             ", gvar->mmi.nearheap); printf("farheap:        %lu\n", gvar->mmi.farheap);\r
1721 }\r
1722 \r
1723 //==========================================================================\r
1724 \r
1725 /*\r
1726 =====================\r
1727 =\r
1728 = MM_EMSerr\r
1729 =\r
1730 =====================\r
1731 */\r
1732 \r
1733 void MM_EMSerr(byte *stri, byte err)\r
1734 {\r
1735         //Returns a text string describing the error code in EMS.Error.\r
1736         switch(err)\r
1737         {\r
1738                 case 0x0:\r
1739                         strcat(stri, "successful");\r
1740                 break;\r
1741                 case 0x80:\r
1742                         strcat(stri, "internal error");\r
1743                 break;\r
1744                 case 0x81:\r
1745                         strcat(stri, "hardware malfunction");\r
1746                 break;\r
1747                 case 0x82:\r
1748                         strcat(stri, "busy .. retry later");\r
1749                 break;\r
1750                 case 0x83:\r
1751                         strcat(stri, "invalid handle");\r
1752                 break;\r
1753                 case 0x84:\r
1754                         strcat(stri, "undefined function requested by application");\r
1755                 break;\r
1756                 case 0x85:\r
1757                         strcat(stri, "no more handles available");\r
1758                 break;\r
1759                 case 0x86:\r
1760                         strcat(stri, "error in save or restore of mapping context");\r
1761                 break;\r
1762                 case 0x87:\r
1763                         strcat(stri, "insufficient memory pages in system");\r
1764                 break;\r
1765                 case 0x88:\r
1766                         strcat(stri, "insufficient memory pages available");\r
1767                 break;\r
1768                 case 0x89:\r
1769                         strcat(stri, "zero pages requested");\r
1770                 break;\r
1771                 case 0x8A:\r
1772                         strcat(stri, "invalid logical page number encountered");\r
1773                 break;\r
1774                 case 0x8B:\r
1775                         strcat(stri, "invalid physical page number encountered");\r
1776                 break;\r
1777                 case 0x8C:\r
1778                         strcat(stri, "page-mapping hardware state save area is full");\r
1779                 break;\r
1780                 case 0x8D:\r
1781                         strcat(stri, "save of mapping context failed");\r
1782                 break;\r
1783                 case 0x8E:\r
1784                         strcat(stri, "restore of mapping context failed");\r
1785                 break;\r
1786                 case 0x8F:\r
1787                         strcat(stri, "undefined subfunction");\r
1788                 break;\r
1789                 case 0x90:\r
1790                         strcat(stri, "undefined attribute type");\r
1791                 break;\r
1792                 case 0x91:\r
1793                         strcat(stri, "feature not supported");\r
1794                 break;\r
1795                 case 0x92:\r
1796                         strcat(stri, "successful, but a portion of the source region has been overwritten");\r
1797                 break;\r
1798                 case 0x93:\r
1799                         strcat(stri, "length of source or destination region exceeds length of region allocated to either source or destination handle");\r
1800                 break;\r
1801                 case 0x94:\r
1802                         strcat(stri, "conventional and expanded memory regions overlap");\r
1803                 break;\r
1804                 case 0x95:\r
1805                         strcat(stri, "offset within logical page exceeds size of logical page");\r
1806                 break;\r
1807                 case 0x96:\r
1808                         strcat(stri, "region length exceeds 1 MB");\r
1809                 break;\r
1810                 case 0x97:\r
1811                         strcat(stri, "source and destination EMS regions have same handle and overlap");\r
1812                 break;\r
1813                 case 0x98:\r
1814                         strcat(stri, "memory source or destination type undefined");\r
1815                 break;\r
1816                 case 0x9A:\r
1817                         strcat(stri, "specified alternate map register or DMA register set not supported");\r
1818                 break;\r
1819                 case 0x9B:\r
1820                         strcat(stri, "all alternate map register or DMA register sets currently allocated");\r
1821                 break;\r
1822                 case 0x9C:\r
1823                         strcat(stri, "alternate map register or DMA register sets not supported");\r
1824                 break;\r
1825                 case 0x9D:\r
1826                         strcat(stri, "undefined or unallocated alternate map register or DMA register set");\r
1827                 break;\r
1828                 case 0x9E:\r
1829                         strcat(stri, "dedicated DMA channels not supported");\r
1830                 break;\r
1831                 case 0x9F:\r
1832                         strcat(stri, "specified dedicated DMA channel not supported");\r
1833                 break;\r
1834                 case 0xA0:\r
1835                         strcat(stri, "no such handle name");\r
1836                 break;\r
1837                 case 0xA1:\r
1838                         strcat(stri, "a handle found had no name, or duplicate handle name");\r
1839                 break;\r
1840                 case 0xA2:\r
1841                         strcat(stri, "attempted to wrap around 1M conventional address space");\r
1842                 break;\r
1843                 case 0xA3:\r
1844                         strcat(stri, "source array corrupted");\r
1845                 break;\r
1846                 case 0xA4:\r
1847                         strcat(stri, "operating system denied access");\r
1848                 break;\r
1849                 default:\r
1850                         strcat(stri, "undefined error");\r
1851         }\r
1852 }\r
1853 \r
1854 //==========================================================================\r
1855 \r
1856 /*\r
1857 =====================\r
1858 =\r
1859 = MM_BombOnError\r
1860 =\r
1861 =====================\r
1862 */\r
1863 \r
1864 void MM_BombOnError (boolean bomb, global_game_variables_t *gvar)\r
1865 {\r
1866         gvar->mm.bombonerror = bomb;\r
1867 }\r
1868 \r
1869 #if 0\r
1870 void MM_GetNewBlock(global_game_variables_t *gvar)\r
1871 {\r
1872         if(!gvar->mm.mmfree)\r
1873                 MML_ClearBlock(gvar);\r
1874         gvar->mm.mmnew=gvar->mm.mmfree;\r
1875         gvar->mm.mmfree=gvar->mm.mmfree->next;\r
1876         if(!(gvar->mm.mmnew=gvar->mm.mmfree))\r
1877         {\r
1878                 printf("MM_GETNEWBLOCK: No free blocks!\n");\r
1879                 return;\r
1880         }\r
1881         gvar->mm.mmfree=gvar->mm.mmfree->next;\r
1882 }\r
1883 \r
1884 void MM_FreeBlock(mmblocktype *x, global_game_variables_t *gvar)\r
1885 {\r
1886         x->useptr=NULL;\r
1887         x->next=gvar->mm.mmfree;\r
1888         gvar->mm.mmfree=x;\r
1889 }\r
1890 #endif\r
1891 \r
1892 void xms_call(byte v, global_game_variables_t *gvar)\r
1893 {\r
1894         dword XMSDriver = gvar->pm.xmm.XMSDriver;\r
1895         __asm {\r
1896                 mov     ah,[v]\r
1897                 call [DWORD PTR XMSDriver]\r
1898         }\r
1899 }\r
1900 \r
1901 /*void MM_seguin(void)\r
1902 {\r
1903         __asm {\r
1904                 push    ds\r
1905                 mov     ax,ds\r
1906                 inc             ax\r
1907                 mov     ds,ax\r
1908         }\r
1909 }\r
1910 \r
1911 void MM_segude(void)\r
1912 {\r
1913         __asm {\r
1914                 pop ds\r
1915         }\r
1916 }*/\r
1917 \r
1918 /*\r
1919 pull data from far and put it into ds var\r
1920 mov ax,es:si\r
1921 mov x,ax\r
1922 */\r
1923 /*\r
1924 ss stack segment\r
1925 sp top of stack\r
1926 bp bottem of stack\r
1927 */\r