2016-09-19 67 views
1

我正在用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("%d\n", stack[(*sp)--]); 
    break; 

    case SIO: 
    scanf("%d", &stack[++(*sp)]); 
    break; 
    } 

    return 1; //A non-zero return value keeps the machine running 
} 
+0

增量计算机并调用'execOp'后更新堆栈指针。或者在'execOp'之前存储pc值,如果改变,请不要增加... –

+0

考虑在指令提取之后但在解释指令之前递增PC。改变PC的指令将写入递增的值 – infixed

+2

将PC递增到'execOp'。对于大多数指令,它会执行'(* pC++)',但是对于跳转指令,它会执行其他操作。 – Barmar

回答

0

的这部分您的指令解码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推全太,以及检查你的血压逻辑太

+0

这可能是我试过的修复之一。我会仔细看看 – WalterC

+0

好吧,你建议加上我刚刚做的其他一些事情似乎已经奏效。我的(堆栈)答案似乎不完全正确,所以我必须仔细检查我所有的函数,但至少现在看起来正在经历它们的正确顺序。谢谢! – WalterC