示例#1
0
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;
	}