// Subtracts the input from the specified register
// TODO: Verify overflow checking
bool SUR() {
  unsigned short int *reg = getRegister();
  unsigned short int addr = getAddrMode(machine.IR);
  unsigned short int operand = getOperand(machine.IR);
  int over = (int)*reg;

  *reg -= (addr == DIRECT ? main_memory[MMU(operand)] : operand);
  over -= (int)(addr == DIRECT ? main_memory[MMU(operand)] : operand);

  #ifdef DEBUG
  printDebug("SUR");
  #endif

  // Effect condition code; return false if overflow
  if (over == (int)*reg) {
    machine.CR = getCondCode(*reg);
  } else {
    #ifdef DEBUG_VERBOSE
    cerr << red;
    cerr << "!! OVERFLOW IN SUR()" << endl;
    cerr << normal;
    return false;
    #endif
  }
  return true;
}
// Subtracts the input from rA
// TODO: Verify overflow checking
bool SUB() {
  unsigned short int addr = getAddrMode(machine.IR);
  unsigned short int operand = getOperand(machine.IR);
  int over = (int)machine.rA;

  machine.rA -= (addr == DIRECT ? main_memory[MMU(operand)] : operand);
  over -= (int)(addr == DIRECT ? main_memory[MMU(operand)] : operand);

  #ifdef DEBUG
  printDebug("SUB");
  #endif

  // If overflow occurs, return false
  if (over == (int)machine.rA) {
    machine.CR = getCondCode(machine.rA);
  } else {
    #ifdef DEBUG_VERBOSE
    cerr << red;
    cerr << "!! OVERFLOW IN SUB()" << endl;
    cerr << normal;
    return false;
    #endif
  }
  return true;
}
// Uses value in IR to determine course of action
// Returns false if errors
bool interpreter() {
  bool success = true;
  //While no error flag and no timer interrupt
  while (success && timer_interrupt < QUANTUM) {
    machine.IR = main_memory[MMU(machine.PC)];
    machine.PC++; // Increment Program Counter
    unsigned short int op = getOpcode(machine.IR);
    switch (op) {
      case 0:  success = LOD(); break;
      case 1:  success = STO(); break;
      case 2:  success = ADD(); break;
      case 3:  success = SUB(); break;
      case 4:  success = ADR(); break;
      case 5:  success = SUR(); break;
      case 6:  success = AND(); break;
      case 7:  success = IOR(); break;
      case 8:  success = NOT(); break;
      case 9:  success = JMP(); break;
      case 10: success = JEQ(); break;
      case 11: success = JGT(); break;
      case 12: success = JLT(); break;
      case 13: success = CMP(); break;
      case 14: success = CLR(); break;
      case 15:    return HLT(); break; //Quit early on HLT
      default: success = false; break;
    }
    usleep(1000000); // Sleep 1 second to allow easier instruction tracing
    (*sysclock)++;
    timer_interrupt++;
  }
  timer_interrupt = 0;
  return success;
}
// Stores a value from a register to a memory location
bool STO() {
  unsigned short int operand = getOperand(machine.IR);
  unsigned short int *reg = getRegister();
  main_memory[MMU(operand)] = *reg;

  #ifdef DEBUG
  printDebug("STO");
  #endif
  return true;
}
// Loads a value into a register
bool LOD() {
  unsigned short int addr = getAddrMode(machine.IR);
  unsigned short int operand = getOperand(machine.IR);
  unsigned short int *reg = getRegister();

  *reg = (addr == DIRECT ? main_memory[MMU(operand)] : operand);

  #ifdef DEBUG
  printDebug("LOD");
  #endif
  return true;
}
// The IOR fuction will do the bitwise operation Or using the specified
// register, and the address of a value provided in the arguments
bool IOR() {
  unsigned short int *reg = getRegister();
  unsigned short int operand =  main_memory[MMU(getOperand(machine.IR))];
  unsigned short int result = (*reg | operand);

  *reg = result; // set the new result into the register specified

  machine.CR = getCondCode(*reg);

  #ifdef DEBUG
  printDebug("IOR");
  #endif
  return true;
}
// This is the compare function, it compares a
// direct or indirect value to the specified
// register, it will always be register oriented
// I.E. It's always of the style of (reg < instruction)
bool CMP() {

  unsigned short int *reg = getRegister();
  unsigned short int operand = getOperand(machine.IR);
  unsigned short int addr = getAddrMode(machine.IR);
  unsigned short int left_operand, right_operand;

  left_operand = *reg;
  right_operand = (addr == DIRECT ? main_memory[MMU(operand)] : operand);

  if (left_operand < right_operand) {
    machine.CR = LST;
  } else if (left_operand == right_operand) {
    machine.CR = EQL;
  } else if (left_operand > right_operand) {
    machine.CR = GRT;
  }

  #ifdef DEBUG
  printDebug("CMP");
  #endif
  return true;
}
/* Direct addressing is allowed, provided the value in the memory location
is actually only using 8 bits. If the 8 highest-order bits contain anything,
that would be a reference to a memory location that does not exist (PC: 8bits)
and thus the JMP would return an error (essentially OutOfBounds) */
bool JMP() {
  unsigned short int addr = getAddrMode(machine.IR);
  unsigned short int jmpTo;
  if (addr == DIRECT) {
    jmpTo = main_memory[MMU(getOperand(machine.IR))];
    // Check high-order bits
    if ((jmpTo & 65280) != 0)
    return false;
  } else if (addr == IMMEDIATE) {
    jmpTo = getOperand(machine.IR);
  } else {
    return false;
  }

  // Set program counter to new address
  machine.PC = jmpTo;

  #ifdef DEBUG
  if (getOpcode(machine.IR) == 9)
  printDebug("JMP");
  #endif
  return true;
}
void installProcessInFiles(){
    
    int iproc11[] = {0,4,6,8,9,5,6,3};
    int nproc11[] = {1,2,3,5,7,10,11};
    int recursos11[] = {0,1};
    
    Processo proc11;
    setProcesso(&proc11,11,1,(sizeof(iproc11)/sizeof(int))+(sizeof(nproc11)/sizeof(int)),12,43,0,122,1,(sizeof(iproc11)/sizeof(int)),iproc11,(sizeof(nproc11)/sizeof(int)),nproc11, recursos11);
    //pagNRU(proc11);
    //fifo(proc11);
    //secondChance(proc11);
    MMU(proc11);
    gravaProcesso(&proc11,"proc11.proc");
    
    int iproc12[] = {0,2,4,5,8};
    int nproc12[] = {1,3,6,7,9,10};
    int recursos12[] = {1,2};
    
    Processo proc12;
    setProcesso(&proc12,12,1,(sizeof(iproc12)/sizeof(int)) + (sizeof(nproc12)/sizeof(int)),12,43,0,200,1,(sizeof(iproc12)/sizeof(int)),iproc12,(sizeof(nproc12)/sizeof(int)),nproc12, recursos12);
    MMU(proc12);
    gravaProcesso(&proc12,"proc12.proc");
    

    int iproc13[] = {0,2,4,5,8,3,4,23,5};
    int nproc13[] = {1,3,6,7,9,10,6,3,2,5};
    int recursos13[] = {2,0};
    
    Processo proc13;
    setProcesso(&proc13,13,0,(sizeof(iproc13)/sizeof(int)) + (sizeof(nproc13)/sizeof(int)),12,43,0,200,1,(sizeof(iproc13)/sizeof(int)),iproc13,(sizeof(nproc13)/sizeof(int)),nproc13, recursos13);
    MMU(proc13);
    gravaProcesso(&proc13,"proc13.proc");   

    
/*    
    Processo proc0;        
    int iproc0[] = {1,5,6};            
    int nproc0[] = {2,3,4,7};   
    
    setProcesso(
            &proc0,             //é o processo
            10,                 //pid do processo
            0,                  //prioridade do processo 0/1
            (sizeof(iproc0)/sizeof(int)) + (sizeof(nproc0)/sizeof(int)),  //nro instruções(importantes+menos importantes)
            4,                  //entrada e saída
            2,                  //regiao critica
            0,                  //errofatal
            12345,              //referencia memoria
            10,                 //chamadas de sistema
            (sizeof(iproc0)/sizeof(int)),       //tam instrucoes importantes
            iproc0,             //instrucoes importantes
            (sizeof(nproc0)/sizeof(int)),       //tam instrucoes menos importantes
            nproc0);            //instrucoes menos importantes
    gravaProcesso(&proc0,"init.proc");
       
    
    int iproc1[] = {0,1,2};
    int nproc1[] =  {3,4,5,6};          
    Processo proc1;
    setProcesso(&proc1,11,1,(sizeof(iproc1)/sizeof(int)) + (sizeof(nproc1)/sizeof(int)),
            10,0,1,13,10,(sizeof(iproc1)/sizeof(int)),iproc1,(sizeof(nproc1)/sizeof(int)),nproc1); 
    gravaProcesso(&proc1,"proc11.proc");
    
 
    int iproc2[] = {5,2,1};
    int nproc2[] = {3,4,6,7};       
    Processo proc2;
    setProcesso(&proc2,12,1,(sizeof(iproc2)/sizeof(int)) + (sizeof(nproc2)/sizeof(int)),
            5,4,0,0,13,(sizeof(iproc2)/sizeof(int)),iproc2,(sizeof(nproc2)/sizeof(int)),nproc2);    
    gravaProcesso(&proc2,"proc12.proc");
    
       
    int iproc3[] = {0,2,4};
    int nproc3[] = {1,3,5,6};                   
    Processo proc3;            
    setProcesso(&proc3,13,1,(sizeof(iproc3)/sizeof(int)) + (sizeof(nproc3)/sizeof(int)),
            5,44,0,0,110,(sizeof(iproc3)/sizeof(int)),iproc3,(sizeof(nproc3)/sizeof(int)),nproc3);
    gravaProcesso(&proc3,"proc13.proc");
        
    
    int iproc4[] = {0,1,5};
    int nproc4[] = {2,3,4,6};
    Processo proc4;
    setProcesso(&proc4,14,1,(sizeof(iproc4)/sizeof(int)) + (sizeof(nproc4)/sizeof(int)),
            2,1,0,1,112,(sizeof(iproc4)/sizeof(int)),iproc4,(sizeof(nproc4)/sizeof(int)),nproc4);
    gravaProcesso(&proc4,"proc14.proc");
    
    
    int iproc5[] = {0,1,2,5};
    int nproc5[] = {3,4,6,7,8};
    Processo proc5;
    setProcesso(&proc5,15,1,(sizeof(iproc5)/sizeof(int)) + (sizeof(nproc5)/sizeof(int)),
            3,2,1,2,113,(sizeof(iproc5)/sizeof(int)),iproc5,(sizeof(nproc5)/sizeof(int)),nproc5);
    gravaProcesso(&proc5,"proc15.proc");
    
    int iproc6[] = {0,2,4,5,8};
    int nproc6[] = {1,3,6,7,9,10};
    Processo proc6;
    setProcesso(&proc6,16,1,(sizeof(iproc6)/sizeof(int)) + (sizeof(nproc6)/sizeof(int)),
            7,22,43,55,21,(sizeof(iproc6)/sizeof(int)),iproc6,(sizeof(nproc6)/sizeof(int)),nproc6);
    gravaProcesso(&proc6,"proc16.proc");
    
    int iproc7[] = {1,2,5,7,9};
    int nproc7[] = {0,3,4,6,8,10};
    Processo proc7;
    setProcesso(&proc7,17,1,(sizeof(iproc7)/sizeof(int)) + (sizeof(nproc7)/sizeof(int)),
            45,23,54,21,43,(sizeof(iproc7)/sizeof(int)),iproc7,(sizeof(nproc7)/sizeof(int)),nproc7);
    gravaProcesso(&proc7,"proc17.proc");
    
    int iproc8[] = {0,1,2,6,8};
    int nproc8[] = {3,4,5,7,9,10};
    Processo proc8;
    setProcesso(&proc8,18,1,(sizeof(iproc8)/sizeof(int)) + (sizeof(nproc8)/sizeof(int)),
            32,43,1,7,23,(sizeof(iproc8)/sizeof(int)),iproc8,(sizeof(nproc8)/sizeof(int)),nproc8);
    gravaProcesso(&proc8,"proc18.proc");
    
    int iproc9[] = {1,5,8,10};
    int nproc9[] = {0,2,3,4,6,7,9};
    Processo proc9;
    setProcesso(&proc9,19,1,(sizeof(iproc9)/sizeof(int)) + (sizeof(nproc9)/sizeof(int)),
            32,52,12,65,45,(sizeof(iproc9)/sizeof(int)),iproc9,(sizeof(nproc9)/sizeof(int)),nproc9);
    gravaProcesso(&proc9,"proc19.proc");
    
    int iproc10[] = {0,4,6,8,9};
    int nproc10[] = {1,2,3,5,7,10,11};
    Processo proc10;
    setProcesso(&proc10,20,1,(sizeof(iproc10)/sizeof(int)) + (sizeof(nproc10)/sizeof(int)),
            12,43,77,122,1,(sizeof(iproc10)/sizeof(int)),iproc10,(sizeof(nproc10)/sizeof(int)),nproc10);
    gravaProcesso(&proc10,"proc20.proc");
    
    */
 
}