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