package vue; // Java imports import java.util.*; // CPU state class CPU { // Private fields private JavaVUE vue; // Emulation state // Package fields Access access; // Access state int cycles; // Cycles until next stage int exception; // Exception code int fetch; // Fetch unit index Instruction inst; // Instruction state int irq; // Interrupt lines int[] jumpFrom; // Source PCs of most recent jumps int[] jumpTo; // Destination PCs of most recent jumps int stage; // Current processing stage // Program registers int[] program; // System registers int adtre; // Address Trap Register for Execution int eipc; // Exception/interrupt PC int eipsw; // Exception/interrupt PSW int fepc; // Duplexed exception PC int fepsw; // Duplexed exception PSW int pc; // Program Counter int sr29; // System register 29 int sr31; // System register 31 // Program Status Word int psw_ae; // Address Trap Enable int psw_ep; // Exception Pending int psw_id; // Interrupt Disable int psw_cy; // Carry int psw_fiv; // Floating Reserved Operand int psw_fov; // Floating Overflow int psw_fpr; // Floating Precision int psw_fro; // Floating Reserved Operand int psw_fud; // Floating Underflow int psw_fzd; // Floating Zero Divide int psw_i; // Interrupt Level int psw_np; // NMI Pending int psw_ov; // Overflow int psw_s; // Sign int psw_z; // Zero // Cache Control Word int chcw_cec; // Clear Entry Count int chcw_cen; // Clear Entry Number int chcw_icc; // Instruction Cache Clear int chcw_icd; // Instruction Cache Dump int chcw_ice; // Instruction Cache Enable int chcw_icr; // Instruction Cache Restore int chcw_sa; // Spill-Out Base Address // Exception Cause Register int ecr_eicc; // Exception/Interrupt Cause Code int ecr_fecc; // Fatal Error Cause Code /////////////////////////////////////////////////////////////////////////// // Constants // /////////////////////////////////////////////////////////////////////////// // Stages static final int FATAL = -1; static final int FETCH = 0; static final int EXECUTE = 1; static final int EXCEPTION = 2; static final int HALT = 3; static final int CLEAR = 4; static final int DUMP = 5; static final int RESTORE = 6; // Instruction cycle counts private static final byte[] CYCLES = { 1, 1, 28, 1, 1, 1, 1, 1, 1, 26, 12, 1, 1, 10, 14, 16, 38, 44, 36, 1, 5, 5, 5, 3, 3, 3, 5, 5, 5, 8, 1, 1, 1, 1, 1, 9, 13, 30, 13, 1, 1, 1, 1, 1, 1, 4, 4, 4, 10, 22, 1, 1, 1, 1, 1, 1, 12, 1, 1, 1, 1, 1, 4, 4, 4, 8, 1, 28, 15, 14, 6, 1, 1, 1, 1, 1 }; /////////////////////////////////////////////////////////////////////////// // Constructors // /////////////////////////////////////////////////////////////////////////// // Default constructor CPU(JavaVUE vue) { access = new Access(); inst = new Instruction(); jumpFrom = new int[3]; jumpTo = new int[3]; program = new int[32]; this.vue = vue; } /////////////////////////////////////////////////////////////////////////// // Package Methods // /////////////////////////////////////////////////////////////////////////// // Process the simulation void emulate(int cycles) { // The CPU is in permanent halt if (stage == FATAL) return; // Process for the given number of cycles do { // The next event occurs after the given number of cycles if (this.cycles > cycles) { this.cycles -= cycles; return; } // Processing by stage switch (stage) { case FETCH : if (fetch ()) return; case EXECUTE : if (execute ()) return; case HALT : testException(); break; case EXCEPTION: if (exception()) return; } } while (cycles > 0); } // Read a system register int getSystemRegister(int index) { switch (index) { case VUE.ADTRE: return adtre; case VUE.EIPC : return eipc; case VUE.EIPSW: return eipsw; case VUE.FEPC : return fepc; case VUE.FEPSW: return fepsw; case VUE.ECR : return ecr_fecc << 16 | ecr_eicc; case VUE.PIR : return 0x00005346; case VUE.TKCW : return 0x000000E0; case VUE.CHCW : return chcw_ice << 1; case 29 : return sr29; case 30 : return 0x00000004; case 31 : return sr31; case VUE.PSW : return psw_i << 16 | psw_fro << 9 | psw_fpr << 4 | psw_np << 15 | psw_fiv << 8 | psw_cy << 3 | psw_ep << 14 | psw_fzd << 7 | psw_ov << 2 | psw_ae << 13 | psw_fov << 6 | psw_s << 1 | psw_id << 12 | psw_fud << 5 | psw_z ; // Remaining cases to encourage tableswitch case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: return 0; } return 1; // Unreachable } // System reset void reset() { // Configure instance fields cycles = 0; // Duration of first fetch exception = 0; fetch = 0; irq = 0; stage = FETCH; // Clear all registers (hardware only sets ECR, PC and PSW) for (int x = 0; x < 32; x++) { program[x] = 0; setSystemRegister(x, 0, true); } // Configure jump histories Arrays.fill(jumpFrom, 0xFFFFFFF0); Arrays.fill(jumpTo , 0xFFFFFFF0); // Configure registers ecr_eicc = 0xFFF0; pc = 0xFFFFFFF0; psw_np = 1; } // Write a system register int setSystemRegister(int index, int value, boolean debug) { switch (index) { case VUE.ADTRE: return adtre = value & 0xFFFFFFFE; case VUE.EIPC : return eipc = value & 0xFFFFFFFE; case VUE.EIPSW: return eipsw = value & 0x000FF3FF; case VUE.FEPC : return fepc = value & 0xFFFFFFFE; case VUE.FEPSW: return fepsw = value & 0x000FF3FF; case 29 : return sr29 = value; case 31 : return sr31 = debug || value >= 0 ? value : -value; case VUE.ECR: if (debug) { ecr_fecc = value >> 16 & 0xFFFF; ecr_eicc = value & 0xFFFF; } return ecr_fecc << 16 | ecr_eicc; case VUE.CHCW : chcw_cen = value >> 20 & 0x00000FFF; chcw_cec = value >> 8 & 0x00000FFF; chcw_sa = value >> 8 & 0x00FFFFFF; chcw_icr = value >> 5 & 1; chcw_icd = value >> 4 & 1; chcw_ice = value >> 1 & 1; chcw_icc = value & 1; // Only one of ICC, ICD or ICR is set value &= 0x00000031; if ((value & value - 1) == 0) { // Clear // Dump // Restore } return chcw_ice << 1; case VUE.PSW : psw_i = value >> 16 & 15; psw_fov = value >> 6 & 1; psw_np = value >> 15 & 1; psw_fud = value >> 5 & 1; psw_ep = value >> 14 & 1; psw_fpr = value >> 4 & 1; psw_ae = value >> 13 & 1; psw_cy = value >> 3 & 1; psw_id = value >> 12 & 1; psw_ov = value >> 2 & 1; psw_fro = value >> 9 & 1; psw_s = value >> 1 & 1; psw_fiv = value >> 8 & 1; psw_z = value & 1; psw_fzd = value >> 7 & 1; return value & 0x000FF3FF; // Remaining cases to encourage tableswitch case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 26: case 27: case 28: case 30: return 0; } return 1; // Unreachable } // Test a condition int test(int condition) { switch (condition) { case 0: return psw_ov; case 1: return psw_cy; case 2: return psw_z; case 3: return psw_cy | psw_z; case 4: return psw_s; case 5: return 1; case 6: return psw_ov | psw_s; case 7: return psw_ov ^ psw_s | psw_z; } return test(condition & 7) ^ 1; } // Determine the number of CPU cycles until something can happen int until(int cycles) { if (stage == FATAL || stage == HALT) return cycles; return cycles < 0 ? this.cycles : Math.min(cycles, this.cycles); } /////////////////////////////////////////////////////////////////////////// // Private Methods // /////////////////////////////////////////////////////////////////////////// // Operations for exception stage private boolean exception() { // Application callback if (vue.onException != null) { vue.breakCode = vue.onException.call(vue, exception); if (vue.breakCode != 0) return true; } exception &= 0xFFFF; boolean isIRQ = (exception & 0xFF00) == 0xFE00; int psw = getSystemRegister(VUE.PSW); // Fatal exception if (psw_np != 0) { vue.write(0x00000000, VUE.S32, 0xFFFF0000 | exception); vue.write(0x00000004, VUE.S32, psw); vue.write(0x00000008, VUE.S32, pc); } // Duplexed exception if (psw_ep != 0) { ecr_fecc = exception; fepc = pc; fepsw = psw; pc = 0xFFFFFFD0; } // Regular exception else { ecr_eicc = exception; eipc = pc; eipsw = psw; pc = 0xFFFF0000 | exception & 0xFFF0; if (pc == 0xFFFFFF70) // FIV pc = 0xFFFFFF60; } // Interrupt if (isIRQ) psw_i = Math.min(15, exception >> 4 & 15); // Common processing exception = 0; psw_ae = 0; psw_id = 1; stage = FETCH; return false; } // Operations for execute stage private boolean execute() { // Application callback if (vue.onExecute != null) { vue.breakCode = vue.onExecute.call(vue, inst); if (vue.breakCode != 0) return true; } // Determine the default number of cycles for the instruction if (inst.id >= 0 && inst.id <= 75) cycles = CYCLES[inst.id]; // Processing by instruction ID switch (inst.id) { //case VUE.ADD_IMM: ADD_IMM(); break; //case VUE.ADD_REG: ADD_REG(); break; //case VUE.ADDF_S : ADDF_S (); break; //case VUE.ADDI : ADDI (); break; //case VUE.AND : AND (); break; //case VUE.ANDBSU : ANDBSU (); break; //case VUE.ANDI : ANDI (); break; //case VUE.ANDNBSU: ANDNBSU(); break; //case VUE.BCOND : BCOND (); break; //case VUE.CAXI : CAXI (); break; //case VUE.CLI : CLI (); break; //case VUE.CMP_IMM: CMP_IMM(); break; //case VUE.CMP_REG: CMP_REG(); break; //case VUE.CMPF_S : CMPF_S (); break; //case VUE.CVT_SW : CVT_SW (); break; //case VUE.CVT_WS : CVT_WS (); break; //case VUE.DIV : DIV (); break; //case VUE.DIVF_S : DIVF_S (); break; //case VUE.DIVU : DIVU (); break; //case VUE.HALT : HALT (); break; //case VUE.IN_B : IN_B (); break; //case VUE.IN_H : IN_H (); break; //case VUE.IN_W : IN_W (); break; //case VUE.JAL : JAL (); break; //case VUE.JMP : JMP (); break; //case VUE.JR : JR (); break; //case VUE.LD_B : LD_B (); break; //case VUE.LD_H : LD_H (); break; //case VUE.LD_W : LD_W (); break; //case VUE.LDSR : LDSR (); break; //case VUE.MOV_IMM: MOV_IMM(); break; //case VUE.MOV_REG: MOV_REG(); break; //case VUE.MOVBSU : MOVBSU (); break; //case VUE.MOVEA : MOVEA (); break; //case VUE.MOVHI : MOVHI (); break; //case VUE.MPYHW : MPYHW (); break; //case VUE.MUL : MUL (); break; //case VUE.MULF_S : MULF_S (); break; //case VUE.MULU : MULU (); break; //case VUE.NOT : NOT (); break; //case VUE.NOTBSU : NOTBSU (); break; //case VUE.OR : OR (); break; //case VUE.ORBSU : ORBSU (); break; //case VUE.ORI : ORI (); break; //case VUE.ORNBSU : ORNBSU (); break; //case VUE.OUT_B : OUT_B (); break; //case VUE.OUT_H : OUT_H (); break; //case VUE.OUT_W : OUT_W (); break; //case VUE.RETI : RETI (); break; //case VUE.REV : REV (); break; //case VUE.SAR_IMM: SAR_IMM(); break; //case VUE.SAR_REG: SAR_REG(); break; //case VUE.SCH0BSD: SCH0BSD(); break; //case VUE.SCH0BSU: SCH0BSU(); break; //case VUE.SCH1BSD: SCH1BSD(); break; //case VUE.SCH1BSU: SCH1BSU(); break; //case VUE.SEI : SEI (); break; //case VUE.SETF : SETF (); break; //case VUE.SHL_IMM: SHL_IMM(); break; //case VUE.SHL_REG: SHL_REG(); break; //case VUE.SHR_IMM: SHR_IMM(); break; //case VUE.SHR_REG: SHR_REG(); break; //case VUE.ST_B : ST_B (); break; //case VUE.ST_H : ST_H (); break; //case VUE.ST_W : ST_W (); break; //case VUE.STSR : STSR (); break; //case VUE.SUB : SUB (); break; //case VUE.SUBF_S : SUBF_S (); break; //case VUE.TRAP : TRAP (); break; //case VUE.TRNC_SW: TRNC_SW(); break; //case VUE.XB : XB (); break; //case VUE.XH : XH (); break; //case VUE.XOR : XOR (); break; //case VUE.XORBSU : XORBSU (); break; //case VUE.XORI : XORI (); break; //case VUE.XORNBSU: XORNBSU(); break; default: exception = 0xFF90; // Invalid instruction } // Common processing pc += inst.size; program[0] = 0; testException(); return false; } // Operations for fetch stage private boolean fetch() { // Read the bits from the bus access.address = pc + (fetch << 1); access.fetch = fetch; access.type = VUE.U16; access.value = vue.read(access.address, VUE.U16); // Application callback if (vue.onRead != null) { vue.breakCode = vue.onRead.call(vue, access); if (vue.breakCode != 0) return true; } // First unit if (fetch == 0) { inst.bits = access.value << 16; if (Instruction.size(access.value & 0x3F) == 4) { fetch = 1; return false; } } // Second unit else { inst.bits |= access.value & 0xFFFF; fetch = 0; } // Decode the instruction and advance to execute stage inst.decode(inst.bits); stage = EXECUTE; return false; } // Check for an exception or interrupt private void testException() { // Check for an interrupt if (irq != 0 && (exception | psw_id | psw_ep | psw_np) == 0) { int level; for (level = 4; level >= 0; level--) if ((irq >> level & 1) != 0) break; exception = 0xFE00 | level << 4; } // Check for an exception if (exception != 0) { cycles = 0; stage = EXCEPTION; } } }