2016-09-19 45 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