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; }
static void DOS_CompressMemory(void) { Bit16u mcb_segment = dos.firstMCB; DOS_MCB mcb(mcb_segment); DOS_MCB mcb_next(0); Bitu counter = 0; while (mcb.GetType() != 'Z') { if (counter++ > 1000) E_Exit("DOS MCB list corrupted."); mcb_next.SetPt((Bit16u)(mcb_segment+mcb.GetSize()+1)); if ((mcb.GetPSPSeg() == MCB_FREE) && (mcb_next.GetPSPSeg() == MCB_FREE)) { mcb.SetSize(mcb.GetSize()+mcb_next.GetSize()+1); mcb.SetType(mcb_next.GetType()); } else { mcb_segment += mcb.GetSize()+1; mcb.SetPt(mcb_segment); if (mcb.GetType() == 'Z' && mcb_segment < EndConvMem && dos_infoblock.GetStartOfUMBChain() == EndConvMem) // to UMB if used { mcb_segment = EndConvMem; mcb.SetPt(mcb_segment); } } } }
static void DOS_CompressMemory(void) { Bit16u mcb_segment=dos.firstMCB; DOS_MCB mcb(mcb_segment); DOS_MCB mcb_next(0); while (mcb.GetType()!=0x5a) { mcb_next.SetPt((Bit16u)(mcb_segment+mcb.GetSize()+1)); if ((mcb.GetPSPSeg()==0) && (mcb_next.GetPSPSeg()==0)) { mcb.SetSize(mcb.GetSize()+mcb_next.GetSize()+1); mcb.SetType(mcb_next.GetType()); } else { mcb_segment+=mcb.GetSize()+1; mcb.SetPt(mcb_segment); } } }
static void DOS_CompressMemory(void) { Bit16u mcb_segment=dos.firstMCB; DOS_MCB mcb(mcb_segment); DOS_MCB mcb_next(0); while (mcb.GetType()!=0x5a) { mcb_next.SetPt((Bit16u)(mcb_segment+mcb.GetSize()+1)); if (GCC_UNLIKELY((mcb_next.GetType()!=0x4d) && (mcb_next.GetType()!=0x5a))) E_Exit("Corrupt MCB chain"); if ((mcb.GetPSPSeg()==MCB_FREE) && (mcb_next.GetPSPSeg()==MCB_FREE)) { mcb.SetSize(mcb.GetSize()+mcb_next.GetSize()+1); mcb.SetType(mcb_next.GetType()); } else { mcb_segment+=mcb.GetSize()+1; mcb.SetPt(mcb_segment); } } }
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_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; }
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; }