OSDN Git Service

no idea how to get joy buttons 2 and 3 to function.
[proj16/16.git] / 16 / 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 #ifdef __DEBUG_PM__\r
839 goto xmsskip;   //INFO: 16_PM dose this job better\r
840 #endif\r
841 \r
842 //\r
843 // detect EMS and allocate up to 64K at page frame\r
844 //\r
845         gvar->mmi.EMSmem = 0;\r
846 //goto emsskip; //0000\r
847         if(MML_CheckForEMS())\r
848         {\r
849                 MML_SetupEMS(gvar);                                     // allocate space\r
850                 //TODO: EMS4! AND EMS 3.2 MASSIVE DATA HANDLMENT!\r
851                 MML_UseSpace(gvar->pm.emm.EMSPageFrame,(MAPPAGES)*0x4000lu, gvar);\r
852                 //if(gvar->pm.emm.EMSVer<0x40)\r
853                         MM_MapEMS(gvar);                                        // map in used pages\r
854                 //else\r
855                         //MM_MapXEMS(gvar);                                     // map in used pages\r
856         }\r
857 \r
858 //\r
859 // detect XMS and get upper memory blocks\r
860 //\r
861 //emsskip:\r
862         gvar->mmi.XMSmem = 0;\r
863 goto xmsskip;//0000\r
864         if(MML_CheckForXMS(gvar))\r
865         {\r
866                 MML_SetupXMS(gvar);                                     // allocate as many UMBs as possible\r
867         }\r
868 \r
869 //\r
870 // allocate the misc buffer\r
871 //\r
872 xmsskip:\r
873         gvar->mm.mmrover = gvar->mm.mmhead;             // start looking for space after low block\r
874 \r
875         MM_GetPtr(&(gvar->mm.bufferseg),BUFFERSIZE, gvar);\r
876 }\r
877 \r
878 //==========================================================================\r
879 \r
880 /*\r
881 ====================\r
882 =\r
883 = MM_Shutdown\r
884 =\r
885 = Frees all conventional, EMS, and XMS allocated\r
886 =\r
887 ====================\r
888 */\r
889 \r
890 void MM_Shutdown(global_game_variables_t *gvar)\r
891 {\r
892         if(!(gvar->mm.mmstarted))\r
893                 return;\r
894 \r
895         _ffree(gvar->mm.farheap);//     printf("                far freed\n");\r
896 #ifdef __WATCOMC__\r
897         _nfree(gvar->mm.nearheap);//    printf("                near freed\n");\r
898 #endif\r
899 #ifdef __BORLANDC__\r
900         free(gvar->mm.nearheap);//      printf("                near freed\n");\r
901 #endif\r
902 #ifndef __DEBUG_PM__\r
903         if(MML_CheckForEMS()){ MML_ShutdownEMS(gvar); }//printf("               EMS freed\n"); }\r
904         if(MML_CheckForXMS(gvar)){ MML_ShutdownXMS(gvar); }//printf("           XMS freed\n"); }        //INFO: 16_PM dose this job better\r
905 #endif\r
906 }\r
907 \r
908 //==========================================================================\r
909 \r
910 /*\r
911 ====================\r
912 =\r
913 = MM_GetPtr\r
914 =\r
915 = Allocates an unlocked, unpurgable block\r
916 =\r
917 ====================\r
918 */\r
919 \r
920 void MM_GetPtr (memptr *baseptr, dword size, global_game_variables_t *gvar)\r
921 {\r
922         //huge mmblocktype huge *scan,huge *lastscan,huge *endscan,huge *purge,huge *next;\r
923         mmblocktype far *scan,far *lastscan,far *endscan,far *purge,far *next;\r
924         int                     search;\r
925         unsigned        needed,startseg;\r
926 \r
927         needed = (size+15)/16;          // convert size from bytes to paragraphs\r
928 \r
929         GETNEWBLOCK;                            // fill in start and next after a spot is found\r
930         gvar->mm.mmnew->length = needed;\r
931         gvar->mm.mmnew->useptr = baseptr;\r
932         //if(gvar->mm.mmnew->useptr==NULL){\r
933 #ifdef __DEBUG__\r
934                 printf("        MM_GetPtr\n");\r
935                 printf("                baseptr=%04x    ", baseptr); printf("useptr=%04x\n", gvar->mm.mmnew->useptr);\r
936                 printf("                *baseptr=%04x   ", *baseptr); printf("*useptr=%04x\n", *(gvar->mm.mmnew->useptr));\r
937                 printf("                *baseptr=%Fp    ", *baseptr); printf("*useptr=%Fp\n", *(gvar->mm.mmnew->useptr));\r
938 #endif\r
939         //exit(-5); }\r
940         gvar->mm.mmnew->attributes = BASEATTRIBUTES;\r
941 \r
942 //tryagain:\r
943         for (search = 0; search<3; search++)\r
944         {\r
945         //\r
946         // first search:        try to allocate right after the rover, then on up\r
947         // second search:       search from the head pointer up to the rover\r
948         // third search:        compress memory, then scan from start\r
949                 if (search == 1 && gvar->mm.mmrover == gvar->mm.mmhead)\r
950                         search++;\r
951 \r
952                 switch (search)\r
953                 {\r
954                 case 0:\r
955                         lastscan = gvar->mm.mmrover;\r
956                         scan = gvar->mm.mmrover->next;\r
957                         endscan = NULL;\r
958                         break;\r
959                 case 1:\r
960                         lastscan = gvar->mm.mmhead;\r
961                         scan = gvar->mm.mmhead->next;\r
962                         endscan = gvar->mm.mmrover;\r
963                         break;\r
964                 case 2:\r
965                         MM_SortMem (gvar);\r
966                         lastscan = gvar->mm.mmhead;\r
967                         scan = gvar->mm.mmhead->next;\r
968                         endscan = NULL;\r
969                         break;\r
970                 }\r
971 \r
972                 startseg = lastscan->start + lastscan->length;\r
973 \r
974                 while (scan != endscan)\r
975                 {\r
976                         if (scan->start - startseg >= needed)\r
977                         {\r
978                         //\r
979                         // got enough space between the end of lastscan and\r
980                         // the start of scan, so throw out anything in the middle\r
981                         // and allocate the new block\r
982                         //\r
983                                 purge = lastscan->next;\r
984                                 lastscan->next = gvar->mm.mmnew;\r
985                                 gvar->mm.mmnew->start = *(unsigned *)baseptr = startseg;\r
986                                 gvar->mm.mmnew->next = scan;\r
987                                 while ( purge != scan)\r
988                                 {       // free the purgable block\r
989                                         next = purge->next;\r
990                                         FREEBLOCK(purge);\r
991                                         purge = next;           // purge another if not at scan\r
992                                 }\r
993                                 gvar->mm.mmrover = gvar->mm.mmnew;\r
994                                 return; // good allocation!\r
995                         }\r
996 \r
997                         //\r
998                         // if this block is purge level zero or locked, skip past it\r
999                         //\r
1000                         if ( (scan->attributes & LOCKBIT)\r
1001                                 || !(scan->attributes & PURGEBITS) )\r
1002                         {\r
1003                                 lastscan = scan;\r
1004                                 startseg = lastscan->start + lastscan->length;\r
1005                         }\r
1006 \r
1007 \r
1008                         scan=scan->next;                // look at next line\r
1009                 }\r
1010         }\r
1011 \r
1012         if (gvar->mm.bombonerror)\r
1013         {\r
1014 #ifdef __WATCOMC__\r
1015                 //heapdump();\r
1016 #endif\r
1017                 printf(OUT_OF_MEM_MSG,(size-gvar->mmi.nearheap));\r
1018                 printf("for stability reasons the program will shut down! wwww\n");\r
1019                 MM_Shutdown(gvar);\r
1020                 exit(-1);\r
1021         }\r
1022         else\r
1023                 gvar->mm.mmerror = true;\r
1024 }\r
1025 \r
1026 //==========================================================================\r
1027 \r
1028 /*\r
1029 ====================\r
1030 =\r
1031 = MM_FreePtr\r
1032 =\r
1033 = Allocates an unlocked, unpurgable block\r
1034 =\r
1035 ====================\r
1036 */\r
1037 \r
1038 void MM_FreePtr(memptr *baseptr, global_game_variables_t *gvar)\r
1039 {\r
1040         //huge mmblocktype huge *scan,huge *last;\r
1041         mmblocktype far *scan,far *last;\r
1042 \r
1043         last = gvar->mm.mmhead;\r
1044         scan = last->next;\r
1045 \r
1046         if(baseptr == gvar->mm.mmrover->useptr) // removed the last allocated block\r
1047                 gvar->mm.mmrover = gvar->mm.mmhead;\r
1048 \r
1049         while(scan->useptr != baseptr && scan)\r
1050         {\r
1051                 last = scan;\r
1052                 scan = scan->next;\r
1053         }\r
1054 \r
1055         if(!scan)\r
1056         {\r
1057                 printf("MM_FreePtr: Block not found!\n");\r
1058                 return;\r
1059         }\r
1060 \r
1061         last->next = scan->next;\r
1062 \r
1063         FREEBLOCK(scan);\r
1064 }\r
1065 //==========================================================================\r
1066 \r
1067 /*\r
1068 =====================\r
1069 =\r
1070 = MM_SetPurge\r
1071 =\r
1072 = Sets the purge level for a block (locked blocks cannot be made purgable)\r
1073 =\r
1074 =====================\r
1075 */\r
1076 \r
1077 void MM_SetPurge(memptr *baseptr, int purge, global_game_variables_t *gvar)\r
1078 {\r
1079         //huge mmblocktype huge *start;\r
1080         mmblocktype far *start;\r
1081 \r
1082         start = gvar->mm.mmrover;\r
1083 \r
1084         do\r
1085         {\r
1086                 if(gvar->mm.mmrover->useptr == baseptr)\r
1087                         break;\r
1088 \r
1089                 gvar->mm.mmrover = gvar->mm.mmrover->next;\r
1090 \r
1091                 if(!gvar->mm.mmrover)\r
1092                         gvar->mm.mmrover = gvar->mm.mmhead;\r
1093                 else if(gvar->mm.mmrover == start)\r
1094                 {\r
1095 #ifdef __DEBUG_PM__\r
1096                         printf("\nstart->useptr gvar->mm.mmhead->useptr\n");\r
1097                         printf("        %Fp     %Fp\n", start->useptr, gvar->mm.mmhead->useptr);\r
1098                         printf("&       %Fp     %Fp\n", &(start->useptr), &(gvar->mm.mmhead->useptr));\r
1099                         printf("baseptr                 gvar->mm.mmrover->useptr\n");\r
1100                         printf("        %Fp     %Fp\n", baseptr, gvar->mm.mmrover->useptr);\r
1101                         printf("&       %Fp     %Fp\n", &(baseptr), &(gvar->mm.mmrover->useptr));\r
1102                         printf("*       %Fp     %Fp\n", *(baseptr), *(gvar->mm.mmrover->useptr));\r
1103                         printf("start                   gvar->mm.mmrover gvar->mm.mmrover->next\n");\r
1104                         printf("        %Fp     %Fp     %Fp\n", start, gvar->mm.mmrover, gvar->mm.mmrover->next);\r
1105                         printf("&       %Fp     %Fp     %Fp\n", &start, &gvar->mm.mmrover, gvar->mm.mmrover->next);\r
1106                         getch();\r
1107                         MM_ShowMemory(gvar);\r
1108                         MM_DumpData(gvar);\r
1109                         MM_Report_(gvar);\r
1110                         getch();\r
1111 #endif\r
1112                         Quit("MM_SetPurge: Block not found!");\r
1113                         return;\r
1114                 }\r
1115 \r
1116         } while(1);\r
1117 \r
1118         gvar->mm.mmrover->attributes &= ~PURGEBITS;\r
1119         gvar->mm.mmrover->attributes |= purge;\r
1120 }\r
1121 \r
1122 //==========================================================================\r
1123 \r
1124 /*\r
1125 =====================\r
1126 =\r
1127 = MM_SetLock\r
1128 =\r
1129 = Locks / unlocks the block\r
1130 =\r
1131 =====================\r
1132 */\r
1133 \r
1134 void MM_SetLock(memptr *baseptr, boolean locked, global_game_variables_t *gvar)\r
1135 {\r
1136         //huge mmblocktype huge *start;\r
1137         mmblocktype far *start;\r
1138 \r
1139         start = gvar->mm.mmrover;\r
1140 \r
1141         do\r
1142         {\r
1143                 if(gvar->mm.mmrover->useptr == baseptr)\r
1144                         break;\r
1145 \r
1146                 gvar->mm.mmrover = gvar->mm.mmrover->next;\r
1147 \r
1148                 if(!gvar->mm.mmrover)\r
1149                         gvar->mm.mmrover = gvar->mm.mmhead;\r
1150                 else if(gvar->mm.mmrover == start)\r
1151                 {\r
1152                         Quit("MM_SetLock: Block not found!");\r
1153                         //return;\r
1154                 }\r
1155 \r
1156         } while(1);\r
1157 \r
1158         gvar->mm.mmrover->attributes &= ~LOCKBIT;\r
1159         gvar->mm.mmrover->attributes |= locked*LOCKBIT;\r
1160 }\r
1161 \r
1162 //==========================================================================\r
1163 \r
1164 /*\r
1165 =====================\r
1166 =\r
1167 = MM_SortMem\r
1168 =\r
1169 = Throws out all purgable stuff and compresses movable blocks\r
1170 =\r
1171 =====================\r
1172 */\r
1173 \r
1174 void MM_SortMem(global_game_variables_t *gvar)\r
1175 {\r
1176         //huge mmblocktype huge *scan,huge *last,huge *next;\r
1177         mmblocktype far *scan,far *last,far *next;\r
1178         unsigned        start,length,source,dest,oldborder;\r
1179         int                     playing;\r
1180 \r
1181         //\r
1182         // lock down a currently playing sound\r
1183         //\r
1184 /*++++  playing = SD_SoundPlaying ();\r
1185         if(playing)\r
1186         {\r
1187                 switch (SoundMode)\r
1188                 {\r
1189                 case sdm_PC:\r
1190                         playing += STARTPCSOUNDS;\r
1191                         break;\r
1192                 case sdm_AdLib:\r
1193                         playing += STARTADLIBSOUNDS;\r
1194                         break;\r
1195                 }\r
1196                 MM_SetLock(&(memptr)audiosegs[playing],true);\r
1197         }\r
1198 \r
1199 \r
1200         SD_StopSound();*/\r
1201 //      oldborder = bordercolor;\r
1202 //      VW_ColorBorder (15);\r
1203 \r
1204         if(beforesort)\r
1205                 beforesort();\r
1206 \r
1207         scan = gvar->mm.mmhead;\r
1208 \r
1209         last = NULL;            // shut up compiler warning\r
1210 \r
1211         while(scan)\r
1212         {\r
1213                 if(scan->attributes & LOCKBIT)\r
1214                 {\r
1215                 //\r
1216                 // block is locked, so try to pile later blocks right after it\r
1217                 //\r
1218                         start = scan->start + scan->length;\r
1219                 }\r
1220                 else\r
1221                 {\r
1222                         if(scan->attributes & PURGEBITS)\r
1223                         {\r
1224                         //\r
1225                         // throw out the purgable block\r
1226                         //\r
1227                                 next = scan->next;\r
1228                                 FREEBLOCK(scan);\r
1229                                 //MM_FreeBlock(scan, gvar);\r
1230                                 last->next = next;\r
1231                                 scan = next;\r
1232                                 continue;\r
1233                         }\r
1234                         else\r
1235                         {\r
1236                         //\r
1237                         // push the non purgable block on top of the last moved block\r
1238                         //\r
1239                                 if(scan->start != start)\r
1240                                 {\r
1241                                         length = scan->length;\r
1242                                         source = scan->start;\r
1243                                         dest = start;\r
1244                                         while(length > 0xf00)\r
1245                                         {\r
1246                                                 movedata(source,0,dest,0,0xf00*16);\r
1247                                                 length -= 0xf00;\r
1248                                                 source += 0xf00;\r
1249                                                 dest += 0xf00;\r
1250                                         }\r
1251                                         movedata(source,0,dest,0,length*16);\r
1252 \r
1253                                         scan->start = start;\r
1254                                         *(unsigned *)scan->useptr = start;\r
1255                                 }\r
1256                                 start = scan->start + scan->length;\r
1257                         }\r
1258                 }\r
1259 \r
1260                 last = scan;\r
1261                 scan = scan->next;              // go to next block\r
1262         }\r
1263 \r
1264         gvar->mm.mmrover = gvar->mm.mmhead;\r
1265 \r
1266         if(aftersort)\r
1267                 aftersort();\r
1268 \r
1269 //      VW_ColorBorder (oldborder);\r
1270 \r
1271 /*++++  if(playing)\r
1272                 MM_SetLock(&(memptr)audiosegs[playing],false);*/\r
1273 }\r
1274 \r
1275 //==========================================================================\r
1276 \r
1277 /*\r
1278 =====================\r
1279 =\r
1280 = MM_ShowMemory\r
1281 =\r
1282 =====================\r
1283 */\r
1284 \r
1285 void MM_ShowMemory(global_game_variables_t *gvar)\r
1286 {\r
1287         //huge mmblocktype huge *scan;\r
1288         mmblocktype far *scan;\r
1289         word temp;\r
1290         sdword  end,owner;\r
1291         //word chx,chy;\r
1292         word w;\r
1293         //dword wwww;\r
1294         byte    scratch[160],scratch0[4096],scratch1[160],str[16];\r
1295         //byte d = '#';\r
1296 //****  VW_SetDefaultColors();\r
1297 //****  VW_SetLineWidth(40);\r
1298 //++++mh        temp = bufferofs;\r
1299 //++++mh        bufferofs = 0;\r
1300 //****  VW_SetScreen (0,0);\r
1301         scan = gvar->mm.mmhead;\r
1302         end = -1;\r
1303 \r
1304         CA_OpenDebug (gvar);\r
1305         w=0;\r
1306         while(scan)\r
1307         {\r
1308                 strcpy(scratch, AARESET);\r
1309                 if(scan->attributes & PURGEBITS)\r
1310                         strcpy(scratch0, AAMAGENTA);            // dark purple = purgable\r
1311                 else\r
1312                         strcpy(scratch0, AABLUE);               // medium blue = non purgable\r
1313                 if(scan->attributes & LOCKBIT)\r
1314                         strcpy(scratch0, AARED);                // red = locked\r
1315                 if(scan->start<=end)\r
1316                 {\r
1317                         printf("\nend==%d\n\n", end);\r
1318                         strcat(scratch, "MM_ShowMemory: Memory block order currupted!\n");\r
1319                         strcat(scratch, "End's Size: ");\r
1320                         ultoa (end,str,10);\r
1321                         strcat (scratch,str);\r
1322                         strcat(scratch, "\nscan->start's Size: ");\r
1323                         ultoa (scan->start,str,10);\r
1324                         strcat (scratch,str);\r
1325                         write(gvar->handle.debughandle,scratch,strlen(scratch));\r
1326                         //modexprint(&page, chx, chy, 1, 0, 24, "\nMM_ShowMemory: Memory block order currupted!\n");\r
1327                         break;\r
1328                 }\r
1329                 end = scan->start+(scan->length)-1;\r
1330 //++++          chy = scan->start/320;\r
1331 //++++          chx = scan->start%320;\r
1332                                 //modexhlin(page, scan->start, (unsigned)end, chy, color);\r
1333                                 //for(chx=scan->start;chx+4>=(word)end;chx+=4)\r
1334                                 //{\r
1335 //++++                                  modexClearRegion(page, chx, chy, 4, 4, color);\r
1336                                 //}\r
1337 //++++          VW_Hlin(scan->start,(unsigned)end,0,color);\r
1338                 for(w=(scan->start)/80;w<=end/80;w++)\r
1339                 {\r
1340                         //printf("+     %u      %lu\n", w, scan->length);\r
1341                         strcat(scratch0, "+");\r
1342                 }\r
1343                 //++==++==optional strcat(scratch0, AARESET); strcat(scratch0, AAGREY); strcat(scratch0,"_");\r
1344 //++++          VW_Plot(scan->start,0,15);\r
1345 //++++                          modexClearRegion(page, chx, chy, 4, 4, 15);\r
1346 //++++                  VW_Hlin(end+1,scan->next->start,0,0);   // black = free\r
1347 \r
1348                 //wwww=(dword)(scan->next->start)-(dword)scan->start;\r
1349                 //wwww=(dword)scan->start+(dword)(scan->next->start);\r
1350                 if (scan->next && scan->next->start >= end+1)\r
1351                 {\r
1352                         strcat(scratch0, AARESET);\r
1353                         //++==++==optional strcat(scratch0, "\n");\r
1354                         strcat(scratch0,AAGREEN);\r
1355                         for(w=(end+1)/80;w<=((scan->next->start-scan->start)/80);w++)\r
1356                         //for(w=(wwww)/80;w<=((end+1)/80);w++)\r
1357                         //for(w=(end+1)/80;w<=((wwww)/80);w++)\r
1358                         {\r
1359                                 //printf("0     %x      %u      %lu\n", scan->next->start, w, scan->length);\r
1360                                 strcat(scratch0,"0");\r
1361                         }\r
1362                         //printf("==================\n");\r
1363                         //printf("w=%u  wwww=%lu        start=%04x      next=%04x       end=%lu\n", w/80, wwww/80, scan->start, (scan->next->start), end+1);\r
1364                         //printf("==================\n");\r
1365                         strcat(scratch0, "\n");\r
1366                         //getch();\r
1367                 }/*else {//if(scan->next->start <= scan->start){\r
1368                         scan->next->start=scan->start+0x1000;\r
1369                         wwww=(dword)(scan->next->start)-(dword)scan->start;\r
1370                         strcat(scratch0, AARESET);\r
1371                         strcat(scratch0, "\n");\r
1372                         strcat(scratch0,AAGREEN);\r
1373                         for(w=(end+1);w<=(0x1000/80);w++)\r
1374                         {\r
1375                                 //printf("0     %x      %x      %u\n", scan->start, w);\r
1376                                 strcat(scratch0,"0");\r
1377                         }\r
1378                         printf("================\n");\r
1379                         printf("w=%x    start=%x        next=%x end=%u  %lu\n", w, scan->start, (scan->next->start), end+1, wwww);\r
1380                         printf("================\n");\r
1381                         getch();\r
1382                 }*/\r
1383                 strcat(scratch0, AARESET);\r
1384                 //strcat(scratch0,"\n");\r
1385                         //for(chx=scan->next->start;chx+4>=(word)end+1;chx+=4)\r
1386                         //{\r
1387 //                              chx+=scan->next->start;\r
1388 //                              modexClearRegion(page, chx, chy, 4, 4, 2);\r
1389                         //}\r
1390                                         //modexhlin(page, end+1,scan->next->start, chy, 0);\r
1391 /*              y = scan->start/320;\r
1392                 x = scan->start%320;\r
1393                 VW_Hlin(x,x+end,y,color);\r
1394                 VW_Plot(x,y,15);*/\r
1395 //++++                  VW_Hlin(x+end+1,x+(scan->next->start-scan->start),y,0); // black = free\r
1396                 strcat(scratch,"Seg:");\r
1397                 ultoa (scan->start,str,16);\r
1398                 strcat (scratch,str);\r
1399                 strcat (scratch,"\tSize:");\r
1400                 ultoa ((unsigned)scan->length,str,10);\r
1401                 strcat (scratch,str);\r
1402                 strcat (scratch,"\tOwner:0x");\r
1403                 owner = (unsigned)scan->useptr;\r
1404                 ultoa (owner,str,16);\r
1405                 strcat (scratch,str);\r
1406                 strcat (scratch,"\n");\r
1407                 write(gvar->handle.debughandle,scratch,strlen(scratch));\r
1408                 write(gvar->handle.debughandle,scratch0,strlen(scratch0));\r
1409 //modexprint(page, chx, chy, 1, 0, 24, &scratch);\r
1410 //++++chy+=4;\r
1411 //fprintf(stdout, "%s", scratch);\r
1412 \r
1413                 scan = scan->next;\r
1414         }\r
1415         /*strcpy(scratch1, AARESET);\r
1416         strcat(scratch1, "========================================\n");\r
1417         strcat(scratch1, "near=  ");\r
1418         ultoa (*(gvar->mm.nearheap),str,10);\r
1419         strcat (scratch1,str);\r
1420         strcat(scratch1, "      far= ");\r
1421         ultoa (*(gvar->mm.farheap),str,10);\r
1422         strcat (scratch1,str);\r
1423         strcat(scratch1, "\n");\r
1424         //strcat(scratch1, "&near=      %Fp ", &(gvar->mm.nearheap));\r
1425         //strcat(scratch1, "&far=       %Fp", &(gvar->mm.farheap));\r
1426         //strcat(scratch1, "\n");\r
1427         strcat(scratch1, "========================================\n");\r
1428         write(gvar->handle.debughandle,scratch1,strlen(scratch1));*/\r
1429 \r
1430 \r
1431         CA_CloseDebug (gvar);\r
1432 \r
1433 //++++mh        IN_Ack();\r
1434 //****  VW_SetLineWidth(64);\r
1435 //++++mh        bufferofs = temp;\r
1436 }\r
1437 \r
1438 //==========================================================================\r
1439 \r
1440 /*\r
1441 =====================\r
1442 =\r
1443 = MM_DumpData\r
1444 =\r
1445 =====================\r
1446 */\r
1447 \r
1448 void MM_DumpData(global_game_variables_t *gvar)\r
1449 {\r
1450         //huge mmblocktype huge *scan,huge *best;\r
1451         mmblocktype far *scan,far *best;\r
1452         long    lowest,oldlowest;\r
1453         word    owner;\r
1454         byte    lock,purge;\r
1455         FILE    *dumpfile;\r
1456 \r
1457         free(gvar->mm.nearheap);\r
1458 #ifdef __BORLANDC__\r
1459                 dumpfile = fopen ("mmdump.16b","w");\r
1460 #endif\r
1461 #ifdef __WATCOMC__\r
1462                 dumpfile = fopen ("mmdump.16w","w");\r
1463 #endif\r
1464         if (!dumpfile){\r
1465                 printf("MM_DumpData: Couldn't open MMDUMP.16!\n");\r
1466                 return;\r
1467         }\r
1468 \r
1469         lowest = -1;\r
1470         do\r
1471         {\r
1472                 oldlowest = lowest;\r
1473                 lowest = 0xffff;\r
1474 \r
1475                 scan = gvar->mm.mmhead;\r
1476                 while (scan)\r
1477                 {\r
1478                         owner = (unsigned)scan->useptr;\r
1479 \r
1480                         if (owner && owner<lowest && owner > oldlowest)\r
1481                         {\r
1482                                 best = scan;\r
1483                                 lowest = owner;\r
1484                         }\r
1485 \r
1486                         scan = scan->next;\r
1487                 }\r
1488 \r
1489                 if (lowest != 0xffff)\r
1490                 {\r
1491                         if (best->attributes & PURGEBITS)\r
1492                                 purge = 'P';\r
1493                         else\r
1494                                 purge = '-';\r
1495                         if (best->attributes & LOCKBIT)\r
1496                                 lock = 'L';\r
1497                         else\r
1498                                 lock = '-';\r
1499                         fprintf (dumpfile,"0x%p (%c%c) = %u\n"\r
1500                         ,(unsigned)lowest,lock,purge,best->length);\r
1501                 }\r
1502 \r
1503         } while (lowest != 0xffff);\r
1504 \r
1505         fclose(dumpfile);\r
1506         printf("MMDUMP.16 created.\n");\r
1507 }\r
1508 \r
1509 //==========================================================================\r
1510 \r
1511 \r
1512 /*\r
1513 ======================\r
1514 =\r
1515 = MM_UnusedMemory\r
1516 =\r
1517 = Returns the total free space without purging\r
1518 =\r
1519 ======================\r
1520 */\r
1521 \r
1522 dword MM_UnusedMemory(global_game_variables_t *gvar)\r
1523 {\r
1524         dword free;\r
1525         //huge mmblocktype huge *scan;\r
1526         mmblocktype far *scan;\r
1527 \r
1528         free = 0;\r
1529         scan = gvar->mm.mmhead;\r
1530 \r
1531         while(scan->next)\r
1532         {\r
1533                 free += scan->next->start - (scan->start + scan->length);\r
1534                 scan = scan->next;\r
1535         }\r
1536 \r
1537         return free*16lu;\r
1538 //      return free;\r
1539 }\r
1540 \r
1541 //==========================================================================\r
1542 \r
1543 \r
1544 /*\r
1545 ======================\r
1546 =\r
1547 = MM_TotalFree\r
1548 =\r
1549 = Returns the total free space with purging\r
1550 =\r
1551 ======================\r
1552 */\r
1553 \r
1554 dword MM_TotalFree(global_game_variables_t *gvar)\r
1555 {\r
1556         dword free;\r
1557         //huge mmblocktype huge *scan;\r
1558         mmblocktype far *scan;\r
1559 \r
1560         free = 0;\r
1561         scan = gvar->mm.mmhead;\r
1562 \r
1563         while(scan->next)\r
1564         {\r
1565                 if((scan->attributes&PURGEBITS) && !(scan->attributes&LOCKBIT))\r
1566                         free += scan->length;\r
1567                 free += scan->next->start - (scan->start + scan->length);\r
1568                 scan = scan->next;\r
1569         }\r
1570 \r
1571         return free*16lu;\r
1572 //      return free;\r
1573 }\r
1574 \r
1575 //==========================================================================\r
1576 \r
1577 /*\r
1578 =====================\r
1579 =\r
1580 = MM_Report\r
1581 =\r
1582 =====================\r
1583 */\r
1584 \r
1585 void MM_Report_(global_game_variables_t *gvar)\r
1586 {\r
1587         printf("========================================\n");\r
1588         printf("                MM_Report\n");\r
1589         printf("========================================\n");\r
1590         if(MML_CheckForEMS())\r
1591         {\r
1592                 printf("        LIMEMS\n");\r
1593                 printf("                EMM v%x.%x available\n", gvar->pm.emm.EMSVer>>4,gvar->pm.emm.EMSVer&0x0F);\r
1594                 printf("                totalEMSpages:  %u      ", gvar->pm.emm.totalEMSpages); printf("freeEMSpages:   %u\n", gvar->pm.emm.freeEMSpages);\r
1595                 printf("                EMSPageFrame:   %x\n", gvar->pm.emm.EMSPageFrame);\r
1596         }\r
1597         if(MML_CheckForXMS(gvar))\r
1598         {\r
1599                 printf("        XMS\n");\r
1600                 printf("                XMSaddr:        %X\n", *XMSaddr);\r
1601         }\r
1602         printf("near:   %lu     ", gvar->mmi.nearheap); printf("far:    %lu\n", gvar->mmi.farheap); if(MML_CheckForEMS())\r
1603         printf("EMSmem: %lu     ", gvar->mmi.EMSmem); if(MML_CheckForXMS(gvar)) printf("XMSmem: %lu", gvar->mmi.XMSmem); printf("\n");\r
1604         //printf("mainmem:      %lu\n", gvar->mmi.mainmem);\r
1605         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
1606         printf("                        UnusedMemory:   %lu\n", MM_UnusedMemory(gvar));\r
1607 }\r
1608 \r
1609 //==========================================================================\r
1610 \r
1611 /*\r
1612 =====================\r
1613 =\r
1614 = MM_EMSerr\r
1615 =\r
1616 =====================\r
1617 */\r
1618 \r
1619 void MM_EMSerr(byte *stri, byte err)\r
1620 {\r
1621         //Returns a text string describing the error code in EMS.Error.\r
1622         switch(err)\r
1623         {\r
1624                 case 0x0:\r
1625                         strcat(stri, "successful");\r
1626                 break;\r
1627                 case 0x80:\r
1628                         strcat(stri, "internal error");\r
1629                 break;\r
1630                 case 0x81:\r
1631                         strcat(stri, "hardware malfunction");\r
1632                 break;\r
1633                 case 0x82:\r
1634                         strcat(stri, "busy .. retry later");\r
1635                 break;\r
1636                 case 0x83:\r
1637                         strcat(stri, "invalid handle");\r
1638                 break;\r
1639                 case 0x84:\r
1640                         strcat(stri, "undefined function requested by application");\r
1641                 break;\r
1642                 case 0x85:\r
1643                         strcat(stri, "no more handles available");\r
1644                 break;\r
1645                 case 0x86:\r
1646                         strcat(stri, "error in save or restore of mapping context");\r
1647                 break;\r
1648                 case 0x87:\r
1649                         strcat(stri, "insufficient memory pages in system");\r
1650                 break;\r
1651                 case 0x88:\r
1652                         strcat(stri, "insufficient memory pages available");\r
1653                 break;\r
1654                 case 0x89:\r
1655                         strcat(stri, "zero pages requested");\r
1656                 break;\r
1657                 case 0x8A:\r
1658                         strcat(stri, "invalid logical page number encountered");\r
1659                 break;\r
1660                 case 0x8B:\r
1661                         strcat(stri, "invalid physical page number encountered");\r
1662                 break;\r
1663                 case 0x8C:\r
1664                         strcat(stri, "page-mapping hardware state save area is full");\r
1665                 break;\r
1666                 case 0x8D:\r
1667                         strcat(stri, "save of mapping context failed");\r
1668                 break;\r
1669                 case 0x8E:\r
1670                         strcat(stri, "restore of mapping context failed");\r
1671                 break;\r
1672                 case 0x8F:\r
1673                         strcat(stri, "undefined subfunction");\r
1674                 break;\r
1675                 case 0x90:\r
1676                         strcat(stri, "undefined attribute type");\r
1677                 break;\r
1678                 case 0x91:\r
1679                         strcat(stri, "feature not supported");\r
1680                 break;\r
1681                 case 0x92:\r
1682                         strcat(stri, "successful, but a portion of the source region has been overwritten");\r
1683                 break;\r
1684                 case 0x93:\r
1685                         strcat(stri, "length of source or destination region exceeds length of region allocated to either source or destination handle");\r
1686                 break;\r
1687                 case 0x94:\r
1688                         strcat(stri, "conventional and expanded memory regions overlap");\r
1689                 break;\r
1690                 case 0x95:\r
1691                         strcat(stri, "offset within logical page exceeds size of logical page");\r
1692                 break;\r
1693                 case 0x96:\r
1694                         strcat(stri, "region length exceeds 1 MB");\r
1695                 break;\r
1696                 case 0x97:\r
1697                         strcat(stri, "source and destination EMS regions have same handle and overlap");\r
1698                 break;\r
1699                 case 0x98:\r
1700                         strcat(stri, "memory source or destination type undefined");\r
1701                 break;\r
1702                 case 0x9A:\r
1703                         strcat(stri, "specified alternate map register or DMA register set not supported");\r
1704                 break;\r
1705                 case 0x9B:\r
1706                         strcat(stri, "all alternate map register or DMA register sets currently allocated");\r
1707                 break;\r
1708                 case 0x9C:\r
1709                         strcat(stri, "alternate map register or DMA register sets not supported");\r
1710                 break;\r
1711                 case 0x9D:\r
1712                         strcat(stri, "undefined or unallocated alternate map register or DMA register set");\r
1713                 break;\r
1714                 case 0x9E:\r
1715                         strcat(stri, "dedicated DMA channels not supported");\r
1716                 break;\r
1717                 case 0x9F:\r
1718                         strcat(stri, "specified dedicated DMA channel not supported");\r
1719                 break;\r
1720                 case 0xA0:\r
1721                         strcat(stri, "no such handle name");\r
1722                 break;\r
1723                 case 0xA1:\r
1724                         strcat(stri, "a handle found had no name, or duplicate handle name");\r
1725                 break;\r
1726                 case 0xA2:\r
1727                         strcat(stri, "attempted to wrap around 1M conventional address space");\r
1728                 break;\r
1729                 case 0xA3:\r
1730                         strcat(stri, "source array corrupted");\r
1731                 break;\r
1732                 case 0xA4:\r
1733                         strcat(stri, "operating system denied access");\r
1734                 break;\r
1735                 default:\r
1736                         strcat(stri, "undefined error");\r
1737         }\r
1738 }\r
1739 \r
1740 //==========================================================================\r
1741 \r
1742 /*\r
1743 =====================\r
1744 =\r
1745 = MM_BombOnError\r
1746 =\r
1747 =====================\r
1748 */\r
1749 \r
1750 void MM_BombOnError(boolean bomb, global_game_variables_t *gvar)\r
1751 {\r
1752         gvar->mm.bombonerror = bomb;\r
1753 }\r
1754 \r
1755 /*void MM_GetNewBlock(global_game_variables_t *gvar)\r
1756 {\r
1757         if(!gvar->mm.mmfree)\r
1758                 MML_ClearBlock(gvar);\r
1759         gvar->mm.mmnew=gvar->mm.mmfree;\r
1760         gvar->mm.mmfree=gvar->mm.mmfree->next;\r
1761         if(!(gvar->mm.mmnew=gvar->mm.mmfree))\r
1762         {\r
1763                 printf("MM_GETNEWBLOCK: No free blocks!\n");\r
1764                 return;\r
1765         }\r
1766         gvar->mm.mmfree=gvar->mm.mmfree->next;\r
1767 }\r
1768 \r
1769 void MM_FreeBlock(mmblocktype *x, global_game_variables_t *gvar)\r
1770 {\r
1771         x->useptr=NULL;\r
1772         x->next=gvar->mm.mmfree;\r
1773         gvar->mm.mmfree=x;\r
1774 }*/\r
1775 \r
1776 /*void MM_seguin(void)\r
1777 {\r
1778         __asm {\r
1779                 push    ds\r
1780                 mov     ax,ds\r
1781                 inc             ax\r
1782                 mov     ds,ax\r
1783         }\r
1784 }\r
1785 \r
1786 void MM_segude(void)\r
1787 {\r
1788         __asm {\r
1789                 pop ds\r
1790         }\r
1791 }*/\r
1792 \r
1793 /*\r
1794 pull data from far and put it into ds var\r
1795 mov ax,es:si\r
1796 mov x,ax\r
1797 */\r
1798 /*\r
1799 ss stack segment\r
1800 sp top of stack\r
1801 bp bottem of stack\r
1802 */\r