package app; // Project imports import vue.*; // Instruction disassembler class Disassembler { private Disassembler() { } // Cannot be instantiated static { setDefaults(); } // Initialize to default settings /////////////////////////////////////////////////////////////////////////// // Global Settings // /////////////////////////////////////////////////////////////////////////// static boolean bcondCombine; // Merge Bcond condition into mnemonic static boolean bcondNames; // Use symbolic condition names for Bcond static boolean condCaps; // Uppercase condition mnemonics static boolean destLast; // Destination register last static boolean dispDest; // Resolve jump destination addresses static boolean dispInside; // Load/store displacement inside brackets static boolean hexCaps; // Upercase hexadecimal static int hexMode; // Hexadecimal decoration static boolean immNumber; // Use number sign with immediate values static boolean jmpBrackets; // Square brackets around JMP static boolean jumpAddress; // Use jump destination addresses static boolean lower; // Use L instead of C in conditions static boolean mnemonicCaps; // Uppercase mnemonics static boolean programCaps; // Uppercase program register names static boolean programNames; // Use symbolic program register names static boolean setfCombine; // Merge SETF condition into mnemonic static boolean setfNames; // Use symbolic condition names for SETF static boolean systemCaps; // Uppercase system register names static boolean systemNames; // Use symbolic system register names static boolean zero; // Use Z instead of E in conditions /////////////////////////////////////////////////////////////////////////// // Constants // /////////////////////////////////////////////////////////////////////////// // Hexadecimal decorations static final int DOLLAR = 0; static final int H = 1; static final int ZEROX = 2; // Condition mneonics static final String[] CONDITIONS = { "V" , "C" , "E" , "NH", "N", "T", "LT", "LE", "NV", "NC", "NE", "H" , "P", "F", "GE", "GT" }; // Mnemonics static final String[] MNEMONICS = { "---" , "ADD" , "ADD" , "ADDF.S", "ADDI" , "AND" , "ANDBSU" , "ANDI" , "ANDNBSU", "Bcond" , "CAXI" , "CLI" , "CMP" , "CMP" , "CMPF.S" , "CVT.SW", "CVT.WS" , "DIV" , "DIVF.S" , "DIVU" , "HALT" , "IN.B" , "IN.H" , "IN.W" , "JAL" , "JMP" , "JR" , "LD.B" , "LD.H" , "LD.W" , "LDSR" , "MOV" , "MOV" , "MOVBSU", "MOVEA" , "MOVHI" , "MPYHW" , "MUL" , "MULF.S" , "MULU" , "NOT" , "NOTBSU" , "OR" , "ORBSU" , "ORI" , "ORNBSU", "OUT.B" , "OUT.H" , "OUT.W" , "RETI" , "REV" , "SAR" , "SAR" , "SCH0BSD", "SCH0BSU", "SCH1BSD", "SCH1BSU", "SEI" , "SETF" , "SHL" , "SHL" , "SHR" , "SHR" , "ST.B" , "ST.H" , "ST.W" , "STSR" , "SUB" , "SUBF.S" , "TRAP" , "TRNC.SW", "XB" , "XH" , "XOR" , "XORBSU" , "XORI" , "XORNBSU" }; // Program register names private static final String[] PROGRAMS = { null, null, "hp", "sp", "gp", "tp", null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "lp" }; // System register names private static final String[] SYSTEMS = { "EIPC", "EIPSW", "FEPC", "FEPSW", "ECR", "PSW", "PIR", "TKCW", null , null , null , null , null , null , null , null , null , null , null , null , null , null , null , null , "CHCW", "ADTRE", null , null , null , null , null , null }; /////////////////////////////////////////////////////////////////////////// // Classes // /////////////////////////////////////////////////////////////////////////// // One row of output static class Row { String address; // Bus address String bytes; // Encoded bytes in bus order String mnemonic; // Instruction mnemonic String operands; // Instruction operands, if any } /////////////////////////////////////////////////////////////////////////// // Static Methods // /////////////////////////////////////////////////////////////////////////// // Reset all settings to their default values static void setDefaults() { bcondCombine = true; bcondNames = true; condCaps = true; destLast = true; dispDest = true; dispInside = false; hexCaps = true; hexMode = ZEROX; immNumber = false; jmpBrackets = true; jumpAddress = true; lower = true; mnemonicCaps = true; programCaps = false; programNames = true; setfCombine = false; setfNames = true; systemCaps = true; systemNames = true; zero = false; } /////////////////////////////////////////////////////////////////////////// // Package Methods // /////////////////////////////////////////////////////////////////////////// // Represent an instruction as text fields static void disassemble(int address, Instruction inst, Row row) { // Address String x = hexCaps ? "X" : "x"; row.address = String.format("%08" + x, address); // Bytes x = "%02" + x; row.bytes = inst.size == 2 ? String.format(x + " " + x, inst.bits >> 16 & 0xFF, inst.bits >> 24 & 0xFF ) : String.format(x + " " + x + " " + x + " " + x, inst.bits >> 16 & 0xFF, inst.bits >> 24 & 0xFF, inst.bits & 0xFF, inst.bits >> 8 & 0xFF ) ; // Bcond mnemonic if (inst.id == VUE.BCOND && bcondCombine) { row.mnemonic = "B" + CONDITIONS[inst.cond]; if (lower && (inst.cond & 7) == 1) row.mnemonic = inst.cond == 1 ? "BL" : "BNL"; if (zero && (inst.cond & 7) == 2) row.mnemonic = inst.cond == 2 ? "BZ" : "BNZ"; if ( (inst.cond & 7) == 5) row.mnemonic = inst.cond == 5 ? "BR" : "NOP"; } // SETF mnemonic else if (inst.id == VUE.SETF && setfCombine) row.mnemonic = "SETF" + CONDITIONS[inst.imm]; // All other mnemonics else row.mnemonic = MNEMONICS[inst.id]; // Adjust mnemonic case if (!mnemonicCaps) row.mnemonic = row.mnemonic.toLowerCase(); // Operands by format row.operands = null; if (inst.id != VUE.ILLEGAL) switch (inst.format) { case 1: // Fallthrough case 7: row.operands = formatI_VII(inst ); break; case 2: row.operands = formatII (inst ); break; case 3: row.operands = formatIII (inst, address); break; case 4: row.operands = destination(inst, address); break; case 5: row.operands = formatV (inst ); break; case 6: row.operands = formatVI (inst ); break; } } /////////////////////////////////////////////////////////////////////////// // Private Methods // /////////////////////////////////////////////////////////////////////////// // Format the destination of a branch or jump private static String destination(Instruction inst, int address) { return !dispDest ? toHex(inst.disp, 1, immNumber) : String.format("%08" + (hexCaps ? "X" : "x"), address + inst.disp); } // Operands for Format I and Format VII private static String formatI_VII(Instruction inst) { String reg1 = program(inst.reg1); String reg2 = program(inst.reg2); // One-operand instructions switch (inst.id) { case VUE.JMP: return String.format(jmpBrackets ? "[%s]" : "%s", reg1); case VUE.XB: // Fallthrough case VUE.XH: return reg2; } // Generic return String.format("%s, %s", destLast ? reg1 : reg2, destLast ? reg2 : reg1 ); } // Operands for Format II private static String formatII(Instruction inst) { // Bit string if (inst.opcode == 0b011111) return null; // Zero- or one-operand instructions switch (inst.id) { // Zero-operand case VUE.CLI : // Fallthrough case VUE.HALT: // Fallthrough case VUE.RETI: // Fallthrough case VUE.SEI : return null; // One-operand case VUE.TRAP: return Integer.toString(inst.imm); } // Combined SETF String reg2 = program(inst.reg2); if (inst.id == VUE.SETF && setfCombine) return reg2; // Two-operand instructions String imm = String.format("%s%d", immNumber ? "#" : "", inst.imm); switch (inst.id) { case VUE.LDSR: // Fallthrough case VUE.STSR: if (!systemNames || SYSTEMS[inst.imm] == null) break; imm = SYSTEMS[inst.imm]; if (!systemCaps) imm = imm.toLowerCase(); break; case VUE.SETF: if (!setfNames) break; imm = CONDITIONS[inst.imm]; if (!condCaps) imm = imm.toLowerCase(); break; } // Generic return String.format("%s, %s", destLast ? imm : reg2, destLast ? reg2 : imm ); } // Operands for Format III private static String formatIII(Instruction inst, int address) { // NOP if (bcondCombine && inst.cond == 13) return null; // Format destination String dest = destination(inst, address); // One-operand notation if (bcondCombine) return dest; // Two-operand notation String cond = bcondNames ? CONDITIONS[inst.cond] : Integer.toString(inst.cond); if (bcondNames && !condCaps) cond = cond.toLowerCase(); return String.format("%s, %s", cond, dest); } // Operands for Format V private static String formatV(Instruction inst) { String reg1 = program(inst.reg1); String reg2 = program(inst.reg2); String imm = toHex( inst.id == VUE.MOVEA ? inst.imm & 0xFFFF : inst.imm, inst.id == VUE.ADDI ? 1 : 4, immNumber ); return String.format("%s, %s, %s", destLast ? imm : reg2, reg1, destLast ? reg2 : imm ); } // Operands for Format VI private static String formatVI(Instruction inst) { String src = program(inst.reg1); String dest = program(inst.reg2); // Data operand src = inst.disp == 0 ? String.format("[%s]", src) : dispInside ? String.format( "[%s %s %s]", src, inst.disp < 0 ? "-" : "+", toHex(Math.abs(inst.disp), 1, immNumber) ) : String.format( "%s[%s]", toHex(inst.disp, 1, immNumber), src ) ; // Write instruction switch (inst.id) { case VUE.OUT_B: // Fallthrough case VUE.OUT_H: // Fallthrough case VUE.OUT_W: // Fallthrough case VUE.ST_B : // Fallthrough case VUE.ST_H : // Fallthrough case VUE.ST_W : String temp = src; src = dest; dest = temp; } // Format operands return String.format("%s, %s", destLast ? src : dest, destLast ? dest : src ); } // Format a program register private static String program(int index) { String ret = programNames ? PROGRAMS[index] : null; if (ret == null) ret = "r" + index; return programCaps ? ret.toUpperCase() : ret; } // Represent an immediate value as hexadecimal private static String toHex(int value, int digits, boolean number) { return String.format( "%s%s%s%0" + digits + (hexCaps ? "X" : "x") + "%s", number ? "#" : "", value < 0 ? "-" : "", hexMode == DOLLAR ? "$" : hexMode == ZEROX ? "0x" : "", value < 0 ? -value : value, hexMode == H ? "h" : "" ); } }