模拟虚拟机,增加pc vs jumps有问题

Simulating virtual machine, have trouble with incrementing pc versus jumps

我正在用 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
}

你的这部分指令 decode 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;

通常你会想 return 到 return 上的 NEXT 指令。

stack[*sp + 3] = *pc - 1;

*pc-1 部分可能会将您带回到 return

的调用指令

我预计您会想要推送下一条指令的地址。

你可能希望在推送所有这些之后将堆栈指针更新 3,并检查你的 BP 逻辑