]> 4ch.mooo.com Git - 16.git/blob - src/lib/16_pm.c
added debug variable
[16.git] / src / lib / 16_pm.c
1 /* Project 16 Source Code~\r
2  * Copyright (C) 2012-2016 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 //\r
24 //      ID_PM.C\r
25 //      Id Engine's Page Manager v1.0\r
26 //      Primary coder: Jason Blochowiak\r
27 //\r
28 \r
29 #include "src/lib/16_pm.h"\r
30 #pragma hdrstop\r
31 \r
32 boolean pmdebug=0;\r
33 \r
34 /*\r
35 //      Main Mem specific variables\r
36         boolean                 MainPresent;\r
37         memptr                  MainMemPages[PMMaxMainMem];\r
38         PMBlockAttr             gvar->pm.mm.MainMemUsed[PMMaxMainMem];\r
39         int                             gvar->pm.mm.MainPagesAvail;\r
40 \r
41 //      EMS specific variables\r
42         boolean                 gvar->pm.emm.EMSPresent;\r
43         word                    gvar->pm.emm.EMSAvail,gvar->pm.emm.EMSPagesAvail,gvar->pm.emm.EMSHandle,\r
44                                         gvar->pm.emm.EMSPageFrame,gvar->pm.emm.EMSPhysicalPage;\r
45         gvar->pm.emm.EMSListStruct      gvar->pm.emm.EMSList[EMSFrameCount];\r
46 \r
47 //      XMS specific variables\r
48         boolean                 gvar->pm.xmm.XMSPresent;\r
49         word                    gvar->pm.xmm.XMSAvail,gvar->pm.xmm.XMSPagesAvail,gvar->pm.xmm.XMSHandle;*/\r
50         word            XMSDriver;\r
51 /*      int                             gvar->pm.xmm.XMSProtectPage = -1;\r
52 \r
53 //      File specific variables\r
54         char                    gvar->pm.fi.PageFileName[13] = {"VSWAP."};\r
55         int                             PageFile = -1;\r
56         word                    gvar->pm.fi.ChunksInFile;\r
57         word                    PMSpriteStart,PMSoundStart;\r
58 \r
59 //      General usage variables\r
60         boolean                 PMStarted,\r
61                                         gvar->pm.PMPanicMode,\r
62                                         gvar->pm.PMThrashing;\r
63         word                    gvar->pm.XMSPagesUsed,\r
64                                         gvar->pm.EMSPagesUsed,\r
65                                         MainPagesUsed,\r
66                                         gvar->pm.PMNumBlocks;\r
67         long                    PMFrameCount;\r
68         PageListStruct  far *gvar->pm.PMPages,\r
69                                         _seg *gvar->pm.PMSegPages;\r
70 */\r
71 static  char            *ParmStrings[] = {"nomain","noems","noxms",nil};\r
72 \r
73 /////////////////////////////////////////////////////////////////////////////\r
74 //\r
75 //      EMS Management code\r
76 //\r
77 /////////////////////////////////////////////////////////////////////////////\r
78 \r
79 //\r
80 //      PML_MapEMS() - Maps a logical page to a physical page\r
81 //\r
82 byte\r
83 PML_MapEMS(word logical, byte physical, global_game_variables_t *gvar)\r
84 {\r
85         byte    str[160];\r
86         unsigned        EMShandle;\r
87         byte err;\r
88         boolean errorflag=false;\r
89         int     i;\r
90         EMShandle=gvar->pm.emm.EMSHandle;\r
91 \r
92         __asm {\r
93                 mov     ah,EMS_MAPPAGE\r
94                 mov     al,physical\r
95                 mov     bx,logical\r
96                 mov     dx,EMShandle\r
97                 int     EMS_INT\r
98                 or      ah,ah\r
99                 jnz     error\r
100                 jmp End\r
101 #ifdef __BORLANDC__\r
102         }\r
103 #endif\r
104                 error:\r
105 #ifdef __BORLANDC__\r
106         __asm {\r
107 #endif\r
108                 mov     err,ah\r
109                 mov     errorflag,1\r
110 #ifdef __BORLANDC__\r
111         }\r
112 #endif\r
113                 End:\r
114 #ifdef __WATCOMC__\r
115         }\r
116 #endif\r
117         if(errorflag==true)\r
118         {\r
119                 strcpy(str,"MM_MapEMS: EMS error ");\r
120                 MM_EMSerr(str, err);\r
121                 printf("%s\n",str);\r
122                 Quit("PML_MapEMS: Page mapping failed\n");\r
123                 return err;\r
124         }\r
125         return 0;\r
126 }\r
127 \r
128 //\r
129 //      PML_StartupEMS() - Sets up EMS for Page Mgr's use\r
130 //              Checks to see if EMS driver is present\r
131 //      Verifies that EMS hardware is present\r
132 //              Make sure that EMS version is 3.2 or later\r
133 //              If there's more than our minimum (2 pages) available, allocate it (up\r
134 //                      to the maximum we need)\r
135 //\r
136 \r
137         char    EMMDriverName[9] = "EMMXXXX0";\r
138 \r
139 boolean\r
140 PML_StartupEMS(global_game_variables_t *gvar)\r
141 {\r
142         int             i;\r
143         long    size;\r
144         boolean errorflag;\r
145 \r
146         gvar->pm.emm.EMSPresent = false;                        // Assume that we'll fail\r
147         gvar->pm.emm.EMSAvail = 0;\r
148         errorflag=0;\r
149 \r
150         _DX = (word)EMMDriverName;\r
151         _AX = 0x3d00;\r
152         geninterrupt(0x21);                     // try to open EMMXXXX0 device\r
153         __asm {\r
154                 jnc     gothandle\r
155                 mov     errorflag,1\r
156 #ifdef __BORLANDC__\r
157         }\r
158 #endif\r
159                 gothandle:\r
160 #ifdef __WATCOMC__\r
161         }\r
162 #endif\r
163         if(errorflag)\r
164                 goto error;\r
165 \r
166 //gothandle:\r
167         _BX = _AX;\r
168         _AX = 0x4400;\r
169         geninterrupt(0x21);                     // get device info\r
170         __asm {\r
171                 jnc     gotinfo\r
172                 mov     errorflag,1\r
173 #ifdef __BORLANDC__\r
174         }\r
175 #endif\r
176                 gotinfo:\r
177 #ifdef __WATCOMC__\r
178         }\r
179 #endif\r
180         if(errorflag)\r
181                 goto error;\r
182 \r
183 //gotinfo:\r
184 __asm   and     dx,0x80\r
185         if (!_DX)\r
186                 goto error;\r
187 \r
188         _AX = 0x4407;\r
189         geninterrupt(0x21);                     // get status\r
190         __asm {\r
191                 jc      error\r
192                 jmp     end\r
193                 error:\r
194                 mov     errorflag,1\r
195 #ifdef __BORLANDC__\r
196         }\r
197 #endif\r
198                 end:\r
199 #ifdef __WATCOMC__\r
200         }\r
201 #endif\r
202         if (!_AL)\r
203                 goto error;\r
204 \r
205         _AH = 0x3e;\r
206         geninterrupt(0x21);                     // close handle\r
207 \r
208         _AH = EMS_STATUS;\r
209         geninterrupt(EMS_INT);\r
210         if (_AH)\r
211                 goto error;                             // make sure EMS hardware is present\r
212 \r
213         _AH = EMS_VERSION;\r
214         geninterrupt(EMS_INT);\r
215         if (_AH || (_AL < 0x32))        // only work on EMS 3.2 or greater (silly, but...)\r
216                 goto error;\r
217 \r
218         _AH = EMS_GETFRAME;\r
219         geninterrupt(EMS_INT);\r
220         if (_AH)\r
221                 goto error;                             // find the page frame address\r
222         gvar->pm.emm.EMSPageFrame = _BX;\r
223 \r
224         _AH = EMS_GETPAGES;\r
225         geninterrupt(EMS_INT);\r
226         if (_AH)\r
227                 goto error;\r
228         if (_BX < 2)\r
229                 goto error;             // Require at least 2 pages (32k)\r
230         gvar->pm.emm.EMSAvail = _BX;\r
231 \r
232         // Don't hog all available EMS\r
233         size = gvar->pm.emm.EMSAvail * (long)EMSPageSize;\r
234         if (size - (EMSPageSize * 2) > (gvar->pm.fi.ChunksInFile * (long)PMPageSize))\r
235         {\r
236                 size = (gvar->pm.fi.ChunksInFile * (long)PMPageSize) + EMSPageSize;\r
237                 gvar->pm.emm.EMSAvail = size / EMSPageSize;\r
238         }\r
239 \r
240         _AH = EMS_ALLOCPAGES;\r
241         _BX = gvar->pm.emm.EMSAvail;\r
242         geninterrupt(EMS_INT);\r
243         if (_AH)\r
244                 goto error;\r
245         gvar->pm.emm.EMSHandle = _DX;\r
246 \r
247         gvar->mmi.EMSmem += gvar->pm.emm.EMSAvail * (long)EMSPageSize;\r
248 \r
249         // Initialize EMS mapping cache\r
250         for (i = 0;i < EMSFrameCount;i++)\r
251                 gvar->pm.emm.EMSList[i].baseEMSPage = -1;\r
252 \r
253         gvar->pm.emm.EMSPresent = true;                 // We have EMS\r
254 \r
255 error:\r
256         return(gvar->pm.emm.EMSPresent);\r
257 }\r
258 \r
259 //\r
260 //      PML_ShutdownEMS() - If EMS was used, deallocate it\r
261 //\r
262 void\r
263 PML_ShutdownEMS(global_game_variables_t *gvar)\r
264 {\r
265         word EMSHandle;\r
266         EMSHandle=gvar->pm.emm.EMSHandle;\r
267 \r
268         if (gvar->pm.emm.EMSPresent)\r
269         {\r
270                 __asm {\r
271                         mov     ah,EMS_FREEPAGES\r
272                         mov     dx,[EMSHandle]\r
273                         int     EMS_INT\r
274                 }\r
275                 if (_AH)\r
276                 {\r
277                         Quit("PML_ShutdownEMS: Error freeing EMS\n");\r
278                         //return;\r
279                 }\r
280         }\r
281 }\r
282 \r
283 /////////////////////////////////////////////////////////////////////////////\r
284 //\r
285 //      XMS Management code\r
286 //\r
287 /////////////////////////////////////////////////////////////////////////////\r
288 \r
289 //\r
290 //      PML_StartupXMS() - Starts up XMS for the Page Mgr's use\r
291 //              Checks for presence of an XMS driver\r
292 //              Makes sure that there's at least a page of XMS available\r
293 //              Allocates any remaining XMS (rounded down to the nearest page size)\r
294 //\r
295 boolean\r
296 PML_StartupXMS(global_game_variables_t *gvar)\r
297 {\r
298         gvar->pm.xmm.XMSPresent = false;                                        // Assume failure\r
299         gvar->pm.xmm.XMSAvail = 0;\r
300 \r
301         _AX=0x4300;\r
302         geninterrupt(XMS_INT);                                  // Check for presence of XMS driver\r
303         if (_AL != 0x80)\r
304                 goto error;\r
305 \r
306 \r
307         __asm {\r
308                 mov     ax,0x4310\r
309                 int     XMS_INT                                                 // Get address of XMS driver\r
310                 mov     [WORD PTR XMSDriver],bx\r
311                 mov     [WORD PTR XMSDriver+2],es               // function pointer to XMS driver\r
312         }\r
313 \r
314         XMS_CALL(XMS_QUERYFREE);                        // Find out how much XMS is available\r
315         gvar->pm.xmm.XMSAvail = _AX;\r
316         if (!_AX)                               // AJR: bugfix 10/8/92\r
317                 goto error;\r
318 \r
319         gvar->pm.xmm.XMSAvail &= ~(PMPageSizeKB - 1);   // Round off to nearest page size\r
320         if (gvar->pm.xmm.XMSAvail < (PMPageSizeKB * 2)) // Need at least 2 pages\r
321                 goto error;\r
322 \r
323         _DX = gvar->pm.xmm.XMSAvail;\r
324         XMS_CALL(XMS_ALLOC);                            // And do the allocation\r
325         gvar->pm.xmm.XMSHandle = _DX;\r
326 \r
327         if (!_AX)                               // AJR: bugfix 10/8/92\r
328         {\r
329                 gvar->pm.xmm.XMSAvail = 0;\r
330                 goto error;\r
331         }\r
332 \r
333         gvar->mmi.XMSmem += gvar->pm.xmm.XMSAvail * 1024;\r
334 \r
335         gvar->pm.xmm.XMSPresent = true;\r
336 error:\r
337         return(gvar->pm.xmm.XMSPresent);\r
338 }\r
339 \r
340 //\r
341 //      PML_XMSCopy() - Copies a main/EMS page to or from XMS\r
342 //              Will round an odd-length request up to the next even value\r
343 //\r
344 void\r
345 PML_XMSCopy(boolean toxms,byte far *addr,word xmspage,word length, global_game_variables_t *gvar)\r
346 {\r
347         dword   xoffset;\r
348         struct\r
349         {\r
350                 dword   length;\r
351                 word            source_handle;\r
352                 dword   source_offset;\r
353                 word            target_handle;\r
354                 dword   target_offset;\r
355         } copy;\r
356 \r
357         if (!addr)\r
358         {\r
359                 Quit("PML_XMSCopy: zero address\n");\r
360                 //return;\r
361         }\r
362 \r
363         xoffset = (dword)xmspage * PMPageSize;\r
364 \r
365         copy.length = (length + 1) & ~1;\r
366         copy.source_handle = toxms? 0 : gvar->pm.xmm.XMSHandle;\r
367         copy.source_offset = toxms? (long)addr : xoffset;\r
368         copy.target_handle = toxms? gvar->pm.xmm.XMSHandle : 0;\r
369         copy.target_offset = toxms? xoffset : (long)addr;\r
370 \r
371         __asm {\r
372                 push si\r
373         }\r
374         _SI = (word)&copy;\r
375         XMS_CALL(XMS_MOVE);\r
376         __asm {\r
377                 pop     si\r
378         }\r
379         if (!_AX)\r
380         {\r
381                 Quit("PML_XMSCopy: Error on copy");\r
382                 //return;\r
383         }\r
384 }\r
385 \r
386 #if 1\r
387 #define PML_CopyToXMS(s,t,l,gvar)       PML_XMSCopy(true,(s),(t),(l),(gvar))\r
388 #define PML_CopyFromXMS(t,s,l,gvar)     PML_XMSCopy(false,(t),(s),(l),(gvar))\r
389 #else\r
390 //\r
391 //      PML_CopyToXMS() - Copies the specified number of bytes from the real mode\r
392 //              segment address to the specified XMS page\r
393 //\r
394 void\r
395 PML_CopyToXMS(byte far *source,int targetpage,word length,global_game_variables_t *gvar)\r
396 {\r
397         PML_XMSCopy(true,source,targetpage,length, global_game_variables_t *gvar);\r
398 }\r
399 \r
400 //\r
401 //      PML_CopyFromXMS() - Copies the specified number of bytes from an XMS\r
402 //              page to the specified real mode address\r
403 //\r
404 void\r
405 PML_CopyFromXMS(byte far *target,int sourcepage,word length, global_game_variables_t *gvar)\r
406 {\r
407         PML_XMSCopy(false,target,sourcepage,length, global_game_variables_t *gvar);\r
408 }\r
409 #endif\r
410 \r
411 //\r
412 //      PML_ShutdownXMS()\r
413 //\r
414 void\r
415 PML_ShutdownXMS(global_game_variables_t *gvar)\r
416 {\r
417         if (gvar->pm.xmm.XMSPresent)\r
418         {\r
419                 _DX = gvar->pm.xmm.XMSHandle;\r
420                 XMS_CALL(XMS_FREE);\r
421                 if (_BL)\r
422                 {\r
423                         Quit("PML_ShutdownXMS: Error freeing XMS");\r
424                         //return;\r
425                 }\r
426         }\r
427 }\r
428 \r
429 /////////////////////////////////////////////////////////////////////////////\r
430 //\r
431 //      Main memory code\r
432 //\r
433 /////////////////////////////////////////////////////////////////////////////\r
434 \r
435 //\r
436 //      PM_SetMainMemPurge() - Sets the purge level for all allocated main memory\r
437 //              blocks. This shouldn't be called directly - the PM_LockMainMem() and\r
438 //              PM_UnlockMainMem() macros should be used instead.\r
439 //\r
440 void\r
441 PM_SetMainMemPurge(int level, global_game_variables_t *gvar)\r
442 {\r
443         int     i;\r
444 \r
445         for (i = 0;i < PMMaxMainMem;i++)\r
446         {\r
447 #ifdef __DEBUG_PM__\r
448                 printf("PM_SetMainMemPurge()    info of gvar->pm.mm.MainMemPages[i]\n");\r
449                 printf("        %Fp,    %Fp\n", gvar->pm.mm.MainMemPages[i],            (gvar->pm.mm.MainMemPages[i]));\r
450                 printf("&       %Fp,    %Fp\n", &gvar->pm.mm.MainMemPages[i],   &(gvar->pm.mm.MainMemPages[i]));\r
451 #endif\r
452                 if (gvar->pm.mm.MainMemPages[i])\r
453                         MM_SetPurge((gvar->pm.mm.MainMemPages[i]),level, gvar);\r
454         }\r
455 }\r
456 \r
457 //\r
458 //      PM_CheckMainMem() - If something besides the Page Mgr makes requests of\r
459 //              the Memory Mgr, some of the Page Mgr's blocks may have been purged,\r
460 //              so this function runs through the block list and checks to see if\r
461 //              any of the blocks have been purged. If so, it marks the corresponding\r
462 //              page as purged & unlocked, then goes through the block list and\r
463 //              tries to reallocate any blocks that have been purged.\r
464 //      This routine now calls PM_LockMainMem() to make sure that any allocation\r
465 //              attempts made during the block reallocation sweep don't purge any\r
466 //              of the other blocks. Because PM_LockMainMem() is called,\r
467 //              PM_UnlockMainMem() needs to be called before any other part of the\r
468 //              program makes allocation requests of the Memory Mgr.\r
469 //\r
470 void\r
471 PM_CheckMainMem(global_game_variables_t *gvar)\r
472 {\r
473         boolean                 allocfailed;\r
474         int                             i,n;\r
475         memptr                  *p;\r
476         PMBlockAttr             *used;\r
477         PageListStruct  far *page;\r
478 \r
479         if (!gvar->pm.mm.MainPresent)\r
480                 return;\r
481 \r
482         for (i = 0,page = gvar->pm.PMPages;i < gvar->pm.fi.ChunksInFile;i++,page++)\r
483         {\r
484                 n = page->mainPage;\r
485                 if (n != -1)                                            // Is the page using main memory?\r
486                 {\r
487                         if (!gvar->pm.mm.MainMemPages[n])                       // Yep, was the block purged?\r
488                         {\r
489                                 page->mainPage = -1;            // Yes, mark page as purged & unlocked\r
490                                 page->locked = pml_Unlocked;\r
491                         }\r
492                 }\r
493         }\r
494 \r
495         // Prevent allocation attempts from purging any of our other blocks\r
496         PM_LockMainMem(gvar);\r
497         allocfailed = false;\r
498         for (i = 0,p = gvar->pm.mm.MainMemPages,used = gvar->pm.mm.MainMemUsed; i < PMMaxMainMem;i++,p++,used++)\r
499         {\r
500                 if (!*p)                                                        // If the page got purged\r
501                 {\r
502                         if (*used & pmba_Allocated)             // If it was allocated\r
503                         {\r
504                                 *used &= ~pmba_Allocated;       // Mark as unallocated\r
505                                 gvar->pm.mm.MainPagesAvail--;                   // and decrease available count\r
506                         }\r
507 \r
508                         if (*used & pmba_Used)                  // If it was used\r
509                         {\r
510                                 *used &= ~pmba_Used;            // Mark as unused\r
511                                 gvar->pm.MainPagesUsed--;                       // and decrease used count\r
512                         }\r
513 \r
514                         if (!allocfailed)\r
515                         {\r
516                                 MM_BombOnError(false, gvar);\r
517                                 MM_GetPtr(p,PMPageSize, gvar);          // Try to reallocate\r
518                                 if (gvar->mm.mmerror)                                   // If it failed,\r
519                                         allocfailed = true;                     //  don't try any more allocations\r
520                                 else                                                    // If it worked,\r
521                                 {\r
522                                         *used |= pmba_Allocated;        // Mark as allocated\r
523                                         gvar->pm.mm.MainPagesAvail++;                   // and increase available count\r
524                                 }\r
525                                 MM_BombOnError(true, gvar);\r
526                         }\r
527                 }\r
528         }\r
529         if (gvar->mm.mmerror)\r
530                 gvar->mm.mmerror = false;\r
531 }\r
532 \r
533 //\r
534 //      PML_StartupMainMem() - Allocates as much main memory as is possible for\r
535 //              the Page Mgr. The memory is allocated as non-purgeable, so if it's\r
536 //              necessary to make requests of the Memory Mgr, PM_UnlockMainMem()\r
537 //              needs to be called.\r
538 //\r
539 void\r
540 PML_StartupMainMem(global_game_variables_t *gvar)\r
541 {\r
542         int             i,n;\r
543         memptr  *p;\r
544 \r
545         gvar->pm.mm.MainPagesAvail = 0;\r
546         MM_BombOnError(false, gvar);\r
547         for (i = 0,p = gvar->pm.mm.MainMemPages;i < PMMaxMainMem;i++,p++)\r
548         {\r
549                 MM_GetPtr(p,PMPageSize, gvar);\r
550                 if (gvar->mm.mmerror)\r
551                         break;\r
552 \r
553                 gvar->pm.mm.MainPagesAvail++;\r
554                 gvar->pm.mm.MainMemUsed[i] = pmba_Allocated;\r
555         }\r
556         MM_BombOnError(true, gvar);\r
557         if (gvar->mm.mmerror)\r
558                 gvar->mm.mmerror = false;\r
559         if (gvar->pm.mm.MainPagesAvail < PMMinMainMem)\r
560         {\r
561                 Quit("PM_SetupMainMem: Not enough main memory");\r
562                 //return;\r
563         }\r
564         gvar->pm.mm.MainPresent = true;\r
565 }\r
566 \r
567 //\r
568 //      PML_ShutdownMainMem() - Frees all of the main memory blocks used by the\r
569 //              Page Mgr.\r
570 //\r
571 void\r
572 PML_ShutdownMainMem(global_game_variables_t *gvar)\r
573 {\r
574         int             i;\r
575         memptr  *p;\r
576 \r
577         // DEBUG - mark pages as unallocated & decrease page count as appropriate\r
578         for (i = 0,p = gvar->pm.mm.MainMemPages;i < PMMaxMainMem;i++,p++)\r
579                 if (*p)\r
580                         MM_FreePtr(p, gvar);\r
581 }\r
582 \r
583 /////////////////////////////////////////////////////////////////////////////\r
584 //\r
585 //      File management code\r
586 //\r
587 /////////////////////////////////////////////////////////////////////////////\r
588 \r
589 //\r
590 //      PML_ReadFromFile() - Reads some data in from the page file\r
591 //\r
592 void\r
593 PML_ReadFromFile(byte far *buf,long offset,word length, global_game_variables_t *gvar)\r
594 {\r
595         if (!buf)\r
596         {\r
597                 Quit("PML_ReadFromFile: Null pointer");\r
598                 //return;\r
599         }\r
600         if (!offset)\r
601         {\r
602                 Quit("PML_ReadFromFile: Zero offset");\r
603                 //return;\r
604         }\r
605         if (lseek(gvar->pm.fi.PageFile,offset,SEEK_SET) != offset)\r
606         {\r
607                 Quit("PML_ReadFromFile: Seek failed");\r
608                 //return;\r
609         }\r
610         if (!CA_FarRead(gvar->pm.fi.PageFile,buf,length, gvar))\r
611         {\r
612                 Quit("PML_ReadFromFile: Read failed");\r
613                 //return;\r
614         }\r
615 }\r
616 \r
617 //\r
618 //      PML_OpenPageFile() - Opens the page file and sets up the page info\r
619 //\r
620 void\r
621 PML_OpenPageFile(global_game_variables_t *gvar)\r
622 {\r
623         int                             i;\r
624         long                    size;\r
625                                 //__SEGA buf;\r
626         memptr          buf;\r
627         dword           far *offsetptr;\r
628         word                    far *lengthptr;\r
629         PageListStruct  far *page;\r
630 \r
631         gvar->pm.fi.PageFile = open(gvar->pm.fi.PageFileName,O_RDONLY + O_BINARY);\r
632         if (gvar->pm.fi.PageFile == -1)\r
633         {\r
634                 Quit("PML_OpenPageFile: Unable to open page file");\r
635                 //return;\r
636         }\r
637 \r
638         // Read in header variables\r
639         read(gvar->pm.fi.PageFile,&gvar->pm.fi.ChunksInFile,sizeof(gvar->pm.fi.ChunksInFile));\r
640         read(gvar->pm.fi.PageFile,&gvar->pm.fi.PMSpriteStart,sizeof(gvar->pm.fi.PMSpriteStart));\r
641         read(gvar->pm.fi.PageFile,&gvar->pm.fi.PMSoundStart,sizeof(gvar->pm.fi.PMSoundStart));\r
642 \r
643         // Allocate and clear the page list\r
644         gvar->pm.PMNumBlocks = gvar->pm.fi.ChunksInFile;\r
645         MM_GetPtr((memptr *)gvar->pm.PMSegPages, sizeof(PageListStruct) * (gvar->pm.PMNumBlocks), gvar);\r
646         MM_SetLock((memptr *)gvar->pm.PMSegPages,true, gvar);\r
647         gvar->pm.PMPages = (PageListStruct far *)gvar->pm.PMSegPages;\r
648         _fmemset(gvar->pm.PMPages,0,sizeof(PageListStruct) * gvar->pm.PMNumBlocks);\r
649 \r
650         // Read in the chunk offsets\r
651         size = sizeof(dword) * gvar->pm.fi.ChunksInFile;\r
652         MM_GetPtr(&buf, size, gvar);\r
653         if (!CA_FarRead(gvar->pm.fi.PageFile,(byte far *)buf,size, gvar))\r
654         {\r
655                 Quit("PML_OpenPageFile: Offset read failed");\r
656                 //return;\r
657         }\r
658         offsetptr = (dword far *)buf;\r
659         for (i = 0,page = gvar->pm.PMPages;i < gvar->pm.fi.ChunksInFile;i++,page++)\r
660                 page->offset = *offsetptr++;\r
661         MM_FreePtr(&buf, gvar);\r
662 \r
663         // Read in the chunk lengths\r
664         size = sizeof(word) * gvar->pm.fi.ChunksInFile;\r
665         MM_GetPtr(&buf,size, gvar);\r
666         if (!CA_FarRead(gvar->pm.fi.PageFile,(byte far *)buf,size, gvar))\r
667         {\r
668                 Quit("PML_OpenPageFile: Length read failed");\r
669                 //return;\r
670         }\r
671         lengthptr = (word far *)buf;\r
672         for (i = 0,page = gvar->pm.PMPages;i < gvar->pm.fi.ChunksInFile;i++,page++)\r
673                 page->length = *lengthptr++;\r
674         MM_FreePtr(&buf, gvar);\r
675 }\r
676 \r
677 //\r
678 //  PML_ClosePageFile() - Closes the page file\r
679 //\r
680 void\r
681 PML_ClosePageFile(global_game_variables_t *gvar)\r
682 {\r
683         if (gvar->pm.fi.PageFile != -1)\r
684                 close(gvar->pm.fi.PageFile);\r
685         if (gvar->pm.PMSegPages)\r
686         {\r
687                 MM_SetLock((memptr)gvar->pm.PMSegPages,false, gvar);\r
688                 MM_FreePtr((memptr)gvar->pm.PMSegPages, gvar);\r
689         }\r
690 }\r
691 \r
692 /////////////////////////////////////////////////////////////////////////////\r
693 //\r
694 //      Allocation, etc., code\r
695 //\r
696 /////////////////////////////////////////////////////////////////////////////\r
697 \r
698 //\r
699 //      PML_GetEMSAddress()\r
700 //\r
701 //              Page is in EMS, so figure out which EMS physical page should be used\r
702 //              to map our page in. If normal page, use EMS physical page 3, else\r
703 //              use the physical page specified by the lock type\r
704 //\r
705 #ifndef __DEBUG_2__\r
706 #pragma argsused        // DEBUG - remove lock parameter\r
707 memptr\r
708 PML_GetEMSAddress(int page,PMLockType lock, global_game_variables_t *gvar)\r
709 {\r
710         int             i,emspage;\r
711         word    emsoff,emsbase,offset;\r
712 \r
713         emsoff = page & (PMEMSSubPage - 1);\r
714         emsbase = page - emsoff;\r
715 \r
716         emspage = -1;\r
717         // See if this page is already mapped in\r
718         for (i = 0;i < EMSFrameCount;i++)\r
719         {\r
720                 if (gvar->pm.emm.EMSList[i].baseEMSPage == emsbase)\r
721                 {\r
722                         emspage = i;    // Yep - don't do a redundant remapping\r
723                         break;\r
724                 }\r
725         }\r
726 \r
727         // If page isn't already mapped in, find LRU EMS frame, and use it\r
728         if (emspage == -1)\r
729         {\r
730                 dword last = LONG_MAX;\r
731                 for (i = 0;i < EMSFrameCount;i++)\r
732                 {\r
733                         if (gvar->pm.emm.EMSList[i].lastHit < last)\r
734                         {\r
735                                 emspage = i;\r
736                                 last = gvar->pm.emm.EMSList[i].lastHit;\r
737                         }\r
738                 }\r
739 \r
740                 gvar->pm.emm.EMSList[emspage].baseEMSPage = emsbase;\r
741                 PML_MapEMS(page / PMEMSSubPage,emspage, gvar);\r
742         }\r
743 \r
744         if (emspage == -1)\r
745                 Quit("PML_GetEMSAddress: EMS find failed");\r
746 \r
747         gvar->pm.emm.EMSList[emspage].lastHit = gvar->pm.PMFrameCount;\r
748         offset = emspage * EMSPageSizeSeg;\r
749         offset += emsoff * PMPageSizeSeg;\r
750         return((memptr)(gvar->pm.emm.EMSPageFrame + offset));\r
751 }\r
752 #else\r
753 memptr\r
754 PML_GetEMSAddress(int page,PMLockType lock, global_game_variables_t *gvar)\r
755 {\r
756         word    emspage;\r
757 \r
758         emspage = (lock < pml_EMSLock)? 3 : (lock - pml_EMSLock);\r
759 \r
760         PML_MapEMS(page / PMEMSSubPage,emspage);\r
761 \r
762         return((memptr)(EMSPageFrame + (emspage * EMSPageSizeSeg)\r
763                         + ((page & (PMEMSSubPage - 1)) * PMPageSizeSeg)));\r
764 }\r
765 #endif\r
766 \r
767 //\r
768 //      PM_GetPageAddress() - Returns the address of a given page\r
769 //              Maps in EMS if necessary\r
770 //              Returns nil if block isn't cached into Main Memory or EMS\r
771 //\r
772 //\r
773 memptr\r
774 PM_GetPageAddress(int pagenum, global_game_variables_t *gvar)\r
775 {\r
776         PageListStruct  far *page;\r
777 \r
778         page = &gvar->pm.PMPages[pagenum];\r
779         if (page->mainPage != -1)\r
780                 return(gvar->pm.mm.MainMemPages[page->mainPage]);\r
781         else if (page->emsPage != -1)\r
782                 return(PML_GetEMSAddress(page->emsPage,page->locked, gvar));\r
783         else\r
784                 return(nil);\r
785 }\r
786 \r
787 //\r
788 //      PML_GiveLRUPage() - Returns the page # of the least recently used\r
789 //              present & unlocked main/EMS page (or main page if mainonly is true)\r
790 //\r
791 int\r
792 PML_GiveLRUPage(boolean mainonly, global_game_variables_t *gvar)\r
793 {\r
794         int                             i,lru;\r
795         long                    last;\r
796         PageListStruct  far *page;\r
797 \r
798         for (i = 0,page = gvar->pm.PMPages,lru = -1,last = LONG_MAX;i < gvar->pm.fi.ChunksInFile;i++,page++)\r
799         {\r
800                 if\r
801                 (\r
802                         (page->lastHit < last)\r
803                 &&      ((page->emsPage != -1) || (page->mainPage != -1))\r
804                 &&      (page->locked == pml_Unlocked)\r
805                 &&      (!(mainonly && (page->mainPage == -1)))\r
806                 )\r
807                 {\r
808                         last = page->lastHit;\r
809                         lru = i;\r
810                 }\r
811         }\r
812 \r
813         if (lru == -1)\r
814                 Quit("PML_GiveLRUPage: LRU Search failed");\r
815         return(lru);\r
816 }\r
817 \r
818 //\r
819 //      PML_GiveLRUXMSPage() - Returns the page # of the least recently used\r
820 //              (and present) XMS page.\r
821 //      This routine won't return the XMS page protected (by XMSProtectPage)\r
822 //\r
823 int\r
824 PML_GiveLRUXMSPage(global_game_variables_t *gvar)\r
825 {\r
826         int                             i,lru;\r
827         long                    last;\r
828         PageListStruct  far *page;\r
829 \r
830         for (i = 0,page = gvar->pm.PMPages,lru = -1,last = LONG_MAX;i < gvar->pm.fi.ChunksInFile;i++,page++)\r
831         {\r
832                 if\r
833                 (\r
834                         (page->xmsPage != -1)\r
835                 &&      (page->lastHit < last)\r
836                 &&      (i != gvar->pm.xmm.XMSProtectPage)\r
837                 )\r
838                 {\r
839                         last = page->lastHit;\r
840                         lru = i;\r
841                 }\r
842         }\r
843         return(lru);\r
844 }\r
845 \r
846 //\r
847 //      PML_PutPageInXMS() - If page isn't in XMS, find LRU XMS page and replace\r
848 //              it with the main/EMS page\r
849 //\r
850 void\r
851 PML_PutPageInXMS(int pagenum, global_game_variables_t *gvar)\r
852 {\r
853         int                             usexms;\r
854         PageListStruct  far *page;\r
855 \r
856         if (!gvar->pm.xmm.XMSPresent)\r
857                 return;\r
858 \r
859         page = &gvar->pm.PMPages[pagenum];\r
860         if (page->xmsPage != -1)\r
861                 return;                                 // Already in XMS\r
862 \r
863         if (gvar->pm.XMSPagesUsed < gvar->pm.xmm.XMSPagesAvail)\r
864                 page->xmsPage = gvar->pm.XMSPagesUsed++;\r
865         else\r
866         {\r
867                 usexms = PML_GiveLRUXMSPage(gvar);\r
868                 if (usexms == -1)\r
869                         Quit("PML_PutPageInXMS: No XMS LRU");\r
870                 page->xmsPage = gvar->pm.PMPages[usexms].xmsPage;\r
871                 gvar->pm.PMPages[usexms].xmsPage = -1;\r
872         }\r
873         PML_CopyToXMS(PM_GetPageAddress(pagenum, gvar),page->xmsPage,page->length, gvar);\r
874 }\r
875 \r
876 //\r
877 //      PML_TransferPageSpace() - A page is being replaced, so give the new page\r
878 //              the old one's address space. Returns the address of the new page.\r
879 //\r
880 memptr\r
881 PML_TransferPageSpace(int orig,int new, global_game_variables_t *gvar)\r
882 {\r
883         memptr                  addr;\r
884         PageListStruct  far *origpage,far *newpage;\r
885 \r
886         if (orig == new)\r
887                 Quit("PML_TransferPageSpace: Identity replacement");\r
888 \r
889         origpage = &gvar->pm.PMPages[orig];\r
890         newpage = &gvar->pm.PMPages[new];\r
891 \r
892         if (origpage->locked != pml_Unlocked)\r
893                 Quit("PML_TransferPageSpace: Killing locked page");\r
894 \r
895         if ((origpage->emsPage == -1) && (origpage->mainPage == -1))\r
896                 Quit("PML_TransferPageSpace: Reusing non-existent page");\r
897 \r
898         // Copy page that's about to be purged into XMS\r
899         PML_PutPageInXMS(orig, gvar);\r
900 \r
901         // Get the address, and force EMS into a physical page if necessary\r
902         addr = PM_GetPageAddress(orig, gvar);\r
903 \r
904         // Steal the address\r
905         newpage->emsPage = origpage->emsPage;\r
906         newpage->mainPage = origpage->mainPage;\r
907 \r
908         // Mark replaced page as purged\r
909         origpage->mainPage = origpage->emsPage = -1;\r
910 \r
911         if (!addr)\r
912                 Quit("PML_TransferPageSpace: Zero replacement");\r
913 \r
914         return(addr);\r
915 }\r
916 \r
917 //\r
918 //      PML_GetAPageBuffer() - A page buffer is needed. Either get it from the\r
919 //              main/EMS free pool, or use PML_GiveLRUPage() to find which page to\r
920 //              steal the buffer from. Returns a far pointer to the page buffer, and\r
921 //              sets the fields inside the given page structure appropriately.\r
922 //              If mainonly is true, free EMS will be ignored, and only main pages\r
923 //              will be looked at by PML_GiveLRUPage().\r
924 //\r
925 byte far *\r
926 PML_GetAPageBuffer(int pagenum,boolean mainonly, global_game_variables_t *gvar)\r
927 {\r
928         byte                    far *addr = nil;\r
929         int                             i,n;\r
930         PMBlockAttr             *used;\r
931         PageListStruct  far *page;\r
932 \r
933         page = &gvar->pm.PMPages[pagenum];\r
934         if ((gvar->pm.EMSPagesUsed < gvar->pm.emm.EMSPagesAvail) && !mainonly)\r
935         {\r
936                 // There's remaining EMS - use it\r
937                 page->emsPage = gvar->pm.EMSPagesUsed++;\r
938                 addr = PML_GetEMSAddress(page->emsPage,page->locked, gvar);\r
939         }\r
940         else if (gvar->pm.MainPagesUsed < gvar->pm.mm.MainPagesAvail)\r
941         {\r
942                 // There's remaining main memory - use it\r
943                 for (i = 0,n = -1,used = gvar->pm.mm.MainMemUsed;i < PMMaxMainMem;i++,used++)\r
944                 {\r
945                         if ((*used & pmba_Allocated) && !(*used & pmba_Used))\r
946                         {\r
947                                 n = i;\r
948                                 *used |= pmba_Used;\r
949                                 break;\r
950                         }\r
951                 }\r
952                 if (n == -1)\r
953                         Quit("PML_GetPageBuffer: MainPagesAvail lied");\r
954                 addr = gvar->pm.mm.MainMemPages[n];\r
955                 if (!addr)\r
956                         Quit("PML_GetPageBuffer: Purged main block");\r
957                 page->mainPage = n;\r
958                 gvar->pm.MainPagesUsed++;\r
959         }\r
960         else\r
961                 addr = PML_TransferPageSpace(PML_GiveLRUPage(mainonly, gvar),pagenum, gvar);\r
962 \r
963         if (!addr)\r
964                 Quit("PML_GetPageBuffer: Search failed");\r
965         return(addr);\r
966 }\r
967 \r
968 //\r
969 //      PML_GetPageFromXMS() - If page is in XMS, find LRU main/EMS page and\r
970 //              replace it with the page from XMS. If mainonly is true, will only\r
971 //              search for LRU main page.\r
972 //      XMSProtectPage is set to the page to be retrieved from XMS, so that if\r
973 //              the page from which we're stealing the main/EMS from isn't in XMS,\r
974 //              it won't copy over the page that we're trying to get from XMS.\r
975 //              (pages that are being purged are copied into XMS, if possible)\r
976 //\r
977 memptr\r
978 PML_GetPageFromXMS(int pagenum,boolean mainonly, global_game_variables_t *gvar)\r
979 {\r
980         byte                    far *checkaddr;\r
981         memptr                  addr = nil;\r
982         PageListStruct  far *page;\r
983 \r
984         page = &gvar->pm.PMPages[pagenum];\r
985         if (gvar->pm.xmm.XMSPresent && (page->xmsPage != -1))\r
986         {\r
987                 gvar->pm.xmm.XMSProtectPage = pagenum;\r
988                 checkaddr = PML_GetAPageBuffer(pagenum,mainonly, gvar);\r
989                 if (FP_OFF(checkaddr))\r
990                         Quit("PML_GetPageFromXMS: Non segment pointer");\r
991                 addr = (memptr)FP_SEG(checkaddr);\r
992                 PML_CopyFromXMS(addr,page->xmsPage,page->length, gvar);\r
993                 gvar->pm.xmm.XMSProtectPage = -1;\r
994         }\r
995 \r
996         return(addr);\r
997 }\r
998 \r
999 //\r
1000 //      PML_LoadPage() - A page is not in main/EMS memory, and it's not in XMS.\r
1001 //              Load it into either main or EMS. If mainonly is true, the page will\r
1002 //              only be loaded into main.\r
1003 //\r
1004 void\r
1005 PML_LoadPage(int pagenum,boolean mainonly, global_game_variables_t *gvar)\r
1006 {\r
1007         byte                    far *addr;\r
1008         PageListStruct  far *page;\r
1009 \r
1010         addr = PML_GetAPageBuffer(pagenum,mainonly, gvar);\r
1011         page = &gvar->pm.PMPages[pagenum];\r
1012         PML_ReadFromFile(addr,page->offset,page->length, gvar);\r
1013 }\r
1014 \r
1015 //\r
1016 //      PM_GetPage() - Returns the address of the page, loading it if necessary\r
1017 //              First, check if in Main Memory or EMS\r
1018 //              Then, check XMS\r
1019 //              If not in XMS, load into Main Memory or EMS\r
1020 //\r
1021 #pragma warn -pia\r
1022 memptr\r
1023 PM_GetPage(int pagenum, global_game_variables_t *gvar)\r
1024 {\r
1025         memptr  result;\r
1026 \r
1027         if (pagenum >= gvar->pm.fi.ChunksInFile)\r
1028                 Quit("PM_GetPage: Invalid page request");\r
1029 \r
1030 #ifdef __DEBUG_2__      // for debugging\r
1031         __asm {\r
1032                 mov     dx,STATUS_REGISTER_1\r
1033                 in      al,dx\r
1034                 mov     dx,ATR_INDEX\r
1035                 mov     al,ATR_OVERSCAN\r
1036                 out     dx,al\r
1037                 mov     al,10   // bright green\r
1038                 out     dx,al\r
1039         }\r
1040 #endif\r
1041 \r
1042         if (!(result = PM_GetPageAddress(pagenum, gvar)))\r
1043         {\r
1044                 boolean mainonly = (pagenum >= gvar->pm.fi.PMSoundStart);\r
1045 if (!gvar->pm.PMPages[pagenum].offset)  // JDC: sparse page\r
1046         Quit ("Tried to load a sparse page!");\r
1047                 if (!(result = PML_GetPageFromXMS(pagenum,mainonly, gvar)))\r
1048                 {\r
1049                         if (gvar->pm.PMPages[pagenum].lastHit ==  gvar->pm.PMFrameCount)\r
1050                                 gvar->pm.PMThrashing++;\r
1051 \r
1052                         PML_LoadPage(pagenum,mainonly, gvar);\r
1053                         result = PM_GetPageAddress(pagenum, gvar);\r
1054                 }\r
1055         }\r
1056         gvar->pm.PMPages[pagenum].lastHit =  gvar->pm.PMFrameCount;\r
1057 \r
1058 #ifdef __DEBUG_2__      // for debugging\r
1059         __asm{\r
1060                 mov     dx,STATUS_REGISTER_1\r
1061                 in      al,dx\r
1062                 mov     dx,ATR_INDEX\r
1063                 mov     al,ATR_OVERSCAN\r
1064                 out     dx,al\r
1065                 mov     al,3    // blue\r
1066                 out     dx,al\r
1067                 mov     al,0x20 // normal\r
1068                 out     dx,al\r
1069 #endif\r
1070 \r
1071         return(result);\r
1072 }\r
1073 #pragma warn +pia\r
1074 \r
1075 //\r
1076 //      PM_SetPageLock() - Sets the lock type on a given page\r
1077 //              pml_Unlocked: Normal, page can be purged\r
1078 //              pml_Locked: Cannot be purged\r
1079 //              pml_EMS?: Same as pml_Locked, but if in EMS, use the physical page\r
1080 //                                      specified when returning the address. For sound stuff.\r
1081 //\r
1082 void\r
1083 PM_SetPageLock(int pagenum,PMLockType lock, global_game_variables_t *gvar)\r
1084 {\r
1085         if (pagenum < gvar->pm.fi.PMSoundStart)\r
1086                 Quit("PM_SetPageLock: Locking/unlocking non-sound page");\r
1087 \r
1088         gvar->pm.PMPages[pagenum].locked = lock;\r
1089 }\r
1090 \r
1091 //\r
1092 //      PM_Preload() - Loads as many pages as possible into all types of memory.\r
1093 //              Calls the update function after each load, indicating the current\r
1094 //              page, and the total pages that need to be loaded (for thermometer).\r
1095 //\r
1096 void\r
1097 PM_Preload(boolean (*update)(word current,word total), global_game_variables_t *gvar)\r
1098 {\r
1099         int                             i,j,\r
1100                                         page,oogypage;\r
1101         word                    current,total,\r
1102                                         totalnonxms,totalxms,\r
1103                                         mainfree,maintotal,\r
1104                                         emsfree,emstotal,\r
1105                                         xmsfree,xmstotal;\r
1106         memptr                  addr;\r
1107         PageListStruct  far *p;\r
1108 \r
1109         mainfree = (gvar->pm.mm.MainPagesAvail - gvar->pm.MainPagesUsed) + (gvar->pm.emm.EMSPagesAvail - gvar->pm.EMSPagesUsed);\r
1110         xmsfree = (gvar->pm.xmm.XMSPagesAvail - gvar->pm.XMSPagesUsed);\r
1111 \r
1112         xmstotal = maintotal = 0;\r
1113 \r
1114         for (i = 0;i < gvar->pm.fi.ChunksInFile;i++)\r
1115         {\r
1116                 if (!gvar->pm.PMPages[i].offset)\r
1117                         continue;                       // sparse\r
1118 \r
1119                 if ( gvar->pm.PMPages[i].emsPage != -1 || gvar->pm.PMPages[i].mainPage != -1 )\r
1120                         continue;                       // already in main mem\r
1121 \r
1122                 if ( mainfree )\r
1123                 {\r
1124                         maintotal++;\r
1125                         mainfree--;\r
1126                 }\r
1127                 else if ( xmsfree && (gvar->pm.PMPages[i].xmsPage == -1) )\r
1128                 {\r
1129                         xmstotal++;\r
1130                         xmsfree--;\r
1131                 }\r
1132         }\r
1133 \r
1134 \r
1135         total = maintotal + xmstotal;\r
1136 \r
1137         if (!total)\r
1138                 return;\r
1139 \r
1140         page = 0;\r
1141         current = 0;\r
1142 \r
1143 //\r
1144 // cache main/ems blocks\r
1145 //\r
1146         while (maintotal)\r
1147         {\r
1148                 while ( !gvar->pm.PMPages[page].offset || gvar->pm.PMPages[page].mainPage != -1\r
1149                         ||      gvar->pm.PMPages[page].emsPage != -1 )\r
1150                         page++;\r
1151 \r
1152                 if (page >= gvar->pm.fi.ChunksInFile)\r
1153                         Quit ("PM_Preload: Pages>=gvar->pm.fi.ChunksInFile");\r
1154 \r
1155                 PM_GetPage(page, gvar);\r
1156 \r
1157                 page++;\r
1158                 current++;\r
1159                 maintotal--;\r
1160                 update(current,total);\r
1161         }\r
1162 \r
1163 //\r
1164 // load stuff to XMS\r
1165 //\r
1166         if (xmstotal)\r
1167         {\r
1168                 for (oogypage = 0 ; gvar->pm.PMPages[oogypage].mainPage == -1 ; oogypage++)\r
1169                 ;\r
1170                 addr = PM_GetPage(oogypage, gvar);\r
1171                 if (!addr)\r
1172                         Quit("PM_Preload: XMS buffer failed");\r
1173 \r
1174                 while (xmstotal)\r
1175                 {\r
1176                         while ( !gvar->pm.PMPages[page].offset || gvar->pm.PMPages[page].xmsPage != -1 )\r
1177                                 page++;\r
1178 \r
1179                         if (page >= gvar->pm.fi.ChunksInFile)\r
1180                                 Quit ("PM_Preload: Pages>=gvar->pm.fi.ChunksInFile");\r
1181 \r
1182                         p = &gvar->pm.PMPages[page];\r
1183 \r
1184                         p->xmsPage = gvar->pm.XMSPagesUsed++;\r
1185                         if (gvar->pm.XMSPagesUsed > gvar->pm.xmm.XMSPagesAvail)\r
1186                                 Quit("PM_Preload: Exceeded XMS pages");\r
1187                         if (p->length > PMPageSize)\r
1188                                 Quit("PM_Preload: Page too long");\r
1189 \r
1190                         PML_ReadFromFile((byte far *)addr,p->offset,p->length, gvar);\r
1191                         PML_CopyToXMS((byte far *)addr,p->xmsPage,p->length, gvar);\r
1192 \r
1193                         page++;\r
1194                         current++;\r
1195                         xmstotal--;\r
1196                         update(current,total);\r
1197                 }\r
1198 \r
1199                 p = &gvar->pm.PMPages[oogypage];\r
1200                 PML_ReadFromFile((byte far *)addr,p->offset,p->length, gvar);\r
1201         }\r
1202 \r
1203         update(total,total);\r
1204 }\r
1205 \r
1206 /////////////////////////////////////////////////////////////////////////////\r
1207 //\r
1208 //      General code\r
1209 //\r
1210 /////////////////////////////////////////////////////////////////////////////\r
1211 \r
1212 //\r
1213 //      PM_NextFrame() - Increments the frame counter and adjusts the thrash\r
1214 //              avoidence variables\r
1215 //\r
1216 //              If currently in panic mode (to avoid thrashing), check to see if the\r
1217 //                      appropriate number of frames have passed since the last time that\r
1218 //                      we would have thrashed. If so, take us out of panic mode.\r
1219 //\r
1220 //\r
1221 void\r
1222 PM_NextFrame(global_game_variables_t *gvar)\r
1223 {\r
1224         int     i;\r
1225 \r
1226         // Frame count overrun - kill the LRU hit entries & reset frame count\r
1227         if (++gvar->pm.PMFrameCount >= LONG_MAX - 4)\r
1228         {\r
1229                 for (i = 0;i < gvar->pm.PMNumBlocks;i++)\r
1230                         gvar->pm.PMPages[i].lastHit = 0;\r
1231                 gvar->pm.PMFrameCount = 0;\r
1232         }\r
1233 \r
1234 //#if 0\r
1235         for (i = 0;i < gvar->pm.fi.PMSoundStart;i++)\r
1236         {\r
1237                 if (gvar->pm.PMPages[i].locked)\r
1238                 {\r
1239                         char buf[40];\r
1240                         sprintf(buf,"PM_NextFrame: Page %d is locked",i);\r
1241                         Quit(buf);\r
1242                 }\r
1243         }\r
1244 //#endif\r
1245 \r
1246         if (gvar->pm.PMPanicMode)\r
1247         {\r
1248                 // DEBUG - set border color\r
1249                 if ((!gvar->pm.PMThrashing) && (!--gvar->pm.PMPanicMode))\r
1250                 {\r
1251                         // DEBUG - reset border color\r
1252                 }\r
1253         }\r
1254         if (gvar->pm.PMThrashing >= PMThrashThreshold)\r
1255                 gvar->pm.PMPanicMode = PMUnThrashThreshold;\r
1256         gvar->pm.PMThrashing = false;\r
1257 }\r
1258 \r
1259 //\r
1260 //      PM_Reset() - Sets up caching structures\r
1261 //\r
1262 void\r
1263 PM_Reset(global_game_variables_t *gvar)\r
1264 {\r
1265         int                             i;\r
1266         PageListStruct  far *page;\r
1267 \r
1268         gvar->pm.xmm.XMSPagesAvail = gvar->pm.xmm.XMSAvail / PMPageSizeKB;\r
1269 \r
1270         gvar->pm.emm.EMSPagesAvail = gvar->pm.emm.EMSAvail * (EMSPageSizeKB / PMPageSizeKB);\r
1271         gvar->pm.emm.EMSPhysicalPage = 0;\r
1272 \r
1273         gvar->pm.MainPagesUsed = gvar->pm.EMSPagesUsed = gvar->pm.XMSPagesUsed = 0;\r
1274 \r
1275         gvar->pm.PMPanicMode = false;\r
1276 \r
1277         gvar->pm.fi.PageFile = -1;\r
1278         gvar->pm.xmm.XMSProtectPage = -1;\r
1279 \r
1280         // Initialize page list\r
1281         for (i = 0,page = gvar->pm.PMPages;i < gvar->pm.PMNumBlocks;i++,page++)\r
1282         {\r
1283                 page->mainPage = -1;\r
1284                 page->emsPage = -1;\r
1285                 page->xmsPage = -1;\r
1286                 page->locked = false;\r
1287         }\r
1288 }\r
1289 \r
1290 //\r
1291 //      PM_Startup() - Start up the Page Mgr\r
1292 //\r
1293 void\r
1294 PM_Startup(global_game_variables_t *gvar)\r
1295 {\r
1296         boolean nomain,noems,noxms;\r
1297         int             i;\r
1298 \r
1299         if (gvar->pm.PMStarted)\r
1300                 return;\r
1301 \r
1302         strcat(&(gvar->pm.fi.PageFileName), "VSWAP.");\r
1303 \r
1304         nomain = noems = noxms = false;\r
1305         for (i = 1;i <\r
1306 #ifdef __WATCOMC__\r
1307         __argc\r
1308 #endif\r
1309 #ifdef __BORLANDC__\r
1310         _argc\r
1311 #endif\r
1312         ;i++)\r
1313         {\r
1314                 switch (US_CheckParm(\r
1315 #ifdef __WATCOMC__\r
1316         __argv[i]\r
1317 #endif\r
1318 #ifdef __BORLANDC__\r
1319         _argv[i]\r
1320 #endif\r
1321                 ,ParmStrings))\r
1322                 {\r
1323                 case 0:\r
1324                         nomain = true;\r
1325                         break;\r
1326                 case 1:\r
1327                         noems = true;\r
1328                         break;\r
1329                 case 2:\r
1330                         noxms = true;\r
1331                         break;\r
1332                 }\r
1333         }\r
1334 \r
1335         PML_OpenPageFile(gvar);\r
1336 \r
1337         if (!noems)\r
1338                 PML_StartupEMS(gvar);\r
1339         if (!noxms)\r
1340                 PML_StartupXMS(gvar);\r
1341 \r
1342         if (nomain && !gvar->pm.emm.EMSPresent)\r
1343         {\r
1344                 Quit("PM_Startup: No main or EMS\n");\r
1345                 //return;\r
1346         }\r
1347         else\r
1348                 PML_StartupMainMem(gvar);\r
1349 \r
1350         PM_Reset(gvar);\r
1351 \r
1352         gvar->pm.PMStarted = true;\r
1353 }\r
1354 \r
1355 //\r
1356 //      PM_Shutdown() - Shut down the Page Mgr\r
1357 //\r
1358 void\r
1359 PM_Shutdown(global_game_variables_t *gvar)\r
1360 {\r
1361         PML_ShutdownXMS(gvar);\r
1362         PML_ShutdownEMS(gvar);\r
1363 \r
1364         if (!gvar->pm.PMStarted)\r
1365                 return;\r
1366 \r
1367         PML_ClosePageFile(gvar);\r
1368 \r
1369         PML_ShutdownMainMem(gvar);\r
1370 }\r