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