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(); }
void UnMount(int i_drive) { if (dos_kernel_disabled) return; i_drive = toupper(i_drive); if(i_drive-'A' == DOS_GetDefaultDrive()) { DOS_MCB mcb(dos.psp()-1); static char name[9]; mcb.GetFileName(name); if (!strlen(name)) goto umount; LOG_MSG("GUI:Drive %c is being used. Aborted.",i_drive); return; }; umount: if (i_drive-'A' < DOS_DRIVES && i_drive-'A' >= 0 && Drives[i_drive-'A']) { switch (DriveManager::UnmountDrive(i_drive-'A')) { case 0: Drives[i_drive-'A'] = 0; if(i_drive-'A' == DOS_GetDefaultDrive()) DOS_SetDrive(toupper('Z') - 'A'); LOG_MSG("GUI:Drive %c has succesfully been removed.",i_drive); break; case 1: LOG_MSG("GUI:Virtual Drives can not be unMOUNTed."); break; case 2: LOG_MSG(MSCDEX_Output(1).c_str()); break; } } }
void DOS_BuildUMBChain() { Bit16u first_umb_seg = DOS_PRIVATE_SEGMENT_END; Bit16u first_umb_size = 0xf000 - first_umb_seg - (TotEMSMB ? 0x1000 : 0); dos_infoblock.SetStartOfUMBChain(EndConvMem); dos_infoblock.SetUMBChainState(0); // UMBs not linked yet DOS_MCB umb_mcb(first_umb_seg); umb_mcb.SetPSPSeg(MCB_FREE); // Currently free umb_mcb.SetSize(first_umb_size-1); umb_mcb.SetType('Z'); Bit16u mcb_segment = dos.firstMCB; // Scan MCB-chain for last block DOS_MCB mcb(mcb_segment); while (mcb.GetType() != 'Z') { mcb_segment += mcb.GetSize()+1; mcb.SetPt(mcb_segment); } Bit16u cover_mcb = (Bit16u)(mcb_segment+mcb.GetSize()+1); // A system MCB has to cover the space between the regular MCB-chain and the UMBs mcb.SetPt(cover_mcb); mcb.SetType('M'); mcb.SetPSPSeg(0x0008); mcb.SetSize(first_umb_seg-cover_mcb-1); mcb.SetFileName("SC "); }
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); } } } }
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; }
void DOS_UpdatePSPName(void) { DOS_MCB mcb(dos.psp()-1); static char name[9]; mcb.GetFileName(name); if (!strlen(name)) strcpy(name,"DOSBOX"); RunningProgram=name; GFX_SetTitle(-1,-1,false); }
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; }
bool DOS_FreeMemory(Bit16u segment) { // TODO Check if allowed to free this segment if (segment < DOS_MEM_START+1) E_Exit("Program tried to free MCB block %X", segment); DOS_MCB mcb(segment-1); if (mcb.GetType() != 'M' && mcb.GetType() != 'Z') { DOS_SetError(DOSERR_MB_ADDRESS_INVALID); return false; } mcb.SetPSPSeg(MCB_FREE); // DOS_CompressMemory(); return true; }
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); } } }
void SetVal(const std::string secname, std::string preval, const std::string val) { if(preval=="keyboardlayout" && !dos_kernel_disabled) { DOS_MCB mcb(dos.psp()-1); static char name[9]; mcb.GetFileName(name); if (strlen(name)) { LOG_MSG("GUI: Exit %s running in DOSBox, and then try again.",name); return; } } Section* sec = control->GetSection(secname); if(sec) { std::string real_val=preval+"="+val; sec->HandleInputline(real_val); } }
static void SetupPSP(Bit16u pspseg,Bit16u memsize,Bit16u envseg) { /* Fix the PSP for psp and environment MCB's */ DOS_MCB mcb((Bit16u)(pspseg-1)); mcb.SetPSPSeg(pspseg); mcb.SetPt((Bit16u)(envseg-1)); mcb.SetPSPSeg(pspseg); DOS_PSP psp(pspseg); psp.MakeNew(memsize); psp.SetEnvironment(envseg); /* Copy file handles */ DOS_PSP oldpsp(dos.psp()); psp.CopyFileTable(&oldpsp,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; }
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); } } }
void DOS_SetupMemory(bool low) { /* Let DOS claim a few bios interrupts. Makes vDos more compatible with * buggy games, which compare against the interrupt table. (probably a * broken linked list implementation) */ Bitu cbID = CALLBACK_Allocate(); // DOS default int CALLBACK_Setup(cbID, &DOS_default_handler, CB_IRET, 0x708); RealSetVec(0x01, 0x700008); RealSetVec(0x03, 0x700008); RealSetVec(0x04, 0x700008); // Create a dummy device MCB with PSPSeg=0x0008 DOS_MCB mcb_devicedummy((Bit16u)DOS_MEM_START); mcb_devicedummy.SetPSPSeg(MCB_DOS); // Devices mcb_devicedummy.SetSize(1); mcb_devicedummy.SetType(0x4d); // More blocks will follow // mcb_devicedummy.SetFileName("SD "); Bit16u mcb_sizes = 2; // Create a small empty MCB (result from a growing environment block) // DOS_MCB tempmcb((Bit16u)DOS_MEM_START+mcb_sizes); // tempmcb.SetPSPSeg(MCB_FREE); // tempmcb.SetSize(4); // mcb_sizes += 5; // tempmcb.SetType(0x4d); int extra_size = low ? 0 : 4096 - DOS_MEM_START - mcb_sizes - 17; // Disable first 64Kb if low not set in config // Lock the previous empty MCB DOS_MCB tempmcb2((Bit16u)DOS_MEM_START+mcb_sizes); tempmcb2.SetPSPSeg(0x40); tempmcb2.SetSize(16+extra_size); mcb_sizes += 17+extra_size; tempmcb2.SetType(0x4d); DOS_MCB mcb((Bit16u)DOS_MEM_START+mcb_sizes); mcb.SetPSPSeg(MCB_FREE); // Free mcb.SetType(0x5a); // Last Block // mcb.SetSize(0x9FFE - DOS_MEM_START - mcb_sizes); mcb.SetSize(EndConvMem - 1 - DOS_MEM_START - mcb_sizes); dos.firstMCB = DOS_MEM_START; dos_infoblock.SetFirstMCB(DOS_MEM_START); }
bool DOS_LinkUMBsToMemChain(Bit16u linkstate) { /* Get start of UMB-chain */ Bit16u umb_start=dos_infoblock.GetStartOfUMBChain(); if (umb_start!=UMB_START_SEG) { if (umb_start!=0xffff) LOG(LOG_DOSMISC,LOG_ERROR)("Corrupt UMB chain: %x",umb_start); return false; } if ((linkstate&1)==(dos_infoblock.GetUMBChainState()&1)) return true; /* Scan MCB-chain for last block before UMB-chain */ Bit16u mcb_segment=dos.firstMCB; Bit16u prev_mcb_segment=dos.firstMCB; DOS_MCB mcb(mcb_segment); while ((mcb_segment!=umb_start) && (mcb.GetType()!=0x5a)) { prev_mcb_segment=mcb_segment; mcb_segment+=mcb.GetSize()+1; mcb.SetPt(mcb_segment); } DOS_MCB prev_mcb(prev_mcb_segment); switch (linkstate) { case 0x0000: // unlink if ((prev_mcb.GetType()==0x4d) && (mcb_segment==umb_start)) { prev_mcb.SetType(0x5a); } dos_infoblock.SetUMBChainState(0); break; case 0x0001: // link if (mcb.GetType()==0x5a) { mcb.SetType(0x4d); dos_infoblock.SetUMBChainState(1); } break; default: LOG_MSG("Invalid link state %x when reconfiguring MCB chain",linkstate); return false; } return true; }
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(); }
bool DOS_LinkUMBsToMemChain(Bit16u linkstate) { Bit16u umb_start = dos_infoblock.GetStartOfUMBChain(); // Get start of UMB-chain if (umb_start != EndConvMem) return false; if ((linkstate&1) == (dos_infoblock.GetUMBChainState()&1)) return true; Bit16u mcb_segment = dos.firstMCB; // Scan MCB-chain for last block before UMB-chain Bit16u prev_mcb_segment = dos.firstMCB; DOS_MCB mcb(mcb_segment); while (mcb_segment != umb_start && mcb.GetType() != 'Z') { prev_mcb_segment = mcb_segment; mcb_segment += mcb.GetSize()+1; mcb.SetPt(mcb_segment); } DOS_MCB prev_mcb(prev_mcb_segment); switch (linkstate) { case 0: // Unlink if (prev_mcb.GetType() == 'M' && mcb_segment == umb_start) prev_mcb.SetType('Z'); dos_infoblock.SetUMBChainState(0); break; case 1: // Link if (mcb.GetType() == 'Z') { mcb.SetType('M'); dos_infoblock.SetUMBChainState(1); } break; default: return false; } return true; }
void DOS_BuildUMBChain(bool umb_active,bool ems_active) { if (umb_active && (machine!=MCH_TANDY)) { Bit16u first_umb_seg = 0xd000; Bit16u first_umb_size = 0x2000; if(ems_active || (machine == MCH_PCJR)) first_umb_size = 0x1000; dos_infoblock.SetStartOfUMBChain(UMB_START_SEG); dos_infoblock.SetUMBChainState(0); // UMBs not linked yet DOS_MCB umb_mcb(first_umb_seg); umb_mcb.SetPSPSeg(0); // currently free umb_mcb.SetSize(first_umb_size-1); umb_mcb.SetType(0x5a); /* Scan MCB-chain for last block */ Bit16u mcb_segment=dos.firstMCB; DOS_MCB mcb(mcb_segment); while (mcb.GetType()!=0x5a) { mcb_segment+=mcb.GetSize()+1; mcb.SetPt(mcb_segment); } /* A system MCB has to cover the space between the regular MCB-chain and the UMBs */ Bit16u cover_mcb=(Bit16u)(mcb_segment+mcb.GetSize()+1); mcb.SetPt(cover_mcb); mcb.SetType(0x4d); mcb.SetPSPSeg(0x0008); mcb.SetSize(first_umb_seg-cover_mcb-1); mcb.SetFileName("SC "); } else { dos_infoblock.SetStartOfUMBChain(0xffff); dos_infoblock.SetUMBChainState(0); } }
void DOS_SetupMemory(void) { /* Let dos claim a few bios interrupts. Makes DOSBox more compatible with * buggy games, which compare against the interrupt table. (probably a * broken linked list implementation) */ Bit16u ihseg = 0x70; Bit16u ihofs = 0x08; real_writeb(ihseg,ihofs,(Bit8u)0xCF); //An IRET Instruction RealSetVec(0x01,RealMake(ihseg,ihofs)); //BioMenace (offset!=4) RealSetVec(0x02,RealMake(ihseg,ihofs)); //BioMenace (segment<0x8000) RealSetVec(0x03,RealMake(ihseg,ihofs)); //Alien Incident (offset!=0) RealSetVec(0x04,RealMake(ihseg,ihofs)); //Shadow President (lower byte of segment!=0) RealSetVec(0x0f,RealMake(ihseg,ihofs)); //Always a tricky one (soundblaster irq) // Create a dummy device MCB with PSPSeg=0x0008 DOS_MCB mcb_devicedummy((Bit16u)DOS_MEM_START); mcb_devicedummy.SetPSPSeg(MCB_DOS); // Devices mcb_devicedummy.SetSize(1); mcb_devicedummy.SetType(0x4d); // More blocks will follow // mcb_devicedummy.SetFileName("SD "); Bit16u mcb_sizes=2; // Create a small empty MCB (result from a growing environment block) DOS_MCB tempmcb((Bit16u)DOS_MEM_START+mcb_sizes); tempmcb.SetPSPSeg(MCB_FREE); tempmcb.SetSize(4); mcb_sizes+=5; tempmcb.SetType(0x4d); // Lock the previous empty MCB DOS_MCB tempmcb2((Bit16u)DOS_MEM_START+mcb_sizes); tempmcb2.SetPSPSeg(0x40); // can be removed by loadfix tempmcb2.SetSize(16); mcb_sizes+=17; tempmcb2.SetType(0x4d); DOS_MCB mcb((Bit16u)DOS_MEM_START+mcb_sizes); mcb.SetPSPSeg(MCB_FREE); //Free mcb.SetType(0x5a); //Last Block if (machine==MCH_TANDY) { /* memory up to 608k available, the rest (to 640k) is used by the tandy graphics system's variable mapping of 0xb800 */ mcb.SetSize(0x9BFF - DOS_MEM_START - mcb_sizes); } else if (machine==MCH_PCJR) { /* memory from 128k to 640k is available */ mcb_devicedummy.SetPt((Bit16u)0x2000); mcb_devicedummy.SetPSPSeg(MCB_FREE); mcb_devicedummy.SetSize(0x9FFF - 0x2000); mcb_devicedummy.SetType(0x5a); /* exclude PCJr graphics region */ mcb_devicedummy.SetPt((Bit16u)0x17ff); mcb_devicedummy.SetPSPSeg(MCB_DOS); mcb_devicedummy.SetSize(0x800); mcb_devicedummy.SetType(0x4d); /* memory below 96k */ mcb.SetSize(0x1800 - DOS_MEM_START - (2+mcb_sizes)); mcb.SetType(0x4d); } else { /* complete memory up to 640k available */ /* last paragraph used to add UMB chain to low-memory MCB chain */ mcb.SetSize(0x9FFE - DOS_MEM_START - mcb_sizes); } dos.firstMCB=DOS_MEM_START; dos_infoblock.SetFirstMCB(DOS_MEM_START); }
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; }
void DOS_SetupMemory(void) { /* Let dos claim a few bios interrupts. Makes DOSBox more compatible with * buggy games, which compare against the interrupt table. (probably a * broken linked list implementation) */ callbackhandler.Allocate(&DOS_default_handler,"DOS default int"); real_writeb(0x70,4,(Bit8u)0xFE); //GRP 4 real_writeb(0x70,5,(Bit8u)0x38); //Extra Callback instruction real_writew(0x70,6,callbackhandler.Get_callback()); //The immediate word real_writeb(0x70,8,(Bit8u)0xCF); //An IRET Instruction real_writed(0,0x01*4,0x700004); real_writed(0,0x02*4,0x700004); //BioMenace (segment<0x8000) real_writed(0,0x03*4,0x700004); //Alien Incident (offset!=0) real_writed(0,0x04*4,0x700004); //Shadow President (lower byte of segment!=0) // real_writed(0,0x0f*4,0x700004); //Always a tricky one (soundblaster irq) // Create a dummy device MCB with PSPSeg=0x0008 DOS_MCB mcb_devicedummy((Bit16u)DOS_MEM_START); mcb_devicedummy.SetPSPSeg(MCB_DOS); // Devices mcb_devicedummy.SetSize(1); mcb_devicedummy.SetType(0x4d); // More blocks will follow // mcb_devicedummy.SetFileName("SD "); Bit16u mcb_sizes=2; // Create a small empty MCB (result from a growing environment block) DOS_MCB tempmcb((Bit16u)DOS_MEM_START+mcb_sizes); tempmcb.SetPSPSeg(MCB_FREE); tempmcb.SetSize(4); mcb_sizes+=5; tempmcb.SetType(0x4d); // Lock the previous empty MCB DOS_MCB tempmcb2((Bit16u)DOS_MEM_START+mcb_sizes); tempmcb2.SetPSPSeg(0x40); // can be removed by loadfix tempmcb2.SetSize(16); mcb_sizes+=17; tempmcb2.SetType(0x4d); DOS_MCB mcb((Bit16u)DOS_MEM_START+mcb_sizes); mcb.SetPSPSeg(MCB_FREE); //Free mcb.SetType(0x5a); //Last Block if (machine==MCH_TANDY) { /* memory up to 608k available, the rest (to 640k) is used by the tandy graphics system's variable mapping of 0xb800 */ mcb.SetSize(0x97FE - DOS_MEM_START - mcb_sizes); } else if (machine==MCH_PCJR) { /* memory from 128k to 640k is available */ mcb_devicedummy.SetPt((Bit16u)0x2000); mcb_devicedummy.SetPSPSeg(MCB_FREE); mcb_devicedummy.SetSize(0x9FFE - 0x2000); mcb_devicedummy.SetType(0x5a); /* exclude PCJr graphics region */ mcb_devicedummy.SetPt((Bit16u)0x17ff); mcb_devicedummy.SetPSPSeg(MCB_DOS); mcb_devicedummy.SetSize(0x800); mcb_devicedummy.SetType(0x4d); /* memory below 96k */ mcb.SetSize(0x1800 - DOS_MEM_START - (2+mcb_sizes)); mcb.SetType(0x4d); } else { /* complete memory up to 640k available */ mcb.SetSize(0x9FFE - DOS_MEM_START - mcb_sizes); } dos.firstMCB=DOS_MEM_START; dos_infoblock.SetFirstMCB(DOS_MEM_START); }
void DOS_BuildUMBChain(const char* use_umbs,bool ems_active) { if ((strcmp(use_umbs,"false")!=0) && (machine!=MCH_TANDY)) { Bit16u first_umb_seg=0xca00; Bit16u first_umb_size=0x600; if (strcmp(use_umbs,"max")==0) { first_umb_seg-=0x100; first_umb_size+=0x100; } dos_infoblock.SetStartOfUMBChain(UMB_START_SEG); dos_infoblock.SetUMBChainState(0); // UMBs not linked yet DOS_MCB umb_mcb(first_umb_seg); umb_mcb.SetPSPSeg(0); // currently free umb_mcb.SetSize(first_umb_size-1); umb_mcb.SetType(0x5a); /* Scan MCB-chain for last block */ Bit16u mcb_segment=dos.firstMCB; DOS_MCB mcb(mcb_segment); while (mcb.GetType()!=0x5a) { mcb_segment+=mcb.GetSize()+1; mcb.SetPt(mcb_segment); } /* A system MCB has to cover the space between the regular MCB-chain and the UMBs */ Bit16u cover_mcb=(Bit16u)(mcb_segment+mcb.GetSize()+1); mcb.SetPt(cover_mcb); mcb.SetType(0x4d); mcb.SetPSPSeg(0x0008); mcb.SetSize(first_umb_seg-cover_mcb-1); mcb.SetFileName("SC "); if (!ems_active && (strcmp(use_umbs,"max")==0) && (machine!=MCH_PCJR)) { Bit16u ems_umb_seg=0xe000; Bit16u ems_umb_size=0x1000; /* Continue UMB-chain */ umb_mcb.SetSize(first_umb_size-2); umb_mcb.SetType(0x4d); DOS_MCB umb2_mcb(ems_umb_seg); umb2_mcb.SetPSPSeg(0); // currently free umb2_mcb.SetSize(ems_umb_size-1); umb2_mcb.SetType(0x5a); /* A system MCB has to take out the space between the previous and this UMB */ cover_mcb=(Bit16u)(first_umb_seg+umb_mcb.GetSize()+1); mcb.SetPt(cover_mcb); mcb.SetType(0x4d); mcb.SetPSPSeg(0x0008); mcb.SetSize(ems_umb_seg-cover_mcb-1); mcb.SetFileName("SC "); } } else { dos_infoblock.SetStartOfUMBChain(0xffff); dos_infoblock.SetUMBChainState(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; }
// change model callback void MCSIEPlugin::setupProgramCtx(ProgramCtx& ctx) { ProgramCtxData& pcd = ctx.getPluginData<MCSIE>(); if( pcd.isEnabled() ) { // setup predicate masks RegistryPtr reg(ctx.registry()); // store registry in ProgramCtxData pcd.reg = reg; // configure predicate mask for d1/d2 pcd.idd1 = reg->storeConstantTerm("d1"); pcd.idd2 = reg->storeConstantTerm("d2"); pcd.brdmask.setRegistry(reg); pcd.brdmask.addPredicate(pcd.idd1); pcd.brdmask.addPredicate(pcd.idd2); pcd.brd1mask.setRegistry(reg); pcd.brd1mask.addPredicate(pcd.idd1); pcd.brd2mask.setRegistry(reg); pcd.brd2mask.addPredicate(pcd.idd2); // configure collector (if we do not use them this will not hurt performance) pcd.mindcollector.reset( new MinimalNotionCollector(pcd.brd1mask, pcd.brd2mask)); // configure predicate mask for e1/e2 pcd.ide1 = reg->storeConstantTerm("e1"); pcd.ide2 = reg->storeConstantTerm("e2"); pcd.bremask.setRegistry(reg); pcd.bremask.addPredicate(pcd.ide1); pcd.bremask.addPredicate(pcd.ide2); pcd.bre1mask.setRegistry(reg); pcd.bre1mask.addPredicate(pcd.ide1); pcd.bre2mask.setRegistry(reg); pcd.bre2mask.addPredicate(pcd.ide2); // configure collector (if we do not use them this will not hurt performance) pcd.minecollector.reset( new MinimalNotionCollector(pcd.bre1mask, pcd.bre2mask)); // configure predicate mask for each context's output beliefs assert(!pcd.mcs().contexts.empty() && "here we expect to have parsed the input and " "we expect to know the number of contexts"); for(ContextIterator it = pcd.mcs().contexts.begin(); it != pcd.mcs().contexts.end(); ++it) { pcd.obmasks.push_back(PredicateMask()); PredicateMask& mask = pcd.obmasks.back(); std::ostringstream s; s << "a" << it->ContextNum(); mask.setRegistry(reg); ID idob(reg->storeConstantTerm(s.str())); mask.addPredicate(idob); } // register model callbacks (accumulate minimal notions, print nonminimal notions) // register final callback (print minmimal notions, convert to dual notions) switch(pcd.getMode()) { case ProgramCtxData::DIAGREWRITING: { PrintAndAccumulateModelCallback* ppcd = new PrintAndAccumulateModelCallback(pcd, pcd.idd1, pcd.idd2, pcd.brdmask, pcd.mindcollector); ModelCallbackPtr mcb(ppcd); WARNING("here we could try to only remove the default answer set printer") ctx.modelCallbacks.clear(); ctx.modelCallbacks.push_back(mcb); FinalCallbackPtr fcb(new DiagRewritingFinalCallback(pcd, *ppcd, ctx.aspsoftware)); ctx.finalCallbacks.push_back(fcb); } break; case ProgramCtxData::EXPLREWRITING: { PrintAndAccumulateModelCallback* ppcd = new PrintAndAccumulateModelCallback(pcd, pcd.ide1, pcd.ide2, pcd.bremask, pcd.minecollector); ModelCallbackPtr mcb(ppcd); WARNING("here we could try to only remove the default answer set printer") ctx.modelCallbacks.clear(); ctx.modelCallbacks.push_back(mcb); FinalCallbackPtr fcb(new ExplRewritingFinalCallback(pcd, *ppcd, ctx.aspsoftware)); ctx.finalCallbacks.push_back(fcb); } break; case ProgramCtxData::EQREWRITING: { ModelCallbackPtr mcb(new PrintEQModelCallback(pcd)); WARNING("here we could try to only remove the default answer set printer") ctx.modelCallbacks.clear(); ctx.modelCallbacks.push_back(mcb); // no final callback } break; } } }