模拟虚拟机,在增加pc和跳转时遇到麻烦



我正在用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逻辑也

最新更新