ID_MM.C 21 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147
  1. /* Catacomb Armageddon Source Code
  2. * Copyright (C) 1993-2014 Flat Rock Software
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along
  15. * with this program; if not, write to the Free Software Foundation, Inc.,
  16. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  17. */
  18. // NEWMM.C
  19. /*
  20. =============================================================================
  21. ID software memory manager
  22. --------------------------
  23. Primary coder: John Carmack
  24. RELIES ON
  25. ---------
  26. Quit (char *error) function
  27. WORK TO DO
  28. ----------
  29. MM_SizePtr to change the size of a given pointer
  30. Multiple purge levels utilized
  31. EMS / XMS unmanaged routines
  32. =============================================================================
  33. */
  34. #include "ID_HEADS.H"
  35. #pragma hdrstop
  36. #pragma warn -pro
  37. #pragma warn -use
  38. #if 0 // 1 == Debug/Dev ; 0 == Production/final
  39. #define OUT_OF_MEM_MSG "MM_GetPtr: Out of memory!\nYou were short :%ld bytes"
  40. #else
  41. #define OUT_OF_MEM_MSG "\n" \
  42. "You need more memory to run CATACOMB ARMAGEDDON. Read the INSTRUCTION\n" \
  43. "section of the START program for tips on getting more memory.\n"
  44. #endif
  45. /*
  46. =============================================================================
  47. LOCAL INFO
  48. =============================================================================
  49. */
  50. #define LOCKBIT 0x80 // if set in attributes, block cannot be moved
  51. #define PURGEBITS 3 // 0-3 level, 0= unpurgable, 3= purge first
  52. #define PURGEMASK 0xfffc
  53. #define BASEATTRIBUTES 0 // unlocked, non purgable
  54. #define MAXUMBS 10
  55. typedef struct mmblockstruct
  56. {
  57. unsigned start,length;
  58. unsigned attributes;
  59. memptr *useptr; // pointer to the segment start
  60. struct mmblockstruct far *next;
  61. } mmblocktype;
  62. //#define GETNEWBLOCK {if(!(mmnew=mmfree))Quit("MM_GETNEWBLOCK: No free blocks!")\
  63. // ;mmfree=mmfree->next;}
  64. #define GETNEWBLOCK {if(!mmfree)MML_ClearBlock();mmnew=mmfree;mmfree=mmfree->next;}
  65. #define FREEBLOCK(x) {*x->useptr=NULL;x->next=mmfree;mmfree=x;}
  66. /*
  67. =============================================================================
  68. GLOBAL VARIABLES
  69. =============================================================================
  70. */
  71. mminfotype mminfo;
  72. memptr bufferseg;
  73. boolean mmerror;
  74. void (* beforesort) (void);
  75. void (* aftersort) (void);
  76. /*
  77. =============================================================================
  78. LOCAL VARIABLES
  79. =============================================================================
  80. */
  81. boolean mmstarted;
  82. void far *farheap;
  83. void *nearheap;
  84. mmblocktype far mmblocks[MAXBLOCKS]
  85. ,far *mmhead,far *mmfree,far *mmrover,far *mmnew;
  86. boolean bombonerror;
  87. unsigned totalEMSpages,freeEMSpages,EMSpageframe,EMSpagesmapped,EMShandle;
  88. void (* XMSaddr) (void); // far pointer to XMS driver
  89. unsigned numUMBs,UMBbase[MAXUMBS];
  90. //==========================================================================
  91. //
  92. // local prototypes
  93. //
  94. boolean MML_CheckForEMS (void);
  95. void MML_ShutdownEMS (void);
  96. void MM_MapEMS (void);
  97. boolean MML_CheckForXMS (void);
  98. void MML_ShutdownXMS (void);
  99. void MML_UseSpace (unsigned segstart, unsigned seglength);
  100. void MML_ClearBlock (void);
  101. //==========================================================================
  102. /*
  103. ======================
  104. =
  105. = MML_CheckForEMS
  106. =
  107. = Routine from p36 of Extending DOS
  108. =
  109. =======================
  110. */
  111. char emmname[9] = "EMMXXXX0";
  112. boolean MML_CheckForEMS (void)
  113. {
  114. asm mov dx,OFFSET emmname[0]
  115. asm mov ax,0x3d00
  116. asm int 0x21 // try to open EMMXXXX0 device
  117. asm jc error
  118. asm mov bx,ax
  119. asm mov ax,0x4400
  120. asm int 0x21 // get device info
  121. asm jc error
  122. asm and dx,0x80
  123. asm jz error
  124. asm mov ax,0x4407
  125. asm int 0x21 // get status
  126. asm jc error
  127. asm or al,al
  128. asm jz error
  129. asm mov ah,0x3e
  130. asm int 0x21 // close handle
  131. asm jc error
  132. //
  133. // EMS is good
  134. //
  135. return true;
  136. error:
  137. //
  138. // EMS is bad
  139. //
  140. return false;
  141. }
  142. /*
  143. ======================
  144. =
  145. = MML_SetupEMS
  146. =
  147. =======================
  148. */
  149. void MML_SetupEMS (void)
  150. {
  151. char str[80],str2[10];
  152. unsigned error;
  153. totalEMSpages = freeEMSpages = EMSpageframe = EMSpagesmapped = 0;
  154. asm {
  155. mov ah,EMS_STATUS
  156. int EMS_INT // make sure EMS hardware is present
  157. or ah,ah
  158. jnz error
  159. mov ah,EMS_VERSION
  160. int EMS_INT
  161. or ah,ah
  162. jnz error
  163. cmp al,0x32 // only work on ems 3.2 or greater
  164. jb error
  165. mov ah,EMS_GETFRAME
  166. int EMS_INT // find the page frame address
  167. or ah,ah
  168. jnz error
  169. mov [EMSpageframe],bx
  170. mov ah,EMS_GETPAGES
  171. int EMS_INT // find out how much EMS is there
  172. or ah,ah
  173. jnz error
  174. mov [totalEMSpages],dx
  175. mov [freeEMSpages],bx
  176. or bx,bx
  177. jz noEMS // no EMS at all to allocate
  178. cmp bx,4
  179. jle getpages // there is only 1,2,3,or 4 pages
  180. mov bx,4 // we can't use more than 4 pages
  181. }
  182. getpages:
  183. asm {
  184. mov [EMSpagesmapped],bx
  185. mov ah,EMS_ALLOCPAGES // allocate up to 64k of EMS
  186. int EMS_INT
  187. or ah,ah
  188. jnz error
  189. mov [EMShandle],dx
  190. }
  191. return;
  192. error:
  193. error = _AH;
  194. strcpy (str,"MML_SetupEMS: EMS error 0x");
  195. itoa(error,str2,16);
  196. strcpy (str,str2);
  197. Quit (str);
  198. noEMS:
  199. ;
  200. }
  201. /*
  202. ======================
  203. =
  204. = MML_ShutdownEMS
  205. =
  206. =======================
  207. */
  208. void MML_ShutdownEMS (void)
  209. {
  210. if (!EMShandle)
  211. return;
  212. asm {
  213. mov ah,EMS_FREEPAGES
  214. mov dx,[EMShandle]
  215. int EMS_INT
  216. or ah,ah
  217. jz ok
  218. }
  219. Quit ("MML_ShutdownEMS: Error freeing EMS!");
  220. ok:
  221. ;
  222. }
  223. /*
  224. ====================
  225. =
  226. = MM_MapEMS
  227. =
  228. = Maps the 64k of EMS used by memory manager into the page frame
  229. = for general use. This only needs to be called if you are keeping
  230. = other things in EMS.
  231. =
  232. ====================
  233. */
  234. void MM_MapEMS (void)
  235. {
  236. char str[80],str2[10];
  237. unsigned error;
  238. int i;
  239. for (i=0;i<EMSpagesmapped;i++)
  240. {
  241. asm {
  242. mov ah,EMS_MAPPAGE
  243. mov bx,[i] // logical page
  244. mov al,bl // physical page
  245. mov dx,[EMShandle] // handle
  246. int EMS_INT
  247. or ah,ah
  248. jnz error
  249. }
  250. }
  251. return;
  252. error:
  253. error = _AH;
  254. strcpy (str,"MM_MapEMS: EMS error 0x");
  255. itoa(error,str2,16);
  256. strcpy (str,str2);
  257. Quit (str);
  258. }
  259. //==========================================================================
  260. /*
  261. ======================
  262. =
  263. = MML_CheckForXMS
  264. =
  265. = Check for XMM driver
  266. =
  267. =======================
  268. */
  269. boolean MML_CheckForXMS (void)
  270. {
  271. numUMBs = 0;
  272. asm {
  273. mov ax,0x4300
  274. int 0x2f // query status of installed diver
  275. cmp al,0x80
  276. je good
  277. }
  278. return false;
  279. good:
  280. return true;
  281. }
  282. /*
  283. ======================
  284. =
  285. = MML_SetupXMS
  286. =
  287. = Try to allocate all upper memory block
  288. =
  289. =======================
  290. */
  291. void MML_SetupXMS (void)
  292. {
  293. unsigned base,size;
  294. asm {
  295. mov ax,0x4310
  296. int 0x2f
  297. mov [WORD PTR XMSaddr],bx
  298. mov [WORD PTR XMSaddr+2],es // function pointer to XMS driver
  299. }
  300. getmemory:
  301. asm {
  302. mov ah,XMS_ALLOCUMB
  303. mov dx,0xffff // try for largest block possible
  304. call [DWORD PTR XMSaddr]
  305. or ax,ax
  306. jnz gotone
  307. cmp bl,0xb0 // error: smaller UMB is available
  308. jne done;
  309. mov ah,XMS_ALLOCUMB
  310. call [DWORD PTR XMSaddr] // DX holds largest available UMB
  311. or ax,ax
  312. jz done // another error...
  313. }
  314. gotone:
  315. asm {
  316. mov [base],bx
  317. mov [size],dx
  318. }
  319. MML_UseSpace (base,size);
  320. mminfo.XMSmem += size*16;
  321. UMBbase[numUMBs] = base;
  322. numUMBs++;
  323. if (numUMBs < MAXUMBS)
  324. goto getmemory;
  325. done:;
  326. }
  327. /*
  328. ======================
  329. =
  330. = MML_ShutdownXMS
  331. =
  332. ======================
  333. */
  334. void MML_ShutdownXMS (void)
  335. {
  336. int i;
  337. unsigned base;
  338. for (i=0;i<numUMBs;i++)
  339. {
  340. base = UMBbase[i];
  341. asm mov ah,XMS_FREEUMB
  342. asm mov dx,[base]
  343. asm call [DWORD PTR XMSaddr]
  344. }
  345. }
  346. //==========================================================================
  347. /*
  348. ======================
  349. =
  350. = MML_UseSpace
  351. =
  352. = Marks a range of paragraphs as usable by the memory manager
  353. = This is used to mark space for the near heap, far heap, ems page frame,
  354. = and upper memory blocks
  355. =
  356. ======================
  357. */
  358. void MML_UseSpace (unsigned segstart, unsigned seglength)
  359. {
  360. mmblocktype far *scan,far *last;
  361. unsigned oldend;
  362. long extra;
  363. scan = last = mmhead;
  364. mmrover = mmhead; // reset rover to start of memory
  365. //
  366. // search for the block that contains the range of segments
  367. //
  368. while (scan->start+scan->length < segstart)
  369. {
  370. last = scan;
  371. scan = scan->next;
  372. }
  373. //
  374. // take the given range out of the block
  375. //
  376. oldend = scan->start + scan->length;
  377. extra = oldend - (segstart+seglength);
  378. if (extra < 0)
  379. Quit ("MML_UseSpace: Segment spans two blocks!");
  380. if (segstart == scan->start)
  381. {
  382. last->next = scan->next; // unlink block
  383. FREEBLOCK(scan);
  384. scan = last;
  385. }
  386. else
  387. scan->length = segstart-scan->start; // shorten block
  388. if (extra > 0)
  389. {
  390. GETNEWBLOCK;
  391. mmnew->next = scan->next;
  392. scan->next = mmnew;
  393. mmnew->start = segstart+seglength;
  394. mmnew->length = extra;
  395. mmnew->attributes = LOCKBIT;
  396. }
  397. }
  398. //==========================================================================
  399. /*
  400. ====================
  401. =
  402. = MML_ClearBlock
  403. =
  404. = We are out of blocks, so free a purgable block
  405. =
  406. ====================
  407. */
  408. void MML_ClearBlock (void)
  409. {
  410. mmblocktype far *scan,far *last;
  411. scan = mmhead->next;
  412. while (scan)
  413. {
  414. if (!(scan->attributes&LOCKBIT) && (scan->attributes&PURGEBITS) )
  415. {
  416. MM_FreePtr(scan->useptr);
  417. return;
  418. }
  419. scan = scan->next;
  420. }
  421. Quit ("MM_ClearBlock: No purgable blocks!");
  422. }
  423. //==========================================================================
  424. /*
  425. ===================
  426. =
  427. = MM_Startup
  428. =
  429. = Grabs all space from turbo with malloc/farmalloc
  430. = Allocates bufferseg misc buffer
  431. =
  432. ===================
  433. */
  434. static char *ParmStrings[] = {"noems","noxms",""};
  435. void MM_Startup (void)
  436. {
  437. int i;
  438. unsigned long length;
  439. void far *start;
  440. unsigned segstart,seglength,endfree;
  441. if (mmstarted)
  442. MM_Shutdown ();
  443. mmstarted = true;
  444. bombonerror = true;
  445. //
  446. // set up the linked list (everything in the free list;
  447. //
  448. mmhead = NULL;
  449. mmfree = &mmblocks[0];
  450. for (i=0;i<MAXBLOCKS-1;i++)
  451. mmblocks[i].next = &mmblocks[i+1];
  452. mmblocks[i].next = NULL;
  453. //
  454. // locked block of all memory until we punch out free space
  455. //
  456. GETNEWBLOCK;
  457. mmhead = mmnew; // this will allways be the first node
  458. mmnew->start = 0;
  459. mmnew->length = 0xffff;
  460. mmnew->attributes = LOCKBIT;
  461. mmnew->next = NULL;
  462. mmrover = mmhead;
  463. //
  464. // get all available near conventional memory segments
  465. //
  466. length=coreleft();
  467. start = (void far *)(nearheap = malloc(length));
  468. length -= 16-(FP_OFF(start)&15);
  469. length -= SAVENEARHEAP;
  470. seglength = length / 16; // now in paragraphs
  471. segstart = FP_SEG(start)+(FP_OFF(start)+15)/16;
  472. MML_UseSpace (segstart,seglength);
  473. mminfo.nearheap = length;
  474. //
  475. // get all available far conventional memory segments
  476. //
  477. length=farcoreleft();
  478. start = farheap = farmalloc(length);
  479. length -= 16-(FP_OFF(start)&15);
  480. length -= SAVEFARHEAP;
  481. seglength = length / 16; // now in paragraphs
  482. segstart = FP_SEG(start)+(FP_OFF(start)+15)/16;
  483. MML_UseSpace (segstart,seglength);
  484. mminfo.farheap = length;
  485. mminfo.mainmem = mminfo.nearheap + mminfo.farheap;
  486. //
  487. // detect EMS and allocate up to 64K at page frame
  488. //
  489. mminfo.EMSmem = 0;
  490. for (i = 1;i < _argc;i++)
  491. {
  492. if ( US_CheckParm(_argv[i],ParmStrings) == 0)
  493. goto emsskip; // param NOEMS
  494. }
  495. if (MML_CheckForEMS())
  496. {
  497. MML_SetupEMS(); // allocate space
  498. MML_UseSpace (EMSpageframe,EMSpagesmapped*0x400);
  499. MM_MapEMS(); // map in used pages
  500. mminfo.EMSmem = EMSpagesmapped*0x4000l;
  501. }
  502. //
  503. // detect XMS and get upper memory blocks
  504. //
  505. emsskip:
  506. mminfo.XMSmem = 0;
  507. for (i = 1;i < _argc;i++)
  508. {
  509. if ( US_CheckParm(_argv[i],ParmStrings) == 0)
  510. goto xmsskip; // param NOXMS
  511. }
  512. if (MML_CheckForXMS())
  513. MML_SetupXMS(); // allocate as many UMBs as possible
  514. //
  515. // allocate the misc buffer
  516. //
  517. xmsskip:
  518. mmrover = mmhead; // start looking for space after low block
  519. MM_GetPtr (&bufferseg,BUFFERSIZE);
  520. }
  521. //==========================================================================
  522. /*
  523. ====================
  524. =
  525. = MM_Shutdown
  526. =
  527. = Frees all conventional, EMS, and XMS allocated
  528. =
  529. ====================
  530. */
  531. void MM_Shutdown (void)
  532. {
  533. if (!mmstarted)
  534. return;
  535. farfree (farheap);
  536. free (nearheap);
  537. MML_ShutdownEMS ();
  538. MML_ShutdownXMS ();
  539. }
  540. //==========================================================================
  541. /*
  542. ====================
  543. =
  544. = MM_GetPtr
  545. =
  546. = Allocates an unlocked, unpurgable block
  547. =
  548. ====================
  549. */
  550. void MM_GetPtr (memptr *baseptr,unsigned long size)
  551. {
  552. mmblocktype far *scan,far *lastscan,far *endscan
  553. ,far *purge,far *next;
  554. int search;
  555. unsigned needed,startseg;
  556. needed = (size+15)/16; // convert size from bytes to paragraphs
  557. GETNEWBLOCK; // fill in start and next after a spot is found
  558. mmnew->length = needed;
  559. mmnew->useptr = baseptr;
  560. mmnew->attributes = BASEATTRIBUTES;
  561. for (search = 0; search<3; search++)
  562. {
  563. //
  564. // first search: try to allocate right after the rover, then on up
  565. // second search: search from the head pointer up to the rover
  566. // third search: compress memory, then scan from start
  567. if (search == 1 && mmrover == mmhead)
  568. search++;
  569. switch (search)
  570. {
  571. case 0:
  572. lastscan = mmrover;
  573. scan = mmrover->next;
  574. endscan = NULL;
  575. break;
  576. case 1:
  577. lastscan = mmhead;
  578. scan = mmhead->next;
  579. endscan = mmrover;
  580. break;
  581. case 2:
  582. MM_SortMem ();
  583. lastscan = mmhead;
  584. scan = mmhead->next;
  585. endscan = NULL;
  586. break;
  587. }
  588. startseg = lastscan->start + lastscan->length;
  589. while (scan != endscan)
  590. {
  591. if (scan->start - startseg >= needed)
  592. {
  593. //
  594. // got enough space between the end of lastscan and
  595. // the start of scan, so throw out anything in the middle
  596. // and allocate the new block
  597. //
  598. purge = lastscan->next;
  599. lastscan->next = mmnew;
  600. mmnew->start = *(unsigned *)baseptr = startseg;
  601. mmnew->next = scan;
  602. while ( purge != scan)
  603. { // free the purgable block
  604. next = purge->next;
  605. FREEBLOCK(purge);
  606. purge = next; // purge another if not at scan
  607. }
  608. mmrover = mmnew;
  609. return; // good allocation!
  610. }
  611. //
  612. // if this block is purge level zero or locked, skip past it
  613. //
  614. if ( (scan->attributes & LOCKBIT)
  615. || !(scan->attributes & PURGEBITS) )
  616. {
  617. lastscan = scan;
  618. startseg = lastscan->start + lastscan->length;
  619. }
  620. scan=scan->next; // look at next line
  621. }
  622. }
  623. if (bombonerror)
  624. Quit (OUT_OF_MEM_MSG,(size-mminfo.nearheap));
  625. else
  626. mmerror = true;
  627. }
  628. //==========================================================================
  629. /*
  630. ====================
  631. =
  632. = MM_FreePtr
  633. =
  634. = Allocates an unlocked, unpurgable block
  635. =
  636. ====================
  637. */
  638. void MM_FreePtr (memptr *baseptr)
  639. {
  640. mmblocktype far *scan,far *last;
  641. last = mmhead;
  642. scan = last->next;
  643. if (baseptr == mmrover->useptr) // removed the last allocated block
  644. mmrover = mmhead;
  645. while (scan->useptr != baseptr && scan)
  646. {
  647. last = scan;
  648. scan = scan->next;
  649. }
  650. if (!scan)
  651. Quit ("MM_FreePtr: Block not found!");
  652. last->next = scan->next;
  653. FREEBLOCK(scan);
  654. }
  655. //==========================================================================
  656. /*
  657. =====================
  658. =
  659. = MM_SetPurge
  660. =
  661. = Sets the purge level for a block (locked blocks cannot be made purgable)
  662. =
  663. =====================
  664. */
  665. void MM_SetPurge (memptr *baseptr, int purge)
  666. {
  667. mmblocktype far *start;
  668. start = mmrover;
  669. do
  670. {
  671. if (mmrover->useptr == baseptr)
  672. break;
  673. mmrover = mmrover->next;
  674. if (!mmrover)
  675. mmrover = mmhead;
  676. else if (mmrover == start)
  677. Quit ("MM_SetPurge: Block not found!");
  678. } while (1);
  679. mmrover->attributes &= ~PURGEBITS;
  680. mmrover->attributes |= purge;
  681. }
  682. //==========================================================================
  683. /*
  684. =====================
  685. =
  686. = MM_SetLock
  687. =
  688. = Locks / unlocks the block
  689. =
  690. =====================
  691. */
  692. void MM_SetLock (memptr *baseptr, boolean locked)
  693. {
  694. mmblocktype far *start;
  695. start = mmrover;
  696. do
  697. {
  698. if (mmrover->useptr == baseptr)
  699. break;
  700. mmrover = mmrover->next;
  701. if (!mmrover)
  702. mmrover = mmhead;
  703. else if (mmrover == start)
  704. Quit ("MM_SetLock: Block not found!");
  705. } while (1);
  706. mmrover->attributes &= ~LOCKBIT;
  707. mmrover->attributes |= locked*LOCKBIT;
  708. }
  709. //==========================================================================
  710. /*
  711. =====================
  712. =
  713. = MM_SortMem
  714. =
  715. = Throws out all purgable stuff and compresses movable blocks
  716. =
  717. =====================
  718. */
  719. void MM_SortMem (void)
  720. {
  721. mmblocktype far *scan,far *last,far *next;
  722. unsigned start,length,source,dest,oldborder;
  723. int playing;
  724. //
  725. // lock down a currently playing sound
  726. //
  727. playing = SD_SoundPlaying ();
  728. if (playing)
  729. {
  730. switch (SoundMode)
  731. {
  732. case sdm_PC:
  733. playing += STARTPCSOUNDS;
  734. break;
  735. case sdm_AdLib:
  736. playing += STARTADLIBSOUNDS;
  737. break;
  738. }
  739. MM_SetLock(&(memptr)audiosegs[playing],true);
  740. }
  741. SD_StopSound();
  742. // oldborder = bordercolor;
  743. // VW_ColorBorder (15);
  744. if (beforesort)
  745. beforesort();
  746. scan = mmhead;
  747. last = NULL; // shut up compiler warning
  748. while (scan)
  749. {
  750. if (scan->attributes & LOCKBIT)
  751. {
  752. //
  753. // block is locked, so try to pile later blocks right after it
  754. //
  755. start = scan->start + scan->length;
  756. }
  757. else
  758. {
  759. if (scan->attributes & PURGEBITS)
  760. {
  761. //
  762. // throw out the purgable block
  763. //
  764. next = scan->next;
  765. FREEBLOCK(scan);
  766. last->next = next;
  767. scan = next;
  768. continue;
  769. }
  770. else
  771. {
  772. //
  773. // push the non purgable block on top of the last moved block
  774. //
  775. if (scan->start != start)
  776. {
  777. length = scan->length;
  778. source = scan->start;
  779. dest = start;
  780. while (length > 0xf00)
  781. {
  782. movedata(source,0,dest,0,0xf00*16);
  783. length -= 0xf00;
  784. source += 0xf00;
  785. dest += 0xf00;
  786. }
  787. movedata(source,0,dest,0,length*16);
  788. scan->start = start;
  789. *(unsigned *)scan->useptr = start;
  790. }
  791. start = scan->start + scan->length;
  792. }
  793. }
  794. last = scan;
  795. scan = scan->next; // go to next block
  796. }
  797. mmrover = mmhead;
  798. if (aftersort)
  799. aftersort();
  800. // VW_ColorBorder (oldborder);
  801. if (playing)
  802. MM_SetLock(&(memptr)audiosegs[playing],false);
  803. }
  804. //==========================================================================
  805. #if 0
  806. /*
  807. =====================
  808. =
  809. = MM_ShowMemory
  810. =
  811. =====================
  812. */
  813. void MM_ShowMemory (void)
  814. {
  815. mmblocktype far *scan;
  816. unsigned color,temp;
  817. long end,owner;
  818. char scratch[80],str[10];
  819. VW_SetDefaultColors();
  820. VW_SetLineWidth(40);
  821. temp = bufferofs;
  822. bufferofs = 0;
  823. VW_SetScreen (0,0);
  824. scan = mmhead;
  825. end = -1;
  826. //CA_OpenDebug ();
  827. while (scan)
  828. {
  829. if (scan->attributes & PURGEBITS)
  830. color = 5; // dark purple = purgable
  831. else
  832. color = 9; // medium blue = non purgable
  833. if (scan->attributes & LOCKBIT)
  834. color = 12; // red = locked
  835. if (scan->start<=end)
  836. Quit ("MM_ShowMemory: Memory block order currupted!");
  837. end = scan->start+scan->length-1;
  838. VW_Hlin(scan->start,(unsigned)end,0,color);
  839. VW_Plot(scan->start,0,15);
  840. if (scan->next->start > end+1)
  841. VW_Hlin(end+1,scan->next->start,0,0); // black = free
  842. #if 0
  843. strcpy (scratch,"Size:");
  844. ltoa ((long)scan->length*16,str,10);
  845. strcat (scratch,str);
  846. strcat (scratch,"\tOwner:0x");
  847. owner = (unsigned)scan->useptr;
  848. ultoa (owner,str,16);
  849. strcat (scratch,str);
  850. strcat (scratch,"\n");
  851. write (debughandle,scratch,strlen(scratch));
  852. #endif
  853. scan = scan->next;
  854. }
  855. //CA_CloseDebug ();
  856. IN_Ack();
  857. VW_SetLineWidth(64);
  858. bufferofs = temp;
  859. }
  860. #endif
  861. //==========================================================================
  862. /*
  863. ======================
  864. =
  865. = MM_UnusedMemory
  866. =
  867. = Returns the total free space without purging
  868. =
  869. ======================
  870. */
  871. long MM_UnusedMemory (void)
  872. {
  873. unsigned free;
  874. mmblocktype far *scan;
  875. free = 0;
  876. scan = mmhead;
  877. while (scan->next)
  878. {
  879. free += scan->next->start - (scan->start + scan->length);
  880. scan = scan->next;
  881. }
  882. return free*16l;
  883. }
  884. //==========================================================================
  885. /*
  886. ======================
  887. =
  888. = MM_TotalFree
  889. =
  890. = Returns the total free space with purging
  891. =
  892. ======================
  893. */
  894. long MM_TotalFree (void)
  895. {
  896. unsigned free;
  897. mmblocktype far *scan;
  898. free = 0;
  899. scan = mmhead;
  900. while (scan->next)
  901. {
  902. if ((scan->attributes&PURGEBITS) && !(scan->attributes&LOCKBIT))
  903. free += scan->length;
  904. free += scan->next->start - (scan->start + scan->length);
  905. scan = scan->next;
  906. }
  907. return free*16l;
  908. }
  909. //==========================================================================
  910. /*
  911. =====================
  912. =
  913. = MM_BombOnError
  914. =
  915. =====================
  916. */
  917. void MM_BombOnError (boolean bomb)
  918. {
  919. bombonerror = bomb;
  920. }