我正在用C写一个虚拟机,我有所有不同的功能工作,但是我有麻烦把它们放在一起。具体来说,我遇到了一个问题,我需要一种方法来增加程序计数器,而不会干扰改变pc指向的指令,如JMP, JPC, CAL和RET。当我试图采取措施来取消pc++,如PCvalueAfterJmp - 1或if
语句,以避免在这些情况下增加,它突然进入一个无限循环,似乎反复通过指令。
这个程序读取一个输入文件,并在屏幕上打印正在处理的指令和堆栈的当前状态
int main(int argc, char* argv[]){
int running = 1;
int numInstructions = 0;
int lineRun;
int arcntr = 0;
//Memory
int stack[MAX_STACK_HEIGHT];
instruction code[MAX_CODE_LENGTH];
int arlist[MAX_STACK_HEIGHT];
//Registers
int sp=0;
int bp=1;
int pc=0;
instruction ir;
//Initializing ir
ir.op = 0;
ir.l = 0;
ir.m = 0;
//Initializing stack
stack[1] = 0;
stack[2] = 0;
stack[3] = 0;
//Reading the input file
numInstructions = readFile(argc, argv, code);
if(numInstructions < 0) //Exit with error if readFile returns invalid
return 1;
//show input code
printFile(code, numInstructions);
//setup and labeling
printState(-1, ir, pc, bp, sp, stack, arlist);
//Execution loop
while(running)
{
lineRun = pc;
//Fetch cycle
ir = code[pc];
//Execution cycle returns a nonzero to keep program running until end
if(!execOp(&sp, &bp, &pc, ir, code, stack, arlist, &arcntr))
running = 0;
//if statement didn't work
printState(lineRun, ir, pc, bp, sp, stack, arlist);
//if (!(ir.op == 5 || ir.op == 7 || ir.op == 8 || (ir.op == 2 && ir.m == 0)))
pc++;
}
return 0;
}
这是我的执行周期
int execOp(int* sp, int* bp, int* pc, instruction ir, instruction code[],
int stack[], int arlist[], int* arcntr){
switch((opcode)ir.op){
case LIT:
stack[++(*sp)] = ir.m;
break;
case OPR: //Operators
switch((operator)ir.m){
case RET:
if(*bp == 1) //Kill the simulation if we're at the base level
return 0;
arlist[--(*arcntr)] = 0;
*sp = *bp - 1;
*pc = stack[*sp+3];
*bp = stack[*sp+2];
break;
case NEG:
stack[*sp] = -stack[*sp];
break;
case ADD:
(*sp)--;
stack[*sp] = stack[*sp] + stack[*sp+1];
break;
case SUB:
(*sp)--;
stack[*sp] = stack[*sp] - stack[*sp+1];
break;
case MUL:
(*sp)--;
stack[*sp] = stack[*sp] * stack[*sp+1];
break;
case DIV:
(*sp)--;
stack[*sp] = stack[*sp] / stack[*sp+1];
break;
case ODD:
stack[*sp] = stack[*sp] % 2;
break;
case MOD:
(*sp)--;
stack[*sp] = stack[*sp] % stack[(*sp)+1];
break;
case EQL:
(*sp)--;
stack[*sp] = stack[*sp] == stack[*sp+1];
break;
case NEQ:
(*sp)--;
stack[*sp] = stack[*sp] != stack[*sp+1];
break;
case LSS:
(*sp)--;
stack[*sp] = stack[*sp] < stack[*sp+1];
break;
case LEQ:
(*sp)--;
stack[*sp] = stack[*sp] <= stack[*sp+1];
break;
case GTR:
(*sp)--;
stack[*sp] = stack[*sp] > stack[*sp+1];
break;
case GEQ:
(*sp)--;
stack[*sp] = stack[*sp] >= stack[*sp+1];
break;
}
break;
case LOD:
stack[++*sp] = stack[base(ir.l, *bp, stack) + ir.m];
break;
case STO:
stack[base(ir.l, *bp, stack) + ir.m] = stack[(*sp)--];
break;
case CAL:
arlist[(*arcntr)++] = *sp + 1;
stack[*sp + 1] = base(ir.l, *bp, stack);
stack[*sp + 2] = *bp;
stack[*sp + 3] = *pc - 1;
*bp = *sp + 1;
*pc = ir.m;
break;
case INC:
*sp = *sp + ir.m;
break;
case JMP:
*pc = ir.m;
break;
case JPC:
if(!stack[(*sp)--])
*pc = ir.m;
break;
case SOI:
printf("%dn", stack[(*sp)--]);
break;
case SIO:
scanf("%d", &stack[++(*sp)]);
break;
}
return 1; //A non-zero return value keeps the machine running
}
您的指令解码select
语句的这一部分似乎是错误的
case CAL:
arlist[(*arcntr)++] = *sp + 1;
stack[*sp + 1] = base(ir.l, *bp, stack);
stack[*sp + 2] = *bp;
stack[*sp + 3] = *pc - 1;
*bp = *sp + 1;
*pc = ir.m;
break;
通常情况下,您希望在返回时返回到NEXT指令。
stack[*sp + 3] = *pc - 1;
*pc-1
部分可能会在返回时将您带回到调用指令
我希望你想要推送下一条指令的地址。
你可能想要更新堆栈指针3后,推所有这些,以及检查你的BP逻辑也