📄 processor.java
字号:
* <p> * Transfer the contents of the nextPC register into the PC register, and * then add 4 to the value in the nextPC register. Same as * <tt>advancePC(readRegister(regNextPC)+4)</tt>. * * <p> * Use after handling a syscall exception so that the processor will move * on to the next instruction. */ public void advancePC() { advancePC(registers[regNextPC]+4); } /** * Transfer the contents of the nextPC register into the PC register, and * then write the nextPC register. * * @param nextPC the new value of the nextPC register. */ private void advancePC(int nextPC) { registers[regPC] = registers[regNextPC]; registers[regNextPC] = nextPC; } /** Caused by a syscall instruction. */ public static final int exceptionSyscall = 0; /** Caused by an access to an invalid virtual page. */ public static final int exceptionPageFault = 1; /** Caused by an access to a virtual page not mapped by any TLB entry. */ public static final int exceptionTLBMiss = 2; /** Caused by a write access to a read-only virtual page. */ public static final int exceptionReadOnly = 3; /** Caused by an access to an invalid physical page. */ public static final int exceptionBusError = 4; /** Caused by an access to a misaligned virtual address. */ public static final int exceptionAddressError = 5; /** Caused by an overflow by a signed operation. */ public static final int exceptionOverflow = 6; /** Caused by an attempt to execute an illegal instruction. */ public static final int exceptionIllegalInstruction = 7; /** The names of the CPU exceptions. */ public static final String exceptionNames[] = { "syscall ", "page fault ", "TLB miss ", "read-only ", "bus error ", "address error", "overflow ", "illegal inst " }; /** Index of return value register 0. */ public static final int regV0 = 2; /** Index of return value register 1. */ public static final int regV1 = 3; /** Index of argument register 0. */ public static final int regA0 = 4; /** Index of argument register 1. */ public static final int regA1 = 5; /** Index of argument register 2. */ public static final int regA2 = 6; /** Index of argument register 3. */ public static final int regA3 = 7; /** Index of the stack pointer register. */ public static final int regSP = 29; /** Index of the return address register. */ public static final int regRA = 31; /** Index of the low register, used for multiplication and division. */ public static final int regLo = 32; /** Index of the high register, used for multiplication and division. */ public static final int regHi = 33; /** Index of the program counter register. */ public static final int regPC = 34; /** Index of the next program counter register. */ public static final int regNextPC = 35; /** Index of the exception cause register. */ public static final int regCause = 36; /** Index of the exception bad virtual address register. */ public static final int regBadVAddr = 37; /** The total number of software-accessible CPU registers. */ public static final int numUserRegisters = 38; /** Provides privilege to this processor. */ private Privilege privilege; /** MIPS registers accessible to the kernel. */ private int registers[] = new int[numUserRegisters]; /** The registered target of the delayed load currently in progress. */ private int loadTarget = 0; /** The bits to be modified by the delayed load currently in progress. */ private int loadMask; /** The value to be loaded by the delayed load currently in progress. */ private int loadValue; /** <tt>true</tt> if using a software-managed TLB. */ private boolean usingTLB; /** Number of TLB entries. */ private int tlbSize = 4; /** * Either an associative or direct-mapped set of translation entries, * depending on whether there is a TLB. */ private TranslationEntry[] translations; /** Size of a page, in bytes. */ public static final int pageSize = 0x400; /** Number of pages in a 32-bit address space. */ public static final int maxPages = (int) (0x100000000L / pageSize); /** Number of physical pages in memory. */ private int numPhysPages; /** Main memory for user programs. */ private byte[] mainMemory; /** The kernel exception handler, called on every user exception. */ private Runnable exceptionHandler = null; private static final char dbgProcessor = 'p'; private static final char dbgDisassemble = 'm'; private static final char dbgFullDisassemble = 'M'; private class ProcessorPrivilege implements Privilege.ProcessorPrivilege { public void flushPipe() { finishLoad(); } } private class MipsException extends Exception { public MipsException(int cause) { Lib.assert(cause >= 0 && cause < exceptionNames.length); this.cause = cause; } public MipsException(int cause, int badVAddr) { this(cause); hasBadVAddr = true; this.badVAddr = badVAddr; } public void handle() { writeRegister(regCause, cause); if (hasBadVAddr) writeRegister(regBadVAddr, badVAddr); if (Lib.test(dbgDisassemble) || Lib.test(dbgFullDisassemble)) System.out.println("exception: " + exceptionNames[cause]); finishLoad(); Lib.assert(exceptionHandler != null); // autograder might not want kernel to know about this exception if (!Machine.autoGrader().exceptionHandler(privilege)) return; exceptionHandler.run(); } private boolean hasBadVAddr = false; private int cause, badVAddr; } private class Instruction { public void run() throws MipsException { // hopefully this looks familiar to 152 students? fetch(); decode(); execute(); writeBack(); } private boolean test(int flag) { return Lib.test(flag, flags); } private void fetch() throws MipsException { if ((Lib.test(dbgDisassemble) && !Lib.test(dbgProcessor)) || Lib.test(dbgFullDisassemble)) System.out.print("PC=0x" + Lib.toHexString(registers[regPC]) + "\t"); value = readMem(registers[regPC], 4); } private void decode() { op = Lib.extract(value, 26, 6); rs = Lib.extract(value, 21, 5); rt = Lib.extract(value, 16, 5); rd = Lib.extract(value, 11, 5); sh = Lib.extract(value, 6, 5); func = Lib.extract(value, 0, 6); target = Lib.extract(value, 0, 26); imm = Lib.extend(value, 0, 16); Mips info; switch (op) { case 0: info = Mips.specialtable[func]; break; case 1: info = Mips.regimmtable[rt]; break; default: info = Mips.optable[op]; break; } operation = info.operation; name = info.name; format = info.format; flags = info.flags; mask = 0xFFFFFFFF; branch = true; // get memory access size if (test(Mips.SIZEB)) size = 1; else if (test(Mips.SIZEH)) size = 2; else if (test(Mips.SIZEW)) size = 4; else size = 0; // get nextPC nextPC = registers[regNextPC]+4; // get dstReg if (test(Mips.DSTRA)) dstReg = regRA; else if (format == Mips.IFMT) dstReg = rt; else if (format == Mips.RFMT) dstReg = rd; else dstReg = -1; // get jtarget if (format == Mips.RFMT) jtarget = registers[rs]; else if (format == Mips.IFMT) jtarget = registers[regNextPC] + (imm<<2); else if (format == Mips.JFMT) jtarget = (registers[regNextPC]&0xF0000000) | (target<<2); else jtarget = -1; // get imm if (test(Mips.UNSIGNED)) { imm &= 0xFFFF; } // get addr addr = registers[rs] + imm; // get src1 if (test(Mips.SRC1SH)) src1 = sh; else src1 = registers[rs]; // get src2 if (test(Mips.SRC2IMM)) src2 = imm; else src2 = registers[rt]; if (test(Mips.UNSIGNED)) { src1 &= 0xFFFFFFFFL; src2 &= 0xFFFFFFFFL; } if (Lib.test(dbgDisassemble) || Lib.test(dbgFullDisassemble)) print(); } private void print() { if (Lib.test(dbgDisassemble) && Lib.test(dbgProcessor) && !Lib.test(dbgFullDisassemble)) System.out.print("PC=0x" + Lib.toHexString(registers[regPC]) + "\t"); if (operation == Mips.INVALID) { System.out.print("invalid: op=" + Lib.toHexString(op, 2) + " rs=" + Lib.toHexString(rs, 2) + " rt=" + Lib.toHexString(rt, 2) + " rd=" + Lib.toHexString(rd, 2) + " sh=" + Lib.toHexString(sh, 2) + " func=" + Lib.toHexString(func, 2) + "\n"); return; } int spaceIndex = name.indexOf(' '); Lib.assert(spaceIndex!=-1 && spaceIndex==name.lastIndexOf(' ')); String instname = name.substring(0, spaceIndex); char[] args = name.substring(spaceIndex+1).toCharArray(); System.out.print(instname + "\t"); int minCharsPrinted = 0, maxCharsPrinted = 0; for (int i=0; i<args.length; i++) { switch (args[i]) { case Mips.RS: System.out.print("$" + rs); minCharsPrinted += 2; maxCharsPrinted += 3; if (Lib.test(dbgFullDisassemble)) { System.out.print("#0x" + Lib.toHexString(registers[rs])); minCharsPrinted += 11; maxCharsPrinted += 11; } break; case Mips.RT: System.out.print("$" + rt); minCharsPrinted += 2; maxCharsPrinted += 3; if (Lib.test(dbgFullDisassemble) && (i!=0 || !test(Mips.DST)) && !test(Mips.DELAYEDLOAD)) { System.out.print("#0x" + Lib.toHexString(registers[rt])); minCharsPrinted += 11; maxCharsPrinted += 11; } break; case Mips.RETURNADDRESS: if (rd == 31) continue; case Mips.RD: System.out.print("$" + rd); minCharsPrinted += 2; maxCharsPrinted += 3; break; case Mips.IMM: System.out.print(imm); minCharsPrinted += 1; maxCharsPrinted += 6; break; case Mips.SHIFTAMOUNT: System.out.print(sh); minCharsPrinted += 1; maxCharsPrinted += 2; break; case Mips.ADDR: System.out.print(imm + "($" + rs); minCharsPrinted += 4; maxCharsPrinted += 5; if (Lib.test(dbgFullDisassemble)) { System.out.print("#0x" + Lib.toHexString(registers[rs])); minCharsPrinted += 11; maxCharsPrinted += 11; } System.out.print(")"); break; case Mips.TARGET: System.out.print("0x" + Lib.toHexString(jtarget)); minCharsPrinted += 10; maxCharsPrinted += 10; break; default: Lib.assert(false); } if (i+1 < args.length) { System.out.print(", "); minCharsPrinted += 2; maxCharsPrinted += 2; } else { // most separation possible is tsi, 5+1+1=7, // thankfully less than 8 (makes this possible) Lib.assert(maxCharsPrinted-minCharsPrinted < 8); // longest string is stj, which is 40-42 chars w/ -d M; // go for 48 while ((minCharsPrinted%8) != 0) { System.out.print(" "); minCharsPrinted++; maxCharsPrinted++; } while (minCharsPrinted < 48) { System.out.print("\t"); minCharsPrinted += 8; } } } if (Lib.test(dbgDisassemble) && Lib.test(dbgProcessor) && !Lib.test(dbgFullDisassemble)) System.out.print("\n"); } private void execute() throws MipsException { int value; int preserved; switch (operation) { case Mips.ADD: dst = src1 + src2; break; case Mips.SUB: dst = src1 - src2; break; case Mips.MULT: dst = src1 * src2; registers[regLo] = (int) Lib.extract(dst, 0, 32); registers[regHi] = (int) Lib.extract(dst, 32, 32); break; case Mips.DIV: try { registers[regLo] = (int) (src1 / src2); registers[regHi] = (int) (src1 % src2); if (registers[regLo]*src2 + registers[regHi] != src1) throw new ArithmeticException(); } catch (ArithmeticException e) { throw new MipsException(exceptionOverflow); } break; case Mips.SLL: dst = src2 << (src1&0x1F); break; case Mips.SRA: dst = src2 >> (src1&0x1F); break; case Mips.SRL:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -