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