private string DisassembleInstruction(CmdInfo info) { switch (info.ID) { case CmdID.G_NOOP: return($"gsDPNoOpTag(0x{(uint)info.Args["tag"]:X})"); case CmdID.G_VTX: return($"gsSPVertex({DisAddress(info.Args["vaddr"])}, {info.Args["numv"]}, {info.Args["vbidx"]})"); case CmdID.G_MODIFYVTX: return($"gsSPModifyVertex({info.Args["where"]}, {info.Args["vbidx"]}, {info.Args["val"]})"); case CmdID.G_CULLDL: return($"gsSPCullDisplayList({info.Args["vfirst"]}, {info.Args["vlast"]})"); case CmdID.G_BRANCH_Z: return($"gsSPBranchLessZraw({DisAddress(_wordHi)}, {info.Args["vbidx"]}, 0x{info.Args["zval"]:X})"); case CmdID.G_TRI1: return($"gsSP1Triangle({info.Args["v0"]}, {info.Args["v1"]}, {info.Args["v2"]}, 0)"); case CmdID.G_TRI2: return($"gsSP2Triangles({info.Args["v00"]}, {info.Args["v01"]}, {info.Args["v02"]}, 0, {info.Args["v10"]}, {info.Args["v11"]}, {info.Args["v12"]}, 0)"); case CmdID.G_QUAD: return($"gsSPQuadrangle({info.Args["v0"]}, {info.Args["v1"]}, {info.Args["v2"]}, {info.Args["v3"]}, 0)"); case CmdID.G_DMA_IO: return($"gsSPDma_io(0x{info.Args["flag"]:X}, 0x{info.Args["dmem"]:X}, 0x{ info.Args["dram"]:X}, 0x{info.Args["size"]:X})"); case CmdID.G_TEXTURE: return($"gsSPTexture(0x{info.Args["scaleS"]:X}, 0x{info.Args["scaleT"]:X}, {info.Args["level"]}, {(G_TX_TILE)info.Args["tile"]}, {info.Args["on"]})"); case CmdID.G_POPMTX: return($"gsSPPopMatrixN(G_MTX_MODELVIEW, {info.Args["num"]})"); case CmdID.G_GEOMETRYMODE: { int clearbits = (int)info.Args["clearbits"]; int setbits = (int)info.Args["setbits"]; if (clearbits == 0) { var flag = new BitFlag <G_GEO_MODE>((G_GEO_MODE)setbits); return($"gsSPLoadGeometryMode({flag})"); } else if (setbits == 0) { var flag = new BitFlag <G_GEO_MODE>((G_GEO_MODE) ~clearbits); return($"gsSPClearGeometryMode({flag})"); } else if (clearbits == 0xFFFFFF) { var flag = new BitFlag <G_GEO_MODE>((G_GEO_MODE)setbits); return($"gsSPSetGeometryMode({flag})"); } else { var clearFlag = new BitFlag <G_GEO_MODE>((G_GEO_MODE) ~clearbits); var setFlag = new BitFlag <G_GEO_MODE>((G_GEO_MODE)setbits); return($"gsSPGeometryMode({clearFlag}, {setFlag})"); } } case CmdID.G_MTX: return($"gsSPMatrix({DisAddress(info.Args["mtxaddr"])}, {DisMtxParams((int)info.Args["param"])})"); case CmdID.G_MOVEWORD: break; case CmdID.G_MOVEMEM: break; case CmdID.G_LOAD_UCODE: return($"gsSPLoadUcodeEx({DisAddress(info.Args["tstart"])}, {DisAddress(_wordHi)}, 0x{info.Args["dsize"]:X})"); case CmdID.G_DL: { var branch = info.GetArg <bool>("branch"); return(branch ? $"gsSPBranchList({DisAddress(info.Args["dl"])})" : $"gsSPDisplayList({DisAddress(info.Args["dl"])})"); } case CmdID.G_ENDDL: return($"gsSPEndDisplayList()"); case CmdID.G_SPNOOP: return($"gsSPNoOp()"); case CmdID.G_RDPHALF_1: { _wordHi = (uint)info.Args["word"]; break; } case CmdID.G_SETOTHERMODE_L: { var cmd = info.Convert <GSetOtherMode>(); var macro = OtherModeMacro.MacrosL.Find(m => m.Match(cmd)); if (macro != null) { var value = macro.values.Find(v => (uint)v.Item2 == cmd.data); return($"gsDP{macro.Name}({value?.Item1??("0x" +cmd.data.ToString("X"))})"); } return($"gsSPSetOtherMode(G_SETOTHERMODE_L, {(G_MDSFT_L)cmd.shift}, {cmd.len}, 0x{cmd.data:X})"); } case CmdID.G_SETOTHERMODE_H: { var cmd = info.Convert <GSetOtherMode>(); var macro = OtherModeMacro.MacrosH.Find(m => m.Match(cmd)); if (macro != null) { var value = macro.values.Find(v => (uint)v.Item2 == cmd.data); return($"gsDP{macro.Name}({value?.Item1 ?? ("0x" + cmd.data.ToString("X"))})"); } return($"gsSPSetOtherMode(G_SETOTHERMODE_H, {(G_MDSFT_H)cmd.shift}, {cmd.len}, 0x{cmd.data:X})"); } case CmdID.G_TEXRECT: { var cmd = info.Convert <GTexRect>(); return($"gsSPTextureRectangle({cmd.ulx}, {cmd.uly}, {cmd.lrx}, {cmd.lry}, {cmd.tile}, {cmd.uls}, {cmd.ult}, {cmd.dsdx}, {cmd.dtdy})"); } case CmdID.G_TEXRECTFLIP: { var cmd = info.Convert <GTexRect>(); return($"gsSPTextureRectangleFlip({cmd.ulx}, {cmd.uly}, {cmd.lrx}, {cmd.lry}, {cmd.tile}, {cmd.uls}, {cmd.ult}, {cmd.dsdx}, {cmd.dtdy})"); } case CmdID.G_RDPLOADSYNC: return("gsDPLoadSync()"); case CmdID.G_RDPPIPESYNC: return("gsDPPipeSync()"); case CmdID.G_RDPTILESYNC: return("gsDPTileSync()"); case CmdID.G_RDPFULLSYNC: return("gsDPFullSync()"); case CmdID.G_SETKEYGB: { var cmd = info.Convert <GSetKeyGB>(); return($"gsDPSetKeyGB({cmd.centerG}, {cmd.scaleG}, {cmd.widthG}, {cmd.centerB}, {cmd.scaleB}, {cmd.widthB})"); } case CmdID.G_SETKEYR: { var cmd = info.Convert <GSetKeyR>(); return($"gsDPSetKeyR({cmd.centerR}, {cmd.widthR}, {cmd.scaleR})"); } case CmdID.G_SETCONVERT: return($"gsDPSetConvert({info.Args["k0"]}, {info.Args["k1"]}, {info.Args["k2"]}, {info.Args["k3"]}, {info.Args["k4"]}, {info.Args["k5"]})"); case CmdID.G_SETSCISSOR: { var cmd = info.Convert <GSetScissor>(); if (cmd.lrx.FracPart() == 0 && cmd.lry.FracPart() == 0 && cmd.ulx.FracPart() == 0 && cmd.uly.FracPart() == 0) { return($"gsDPSetScissor({cmd.mode}, {cmd.ulx.IntPart()}, {cmd.uly.IntPart()}, {cmd.lrx.IntPart()}, {cmd.uly.IntPart()})"); } else { return($"gsDPSetScissorFrac({cmd.mode}, {cmd.ulx}, {cmd.uly}, {cmd.lrx}, {cmd.lry})"); } } case CmdID.G_SETPRIMDEPTH: return($"gsDPSetPrimDepth({info.Args["z"]}, {info.Args["dz"]})"); case CmdID.G_RDPSETOTHERMODE: return($"gsDPSetOtherMode(0x{info.Args["omodeH"]:X}, 0x{info.Args["omodeL"]:X})"); case CmdID.G_LOADTLUT: return($"gsDPLoadTLUTCmd({info.Args["tile"]}, {info.Args["count"]})"); case CmdID.G_RDPHALF_2: { _wordLo = (uint)info.Args["word"]; break; } case CmdID.G_SETTILESIZE: { var cmd = info.Convert <GLoadTile>(); return($"gsDPSetTileSize({cmd.tile}, {cmd.uls}, {cmd.ult}, {cmd.lrs}, {cmd.lrt})"); } case CmdID.G_LOADBLOCK: { var cmd = info.Convert <GLoadBlock>(); return($"gsDPLoadBlock({cmd.tile}, {cmd.uls}, {cmd.ult}, {cmd.texels}, {cmd.dxt})"); } case CmdID.G_LOADTILE: { var cmd = info.Convert <GLoadTile>(); return($"gsDPLoadTile({cmd.tile}, {cmd.uls}, {cmd.ult}, {cmd.lrs}, {cmd.lrt})"); } case CmdID.G_SETTILE: { var cmt = DisTexWrap((int)info.Args["cmT"]); var cmS = DisTexWrap((int)info.Args["cmS"]); return($"gsDPSetTile({info.Args["fmt"]}, {info.Args["siz"]}, {info.Args["line"]}, 0x{info.Args["tmem"]:X}, {(G_TX_TILE)info.Args["tile"]}, {info.Args["palette"]}, {cmt}, {info.Args["maskT"]}, {info.Args["shiftT"]}, {cmS}, {info.Args["maskS"]}, {info.Args["shiftS"]})"); } case CmdID.G_FILLRECT: { var cmd = info.Convert <GFillRect>(); return($"gsDPFillRectangle({cmd.ulx}, {cmd.uly}, {cmd.lrx}, {cmd.lry})"); } case CmdID.G_SETFILLCOLOR: return($"gsDPSetFillColor(0x{info.Args["color"]:X8})"); case CmdID.G_SETFOGCOLOR: return($"gsDPSetFogColor({info.Args["R"]}, {info.Args["G"]}, {info.Args["B"]}, {info.Args["A"]})"); case CmdID.G_SETBLENDCOLOR: return($"gsDPBlendColor({info.Args["R"]}, {info.Args["G"]}, {info.Args["B"]}, {info.Args["A"]})"); case CmdID.G_SETPRIMCOLOR: return($"gsDPSetPrimColor(0x{info.Args["minlevel"]:X2}, 0x{info.Args["lodfrac"]:X2}, {info.Args["R"]}, {info.Args["G"]}, {info.Args["B"]}, {info.Args["A"]})"); case CmdID.G_SETENVCOLOR: return($"gsDPSetEnvColor({info.Args["R"]}, {info.Args["G"]}, {info.Args["B"]}, {info.Args["A"]})"); case CmdID.G_SETCOMBINE: { var cmd = info.Convert <GSetCombine>(); var mode0 = CCMode.Modes.Find(m => m.Match(cmd, 0)); var mode1 = CCMode.Modes.Find(m => m.Match(cmd, 1)); if (mode0 != null && mode1 != null) { return($"gsDPSetCombineMode({mode0.Name}, {mode1.Name})"); } return($"gsDPSetCombineLERP({DisCCM(cmd.a0, 1)}, {DisCCM(cmd.b0, 2)}, {DisCCM(cmd.c0, 3)}, {DisCCM(cmd.d0, 4)}, {DisACM(cmd.Aa0, 1)}, {DisACM(cmd.Ab0, 2)}, {DisACM(cmd.Ac0, 3)}, {DisACM(cmd.Ad0, 4)}, {DisCCM(cmd.a1, 1)}, {DisCCM(cmd.b1, 2)}, {DisCCM(cmd.c1, 3)}, {DisCCM(cmd.d1, 4)}, {DisACM(cmd.Aa1, 1)}, {DisACM(cmd.Ab1, 2)}, {DisACM(cmd.Ac1, 3)}, {DisACM(cmd.Ad1, 4)})"); } case CmdID.G_SETTIMG: return($"gsDPSetTextureImage({info.Args["fmt"]}, {info.Args["siz"]}, {info.Args["width"]}, {DisAddress(info.Args["imgaddr"])})"); case CmdID.G_SETZIMG: return($"gsDPSetDepthImage({DisAddress(info.Args["imgaddr"])})"); case CmdID.G_SETCIMG: return($"gsDPSetColorImage({info.Args["fmt"]}, {info.Args["siz"]}, {info.Args["width"]}, {DisAddress(info.Args["imgaddr"])})"); default: break; } return($"Unsupported Instruction {info.ID}"); }