⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vm.cpp

📁 一个简单的虚拟机和虚拟操作系统
💻 CPP
字号:
#include "StdAfx.h"
#include "VM.h"
#include "CPU.h"
#include "PCB.h"
#include "file.h"
#include "Instruction.h"
#include "dictionary.h"
#include "fs.h"
#include <memory>
#include <process.h>
extern CString msg;
extern CString codeErr;
using namespace std;

int mem[MEM_SIZE];

VM vm;

CString cmd[] = {"SET","LOAD","STOR","MOV","ADD","SUB","MPY","DIV",
"INC","DEC","JMP","JPZ","OPEN","CLOSE","IN","OUT","HALT"};

CString R[] = {"R0","R1","R2","R3","R4","R5","R6","R7","R8","R9","R10","R11","R12",
"R13","R14","R15","R16","R17","R18","R19","R20","R21","R22","R23"};

int compareMem(const void* a, const void* b)
{
	PCB* pcbA = (PCB*)a;
	PCB* pcbB = (PCB*)b;
	return pcbA->PAR - pcbB->PAR;
}

VM::VM(void)
{
	current = NULL;
	memHead = 0;
	time_A = 0;
	time_B = 0;
	run = 0;
	for(int i = 0;i<MAX_PRS_NUM;i++)
		pcb[i] = NULL;
}

void VM::Reset()
{
	current = NULL;
	memHead = 0;
	time_A = 0;
	time_B = 0;

	int length = Q_ready.Length();
	for(int i = 0;i<length;i++)
		Q_ready.Remove();

	length = Q_waitA.Length();
	for(int i = 0;i<length;i++)
		Q_waitA.Remove();

	length = Q_waitB.Length();
	for(int i = 0;i<length;i++)
		Q_waitB.Remove();

	for(int i = 0;i<MAX_PRS_NUM;i++)
		if(pcb[i]!=NULL)
		{
			delete pcb[i];
			pcb[i] = NULL;
		}
}
void VM::Restart()
{
	Sleep(1000);
#ifdef _DEBUG
	_execl("MyVM.exe","MyVM.exe");
#else 
	_execl("MyVM.exe",NULL);
#endif
	PostQuitMessage(0);
}
void VM::Step()
{
	static int cycle = 0;
	static int run = 0;
	

	if(time_A == IRQ_TIMEA)
	{
		Q_ready.Put(Q_waitA.Remove());
		time_A = -1;
	}

	if(time_B == IRQ_TIMEB)
	{
		Q_ready.Put(Q_waitB.Remove());
		time_B = -1;
	}

	//if a process is running
	if(IsActive())
	{
		//start another process if
		//current process has run for too much time
		//and exists a ready process whose PRI is 
		//not lower than current process
		if(current->RUNTIME>=MAX_RUN_TIME&&Q_ready.Length()>0&&current->PRI<=Q_ready.Get()->PRI)
		{
			PCB*cur = this->current;
			this->PauseProcess();
			this->StartProcess();
			this->Q_ready.Put(cur);
		}
		else
		{
			run++;
			CString s;
			s.Format("P %d>  ",current->ID);
			msg+=s;
			cpu.FetchIns();
			cpu.DoOperation();
			if(current!=NULL)
			current->RUNTIME++;
		}
	}
	//if no process is running and exists a ready process,
	//then start it
	else if(this->Q_ready.Length()>0)
		this->StartProcess();
	//increase the waiting time of all the ready and
	//waiting processes
	for(int i = 0;i<MAX_PRS_NUM;i++)
	{
		if(pcb[i] == NULL)continue;
		pcb[i]->TOTALTIME++;
		if(pcb[i]->STATE != STATE_ACTIVE )
			pcb[i]->WAITTIME++;
	}
	//if A is free and some processes are waiting for A,
	//increase the clock.
	if(Q_waitA.Length()!=0&&time_A>=0)
		time_A++;
	//if B is free and some processes are waiting for B,
	//increase the clock.
	if(Q_waitB.Length()!=0&&time_B>=0)
		time_B++;

	if(++cycle == COMPUTERATE)
	{
		this->run = run;
		run = 0;
		cycle = 0;
	}
}
inline bool VM::IsActive()
{
	return this->current!=NULL;
}
int VM::getMemInUse()
{
	int used = 0;
	for(int i = 0;i<MAX_PRS_NUM;i++)
		if(pcb[i]!=NULL)
			used += pcb[i]->PDLR+pcb[i]->PILR;
	return used;
}
int VM::getCPURate()
{
	return run*100/COMPUTERATE;
}
int VM::getActiveNum()
{
	if(current == NULL)
		return 0;
	return 1;
}
int VM::getAllNum()
{
	int all = 0;
	for(int i = 0;i<MAX_PRS_NUM;i++)
		if(pcb[i]!=NULL)
			all++;
	return all;
}
int VM::getReadyNum()
{
	return Q_ready.Length();
}
int VM::getWaitANum()
{
	return Q_waitA.Length();
}
int VM::getWaitBNum()
{
	return Q_waitB.Length();
}
/*
 * trim the memory.
 * there can be only one fragment
 */
void VM::MemTrim()
{
/*
	if(IsActive())throw UNKNOWNERR;
	//get the sum of processes
	int length = Q_ready.Length()+Q_waitA.Length()+Q_waitB.Length();
	if(length == 0)return;
	PCB** p = new PCB*[length];
	int index = 0;
	//initialize p
	for(int i = 0;i<MAX_PRS_NUM;i++)
		if(pcb[i]!=NULL)
			p[index++] = pcb[i];
	//sort p acrossing to the address of process
	::qsort(p,length,sizeof(PCB*),compareMem);
	//the fragment size
	int fragment = p[0]->PAR;
	//compute the fragment size and location
	for(int i = 0;i<length;i++)
	{
		if(fragment>0)
		{
			index = i;
			break;
		}
		if(i == length-1)break;
		fragment = p[i+1]->PAR-(p[i]->PAR+p[i]->PDLR+p[i]->PILR);		
	}
	//no fragment found
	if(fragment == 0)
	{
		delete[]p;
		return;
	}
	//move the memory to avoid fragment
	int head = p[index]->PAR;
	int end = p[length-1]->PAR+p[length-1]->PDLR+p[length-1]->PILR;
	memmove(&mem[head-fragment],&mem[head],(end-head)*sizeof(int));
	memHead -= fragment;
	//update the process information
	for(int i = index;i<length;i++)
	{
		p[i]->PAR -= fragment;
		p[i]->PC -= fragment;
	}
	delete[]p;
*/
}
void VM::LoadProcess(CString s,int pri)
{
	if(pri>PRI_MAX||pri<PRI_MIN)
		throw BAD_PRI;
	//assign the process an id
	int id = -1;
	for(int i = 0;i<MAX_PRS_NUM;i++)
		if(pcb[i] == NULL)
		{
			id = i;
			break;
		}
	if(id == -1)
		throw TOO_MANY_PRS;
	int tmpHead = memHead;
	PCB*p = NULL;
	s.Trim();
	if(s.GetLength() == 0)
	{
		codeErr = "代码不能为空";
		throw BAD_CODE;
	}
	s.Append("\r");
	int sum = 0;
	//get the sum of sentences
	for(int i = 0;i<s.GetLength();i++)
		if(s[i] == '\r')
			sum++;
	//an array to store all the sentences
	CString* sub = new CString[sum];
	
	//fetch sentences into sub line by line
	for(int head = 0,index = 0,i = 0;i<sum;i++)
	{
		index = s.Find('\r',head);
		sub[i] = s.Mid(head,index-head).Trim();
		head = index+2;
	}
	//stores the name of variables
	CString variable = "";
	//stores the values of variables
	int* values = new int[sum];
	//stores the addresses of variables
	int* adsV = new int[sum];
	//stores the name of labels
	CString label = "";
	//stores the addresses of labels
	int* adsL = new int[sum];
	//stores the not done sentences
	//type,variable name,address
	int* toFix = new int[sum*3];
	//sign the position in toFix
	int pos = 0;
	//a temp string to store sub[i]
	CString str = "";
	//translate the sentences to machine codes
	for(int i = 0;i<sum;i++)
	{
		str = sub[i];
		//if there is a label then recorde and delete it
		if(str[1] == ':')
		{
			//if there is areadly a label with this name
			//throws an exception
			if(label.Find(str[0])!=-1||variable.Find(str[0])!=-1)
			{
				codeErr = "标签重定义: "+str.Left(1);
				throw BAD_CODE;
			}
			//adds the label name
			label.AppendChar(str[0]);
			//stores the label's address
			adsL[label.GetLength()-1] = tmpHead-memHead;
			//delete the label
			str.Delete(0,2);
			str.TrimLeft();
		}
		//sign the instruction's opcode
		int ins = -1;
		for(int i = 0;i<INS_NUM;i++)
			if(str.Find(cmd[i]) == 0)
			{
				ins = i;
				break;
			}
		//invalid sentences
		if(ins == -1)
		{
			codeErr = "无法识别的符号: "+str;
			throw BAD_CODE;
		}
		//if is the SET sentences
		else if(ins == SET)
		{
			str.Delete(0,3);
			str.TrimLeft();
			//gets the variable's name
			char c = str[0];
			//if the variable was areadly defined
			if(variable.Find(c)!=-1||label.Find(str[0])!=-1)
			{
				CString s;
				s.AppendChar(c);
				codeErr = "标识符重定义: "+s;
				throw BAD_CODE;
			}
			//delete the variable's name from str
			str.Delete(0,1);
			str.TrimLeft();
			//gets integer
			int value = atoi(str);
			//if can't get an integer
			if((value == 0)&&(str[0]!='0'||str.GetLength()!=1))
			{
				codeErr = "无法识别的符号: "+str;
				throw BAD_CODE;
			}
			//stores the variable's name
			variable.AppendChar(c);
			//stores the variable's value
			values[variable.GetLength()-1] = value;
		}
		else
		{
			//if memory is full
			if(tmpHead == MEM_SIZE)throw OUT_OF_MEM;
			//puts instruction's operation code to memory
			mem[tmpHead++] = ins;
			//delete the string of operation code from str
			str.Delete(0,cmd[ins].GetLength());
			str.TrimLeft();
			switch(ins)
			{
			//operation number is R
			case INC:
			case DEC:
			case _IN:
			case _OUT:
				if(tmpHead == MEM_SIZE)throw OUT_OF_MEM;
				mem[tmpHead++] = this->CutR(str);
				break;
			//operation numbers are R-R
			case MOV:
			case ADD:
			case SUB:
			case MPY:
			case DIV:			
				if(tmpHead == MEM_SIZE-1)throw OUT_OF_MEM;
				mem[tmpHead++] = this->CutR(str);
				mem[tmpHead++] = this->CutR(str);
				break;
			//operation number is L
			case JMP:
				if(tmpHead == MEM_SIZE)throw OUT_OF_MEM;
				if(str.GetLength()!=1)
				{
					codeErr = "无法识别的符号: "+str;
					throw BAD_CODE;
				}
				toFix[pos++] = 1;
				toFix[pos++] = str[0];				
				toFix[pos++] = tmpHead++;
				break;
			//operation numbers are L-R
			case JPZ:
				if(tmpHead == MEM_SIZE-1)throw OUT_OF_MEM;
				toFix[pos++] = 1;
				toFix[pos++] = str[0];				
				toFix[pos++] = tmpHead++;
				str.Delete(0,1);
				str.TrimLeft();
				mem[tmpHead++] = this->CutR(str);
				if(str.GetLength()!=0)
				{
					codeErr = "无法识别的符号: "+str;
					throw BAD_CODE;
				}
				break;
			//operation numbers are R-M
			case LOAD:
				if(tmpHead == MEM_SIZE-1)throw OUT_OF_MEM;
				mem[tmpHead++] = this->CutR(str);
				//not a singal char or not defined
				if(str.GetLength()!=1||variable.Find(str[0]) == -1)
				{
					codeErr = "无法识别的符号: "+str;
					throw BAD_CODE;
				}
				toFix[pos++] = 0;
				toFix[pos++] = str[0];
				toFix[pos++] = tmpHead++;
				break;
			//operation numbers are M-R
			case STOR:
				if(tmpHead == MEM_SIZE-1)throw OUT_OF_MEM;
				//not defined
				if(variable.Find(str[0]) == -1)
				{
					codeErr = "无法识别的符号: "+str;
					throw BAD_CODE;
				}
				toFix[pos++] = 0;
				toFix[pos++] = str[0];				
				toFix[pos++] = tmpHead++;
				str.Delete(0,1);
				str.TrimLeft();
				mem[tmpHead++] = this->CutR(str);
				if(str.GetLength()!=0)
				{
					codeErr = "无法识别的符号: "+str;
					throw BAD_CODE;
				}
				break;
			//IO
			case OPEN:break;
			case CLOSE:break;
				
			//exit
			case HALT:break;
			default:throw BAD_CODE;
			}
		}
	}
	//append a HALT instruction at the end of
	//the process' instruction section
	if(mem[tmpHead-1]!=HALT)
	{
		if(tmpHead == MEM_SIZE)throw OUT_OF_MEM;
		mem[tmpHead++] = HALT;
	}

	int insLength = tmpHead-memHead;
	int dataLength = variable.GetLength();
	//allocate memory for variables
	if(tmpHead+variable.GetLength() > MEM_SIZE)throw OUT_OF_MEM;
	for(int i = 0;i<variable.GetLength();i++)
	{
		adsV[i] = tmpHead-memHead;
		mem[tmpHead++] = values[i];
	}
	//fix the not done sentences
	//LOAD STOR JMP JPZ
	for(int i = 0;i<pos;i+=3)
	{
		//the name of variable or label
		char c = toFix[i+1];
		//the address to fix
		int toFixAds = toFix[i+2];
		//the address the mem[toFixAds] point to
		int pAds = -1;
		//type is variable
		if(toFix[i] == 0)
		{
			int index = variable.Find(c);
			pAds = adsV[index];
		}
		//type is label
		else 
		{
			int index = label.Find(c);
			if(index < 0)
			{
				codeErr = "无法识别的符号: "+(CString)c;
				throw BAD_CODE;
			}
			pAds = adsL[index];
		}
		
		//set the value
		mem[toFixAds] = pAds;
	}
	//create a process
	p = new PCB(id,pri);
	//initinalize the process
	p->PAR = memHead;
	p->PDLR = dataLength;
	p->PILR = insLength;
	p->PC = memHead;
	
	this->Q_ready.Put(p);
	this->pcb[id] = p;
	memHead = tmpHead;
	delete[] values;
	delete[] adsV;
	delete[] adsL;
	delete[] toFix;
	delete[]sub;
}
int VM::CutR(CString&str)
{
	int r = -1;
	for(int i = REG_SIZE-1;i>=0;i--)
		if(str.Find(R[i]) == 0)
		{
			r = i;
			break;
		}
	if(r == -1)
	{
		codeErr = "无法识别的符号: "+str;
		throw BAD_CODE;
	}
	str.Delete(0,R[r].GetLength());
	str.TrimLeft();
	return r;
}
/*
 * start the auto selected process from the ready queue.
 * This operation will first check if the ready queue contains 
 * any processes, if there are any then pause the current process
 * and start the selected one, otherwise throw an exception.
 */
void VM::StartProcess()
{
	//remove a process from ready queue.
	PCB* p = this->Q_ready.Remove();
	
	//modify the state of the process
	this->current = p;
	current->STATE = STATE_ACTIVE;
	current->WAITTIME = 0;
	current->RUNTIME = 0;

	//update the CPU's data
	cpu.PAR = current->PAR;
	cpu.PDLR = current->PDLR;
	cpu.PILR = current->PILR;
	cpu.PC = 0;
	
	//if this process was breaked off before,
	//then recover its data and state
	if(current->BREAKED)
	{
		//MessageBox(NULL,"","",0);
		memcpy(cpu.R,current->R,REG_SIZE*sizeof(int));
		cpu.PC = current->PC;
	}
}


void VM::StartProcess(int ID)
{
	if(pcb[ID] == NULL)
		throw BAD_ID;
	this->Q_ready.Remove(pcb[ID]);

	//if current isn't NULL, pause it.
	if(IsActive())
		PauseProcess();

	//modify the state of the process
	this->current = pcb[ID];
	current->STATE = STATE_ACTIVE;
	current->WAITTIME = 0;
	current->RUNTIME = 0;

	//update the CPU's data
	cpu.PAR = current->PAR;
	cpu.PDLR = current->PDLR;
	cpu.PILR = current->PILR;
	cpu.PC = 0;

	//if this process was breaked off before,
	//then recover its data and state
	if(current->BREAKED)
	{
		memcpy(cpu.R,current->R,REG_SIZE*sizeof(int));
		cpu.PC = current->PC;
	}
}

/*
 * stop the selected process
 */
void VM::StopProcess(int ID)
{
	if(pcb[ID] == NULL)
		throw BAD_ID;
	PCB* p = pcb[ID];
	//if the process is running, then stop it
	if(p->STATE == STATE_ACTIVE)
		StopProcess();
	//if p is in the ready queue,then remove it
	else if(p->STATE == STATE_READY)
	{
		this->Q_ready.Remove(p);
		delete p;
		pcb[ID] = NULL;
	}
	//if p is in the waiting queue,then remove it
	else if(p->STATE == STATE_WAIT)
	{
		if(p->EVENT == IRQA)
			this->Q_waitA.Remove(p);
		else this->Q_waitB.Remove(p);
		delete p;
		pcb[ID] = NULL;
	}
}

/*
 * stop the currently running process.
 * this operation will completely delete the process.
 */
void VM::StopProcess()
{
	cpu.PC = -1;
	pcb[current->ID] = NULL;
	if(current->RES == IRQA)
		time_A = 0;
	else if(current->RES == IRQB)
		time_B = 0;
	delete current;
	current = NULL;
}
/*
 * pause the currently running process.
 * this operation will put the process into the ready queue.
 */
void VM::PauseProcess()
{	
	//set process state
	current->STATE = STATE_READY;
	current->BREAKED = true;
	current->RUNTIME = 0;
	//save process data
	current->PAR = cpu.PAR;
	current->PDLR = cpu.PDLR;
	current->PILR = cpu.PILR;
	current->PC = cpu.PC;
	memcpy(current->R,cpu.R,REG_SIZE*sizeof(int));
		
	current = NULL;
	cpu.PC = -1;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -