bool DOS_AllocateMemory(Bit16u * segment,Bit16u * blocks) { DOS_CompressMemory(); Bit16u bigsize=0; Bit16u mem_strat=memAllocStrategy; Bit16u mcb_segment=dos.firstMCB; Bit16u umb_start=dos_infoblock.GetStartOfUMBChain(); if (umb_start==UMB_START_SEG) { /* start with UMBs if requested (bits 7 or 6 set) */ if (mem_strat&0xc0) mcb_segment=umb_start; } else if (umb_start!=0xffff) LOG(LOG_DOSMISC,LOG_ERROR)("Corrupt UMB chain: %x",umb_start); DOS_MCB mcb(0); DOS_MCB mcb_next(0); DOS_MCB psp_mcb(dos.psp()-1); char psp_name[9]; psp_mcb.GetFileName(psp_name); Bit16u found_seg=0,found_seg_size=0; for (;;) { mcb.SetPt(mcb_segment); if (mcb.GetPSPSeg()==MCB_FREE) { /* Check for enough free memory in current block */ Bit16u block_size=mcb.GetSize(); if (block_size<(*blocks)) { if (bigsize<block_size) { /* current block is largest block that was found, but still not as big as requested */ bigsize=block_size; } } else if ((block_size==*blocks) && ((mem_strat & 0x3f)<2)) { /* MCB fits precisely, use it if search strategy is firstfit or bestfit */ mcb.SetPSPSeg(dos.psp()); *segment=mcb_segment+1; return true; } else { switch (mem_strat & 0x3f) { case 0: /* firstfit */ mcb_next.SetPt((Bit16u)(mcb_segment+*blocks+1)); mcb_next.SetPSPSeg(MCB_FREE); mcb_next.SetType(mcb.GetType()); mcb_next.SetSize(block_size-*blocks-1); mcb.SetSize(*blocks); mcb.SetType(0x4d); mcb.SetPSPSeg(dos.psp()); mcb.SetFileName(psp_name); //TODO Filename *segment=mcb_segment+1; return true; case 1: /* bestfit */ if ((found_seg_size==0) || (block_size<found_seg_size)) { /* first fitting MCB, or smaller than the last that was found */ found_seg=mcb_segment; found_seg_size=block_size; } break; default: /* everything else is handled as lastfit by dos */ /* MCB is large enough, note it down */ found_seg=mcb_segment; found_seg_size=block_size; break; } } } /* Onward to the next MCB if there is one */ if (mcb.GetType()==0x5a) { if ((mem_strat&0x80) && (umb_start==UMB_START_SEG)) { /* bit 7 set: try high memory first, then low */ mcb_segment=dos.firstMCB; mem_strat&=(~0xc0); } else { /* finished searching all requested MCB chains */ if (found_seg) { /* a matching MCB was found (cannot occur for firstfit) */ if ((mem_strat & 0x3f)==0x01) { /* bestfit, allocate block at the beginning of the MCB */ mcb.SetPt(found_seg); mcb_next.SetPt((Bit16u)(found_seg+*blocks+1)); mcb_next.SetPSPSeg(MCB_FREE); mcb_next.SetType(mcb.GetType()); mcb_next.SetSize(found_seg_size-*blocks-1); mcb.SetSize(*blocks); mcb.SetType(0x4d); mcb.SetPSPSeg(dos.psp()); mcb.SetFileName(psp_name); //TODO Filename *segment=found_seg+1; } else { /* lastfit, allocate block at the end of the MCB */ mcb.SetPt(found_seg); if (found_seg_size==*blocks) { /* use the whole block */ mcb.SetPSPSeg(dos.psp()); //Not consistent with line 124. But how many application will use this information ? mcb.SetFileName(psp_name); *segment = found_seg+1; return true; } *segment = found_seg+1+found_seg_size - *blocks; mcb_next.SetPt((Bit16u)(*segment-1)); mcb_next.SetSize(*blocks); mcb_next.SetType(mcb.GetType()); mcb_next.SetPSPSeg(dos.psp()); mcb_next.SetFileName(psp_name); // Old Block mcb.SetSize(found_seg_size-*blocks-1); mcb.SetPSPSeg(MCB_FREE); mcb.SetType(0x4D); } return true; } /* no fitting MCB found, return size of largest block */ *blocks=bigsize; DOS_SetError(DOSERR_INSUFFICIENT_MEMORY); return false; } } else mcb_segment+=mcb.GetSize()+1; } return false; }
bool DOS_AllocateMemory(Bit16u * segment, Bit16u * reqBlocks) { DOS_CompressMemory(); // Mainly to check the NCB chain Bit16u bigsize = 0; Bit16u mem_strat = memAllocStrategy; Bit16u mcb_segment = dos.firstMCB; Bit16u umb_start = dos_infoblock.GetStartOfUMBChain(); if (umb_start == EndConvMem && (mem_strat&0xc0)) // Start with UMBs if requested (bits 7 or 6 set) mcb_segment = umb_start; DOS_MCB mcb(0); DOS_MCB mcb_next(0); DOS_MCB psp_mcb(dos.psp()-1); char psp_name[9]; psp_mcb.GetFileName(psp_name); Bit16u foundSeg = 0, foundSize = 0; for (;;) { mcb.SetPt(mcb_segment); if (mcb.GetPSPSeg() == MCB_FREE) { Bit16u block_size = mcb.GetSize(); if (block_size < (*reqBlocks)) // Check for enough free memory in current block { if (bigsize < block_size) // Current block is largest block that was found, but still not as big as requested bigsize = block_size; } else if ((block_size == *reqBlocks) && ((mem_strat & 0x3f) < 2)) // MCB fits precisely, use it if search strategy is firstfit or bestfit { mcb.SetPSPSeg(dos.psp()); mcb.SetFileName(psp_name); *segment = mcb_segment+1; return true; } else // Found block is larger than requested { switch (mem_strat & 0x3f) { case 0: // Firstfit mcb_next.SetPt((Bit16u)(mcb_segment+*reqBlocks+1)); mcb_next.SetPSPSeg(MCB_FREE); mcb_next.SetType(mcb.GetType()); mcb_next.SetSize(block_size-*reqBlocks-1); mcb.SetSize(*reqBlocks); mcb.SetType('M'); mcb.SetPSPSeg(dos.psp()); mcb.SetFileName(psp_name); *segment = mcb_segment+1; return true; case 1: // Bestfit if ((foundSize == 0) || (block_size < foundSize)) // First fitting MCB, or smaller than the last that was found { foundSeg = mcb_segment; foundSize = block_size; } break; default: // Everything else is handled as lastfit by DOS foundSeg = mcb_segment; // MCB is large enough, note it down foundSize = block_size; break; } } } if (mcb.GetType() == 'Z') // Onward to the next MCB if there is one { if ((mem_strat&0x80) && (umb_start == EndConvMem)) { mcb_segment = dos.firstMCB; // Bit 7 set: try upper memory first, then low mem_strat &= (~0xc0); } else // Finished searching all requested MCB chains { if (foundSeg) // A matching MCB was found (cannot occur for firstfit) { if ((mem_strat & 0x3f) == 1) // Bestfit, allocate block at the beginning of the MCB { mcb.SetPt(foundSeg); mcb_next.SetPt((Bit16u)(foundSeg+*reqBlocks+1)); mcb_next.SetPSPSeg(MCB_FREE); mcb_next.SetType(mcb.GetType()); mcb_next.SetSize(foundSize-*reqBlocks-1); mcb.SetSize(*reqBlocks); mcb.SetType('M'); mcb.SetPSPSeg(dos.psp()); mcb.SetFileName(psp_name); *segment = foundSeg+1; } else // Lastfit, allocate block at the end of the MCB { mcb.SetPt(foundSeg); if (foundSize == *reqBlocks) // If requested size { mcb.SetPSPSeg(dos.psp()); mcb.SetFileName(psp_name); *segment = foundSize+1; return true; } *segment = foundSeg+1+foundSize-*reqBlocks; mcb_next.SetPt((Bit16u)(*segment-1)); mcb_next.SetSize(*reqBlocks); mcb_next.SetType(mcb.GetType()); mcb_next.SetPSPSeg(dos.psp()); mcb_next.SetFileName(psp_name); mcb.SetSize(foundSize-*reqBlocks-1); mcb.SetPSPSeg(MCB_FREE); mcb.SetType('M'); } return true; } *reqBlocks = bigsize; // No fitting MCB found, return size of largest block DOS_SetError(DOSERR_INSUFFICIENT_MEMORY); return false; } } else mcb_segment += mcb.GetSize()+1; } return false; }