Main Page | Alphabetical List | Class List | File List | Class Members | File Members

machine.cc

Go to the documentation of this file.
00001 // machine.cc 00002 // Routines for simulating the execution of user programs. 00003 // 00004 // DO NOT CHANGE -- part of the machine emulation 00005 // 00006 // Copyright (c) 1992-1993 The Regents of the University of California. 00007 // All rights reserved. See copyright.h for copyright notice and limitation 00008 // of liability and disclaimer of warranty provisions. 00009 00010 #include "copyright.h" 00011 #include "machine.h" 00012 #include "system.h" 00013 00014 // Textual names of the exceptions that can be generated by user program 00015 // execution, for debugging. 00016 static char* exceptionNames[] = { "no exception", "syscall", 00017 "page fault/no TLB entry", "page read only", 00018 "bus error", "address error", "overflow", 00019 "illegal instruction" }; 00020 00021 //---------------------------------------------------------------------- 00022 // CheckEndian 00023 // Check to be sure that the host really uses the format it says it 00024 // does, for storing the bytes of an integer. Stop on error. 00025 //---------------------------------------------------------------------- 00026 00027 static 00028 void CheckEndian() 00029 { 00030 union checkit { 00031 char charword[4]; 00032 unsigned int intword; 00033 } check; 00034 00035 check.charword[0] = 1; 00036 check.charword[1] = 2; 00037 check.charword[2] = 3; 00038 check.charword[3] = 4; 00039 00040 #ifdef HOST_IS_BIG_ENDIAN 00041 ASSERT (check.intword == 0x01020304); 00042 #else 00043 ASSERT (check.intword == 0x04030201); 00044 #endif 00045 } 00046 00047 //---------------------------------------------------------------------- 00048 // Machine::Machine 00049 // Initialize the simulation of user program execution. 00050 // 00051 // "debug" -- if TRUE, drop into the debugger after each user instruction 00052 // is executed. 00053 //---------------------------------------------------------------------- 00054 00055 Machine::Machine(bool debug) 00056 { 00057 int i; 00058 00059 for (i = 0; i < NumTotalRegs; i++) 00060 registers[i] = 0; 00061 mainMemory = new char[MemorySize]; 00062 for (i = 0; i < MemorySize; i++) 00063 mainMemory[i] = 0; 00064 #ifdef USE_TLB 00065 tlb = new TranslationEntry[TLBSize]; 00066 for (i = 0; i < TLBSize; i++) 00067 tlb[i].valid = FALSE; 00068 pageTable = NULL; 00069 #else // use linear page table 00070 tlb = NULL; 00071 pageTable = NULL; 00072 #endif 00073 00074 singleStep = debug; 00075 CheckEndian(); 00076 } 00077 00078 //---------------------------------------------------------------------- 00079 // Machine::~Machine 00080 // De-allocate the data structures used to simulate user program execution. 00081 //---------------------------------------------------------------------- 00082 00083 Machine::~Machine() 00084 { 00085 delete [] mainMemory; 00086 if (tlb != NULL) 00087 delete [] tlb; 00088 } 00089 00090 //---------------------------------------------------------------------- 00091 // Machine::RaiseException 00092 // Transfer control to the Nachos kernel from user mode, because 00093 // the user program either invoked a system call, or some exception 00094 // occured (such as the address translation failed). 00095 // 00096 // "which" -- the cause of the kernel trap 00097 // "badVaddr" -- the virtual address causing the trap, if appropriate 00098 //---------------------------------------------------------------------- 00099 00100 void 00101 Machine::RaiseException(ExceptionType which, int badVAddr) 00102 { 00103 DEBUG('m', "Exception: %s\n", exceptionNames[which]); 00104 00105 // ASSERT(interrupt->getStatus() == UserMode); 00106 registers[BadVAddrReg] = badVAddr; 00107 DelayedLoad(0, 0); // finish anything in progress 00108 interrupt->setStatus(SystemMode); 00109 ExceptionHandler(which); // interrupts are enabled at this point 00110 interrupt->setStatus(UserMode); 00111 } 00112 00113 //---------------------------------------------------------------------- 00114 // Machine::Debugger 00115 // Primitive debugger for user programs. Note that we can't use 00116 // gdb to debug user programs, since gdb doesn't run on top of Nachos. 00117 // It could, but you'd have to implement *a lot* more system calls 00118 // to get it to work! 00119 // 00120 // So just allow single-stepping, and printing the contents of memory. 00121 //---------------------------------------------------------------------- 00122 00123 void Machine::Debugger() 00124 { 00125 char *buf = new char[80]; 00126 int num; 00127 00128 interrupt->DumpState(); 00129 DumpState(); 00130 printf("%d> ", stats->totalTicks); 00131 fflush(stdout); 00132 fgets(buf, 80, stdin); 00133 if (sscanf(buf, "%d", &num) == 1) 00134 runUntilTime = num; 00135 else { 00136 runUntilTime = 0; 00137 switch (*buf) { 00138 case '\n': 00139 break; 00140 00141 case 'c': 00142 singleStep = FALSE; 00143 break; 00144 00145 case '?': 00146 printf("Machine commands:\n"); 00147 printf(" <return> execute one instruction\n"); 00148 printf(" <number> run until the given timer tick\n"); 00149 printf(" c run until completion\n"); 00150 printf(" ? print help message\n"); 00151 break; 00152 } 00153 } 00154 delete [] buf; 00155 } 00156 00157 //---------------------------------------------------------------------- 00158 // Machine::DumpState 00159 // Print the user program's CPU state. We might print the contents 00160 // of memory, but that seemed like overkill. 00161 //---------------------------------------------------------------------- 00162 00163 void 00164 Machine::DumpState() 00165 { 00166 int i; 00167 00168 printf("Machine registers:\n"); 00169 for (i = 0; i < NumGPRegs; i++) 00170 switch (i) { 00171 case StackReg: 00172 printf("\tSP(%d):\t0x%x%s", i, registers[i], 00173 ((i % 4) == 3) ? "\n" : ""); 00174 break; 00175 00176 case RetAddrReg: 00177 printf("\tRA(%d):\t0x%x%s", i, registers[i], 00178 ((i % 4) == 3) ? "\n" : ""); 00179 break; 00180 00181 default: 00182 printf("\t%d:\t0x%x%s", i, registers[i], 00183 ((i % 4) == 3) ? "\n" : ""); 00184 break; 00185 } 00186 00187 printf("\tHi:\t0x%x", registers[HiReg]); 00188 printf("\tLo:\t0x%x\n", registers[LoReg]); 00189 printf("\tPC:\t0x%x", registers[PCReg]); 00190 printf("\tNextPC:\t0x%x", registers[NextPCReg]); 00191 printf("\tPrevPC:\t0x%x\n", registers[PrevPCReg]); 00192 printf("\tLoad:\t0x%x", registers[LoadReg]); 00193 printf("\tLoadV:\t0x%x\n", registers[LoadValueReg]); 00194 printf("\n"); 00195 } 00196 00197 //---------------------------------------------------------------------- 00198 // Machine::ReadRegister/WriteRegister 00199 // Fetch or write the contents of a user program register. 00200 //---------------------------------------------------------------------- 00201 00202 int Machine::ReadRegister(int num) 00203 { 00204 ASSERT((num >= 0) && (num < NumTotalRegs)); 00205 return registers[num]; 00206 } 00207 00208 void Machine::WriteRegister(int num, int value) 00209 { 00210 ASSERT((num >= 0) && (num < NumTotalRegs)); 00211 // DEBUG('m', "WriteRegister %d, value %d\n", num, value); 00212 registers[num] = value; 00213 } 00214

Generated on Thu Sep 16 12:33:45 2004 for NachOS by doxygen 1.3.8