Beispiel #1
0
  public static void raiseException(int which, int badVAddr) {
    Debug.println('m', "Exception: " + exceptionNames[which]);
    
    Debug.ASSERT(Interrupt.getStatus() == Interrupt.UserMode);
    registers[BadVAddrReg] = badVAddr;
    delayedLoad(0, 0);			// finish anything in progress
    Interrupt.setStatus(Interrupt.SystemMode);
    Nachos.exceptionHandler(which); // interrupts are enabled at this point
    Interrupt.setStatus(Interrupt.UserMode);
}
Beispiel #2
0
  static int readMem(int addr, int size) throws MachineException {
    int data = 0;
    int exception;
    int physicalAddress;
    
    if (Debug.isEnabled('a')) {
	Debug.printf('a', "Reading VA 0x%x, size %d\n", 
		     new Integer(addr), new Integer(size));
    }

    try {
//////////////System.out.println("try to read from vir "+addr);
      physicalAddress = translate(addr, size, false);
    } catch (MachineException e) {
//System.out.println("read mem exe"+e.getMessage());
      raiseException(e.exception, addr);
      throw e;
    }
  
    switch (size) {
    case 1:
      data = (mainMemory[physicalAddress] & 0xff);
      break;
    
    case 2:
      data = ((mainMemory[physicalAddress] & 0xff) << 8) |
	(mainMemory[physicalAddress+1] & 0xff);
      break;
	
    case 4:
      data = (mainMemory[physicalAddress+3] << 24) |
	((mainMemory[physicalAddress+2] & 0xff)  << 16) |
	((mainMemory[physicalAddress+1] & 0xff) << 8) |
	(mainMemory[physicalAddress] & 0xff);
      break;

      default: 
	Debug.ASSERT(false);
    }
    
    if (Debug.isEnabled('a')) {
      Debug.printf('a', "\tvalue read = 0x%x\n", new Long(data & LOW32BITS));
    }    

    return data;
  }
Beispiel #3
0
  static boolean writeMem(int addr, int size, int value) {
    int exception;
    int physicalAddress;
     
    if (Debug.isEnabled('a')) {
      Debug.printf('a', "Writing VA 0x%x, size %d, value 0x%x\n",
		   new Integer(addr), new Integer(size), new Integer(value));
    }

    try {
      physicalAddress = translate(addr, size, true);
    } catch (MachineException e) {
      raiseException(e.exception, addr);
      return false;
    }

    switch (size) {
      case 1:
	mainMemory[physicalAddress] = (byte) (value & 0xff);
	break;

      case 2:
	mainMemory[physicalAddress] = (byte) ((value >> 8) & 0xff);
	mainMemory[physicalAddress+1] = (byte) (value & 0xff);
	break;
      
      case 4:
	mainMemory[physicalAddress+3] = (byte) ((value >> 24) & 0xff);
	mainMemory[physicalAddress+2] = (byte) ((value >> 16) & 0xff);
	mainMemory[physicalAddress+1] = (byte) ((value >> 8) & 0xff);
	mainMemory[physicalAddress] = (byte) (value & 0xff);
	break;
	
	default: 
	  Debug.ASSERT(false);
    }
    
    return true;
  }
Beispiel #4
0
  static private void oneInstruction(Instruction instr) {

    int raw;
    int nextLoadReg = 0; 	
    int nextLoadValue = 0; 	// record delayed load operation, to apply
				// in the future

    // Fetch instruction 
    try {
      instr.value = readMem(registers[PCReg], 4);
    } catch (MachineException e) {
      return;			// exception occurred
    }
    instr.decode();

    String str = Instruction.opStrings[instr.opCode];
    byte args[] = Instruction.opRegs[instr.opCode];
    Debug.ASSERT(instr.opCode <= Instruction.MaxOpcode);
    if (Debug.isEnabled('m')) {
      Debug.printf('m', "At PC = 0x%x: ", new Integer(registers[PCReg]));
      Debug.printf('m',  str + "\n", 
		   new Integer(instr.typeToReg(args[0])),
		   new Integer(instr.typeToReg(args[1])),
		   new Integer(instr.typeToReg(args[2])));
    }

    // Compute next pc, but don't install in case there's an error or branch.
    int pcAfter = registers[NextPCReg] + 4;
    int sum, diff, tmp, value;
    long rs, rt, imm;

    // Execute the instruction (cf. Kane's book)
    switch (instr.opCode) {
	
      case Instruction.OP_ADD:
	sum = registers[instr.rs] + registers[instr.rt];
	if (((registers[instr.rs] ^ registers[instr.rt]) & SIGN_BIT) == 0 &&
	    ((registers[instr.rs] ^ sum) & SIGN_BIT) != 0) {
	    raiseException(OverflowException, 0);
	    return;
	}
	registers[instr.rd] = sum;
	break;
	
      case Instruction.OP_ADDI:
	sum = registers[instr.rs] + instr.extra;
	if (((registers[instr.rs] ^ instr.extra) & SIGN_BIT) == 0 &&
	    ((instr.extra ^ sum) & SIGN_BIT) != 0) {
	    raiseException(OverflowException, 0);
	    return;
	}
	registers[instr.rt] = sum;
	break;
	
      case Instruction.OP_ADDIU:
	// the registers are int, so we have to do them unsigned.
	// Now, precisely *WHY* didn't java give us unsigned types, again?

	rs = registers[instr.rs] & LOW32BITS;
	imm = instr.extra & LOW32BITS;
	rt = rs + imm;
	
	registers[instr.rt] = (int)rt;
	break;
	
      case Instruction.OP_ADDU:

	rs = registers[instr.rs] & LOW32BITS;
	rt = registers[instr.rt] & LOW32BITS;
		
	registers[instr.rd] = (int)(rs + rt);
	break;
	
      case Instruction.OP_AND:
	registers[instr.rd] = registers[instr.rs] & registers[instr.rt];
	break;
	
      case Instruction.OP_ANDI:
	registers[instr.rt] = registers[instr.rs] & (instr.extra & 0xffff);
	break;
	
      case Instruction.OP_BEQ:
	if (registers[instr.rs] == registers[instr.rt])
	    pcAfter = registers[NextPCReg] + (instr.extra << 2);
	break;
	
      case Instruction.OP_BGEZAL:
	registers[R31] = registers[NextPCReg] + 4;
      case Instruction.OP_BGEZ:
	if ((registers[instr.rs] & SIGN_BIT) == 0)
	    pcAfter = registers[NextPCReg] + (instr.extra << 2);
	break;
	
      case Instruction.OP_BGTZ:
	if (registers[instr.rs] > 0)
	    pcAfter = registers[NextPCReg] + (instr.extra << 2);
	break;
	
      case Instruction.OP_BLEZ:
	if (registers[instr.rs] <= 0)
	    pcAfter = registers[NextPCReg] + (instr.extra << 2);
	break;
	
      case Instruction.OP_BLTZAL:
	registers[R31] = registers[NextPCReg] + 4;
      case Instruction.OP_BLTZ:
	if ((registers[instr.rs] & SIGN_BIT) != 0)
	    pcAfter = registers[NextPCReg] + (instr.extra << 2);
	break;
	
      case Instruction.OP_BNE:
	if (registers[instr.rs] != registers[instr.rt])
	    pcAfter = registers[NextPCReg] + (instr.extra << 2);
	break;
	
      case Instruction.OP_DIV:
	if (registers[instr.rt] == 0) {
	    registers[LoReg] = 0;
	    registers[HiReg] = 0;
	} else {
	    registers[LoReg] =  registers[instr.rs] / registers[instr.rt];
	    registers[HiReg] = registers[instr.rs] % registers[instr.rt];
	}
	break;
	
      case Instruction.OP_DIVU:
	// don't sign extend
	rs = (registers[instr.rs] & LOW32BITS);
	rt = (registers[instr.rt] & LOW32BITS);
	if (rt == 0) {
	  registers[LoReg] = 0;
	  registers[HiReg] = 0;
	} else {
	  tmp = (int) (rs / rt);
	  registers[LoReg] = tmp;
	  tmp = (int) (rs % rt);
	  registers[HiReg] = tmp;
	}
	break;
	
      case Instruction.OP_JAL:
	registers[R31] = registers[NextPCReg] + 4;
      case Instruction.OP_J:
	pcAfter = (pcAfter & 0xf0000000) | instr.extra << 2;
	break;
	
      case Instruction.OP_JALR:
	registers[instr.rd] = registers[NextPCReg] + 4;
      case Instruction.OP_JR:
	pcAfter = registers[instr.rs];
	break;
	
      case Instruction.OP_LB:
      case Instruction.OP_LBU:
	tmp = registers[instr.rs] + instr.extra;
	try {
	  value = readMem(tmp, 1);
	} catch (MachineException e) {
	  return;			// exception occurred
	}

	if ((value & 0x80) != 0 && (instr.opCode == Instruction.OP_LB))
	    value |= 0xffffff00;
	else
	    value &= 0xff;
	nextLoadReg = instr.rt;
	nextLoadValue = value;
	break;
	
      case Instruction.OP_LH:
      case Instruction.OP_LHU:
	tmp = registers[instr.rs] + instr.extra;
	if ((tmp & 0x1) != 0) {
	    raiseException(AddressErrorException, tmp);
	    return;
	}
	try {
	  value = readMem(tmp, 2);
	} catch (MachineException e) {
	  return;			// exception occurred
	}

	if ((value & 0x8000) != 0 && (instr.opCode == Instruction.OP_LH))
	    value |= 0xffff0000;
	else
	    value &= 0xffff;
	nextLoadReg = instr.rt;
	nextLoadValue = value;
	break;
      	
      case Instruction.OP_LUI:
	
	if (Debug.isEnabled('m')) 
	  Debug.printf('m', "Executing: LUI r%d,%d\n", 
		       new Integer(instr.rt), new Integer(instr.extra));
	registers[instr.rt] = instr.extra << 16;
	break;
	
      case Instruction.OP_LW:
	tmp = registers[instr.rs] + instr.extra;
	if ((tmp & 0x3) != 0) {
	    raiseException(AddressErrorException, tmp);
	    return;
	}
	try {
	  value = readMem(tmp, 4);
	} catch (MachineException e) {
	  return;			// exception occurred
	}
	nextLoadReg = instr.rt;
	nextLoadValue = value;
	break;
    	
      case Instruction.OP_LWL:	  
	tmp = registers[instr.rs] + instr.extra;

	// ReadMem assumes all 4 byte requests are aligned on an even 
	// word boundary.  Also, the little endian/big endian swap code would
        // fail (I think) if the other cases are ever exercised.
	Debug.ASSERT((tmp & 0x3) == 0);  

	try {
	  value = readMem(tmp, 4);
	} catch (MachineException e) {
	  return;			// exception occurred
	}	
	if (registers[LoadReg] == instr.rt)
	    nextLoadValue = registers[LoadValueReg];
	else
	    nextLoadValue = registers[instr.rt];
	switch (tmp & 0x3) {
	  case 0:
	    nextLoadValue = value;
	    break;
	  case 1:
	    nextLoadValue = (nextLoadValue & 0xff) | (value << 8);
	    break;
	  case 2:
	    nextLoadValue = (nextLoadValue & 0xffff) | (value << 16);
	    break;
	  case 3:
	    nextLoadValue = (nextLoadValue & 0xffffff) | (value << 24);
	    break;
	}
	nextLoadReg = instr.rt;
	break;
      	
      case Instruction.OP_LWR:
	tmp = registers[instr.rs] + instr.extra;

	// ReadMem assumes all 4 byte requests are aligned on an even 
	// word boundary.  Also, the little endian/big endian swap code would
        // fail (I think) if the other cases are ever exercised.
	Debug.ASSERT((tmp & 0x3) == 0);  

	try {
	  value = readMem(tmp, 4);
	} catch (MachineException e) {
	  return;			// exception occurred
	}	
	if (registers[LoadReg] == instr.rt)
	    nextLoadValue = registers[LoadValueReg];
	else
	    nextLoadValue = registers[instr.rt];
	switch (tmp & 0x3) {
	  case 0:
	    nextLoadValue = (nextLoadValue & 0xffffff00) |
		((value >> 24) & 0xff);
	    break;
	  case 1:
	    nextLoadValue = (nextLoadValue & 0xffff0000) |
		((value >> 16) & 0xffff);
	    break;
	  case 2:
	    nextLoadValue = (nextLoadValue & 0xff000000)
		| ((value >> 8) & 0xffffff);
	    break;
	  case 3:
	    nextLoadValue = value;
	    break;
	}
	nextLoadReg = instr.rt;
	break;
    	
      case Instruction.OP_MFHI:
	registers[instr.rd] = registers[HiReg];
	break;
	
      case Instruction.OP_MFLO:
	registers[instr.rd] = registers[LoReg];
	break;
	
      case Instruction.OP_MTHI:
	registers[HiReg] = registers[instr.rs];
	break;
	
      case Instruction.OP_MTLO:
	registers[LoReg] = registers[instr.rs];
	break;
	
      case Instruction.OP_MULT:
	mult(registers[instr.rs], registers[instr.rt], true,
	     mresult);
	registers[HiReg] = mresult[0];
	registers[LoReg] = mresult[1];
	break;
	
      case Instruction.OP_MULTU:
	mult(registers[instr.rs], registers[instr.rt], false,
	     mresult);
	registers[HiReg] = mresult[0];
	registers[LoReg] = mresult[1];
	break;
	
      case Instruction.OP_NOR:
	registers[instr.rd] = ~(registers[instr.rs] | registers[instr.rt]);
	break;
	
      case Instruction.OP_OR:
	registers[instr.rd] = registers[instr.rs] | registers[instr.rt];
	break;
	
      case Instruction.OP_ORI:
	registers[instr.rt] = registers[instr.rs] | (instr.extra & 0xffff);
	break;
	
      case Instruction.OP_SB:
	if (!writeMem(
		(registers[instr.rs] + instr.extra), 1, registers[instr.rt]))
	    return;
	break;
	
      case Instruction.OP_SH:
	if (!writeMem(
		(registers[instr.rs] + instr.extra), 2, registers[instr.rt]))
	    return;
	break;
	
      case Instruction.OP_SLL:
	registers[instr.rd] = registers[instr.rt] << instr.extra;
	break;
	
      case Instruction.OP_SLLV:
	registers[instr.rd] = registers[instr.rt] <<
	    (registers[instr.rs] & 0x1f);
	break;
	
      case Instruction.OP_SLT:
	if (registers[instr.rs] < registers[instr.rt])
	    registers[instr.rd] = 1;
	else
	    registers[instr.rd] = 0;
	break;
	
      case Instruction.OP_SLTI:
	if (registers[instr.rs] < instr.extra)
	    registers[instr.rt] = 1;
	else
	    registers[instr.rt] = 0;
	break;
	
      case Instruction.OP_SLTIU:	  
	rs = (registers[instr.rs] & LOW32BITS);
	imm = (instr.extra & LOW32BITS);
	if (rs < imm)
	    registers[instr.rt] = 1;
	else
	    registers[instr.rt] = 0;
	break;
      	
      case Instruction.OP_SLTU:	  
	rs = registers[instr.rs] & LOW32BITS;
	rt = registers[instr.rt] & LOW32BITS;
	if (rs < rt)
	    registers[instr.rd] = 1;
	else
	    registers[instr.rd] = 0;
	break;
      	
      case Instruction.OP_SRA:
	registers[instr.rd] = registers[instr.rt] >> instr.extra;
	break;
	
      case Instruction.OP_SRAV:
	registers[instr.rd] = registers[instr.rt] >>
	    (registers[instr.rs] & 0x1f);
	break;
	
      case Instruction.OP_SRL:
	tmp = registers[instr.rt];
	tmp >>= instr.extra;
	registers[instr.rd] = tmp;
	break;
	
      case Instruction.OP_SRLV:
	tmp = registers[instr.rt];
	tmp >>= (registers[instr.rs] & 0x1f);
	registers[instr.rd] = tmp;
	break;
	
      case Instruction.OP_SUB:	  
	diff = registers[instr.rs] - registers[instr.rt];
	if (((registers[instr.rs] ^ registers[instr.rt]) & SIGN_BIT) != 0 &&
	    ((registers[instr.rs] ^ diff) & SIGN_BIT) != 0) {
	    raiseException(OverflowException, 0);
	    return;
	}
	registers[instr.rd] = diff;
	break;
      	
      case Instruction.OP_SUBU:
	
	rs = (registers[instr.rs] & LOW32BITS);
	rt = (registers[instr.rt] & LOW32BITS);
	
	registers[instr.rd] = (int)(rs - rt);
	break;
	
      case Instruction.OP_SW:
	if (!writeMem(
		(registers[instr.rs] + instr.extra), 4, registers[instr.rt]))
	    return;
	break;
	
      case Instruction.OP_SWL:	  
	tmp = registers[instr.rs] + instr.extra;

	// The little endian/big endian swap code would
        // fail (I think) if the other cases are ever exercised.
	Debug.ASSERT((tmp & 0x3) == 0);  

	try {
	  value = readMem((tmp & ~0x3), 4);
	} catch (MachineException e) {
	  return;			// exception occurred
	}	
	switch (tmp & 0x3) {
	  case 0:
	    value = registers[instr.rt];
	    break;
	  case 1:
	    value = (value & 0xff000000) | ((registers[instr.rt] >> 8) &
					    0xffffff);
	    break;
	  case 2:
	    value = (value & 0xffff0000) | ((registers[instr.rt] >> 16) &
					    0xffff);
	    break;
	  case 3:
	    value = (value & 0xffffff00) | ((registers[instr.rt] >> 24) &
					    0xff);
	    break;
	}
	if (!writeMem((tmp & ~0x3), 4, value))
	    return;
	break;
    	
      case Instruction.OP_SWR:	  
	tmp = registers[instr.rs] + instr.extra;

	// The little endian/big endian swap code would
        // fail (I think) if the other cases are ever exercised.
	Debug.ASSERT((tmp & 0x3) == 0);  

	try {
	  value = readMem((tmp & ~0x3), 4);
	} catch (MachineException e) {
	  return;			// exception occurred
	}	
	switch (tmp & 0x3) {
	  case 0:
	    value = (value & 0xffffff) | (registers[instr.rt] << 24);
	    break;
	  case 1:
	    value = (value & 0xffff) | (registers[instr.rt] << 16);
	    break;
	  case 2:
	    value = (value & 0xff) | (registers[instr.rt] << 8);
	    break;
	  case 3:
	    value = registers[instr.rt];
	    break;
	}
	if (!writeMem((tmp & ~0x3), 4, value))
	    return;
	break;
    	
      case Instruction.OP_SYSCALL:
	raiseException(SyscallException, 0);
	return; 
	
      case Instruction.OP_XOR:
	registers[instr.rd] = registers[instr.rs] ^ registers[instr.rt];
	break;
	
      case Instruction.OP_XORI:
	registers[instr.rt] = registers[instr.rs] ^ (instr.extra & 0xffff);
	break;
	
      case Instruction.OP_RES:
      case Instruction.OP_UNIMP:
	raiseException(IllegalInstrException, 0);
	return;
	
      default:
	System.out.println("Bogus opcode, should not happen");
	return;
    }
    
    // Now we have successfully executed the instruction.
    
    // Do any delayed load operation
    delayedLoad(nextLoadReg, nextLoadValue);
    
    // Advance program counters.
    registers[PrevPCReg] = registers[PCReg];	// for debugging, in case we
						// are jumping into lala-land
    registers[PCReg] = registers[NextPCReg];
    registers[NextPCReg] = pcAfter;
  }
Beispiel #5
0
  static private int translate(int virtAddr, int size, boolean writing) 
       throws MachineException {
    int i = 0;
    long vpn, offset;
    TranslationEntry entry;
    long pageFrame;
    int physAddr;

    if (Debug.isEnabled('a')) {
      if (writing) 
	Debug.printf('a', "\tTranslate 0x%x, %s: ", new Integer(virtAddr), 
		     "write");
      else
	Debug.printf('a', "\tTranslate 0x%x, %s: ", new Integer(virtAddr), 
		     "read");
    }

    // check for alignment errors
    if (((size == 4) && (virtAddr & 0x3) != 0) || 
	((size == 2) && (virtAddr & 0x1) != 0)) {
      Debug.println('a', "alignment problem at " + virtAddr + ", size " + size);
      throw new MachineException(exceptionNames[AddressErrorException], 
				 AddressErrorException);
    }
    
    // we must have either a TLB or a page table, but not both!
    Debug.ASSERT(tlb == null || pageTable == null);	
    Debug.ASSERT(tlb != null || pageTable != null);	

    // calculate the virtual page number, and offset within the page,
    // from the virtual address
    vpn = ((long) virtAddr & LOW32BITS) / PageSize;
    offset = ((long) virtAddr & LOW32BITS) % PageSize;
    
    if (tlb == null) {		// => page table => vpn is index into table
      if (vpn >= pageTableSize) {
	Debug.println('a', "virtual page # " + virtAddr + 
		    " too large for page table size " + pageTableSize);
	throw new MachineException(exceptionNames[AddressErrorException], 
				   AddressErrorException);
      } else if (!pageTable[(int)vpn].valid) {
	Debug.println('a', "virtual page # " + virtAddr + 
		    " too large for page table size " + pageTableSize);
	throw new MachineException(exceptionNames[PageFaultException], 
				   PageFaultException);
      }
      entry = pageTable[(int)vpn];
    } else {
      for (entry = null, i = 0; i < TLBSize; i++)
	if (tlb[i].valid && (tlb[i].virtualPage == vpn)) {
	  entry = tlb[i];			// FOUND!
	  break;
	}
      if (entry == null) {				// not found
	Debug.println('a', "** no valid TLB entry found for this virtual page!");

	// really, this is a TLB fault,
	// the page may be in memory,
	// but not in the TLB
	throw new MachineException(exceptionNames[PageFaultException], 
				   PageFaultException);
      }
    }

    if (entry.readOnly && writing) {	// trying to write to a read-only page
      Debug.println('a', virtAddr + " mapped read-only at " + i + " in TLB!");
      throw new MachineException(exceptionNames[ReadOnlyException], 
				 ReadOnlyException);
    }
    pageFrame = entry.physicalPage;

    // if the pageFrame is too big, there is something really wrong! 
    // An invalid translation was loaded into the page table or TLB. 
    if (pageFrame >= NumPhysPages) { 
      Debug.println('a', "*** frame " + pageFrame + " > " + NumPhysPages);
      throw new MachineException(exceptionNames[BusErrorException], 
				 BusErrorException);
    }
    entry.use = true;		// set the use, dirty bits
    if (writing)
	entry.dirty = true;
    physAddr = (int) (pageFrame * PageSize + offset);

    Debug.ASSERT((physAddr >= 0) && ((physAddr + size) <= MemorySize));
    if (Debug.isEnabled('a')) {
      Debug.printf('a', "phys addr = 0x%x\n", new Integer(physAddr));
    }

    return physAddr;
  }