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