📄 vm.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&¤t->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 + -