/* This file is part of jpcsp. Jpcsp is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Jpcsp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Jpcsp. If not, see <http://www.gnu.org/licenses/>. */ package jpcsp.Allegrex; import jpcsp.Memory; import jpcsp.Processor; import jpcsp.Allegrex.compiler.ICompilerContext; import jpcsp.HLE.HLEModuleFunction; import jpcsp.HLE.HLEModuleManager; import jpcsp.HLE.Modules; import jpcsp.util.Utilities; /** * * @author hli */ public class Common { public static abstract class Instruction { private int m_count = 0; private int flags = 0; public final static int FLAG_INTERPRETED = (1 << 0); public final static int FLAG_CANNOT_BE_SPLIT = (1 << 1); public final static int FLAG_HAS_DELAY_SLOT = (1 << 2); public final static int FLAG_IS_BRANCHING = (1 << 3); public final static int FLAG_IS_JUMPING = (1 << 4); public final static int FLAG_IS_CONDITIONAL = (1 << 5); public final static int FLAG_STARTS_NEW_BLOCK = (1 << 6); public final static int FLAG_ENDS_BLOCK = (1 << 7); public final static int FLAG_USE_VFPU_PFXS = (1 << 8); public final static int FLAG_USE_VFPU_PFXT = (1 << 9); public final static int FLAG_USE_VFPU_PFXD = (1 << 10); public final static int FLAG_CONSUMES_VFPU_PFXT = (1 << 11); public final static int FLAG_COMPILED_PFX = (1 << 12); public final static int FLAG_WRITES_RT = (1 << 13); public final static int FLAG_WRITES_RD = (1 << 14); public final static int FLAG_SYSCALL = (1 << 15); public final static int FLAGS_BRANCH_INSTRUCTION = FLAG_CANNOT_BE_SPLIT | FLAG_HAS_DELAY_SLOT | FLAG_IS_BRANCHING | FLAG_IS_CONDITIONAL; public final static int FLAGS_LINK_INSTRUCTION = FLAG_HAS_DELAY_SLOT | FLAG_STARTS_NEW_BLOCK; public abstract void interpret(Processor processor, int insn); public void compile(ICompilerContext context, int insn) { flags |= FLAG_INTERPRETED; context.compileInterpreterInstruction(); } public abstract String disasm(int address, int insn); public abstract String name(); public abstract String category(); public void resetCount() { m_count = 0; } public void increaseCount() { m_count++; } public int getCount() { return m_count; } public int count() { return m_count; } public Instruction instance(int insn) { return this; } private void setInstance(int index) { m_instances[index] = this; } public Instruction(int index) { setInstance(index); } public Instruction(int index, int flags) { setInstance(index); this.flags = flags; } public Instruction() { } public int getFlags() { return flags; } public boolean hasFlags(int testFlags) { return (flags & testFlags) == testFlags; } private void appendFlagString(StringBuilder result, String flagString) { if (result.length() > 0) { result.append(" | "); } result.append(flagString); } private String flagsToString() { StringBuilder result = new StringBuilder(); if (hasFlags(FLAG_INTERPRETED)) { appendFlagString(result, "FLAG_INTERPRETED"); } if (hasFlags(FLAG_CANNOT_BE_SPLIT)) { appendFlagString(result, "FLAG_CANNOT_BE_SPLIT"); } if (hasFlags(FLAG_HAS_DELAY_SLOT)) { appendFlagString(result, "FLAG_HAS_DELAY_SLOT"); } if (hasFlags(FLAG_IS_BRANCHING)) { appendFlagString(result, "FLAG_IS_BRANCHING"); } if (hasFlags(FLAG_IS_JUMPING)) { appendFlagString(result, "FLAG_IS_JUMPING"); } if (hasFlags(FLAG_IS_CONDITIONAL)) { appendFlagString(result, "FLAG_IS_CONDITIONAL"); } if (hasFlags(FLAG_STARTS_NEW_BLOCK)) { appendFlagString(result, "FLAG_STARTS_NEW_BLOCK"); } if (hasFlags(FLAG_ENDS_BLOCK)) { appendFlagString(result, "FLAG_ENDS_BLOCK"); } return result.toString(); } @Override public String toString() { return name() + "(" + flagsToString() + ")"; } } public static abstract class STUB extends Instruction { @Override public void interpret(Processor processor, int insn) { instance(insn).interpret(processor, insn); } @Override public void compile(ICompilerContext context, int insn) { instance(insn).compile(context, insn); } @Override public String disasm(int address, int insn) { return instance(insn).disasm(address, insn); } @Override public abstract Instruction instance(int insn); @Override public final String name() { return null; } @Override public final String category() { return null; } } public static final Instruction UNK = new Instruction() { @Override public void interpret(Processor processor, int insn) { Modules.log.warn(String.format("%08X %s", processor.cpu.pc, disasm(processor.cpu.pc, insn))); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { return String.format("Unknown instruction %32s (0x%08X)", Utilities.integerToBin(insn), insn); } @Override public final String name() { return "UNK"; } @Override public final String category() { return "UNK"; } }; public static final int _zr = 0; public static final int _at = 1; public static final int _v0 = 2; public static final int _v1 = 3; public static final int _a0 = 4; public static final int _a1 = 5; public static final int _a2 = 6; public static final int _a3 = 7; public static final int _t0 = 8; public static final int _t1 = 9; public static final int _t2 = 10; public static final int _t3 = 11; public static final int _t4 = 12; public static final int _t5 = 13; public static final int _t6 = 14; public static final int _t7 = 15; public static final int _s0 = 16; public static final int _s1 = 17; public static final int _s2 = 18; public static final int _s3 = 19; public static final int _s4 = 20; public static final int _s5 = 21; public static final int _s6 = 22; public static final int _s7 = 23; public static final int _t8 = 24; public static final int _t9 = 25; public static final int _k0 = 26; public static final int _k1 = 27; public static final int _gp = 28; public static final int _sp = 29; public static final int _fp = 30; public static final int _ra = 31; public static final int _f0 = 0; public static final int _f12 = 12; public static final int _f31 = 31; public static String[] gprNames = { "$zr", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3", "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7", "$t8", "$t9", "$k0", "$k1", "$gp", "$sp", "$fp", "$ra" }; public static String[] fprNames = { "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31" }; public static String[][] vprNames = { { "S000.s", "S010.s", "S020.s", "S030.s", "S100.s", "S110.s", "S120.s", "S130.s", "S200.s", "S210.s", "S220.s", "S230.s", "S300.s", "S310.s", "S320.s", "S330.s", "S400.s", "S410.s", "S420.s", "S430.s", "S500.s", "S510.s", "S520.s", "S530.s", "S600.s", "S610.s", "S620.s", "S630.s", "S700.s", "S710.s", "S720.s", "S730.s", "S001.s", "S011.s", "S021.s", "S031.s", "S101.s", "S111.s", "S121.s", "S131.s", "S201.s", "S211.s", "S221.s", "S231.s", "S301.s", "S311.s", "S321.s", "S331.s", "S401.s", "S411.s", "S421.s", "S431.s", "S501.s", "S511.s", "S521.s", "S531.s", "S601.s", "S611.s", "S621.s", "S631.s", "S701.s", "S711.s", "S721.s", "S731.s", "S002.s", "S012.s", "S022.s", "S032.s", "S102.s", "S112.s", "S122.s", "S132.s", "S202.s", "S212.s", "S222.s", "S232.s", "S302.s", "S312.s", "S322.s", "S332.s", "S402.s", "S412.s", "S422.s", "S432.s", "S502.s", "S512.s", "S522.s", "S532.s", "S602.s", "S612.s", "S622.s", "S632.s", "S702.s", "S712.s", "S722.s", "S732.s", "S003.s", "S013.s", "S023.s", "S033.s", "S103.s", "S113.s", "S123.s", "S133.s", "S203.s", "S213.s", "S223.s", "S233.s", "S303.s", "S313.s", "S323.s", "S333.s", "S403.s", "S413.s", "S423.s", "S433.s", "S503.s", "S513.s", "S523.s", "S533.s", "S603.s", "S613.s", "S623.s", "S633.s", "S703.s", "S713.s", "S723.s", "S733.s" }, { "C000.p", "C010.p", "C020.p", "C030.p", "C100.p", "C110.p", "C120.p", "C130.p", "C200.p", "C210.p", "C220.p", "C230.p", "C300.p", "C310.p", "C320.p", "C330.p", "C400.p", "C410.p", "C420.p", "C430.p", "C500.p", "C510.p", "C520.p", "C530.p", "C600.p", "C610.p", "C620.p", "C630.p", "C700.p", "C710.p", "C720.p", "C730.p", "R000.p", "R001.p", "R002.p", "R003.p", "R100.p", "R101.p", "R102.p", "R103.p", "R200.p", "R201.p", "R202.p", "R203.p", "R300.p", "R301.p", "R302.p", "R303.p", "R400.p", "R401.p", "R402.p", "R403.p", "R500.p", "R501.p", "R502.p", "R503.p", "R600.p", "R601.p", "R602.p", "R603.p", "R700.p", "R701.p", "R702.p", "R703.p", "C002.p", "C012.p", "C022.p", "C032.p", "C102.p", "C112.p", "C122.p", "C132.p", "C202.p", "C212.p", "C222.p", "C232.p", "C302.p", "C312.p", "C322.p", "C332.p", "C402.p", "C412.p", "C422.p", "C432.p", "C502.p", "C512.p", "C522.p", "C532.p", "C602.p", "C612.p", "C622.p", "C632.p", "C702.p", "C712.p", "C722.p", "C732.p", "R020.p", "R021.p", "R022.p", "R023.p", "R120.p", "R121.p", "R122.p", "R123.p", "R220.p", "R221.p", "R222.p", "R223.p", "R320.p", "R321.p", "R322.p", "R323.p", "R420.p", "R421.p", "R422.p", "R423.p", "R520.p", "R521.p", "R522.p", "R523.p", "R620.p", "R621.p", "R622.p", "R623.p", "R720.p", "R721.p", "R722.p", "R723.p" }, { "C000.t", "C010.t", "C020.t", "C030.t", "C100.t", "C110.t", "C120.t", "C130.t", "C200.t", "C210.t", "C220.t", "C230.t", "C300.t", "C310.t", "C320.t", "C330.t", "C400.t", "C410.t", "C420.t", "C430.t", "C500.t", "C510.t", "C520.t", "C530.t", "C600.t", "C610.t", "C620.t", "C630.t", "C700.t", "C710.t", "C720.t", "C730.t", "R000.t", "R001.t", "R002.t", "R003.t", "R100.t", "R101.t", "R102.t", "R103.t", "R200.t", "R201.t", "R202.t", "R203.t", "R300.t", "R301.t", "R302.t", "R303.t", "R400.t", "R401.t", "R402.t", "R403.t", "R500.t", "R501.t", "R502.t", "R503.t", "R600.t", "R601.t", "R602.t", "R603.t", "R700.t", "R701.t", "R702.t", "R703.t", "C001.t", "C011.t", "C021.t", "C031.t", "C101.t", "C111.t", "C121.t", "C131.t", "C201.t", "C211.t", "C221.t", "C231.t", "C301.t", "C311.t", "C321.t", "C331.t", "C401.t", "C411.t", "C421.t", "C431.t", "C501.t", "C511.t", "C521.t", "C531.t", "C601.t", "C611.t", "C621.t", "C631.t", "C701.t", "C711.t", "C721.t", "C731.t", "R010.t", "R011.t", "R012.t", "R013.t", "R110.t", "R111.t", "R112.t", "R113.t", "R210.t", "R211.t", "R212.t", "R213.t", "R310.t", "R311.t", "R312.t", "R313.t", "R410.t", "R411.t", "R412.t", "R413.t", "R510.t", "R511.t", "R512.t", "R513.t", "R610.t", "R611.t", "R612.t", "R613.t", "R710.t", "R711.t", "R712.t", "R713.t" }, { "C000.q", "C010.q", "C020.q", "C030.q", "C100.q", "C110.q", "C120.q", "C130.q", "C200.q", "C210.q", "C220.q", "C230.q", "C300.q", "C310.q", "C320.q", "C330.q", "C400.q", "C410.q", "C420.q", "C430.q", "C500.q", "C510.q", "C520.q", "C530.q", "C600.q", "C610.q", "C620.q", "C630.q", "C700.q", "C710.q", "C720.q", "C730.q", "R000.q", "R001.q", "R002.q", "R003.q", "R100.q", "R101.q", "R102.q", "R103.q", "R200.q", "R201.q", "R202.q", "R203.q", "R300.q", "R301.q", "R302.q", "R303.q", "R400.q", "R401.q", "R402.q", "R403.q", "R500.q", "R501.q", "R502.q", "R503.q", "R600.q", "R601.q", "R602.q", "R603.q", "R700.q", "R701.q", "R702.q", "R703.q", "C002.q", "C012.q", "C022.q", "C032.q", "C102.q", "C112.q", "C122.q", "C132.q", "C202.q", "C212.q", "C222.q", "C232.q", "C302.q", "C312.q", "C322.q", "C332.q", "C402.q", "C412.q", "C422.q", "C432.q", "C502.q", "C512.q", "C522.q", "C532.q", "C602.q", "C612.q", "C622.q", "C632.q", "C702.q", "C712.q", "C722.q", "C732.q", "R020.q", "R021.q", "R022.q", "R023.q", "R120.q", "R121.q", "R122.q", "R123.q", "R220.q", "R221.q", "R222.q", "R223.q", "R320.q", "R321.q", "R322.q", "R323.q", "R420.q", "R421.q", "R422.q", "R423.q", "R520.q", "R521.q", "R522.q", "R523.q", "R620.q", "R621.q", "R622.q", "R623.q", "R720.q", "R721.q", "R722.q", "R723.q" } }; public static String[][] vprMatNames = { {}, { "M000.p", "", "M020.p", "", "M100.p", "", "M120.p", "", "M200.p", "", "M220.p", "", "M300.p", "", "M320.p", "", "M400.p", "", "M420.p", "", "M500.p", "", "M520.p", "", "M600.p", "", "M620.p", "", "M700.p", "", "M720.p", "", "E000.p", "", "E002.p", "", "E100.p", "", "E102.p", "", "E200.p", "", "E202.p", "", "E300.p", "", "E302.p", "", "E400.p", "", "E402.p", "", "E500.p", "", "E502.p", "", "E600.p", "", "E602.p", "", "E700.p", "", "E702.p", "", "M002.p", "", "M022.p", "", "M102.p", "", "M122.p", "", "M202.p", "", "M222.p", "", "M302.p", "", "M322.p", "", "M402.p", "", "M422.p", "", "M502.p", "", "M522.p", "", "M602.p", "", "M622.p", "", "M702.p", "", "M722.p", "", "E020.p", "", "E022.p", "", "E120.p", "", "E122.p", "", "E220.p", "", "E222.p", "", "E320.p", "", "E322.p", "", "E420.p", "", "E422.p", "", "E520.p", "", "E522.p", "", "E620.p", "", "E622.p", "", "E720.p", "", "E722.p", "" }, { "M000.t", "M010.t", "", "", "M100.t", "M110.t", "", "", "M200.t", "M210.t", "", "", "M300.t", "M310.t", "", "", "M400.t", "M410.t", "", "", "M500.t", "M510.t", "", "", "M600.t", "M610.t", "", "", "M700.t", "M710.t", "", "", "E000.t", "E001.t", "", "", "E100.t", "E101.t", "", "", "E200.t", "E201.t", "", "", "E300.t", "E301.t", "", "", "E400.t", "E401.t", "", "", "E500.t", "E501.t", "", "", "E600.t", "E601.t", "", "", "E700.t", "E701.t", "", "", "M001.t", "M011.t", "", "", "M101.t", "M111.t", "", "", "M201.t", "M211.t", "", "", "M301.t", "M311.t", "", "", "M401.t", "M411.t", "", "", "M501.t", "M511.t", "", "", "M601.t", "M611.t", "", "", "M701.t", "M711.t", "", "", "E010.t", "E011.t", "", "", "E110.t", "E111.t", "", "", "E210.t", "E211.t", "", "", "E310.t", "E311.t", "", "", "E410.t", "E411.t", "", "", "E510.t", "E511.t", "", "", "E610.t", "E611.t", "", "", "E710.t", "E711.t", "", "" }, { "M000.q", "", "", "", "M100.q", "", "", "", "M200.q", "", "", "", "M300.q", "", "", "", "M400.q", "", "", "", "M500.q", "", "", "", "M600.q", "", "", "", "M700.q", "", "", "", "E000.q", "", "", "", "E100.q", "", "", "", "E200.q", "", "", "", "E300.q", "", "", "", "E400.q", "", "", "", "E500.q", "", "", "", "E600.q", "", "", "", "E700.q", "", "", "" } }; private static final String vfpuConstants[] = { "", "VFPU_HUGE", "VFPU_SQRT2", "VFPU_SQRT1_2", "VFPU_2_SQRTPI", "VFPU_2_PI", "VFPU_1_PI", "VFPU_PI_4", "VFPU_PI_2", "VFPU_PI", "VFPU_E", "VFPU_LOG2E", "VFPU_LOG10E", "VFPU_LN2", "VFPU_LN10", "VFPU_2PI", "VFPU_PI_6", "VFPU_LOG10TWO", "VFPU_LOG2TEN", "VFPU_SQRT3_2", "", "", "", "", "", "", "", "", "", "", "", "" }; public static String[] fcrNames = { "$fcsr0", "$fcsr1", "$fcsr2", "$fcsr3", "$fcsr4", "$fcsr5", "$fcsr6", "$fcsr7", "$fcsr8", "$fcsr9", "$fcsr10", "$fcsr11", "$fcsr12", "$fcsr13", "$fcsr14", "$fcsr15", "$fcsr16", "$fcsr17", "$fcsr18", "$fcsr19", "$fcsr20", "$fcsr21", "$fcsr22", "$fcsr23", "$fcsr24", "$fcsr25", "$fcsr26", "$fcsr27", "$fcsr28", "$fcsr29", "$fcsr30", "$fcsr31" }; public static String[] cop0Names = { "Index", "Random", "EntryLo0", "EntryLo1", "Context", "PageMask", "Wired", "cop0reg7", "BadVaddr", "Count", "EntryHi", "Compare", "Status", "Cause", "EPC", "PrID", "Config", "LLAddr", "WatchLo", "WatchHi", "XContext", "cop0reg21", "cop0reg22", "cop0reg23", "cop0reg24", "EBase", "ECC", "CacheErr", "TagLo", "TagHi", "ErrorPC", "cop0reg31" }; public static String vsuffix[] = { ".s", ".p", ".t", ".q" }; public static String[] vpfxNames = { "x", "y", "z", "w" }; public static final String ccondsNames[] = { "c.f.s", "c.un.s", "c.eq.s", "c.ueq.s", "c.olt.s", "c.ult.s", "c.ole.s", "c.ule.s", "c.sf.s", "c.ngle.s", "c.seq.s", "c.ngl.s", "c.lt.s", "c.nge.s", "c.le.s", "c.ngt.s" }; public static final String vcondNames[] = { "FL", "EQ", "LT", "LE", "TR", "NE", "GE", "GT", "EZ", "EN", "EI", "ES", "NZ", "NN", "NI", "NS" }; public static String disasmRDRTSA(String opname, int rd, int rt, int sa) { if ((rd == 0) && sa == 0) { return "nop"; } return String.format("%1$-10s %2$s, %3$s, 0x%4$04X", opname, gprNames[rd], gprNames[rt], sa); } public static String disasmRDRTRS(String opname, int rd, int rt, int rs) { return String.format("%1$-10s %2$s, %3$s, %4$s", opname, gprNames[rd], gprNames[rt], gprNames[rs]); } public static String disasmRS(String opname, int rs) { return String.format("%1$-10s %2$s", opname, gprNames[rs]); } public static String disasmRT(String opname, int rt) { return String.format("%1$-10s %2$s", opname, gprNames[rt]); } public static String disasmRDRS(String opname, int rd, int rs) { return String.format("%1$-10s %2$s, %3$s", opname, gprNames[rd], gprNames[rs]); } public static String disasmRDRT(String opname, int rd, int rt) { return String.format("%1$-10s %2$s, %3$s", opname, gprNames[rd], gprNames[rt]); } public static String disasmRD(String opname, int rd) { return String.format("%1$-10s %2$s", opname, gprNames[rd]); } public static String disasmRSRT(String opname, int rs, int rt) { return String.format("%1$-10s %2$s, %3$s", opname, gprNames[rs], gprNames[rt]); } public static String disasmEXT(int rt, int rs, int lsb, int msb) { return String.format("%1$-10s %2$s, %3$s, %4$d, %5$d", "ext", gprNames[rt], gprNames[rs], lsb, (msb + 1)); } public static String disasmINS(int rt, int rs, int lsb, int msb) { return String.format("%1$-10s %2$s, %3$s, %4$d, %5$d", "ins", gprNames[rt], gprNames[rs], lsb, (msb - lsb + 1)); } public static String disasmRDRSRT(String opname, int rd, int rs, int rt) { String s = String.format("%1$-10s %2$s, %3$s, %4$s", opname, gprNames[rd], gprNames[rs], gprNames[rt]); if (rs == 0 && rt == 0) { if (opname.equals("xor") || opname.equals("nor")) { return String.format("%2$s <=> li %1$s, -1", gprNames[rd], s); } return String.format("%2$s <=> li %1$s, 0", gprNames[rd], s); } else if (rs == 0) { if (opname.equals("and")) { return String.format("%2$s <=> li %1$s, 0", gprNames[rd], s); } if (opname.equals("nor")) { return String.format("%3$s <=> li %1$s, not %2$s", gprNames[rd], gprNames[rt], s); } if (opname.equals("sub")) { return String.format("%3$s <=> neg %1$s, %2$s", gprNames[rd], gprNames[rt], s); } if (opname.equals("subu")) { return String.format("%3$s <=> negu %1$s, %2$s", gprNames[rd], gprNames[rt], s); } return String.format("%3$s <=> move %1$s, %2$s", gprNames[rd], gprNames[rt], s); } else if (rt == 0) { if (opname.equals("and")) { return String.format("%2$s <=> li %1$s, 0", gprNames[rd], s); } if (opname.equals("nor")) { return String.format("%3$s <=> li %1$s, not %2$s", gprNames[rd], gprNames[rs], s); } return String.format("%3$s <=> move %1$s, %2$s", gprNames[rd], gprNames[rs], s); } return s; } public static String disasmRSOFFSET(String opname, int rs, int simm16, int opcode_address) { return String.format("%1$-10s %2$s, 0x%3$08X", opname, gprNames[rs], ((int) (short) simm16) * 4 + opcode_address + 4); } public static String disasmRSRTOFFSET(String opname, int rs, int rt, int simm16, int opcode_address) { if (rs == rt && opname.equals("beq")) { return String.format("%1$-10s 0x%2$08X", "b", ((int) (short) simm16) * 4 + opcode_address + 4); } return String.format("%1$-10s %2$s, %3$s, 0x%4$08X", opname, gprNames[rs], gprNames[rt], ((int) (short) simm16) * 4 + opcode_address + 4); } public static String disasmOFFSET(String opname, int simm16, int opcode_address) { return String.format("%1$-10s 0x%2$08X", opname, ((int) (short) simm16) * 4 + opcode_address + 4); } public static String disasmRTRSIMM(String opname, int rt, int rs, int imm16) { String s = String.format("%1$-10s %2$s, %3$s, %4$d", opname, gprNames[rt], gprNames[rs], ((int) (short) imm16)); if (rs == 0) { if (opname.equals("andi")) { return String.format("%2$s <=> li %1$s, 0", gprNames[rt], s); } else if (opname.matches("slti")) { return String.format("%3$s <=> li %1$s, %2$d", gprNames[rt], ((0 < imm16) ? 1 : 0), s); } else if (opname.matches("addiu") || opname.equals("ori")) { return String.format("%3$s <=> li %1$s, %2$d", gprNames[rt], imm16, s); } } return s; } public static String disasmSYSCALL(int code) { String functionName = null; HLEModuleFunction func = HLEModuleManager.getInstance().getFunctionFromSyscallCode(code); if (func != null) { functionName = func.getFunctionName(); } if (functionName == null) { functionName = "unknown"; } return String.format("%1$-10s 0x%2$05X [%3$s]", "syscall", code, functionName); } public static String disasmBREAK(int code) { return String.format("%1$-10s 0x%2$05X", "break", code); } public static String disasmJUMP(String opname, int uimm26, int opcode_address) { int jump = (opcode_address & 0xf0000000) | ((uimm26 & 0x3ffffff) << 2); int jumpToSyscall = jump + 4; // If we think the target is a stub, try and append the syscall name if ((opname.equals("jal") || opname.equals("j")) && jump != 0 && jumpToSyscall != opcode_address && Memory.isAddressGood(jumpToSyscall)) { String hleFunctionName = null; HLEModuleFunction func = HLEModuleManager.getInstance().getFunctionFromAddress(jump); if (func != null) { hleFunctionName = func.getFunctionName(); } if (hleFunctionName != null) { return String.format("%1$-10s 0x%2$08X [%3$s]", opname, jump, hleFunctionName); } int nextOpcode = jpcsp.Memory.getInstance().read32(jumpToSyscall); Instruction nextInsn = Decoder.instruction(nextOpcode); String secondTarget = nextInsn.disasm(jumpToSyscall, nextOpcode); if (secondTarget.startsWith("syscall") && !secondTarget.contains("[unknown]")) { return String.format("%1$-10s 0x%2$08X %3$s", opname, jump, secondTarget.substring(19)); } } return String.format("%1$-10s 0x%2$08X", opname, jump); } public static String disasmRTIMM(String opname, int rt, int imm) { return String.format("%1$-10s %2$s, 0x%3$04X <=> li %2$s, 0x%3$04X0000", opname, gprNames[rt], (imm & 0xFFFF)); } public static String disasmRTIMM7(String opname, int rt, int imm7) { return String.format("%1$-10s 0x%2$02X, %3$s", opname, imm7, gprNames[rt]); } public static String disasmRTIMMRS(String opname, int rt, int rs, int imm) { return String.format("%1$-10s %2$s, %4$d(%3$s)", opname, gprNames[rt], gprNames[rs], ((int) (short) imm)); } public static String disasmCODEIMMRS(String opname, int code, int imm, int rs) { return String.format("%1$-10s 0x%2$02X, %4$d(%3$s)", opname, code, gprNames[rs], ((int) (short) imm)); } public static String disasmFTIMMRS(String opname, int ft, int rs, int imm) { return String.format("%1$-10s %2$s, %4$d(%3$s)", opname, fprNames[ft], gprNames[rs], ((int) (short) imm)); } public static String disasmFDFSFT(String opname, int fd, int fs, int ft) { return String.format("%1$-10s %2$s, %3$s, %4$s", opname, fprNames[fd], fprNames[fs], fprNames[ft]); } public static String disasmFDFS(String opname, int fd, int fs) { return String.format("%1$-10s %2$s, %3$s", opname, fprNames[fd], fprNames[fs]); } public static String disasmRTFS(String opname, int rt, int fs) { return String.format("%1$-10s %2$s, %3$s", opname, gprNames[rt], fprNames[fs]); } public static String disasmRTFC(String opname, int rt, int fc) { return String.format("%1$-10s %2$s, %3$s", opname, gprNames[rt], fcrNames[fc]); } public static String disasmCcondS(int cconds, int fs, int ft) { return String.format("%1$-10s %2$s, %3$s", ccondsNames[cconds], fprNames[fs], fprNames[ft]); } public static String disasmFSFT(String opname, int fs, int ft) { return String.format("%1$-10s %2$s, %3$s", opname, fprNames[fs], fprNames[ft]); } public static String disasmVD(String opname, int vsize, int vd) { return String.format("%1$-10s %2$s", opname + vsuffix[vsize - 1], vprNames[vsize - 1][vd]); } public static String disasmVS(String opname, int vsize, int vs) { return String.format("%1$-10s %2$s", opname + vsuffix[vsize - 1], vprNames[vsize - 1][vs]); } public static String disasmVDVS(String opname, int vsize, int vd, int vs) { return String.format("%1$-10s %2$s, %3$s", opname + vsuffix[vsize - 1], vprNames[vsize - 1][vd], vprNames[vsize - 1][vs]); } public static String disasmVDVS(String opname, int vsize, int vsizeVd, int vd, int vs) { return String.format("%1$-10s %2$s, %3$s", opname + vsuffix[vsize - 1], vprNames[vsizeVd - 1][vd], vprNames[vsize - 1][vs]); } public static String disasmVDVSIMM(String opname, int vsize, int vd, int vs, int imm) { return String.format("%1$-10s %2$s, %3$s, %4$d", opname + vsuffix[vsize - 1], vprNames[vsize - 1][vd], vprNames[vsize - 1][vs], imm); } public static String disasmVD1VS(String opname, int vsize, int vd, int vs) { return String.format("%1$-10s %2$s, %3$s", opname + vsuffix[vsize - 1], vprNames[0][vd], vprNames[vsize - 1][vs]); } public static String disasmVTIMMRS(String opname, int vsize, int vt, int rs, int imm) { return String.format( "%1$-10s %2$s, %4$d(%3$s)", opname + vsuffix[vsize - 1], vprNames[vsize - 1][vt], gprNames[rs], imm); } public static String disasmVDVSVT(String opname, int vsize, int vd, int vs, int vt) { return String.format("%1$-10s %2$s, %3$s, %4$s", opname + vsuffix[vsize - 1], vprNames[vsize - 1][vd], vprNames[vsize - 1][vs], vprNames[vsize - 1][vt]); } public static String disasmVDVSMVT(String opname, int vsize, int vd, int vs, int vt) { return String.format("%1$-10s %2$s, %3$s, %4$s", opname + vsuffix[vsize - 1], vprNames[vsize - 1][vd], vprMatNames[vsize - 1][vs], vprNames[vsize - 1][vt]); } public static String disasmVDVSVT1(String opname, int vsize, int vd, int vs, int vt) { return String.format("%1$-10s %2$s, %3$s, %4$s", opname + vsuffix[vsize - 1], vprNames[vsize - 1][vd], vprNames[vsize - 1][vs], vprNames[0][vt]); } public static String disasmVD1VSVT(String opname, int vsize, int vd, int vs, int vt) { return String.format("%1$-10s %2$s, %3$s, %4$s", opname + vsuffix[vsize - 1], vprNames[0][vd], vprNames[vsize - 1][vs], vprNames[vsize - 1][vt]); } public static String disasmVCMP(String opname, int vsize, int vcode, int vs, int vt) { if ((vcode & ~4) == 0) { return String.format("%1$-10s %2$s", opname + vsuffix[vsize - 1], vcondNames[vcode]); } else if (vcode < 8) { return String.format("%1$-10s %2$s, %3$s, %4$s", opname + vsuffix[vsize - 1], vcondNames[vcode], vprNames[vsize - 1][vs], vprNames[vsize - 1][vt]); } return String.format("%1$-10s %2$s, %3$s, %4$s", opname + vsuffix[vsize - 1], vcondNames[vcode], vprNames[vsize - 1][vs], vprNames[vsize - 1][vt]); } public static String disasmVROT(String opname, int vsize, int vd, int vs, int vt) { int i; int si = (vt >>> 2) & 3; int ci = (vt >>> 0) & 3; String ca = " c", sa = " s"; String codes[] = new String[4]; if ((vt & 16) != 0) { sa = "-s"; } if (si == ci) { for (i = 0; i < vsize; ++i) { codes[i] = (ci == i) ? ca : sa; } } else { for (i = 0; i < vsize; ++i) { codes[i] = (ci == i) ? ca : ((si == i) ? sa : " 0"); } } StringBuilder rot = new StringBuilder("["); i = 0; for (;;) { rot.append(codes[i++]); if (i >= vsize) { break; } rot.append(","); } rot.append("]"); return String.format("%1$-10s %2$s, %3$s, %4$s", opname + vsuffix[vsize - 1], vprNames[vsize - 1][vd], vprNames[0][vs], rot); } public static String disasmVDM(String opname, int vsize, int vd) { return String.format("%1$-10s %2$s", opname + vsuffix[vsize - 1], vprMatNames[vsize - 1][vd]); } public static String disasmVDMVSM(String opname, int vsize, int vd, int vs) { return String.format("%1$-10s %2$s, %3$s", opname + vsuffix[vsize - 1], vprMatNames[vsize - 1][vd], vprMatNames[vsize - 1][vs]); } public static String disasmVDCST(String opname, int vsize, int vd, int cst) { return String.format("%1$-10s %2$s, %3$s", opname + vsuffix[vsize - 1], vprNames[vsize - 1][vd], vfpuConstants[cst]); } public static String disasmVDIIM(String opcode, int vsize, int vd, int imm16) { return String.format("%1$-10s %2$s, 0x%3$04X", opcode + vsuffix[vsize - 1], vprNames[0][vd], imm16); } public static String disasmVDFIM(String opcode, int vsize, int vd, int imm16) { float s = ((imm16 >> 15) == 0) ? 1.0f : -1.0f; int e = ((imm16 >> 10) & 0x1f); int m = (e == 0) ? ((imm16 & 0x3ff) << 1) : ((imm16 & 0x3ff) | 0x400); float v = (e >= 15) ? (1 << (e - 15)) : 1.0f / (1 << (15 - e)); v = s * m * v / 1024f; return String.format("%1$-10s %2$s, %3$1.8f", opcode + vsuffix[vsize - 1], vprNames[0][vd], v); } public static String disasmVDMVSMVTM(String opname, int vsize, int vd, int vs, int vt) { return String.format("%1$-10s %2$s, %3$s, %4$s", opname + vsuffix[vsize - 1], vprMatNames[vsize - 1][vd], vprMatNames[vsize - 1][vs], vprMatNames[vsize - 1][vt]); } public static String disasmVDRS(String opname, int vd, int rt) { return String.format("%1$-10s %2$s, %3$s", opname + vsuffix[0], gprNames[rt], vprNames[0][vd]); } public static String disasmVPFX(String opname, int[] swz, boolean[] abs, boolean[] cst, boolean[] neg) { String[] values = new String[4]; for (int i = 0; i < 4; ++i) { if (cst[i]) { switch (swz[i]) { case 0: values[i] = abs[i] ? "3" : "0"; break; case 1: values[i] = abs[i] ? "1/3" : "1"; break; case 2: values[i] = abs[i] ? "1/4" : "2"; break; case 3: values[i] = abs[i] ? "1/6" : "1/2"; break; } } else { values[i] = abs[i] ? "|" + vpfxNames[swz[i]] + "|" : vpfxNames[swz[i]]; } if (neg[i]) { values[i] = "-" + values[i]; } } return String.format("%1$-10s [%2$s, %3$s, %4$s, %5$s]", opname, values[0], values[1], values[2], values[3]); } public static String disasmVPFXD(String opname, int[] sat, int[] msk) { String[] values = new String[4]; for (int i = 0; i < 4; ++i) { if (msk[i] == 0) { switch (sat[i]) { case 0: values[i] = vpfxNames[i]; break; case 1: values[i] = "0:1"; break; case 2: values[i] = "???"; break; case 3: values[i] = "-1:1"; break; } } else { values[i] = "M"; } } return String.format("%1$-10s [%2$s, %3$s, %4$s, %5$s]", opname, values[0], values[1], values[2], values[3]); } public static String disasmVCCOFFSET(String opname, int vcc, int simm16, int opcode_address) { return String.format("%1$-10s %2$d, 0x%3$08X", opname, vcc, ((int) (short) simm16) * 4 + opcode_address + 4); } protected static Instruction[] m_instances = new Instruction[252]; public static final Instruction[] instructions() { return m_instances; } }