Пример #1
0
bool DOS_ResizeMemory(Bit16u segment, Bit16u * blocks)
	{
	if (segment < DOS_MEM_START+1)
		E_Exit("Program tried to resize MCB block %X", segment);
	DOS_MCB mcb(segment-1);
	Bit8u mcb_type = mcb.GetType();
	if (mcb_type != 'M' && mcb_type != 'Z')
		{
		DOS_SetError(DOSERR_MCB_DESTROYED);
		return false;
		}

	Bit16u total = mcb.GetSize();
	if (*blocks == total)															// Same size, nothing to do
		return true;
	if (*blocks < total)															// Shrinking MCB
		{
		DOS_MCB	mcb_next(segment+(*blocks));
		mcb_next.SetType(mcb_type);
		mcb_next.SetSize(total-*blocks-1);
		mcb_next.SetPSPSeg(MCB_FREE);
		mcb.SetSize(*blocks);
		mcb.SetType('M');															// Further blocks follow
		DOS_CompressMemory();
		return true;
		}

	DOS_MCB	mcb_next(segment+total);												// MCB will grow, try to join with following MCB
	DOS_CompressMemory();
	if (mcb_type != 'Z' && mcb_next.GetPSPSeg() == MCB_FREE)
		{
		total += mcb_next.GetSize()+1;
		mcb_type = mcb_next.GetType();
		if (*blocks == total)
			{
			mcb.SetType(mcb_type);
			mcb.SetSize(*blocks);
			return true;
			}
		if (*blocks < total)
			{
			mcb_next.SetPt((Bit16u)(segment+*blocks));
			mcb_next.SetSize(total-*blocks-1);
			mcb_next.SetType(mcb_type);
			mcb_next.SetPSPSeg(MCB_FREE);
			mcb.SetSize(*blocks);
			mcb.SetType('M');
			return true;
			}
		}
	mcb.SetType(mcb_type);															// Not the required blocks available
	mcb.SetSize(total);
	*blocks = total;																// Return maximum
	DOS_SetError(DOSERR_INSUFFICIENT_MEMORY);
	return false;
	}
Пример #2
0
void DOS_FreeProcessMemory(Bit16u pspseg) {
	Bit16u mcb_segment=dos.firstMCB;
	DOS_MCB mcb(mcb_segment);
	for (;;) {
		if (mcb.GetPSPSeg()==pspseg) {
			mcb.SetPSPSeg(MCB_FREE);
		}
		if (mcb.GetType()==0x5a) {
			/* check if currently last block reaches up to the PCJr graphics memory */
			if ((machine==MCH_PCJR) && (mcb_segment+mcb.GetSize()==0x17fe) &&
			   (real_readb(0x17ff,0)==0x4d) && (real_readw(0x17ff,1)==8)) {
				/* re-enable the memory past segment 0x2000 */
				mcb.SetType(0x4d);
			} else break;
		}
		if (GCC_UNLIKELY(mcb.GetType()!=0x4d)) E_Exit("Corrupt MCB chain");
		mcb_segment+=mcb.GetSize()+1;
		mcb.SetPt(mcb_segment);
	}

	Bit16u umb_start=dos_infoblock.GetStartOfUMBChain();
	if (umb_start==UMB_START_SEG) {
		DOS_MCB umb_mcb(umb_start);
		for (;;) {
			if (umb_mcb.GetPSPSeg()==pspseg) {
				umb_mcb.SetPSPSeg(MCB_FREE);
			}
			if (umb_mcb.GetType()!=0x4d) break;
			umb_start+=umb_mcb.GetSize()+1;
			umb_mcb.SetPt(umb_start);
		}
	} else if (umb_start!=0xffff) LOG(LOG_DOSMISC,LOG_ERROR)("Corrupt UMB chain: %x",umb_start);

	DOS_CompressMemory();
}
Пример #3
0
bool DOS_GetFreeUMB(Bit16u * total, Bit16u * largest, Bit16u * count)
	{
	*total = *largest = *count = 0;
	Bit16u mcb_segment = dos_infoblock.GetStartOfUMBChain();
	if (mcb_segment != EndConvMem)
		return false;

	DOS_CompressMemory();
	DOS_MCB mcb(mcb_segment);
	while (1)
		{
		Bit16u mcb_size = mcb.GetSize();
		if (mcb.GetPSPSeg() == MCB_FREE)
			{
			*count += 1;
			*total += mcb_size;
			if (*largest < mcb_size)
				*largest = mcb_size;
			}
		if (mcb.GetType() == 'Z')
			break;
		mcb_segment += mcb_size+1;
		mcb.SetPt(mcb_segment);
		}
	return true;
	}
bool DOS_FreeMemory(Bit16u segment) {
//TODO Check if allowed to free this segment
	if (segment < DOS_MEM_START+1) {
		LOG(LOG_DOSMISC,LOG_ERROR)("Program tried to free %X ---ERROR",segment);
		DOS_SetError(DOSERR_MB_ADDRESS_INVALID);
		return false;
	}
      
	DOS_MCB mcb(segment-1);
	if ((mcb.GetType()!=0x4d) && (mcb.GetType()!=0x5a)) {
		DOS_SetError(DOSERR_MB_ADDRESS_INVALID);
		return false;
	}
	mcb.SetPSPSeg(MCB_FREE);
	DOS_CompressMemory();
	return true;
}
Пример #5
0
void DOS_FreeProcessMemory(Bit16u pspseg)
	{
	Bit16u mcb_segment = dos.firstMCB;
	DOS_MCB mcb(mcb_segment);

	for (int counter = 0; ; )
		{
		if (counter++ > 10000)
			E_Exit("DOS MCB list corrupted.");
		if (mcb.GetPSPSeg() == pspseg)
			mcb.SetPSPSeg(MCB_FREE);
		if (mcb.GetType() == 'Z')
			if (mcb_segment < EndConvMem && dos_infoblock.GetStartOfUMBChain() == EndConvMem)	// to UMB if used
				mcb_segment = EndConvMem;
			else
				break;
		else
			mcb_segment += mcb.GetSize()+1;
		mcb.SetPt(mcb_segment);
		}
	DOS_CompressMemory();
	}
Пример #6
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;
}
Пример #7
0
bool DOS_ResizeMemory(Bit16u segment,Bit16u * blocks) {
	if (segment < DOS_MEM_START+1) {
		LOG(LOG_DOSMISC,LOG_ERROR)("Program resizes %X, take care",segment);
	}
      
	DOS_MCB mcb(segment-1);
	if ((mcb.GetType()!=0x4d) && (mcb.GetType()!=0x5a)) {
		DOS_SetError(DOSERR_MCB_DESTROYED);
		return false;
	}

	DOS_CompressMemory();
	Bit16u total=mcb.GetSize();
	DOS_MCB	mcb_next(segment+total);
	if (*blocks<=total) {
		if (GCC_UNLIKELY(*blocks==total)) {
			/* Nothing to do */
			return true;
		}
		/* Shrinking MCB */
		DOS_MCB	mcb_new_next(segment+(*blocks));
		mcb.SetSize(*blocks);
		mcb_new_next.SetType(mcb.GetType());
		if (mcb.GetType()==0x5a) {
			/* Further blocks follow */
			mcb.SetType(0x4d);
		}

		mcb_new_next.SetSize(total-*blocks-1);
		mcb_new_next.SetPSPSeg(MCB_FREE);
		mcb.SetPSPSeg(dos.psp());
		DOS_CompressMemory();
		return true;
	}
	/* MCB will grow, try to join with following MCB */
	if (mcb.GetType()!=0x5a) {
		if (mcb_next.GetPSPSeg()==MCB_FREE) {
			total+=mcb_next.GetSize()+1;
		}
	}
	if (*blocks<total) {
		if (mcb.GetType()!=0x5a) {
			/* save type of following MCB */
			mcb.SetType(mcb_next.GetType());
		}
		mcb.SetSize(*blocks);
		mcb_next.SetPt((Bit16u)(segment+*blocks));
		mcb_next.SetSize(total-*blocks-1);
		mcb_next.SetType(mcb.GetType());
		mcb_next.SetPSPSeg(MCB_FREE);
		mcb.SetType(0x4d);
		mcb.SetPSPSeg(dos.psp());
		return true;
	}

	/* at this point: *blocks==total (fits) or *blocks>total,
	   in the second case resize block to maximum */

	if ((mcb_next.GetPSPSeg()==MCB_FREE) && (mcb.GetType()!=0x5a)) {
		/* adjust type of joined MCB */
		mcb.SetType(mcb_next.GetType());
	}
	mcb.SetSize(total);
	mcb.SetPSPSeg(dos.psp());
	if (*blocks==total) return true;	/* block fit exactly */

	*blocks=total;	/* return maximum */
	DOS_SetError(DOSERR_INSUFFICIENT_MEMORY);
	return false;
}
Пример #8
0
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;
	}