📄 processor.java
字号:
// PART OF THE MACHINE SIMULATION. DO NOT CHANGE.package nachos.machine;import nachos.security.*;/** * The <tt>Processor</tt> class simulates a MIPS processor that supports a * subset of the R3000 instruction set. Specifically, the processor lacks all * coprocessor support, and can only execute in user mode. Address translation * information is accessed via the API. The API also allows a kernel to set an * exception handler to be called on any user mode exception. * * <p> * The <tt>Processor</tt> API is re-entrant, so a single simulated processor * can be shared by multiple user threads. * * <p> * An instance of a <tt>Processor</tt> also includes pages of physical memory * accessible to user programs, the size of which is fixed by the constructor. */public final class Processor { /** * Allocate a new MIPS processor, with the specified amount of memory. * * @param privilege encapsulates privileged access to the Nachos * machine. * @param numPhysPages the number of pages of physical memory to * attach. */ public Processor(Privilege privilege, int numPhysPages) { System.out.print(" processor"); this.privilege = privilege; privilege.processor = new ProcessorPrivilege(); Class clsKernel = Lib.loadClass(Config.getString("Kernel.kernel")); Class clsVMKernel = Lib.tryLoadClass("nachos.vm.VMKernel"); usingTLB = (clsVMKernel != null && clsVMKernel.isAssignableFrom(clsKernel)); this.numPhysPages = numPhysPages; for (int i=0; i<numUserRegisters; i++) registers[i] = 0; mainMemory = new byte[pageSize * numPhysPages]; if (usingTLB) { translations = new TranslationEntry[tlbSize]; for (int i=0; i<tlbSize; i++) translations[i] = new TranslationEntry(); } else { translations = null; } } /** * Set the exception handler, called whenever a user exception occurs. * * <p> * When the exception handler is called, interrupts will be enabled, and * the CPU cause register will specify the cause of the exception (see the * <tt>exception<i>*</i></tt> constants). * * @param exceptionHandler the kernel exception handler. */ public void setExceptionHandler(Runnable exceptionHandler) { this.exceptionHandler = exceptionHandler; } /** * Get the exception handler, set by the last call to * <tt>setExceptionHandler()</tt>. * * @return the exception handler. */ public Runnable getExceptionHandler() { return exceptionHandler; } /** * Start executing instructions at the current PC. Never returns. */ public void run() { Lib.debug(dbgProcessor, "starting program in current thread"); registers[regNextPC] = registers[regPC] + 4; Machine.autoGrader().runProcessor(privilege); Instruction inst = new Instruction(); while (true) { try { inst.run(); } catch (MipsException e) { e.handle(); } privilege.interrupt.tick(false); } } /** * Read and return the contents of the specified CPU register. * * @param number the register to read. * @return the value of the register. */ public int readRegister(int number) { Lib.assert(number >= 0 && number < numUserRegisters); return registers[number]; } /** * Write the specified value into the specified CPU register. * * @param number the register to write. * @param value the value to write. */ public void writeRegister(int number, int value) { Lib.assert(number >= 0 && number < numUserRegisters); if (number != 0) registers[number] = value; } /** * Test whether this processor uses a software-managed TLB, or single-level * paging. * * <p> * If <tt>false</tt>, this processor directly supports single-level paging; * use <tt>setPageTable()</tt>. * * <p> * If <tt>true</tt>, this processor has a software-managed TLB; * use <tt>getTLBSize()</tt>, <tt>readTLBEntry()</tt>, and * <tt>writeTLBEntry()</tt>. * * <p> * Using a method associated with the wrong address translation mechanism * will result in an assertion failure. * * @return <tt>true</tt> if this processor has a software-managed TLB. */ public boolean hasTLB() { return usingTLB; } /** * Get the current page table, set by the last call to setPageTable(). * * @return the current page table. */ public TranslationEntry[] getPageTable() { Lib.assert(!usingTLB); return translations; } /** * Set the page table pointer. All further address translations will use * the specified page table. The size of the current address space will be * determined from the length of the page table array. * * @param pageTable the page table to use. */ public void setPageTable(TranslationEntry[] pageTable) { Lib.assert(!usingTLB); this.translations = pageTable; } /** * Return the number of entries in this processor's TLB. * * @return the number of entries in this processor's TLB. */ public int getTLBSize() { Lib.assert(usingTLB); return tlbSize; } /** * Returns the specified TLB entry. * * @param number the index into the TLB. * @return the contents of the specified TLB entry. */ public TranslationEntry readTLBEntry(int number) { Lib.assert(usingTLB); Lib.assert(number >= 0 && number < tlbSize); return new TranslationEntry(translations[number]); } /** * Fill the specified TLB entry. * * <p> * The TLB is fully associative, so the location of an entry within the TLB * does not affect anything. * * @param number the index into the TLB. * @param entry the new contents of the TLB entry. */ public void writeTLBEntry(int number, TranslationEntry entry) { Lib.assert(usingTLB); Lib.assert(number >= 0 && number < tlbSize); translations[number] = new TranslationEntry(entry); } /** * Return the number of pages of physical memory attached to this simulated * processor. * * @return the number of pages of physical memory. */ public int getNumPhysPages() { return numPhysPages; } /** * Return a reference to the physical memory array. The size of this array * is <tt>pageSize * getNumPhysPages()</tt>. * * @return the main memory array. */ public byte[] getMemory() { return mainMemory; } /** * Concatenate a page number and an offset into an address. * * @param page the page number. Must be between <tt>0</tt> and * <tt>(2<sup>32</sup> / pageSize) - 1</tt>. * @param offset the offset within the page. Must be between <tt>0</tt> * and * <tt>pageSize - 1</tt>. * @return a 32-bit address consisting of the specified page and offset. */ public static int makeAddress(int page, int offset) { Lib.assert(page >= 0 && page < maxPages); Lib.assert(offset >= 0 && offset < pageSize); return (page * pageSize) | offset; } /** * Extract the page number component from a 32-bit address. * * @param address the 32-bit address. * @return the page number component of the address. */ public static int pageFromAddress(int address) { return (int) (((long) address & 0xFFFFFFFFL) / pageSize); } /** * Extract the offset component from an address. * * @param address the 32-bit address. * @return the offset component of the address. */ public static int offsetFromAddress(int address) { return (int) (((long) address & 0xFFFFFFFFL) % pageSize); } private void finishLoad() { delayedLoad(0, 0, 0); } /** * Translate a virtual address into a physical address, using either a * page table or a TLB. Check for alignment, make sure the virtual page is * valid, make sure a read-only page is not being written, make sure the * resulting physical page is valid, and then return the resulting physical * address. * * @param vaddr the virtual address to translate. * @param size the size of the memory reference (must be 1, 2, or 4). * @param writing <tt>true</tt> if the memory reference is a write. * @return the physical address. * @exception MipsException if a translation error occurred. */ private int translate(int vaddr, int size, boolean writing) throws MipsException { if (Lib.test(dbgProcessor)) System.out.println("\ttranslate vaddr=0x" + Lib.toHexString(vaddr) + (writing ? ", write" : ", read...")); // check alignment if ((vaddr & (size-1)) != 0) { Lib.debug(dbgProcessor, "\t\talignment error"); throw new MipsException(exceptionAddressError, vaddr); } // calculate virtual page number and offset from the virtual address int vpn = pageFromAddress(vaddr); int offset = offsetFromAddress(vaddr); TranslationEntry entry = null; // if not using a TLB, then the vpn is an index into the table if (!usingTLB) { if (translations == null || vpn >= translations.length || translations[vpn] == null || !translations[vpn].valid) { privilege.stats.numPageFaults++; Lib.debug(dbgProcessor, "\t\tpage fault"); throw new MipsException(exceptionPageFault, vaddr); } entry = translations[vpn]; } // else, look through all TLB entries for matching vpn else { for (int i=0; i<tlbSize; i++) { if (translations[i].valid && translations[i].vpn == vpn) { entry = translations[i]; break; } } if (entry == null) { privilege.stats.numTLBMisses++; Lib.debug(dbgProcessor, "\t\tTLB miss"); throw new MipsException(exceptionTLBMiss, vaddr); } } // check if trying to write a read-only page if (entry.readOnly && writing) { Lib.debug(dbgProcessor, "\t\tread-only exception"); throw new MipsException(exceptionReadOnly, vaddr); } // check if physical page number is out of range int ppn = entry.ppn; if (ppn < 0 || ppn >= numPhysPages) { Lib.debug(dbgProcessor, "\t\tbad ppn"); throw new MipsException(exceptionBusError, vaddr); } // set used and dirty bits as appropriate entry.used = true; if (writing) entry.dirty = true; int paddr = (ppn*pageSize) + offset; if (Lib.test(dbgProcessor)) System.out.println("\t\tpaddr=0x" + Lib.toHexString(paddr)); return paddr; } /** * Read </i>size</i> (1, 2, or 4) bytes of virtual memory at <i>vaddr</i>, * and return the result. * * @param vaddr the virtual address to read from. * @param size the number of bytes to read (1, 2, or 4). * @return the value read. * @exception MipsException if a translation error occurred. */ private int readMem(int vaddr, int size) throws MipsException { if (Lib.test(dbgProcessor)) System.out.println("\treadMem vaddr=0x" + Lib.toHexString(vaddr) + ", size=" + size); Lib.assert(size==1 || size==2 || size==4); int value = Lib.bytesToInt(mainMemory, translate(vaddr, size, false), size); if (Lib.test(dbgProcessor)) System.out.println("\t\tvalue read=0x" + Lib.toHexString(value, size*2)); return value; } /** * Write <i>value</i> to </i>size</i> (1, 2, or 4) bytes of virtual memory * starting at <i>vaddr</i>. * * @param vaddr the virtual address to write to. * @param size the number of bytes to write (1, 2, or 4). * @param value the value to store. * @exception MipsException if a translation error occurred. */ private void writeMem(int vaddr, int size, int value) throws MipsException { if (Lib.test(dbgProcessor)) System.out.println("\twriteMem vaddr=0x" + Lib.toHexString(vaddr) + ", size=" + size + ", value=0x" + Lib.toHexString(value, size*2)); Lib.assert(size==1 || size==2 || size==4); Lib.bytesFromInt(mainMemory, translate(vaddr, size, true), size, value); } /** * Complete the in progress delayed load and scheduled a new one. * * @param nextLoadTarget the target register of the new load. * @param nextLoadValue the value to be loaded into the new target. * @param nextLoadMask the mask specifying which bits in the new * target are to be overwritten. If a bit in * <tt>nextLoadMask</tt> is 0, then the * corresponding bit of register * <tt>nextLoadTarget</tt> will not be written. */ private void delayedLoad(int nextLoadTarget, int nextLoadValue, int nextLoadMask) { // complete previous delayed load, if not modifying r0 if (loadTarget != 0) { int savedBits = registers[loadTarget] & ~loadMask; int newBits = loadValue & loadMask; registers[loadTarget] = savedBits | newBits; } // schedule next load loadTarget = nextLoadTarget; loadValue = nextLoadValue; loadMask = nextLoadMask; } /** * Advance the PC to the next instruction. *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -