diff --git a/plugins/GSdx/GPUDrawScanline.cpp b/plugins/GSdx/GPUDrawScanline.cpp index 38a4044bfb..ad4b62817f 100644 --- a/plugins/GSdx/GPUDrawScanline.cpp +++ b/plugins/GSdx/GPUDrawScanline.cpp @@ -871,11 +871,11 @@ GPUDrawScanline::GPUDrawScanlineMap::GPUDrawScanlineMap() #endif } -IDrawScanline::DrawScanlinePtr GPUDrawScanline::GPUDrawScanlineMap::GetDefaultFunction(DWORD dw) +IDrawScanline::DrawScanlinePtr GPUDrawScanline::GPUDrawScanlineMap::GetDefaultFunction(DWORD key) { GPUScanlineSelector sel; - sel.dw = dw; + sel.key = key; return m_default[sel]; } @@ -899,11 +899,11 @@ GPUDrawScanline::GPUSetupPrimMap::GPUSetupPrimMap() InitSP_SPRITE(1); } -IDrawScanline::SetupPrimPtr GPUDrawScanline::GPUSetupPrimMap::GetDefaultFunction(DWORD dw) +IDrawScanline::SetupPrimPtr GPUDrawScanline::GPUSetupPrimMap::GetDefaultFunction(DWORD key) { - DWORD sprite = (dw >> 0) & 1; - DWORD tme = (dw >> 1) & 1; - DWORD iip = (dw >> 2) & 1; + DWORD sprite = (key >> 0) & 1; + DWORD tme = (key >> 1) & 1; + DWORD iip = (key >> 2) & 1; return m_default[sprite][tme][iip]; } diff --git a/plugins/GSdx/GPUDrawScanline.h b/plugins/GSdx/GPUDrawScanline.h index 5651580007..f4fcaf55ee 100644 --- a/plugins/GSdx/GPUDrawScanline.h +++ b/plugins/GSdx/GPUDrawScanline.h @@ -50,9 +50,9 @@ union GPUScanlineSelector DWORD tfx:2; // 5 }; - DWORD dw; + DWORD key; - operator DWORD() {return dw & 0xff;} + operator DWORD() {return key & 0xff;} }; __declspec(align(16)) struct GPUScanlineEnvironment @@ -87,28 +87,28 @@ class GPUDrawScanline : public GSAlignedClass<16>, public IDrawScanline // - class GPUDrawScanlineMap : public GSFunctionMap + class GPUDrawScanlineMap : public GSFunctionMap { DrawScanlinePtr m_default[256]; public: GPUDrawScanlineMap(); - DrawScanlinePtr GetDefaultFunction(DWORD dw); + DrawScanlinePtr GetDefaultFunction(DWORD key); }; GPUDrawScanlineMap m_ds; // - class GPUSetupPrimMap : public GSFunctionMap + class GPUSetupPrimMap : public GSFunctionMap { SetupPrimPtr m_default[2][2][2]; public: GPUSetupPrimMap(); - SetupPrimPtr GetDefaultFunction(DWORD dw); + SetupPrimPtr GetDefaultFunction(DWORD key); }; GPUSetupPrimMap m_sp; diff --git a/plugins/GSdx/GPURendererSW.h b/plugins/GSdx/GPURendererSW.h index 1cf3fdfe03..4603b2a76e 100644 --- a/plugins/GSdx/GPURendererSW.h +++ b/plugins/GSdx/GPURendererSW.h @@ -125,7 +125,7 @@ protected: GPUScanlineParam p; - p.sel.dw = 0; + p.sel.key = 0; p.sel.iip = env.PRIM.IIP; p.sel.me = env.STATUS.ME; p.sel.abe = env.PRIM.ABE; diff --git a/plugins/GSdx/GS.h b/plugins/GSdx/GS.h index 51652646b2..f7b1276795 100644 --- a/plugins/GSdx/GS.h +++ b/plugins/GSdx/GS.h @@ -567,41 +567,38 @@ REG64_(GIFReg, COLCLAMP) REG_END REG64_(GIFReg, DIMX) - UINT32 DM00:3; - UINT32 _PAD00:1; - UINT32 DM01:3; - UINT32 _PAD01:1; - UINT32 DM02:3; - UINT32 _PAD02:1; - UINT32 DM03:3; - UINT32 _PAD03:1; - - UINT32 DM10:3; - UINT32 _PAD10:1; - UINT32 DM11:3; - UINT32 _PAD11:1; - UINT32 DM12:3; - UINT32 _PAD12:1; - UINT32 DM13:3; - UINT32 _PAD13:1; - - UINT32 DM20:3; - UINT32 _PAD20:1; - UINT32 DM21:3; - UINT32 _PAD21:1; - UINT32 DM22:3; - UINT32 _PAD22:1; - UINT32 DM23:3; - UINT32 _PAD23:1; - - UINT32 DM30:3; - UINT32 _PAD30:1; - UINT32 DM31:3; - UINT32 _PAD31:1; - UINT32 DM32:3; - UINT32 _PAD32:1; - UINT32 DM33:3; - UINT32 _PAD33:1; + INT32 DM00:3; + INT32 _PAD00:1; + INT32 DM01:3; + INT32 _PAD01:1; + INT32 DM02:3; + INT32 _PAD02:1; + INT32 DM03:3; + INT32 _PAD03:1; + INT32 DM10:3; + INT32 _PAD10:1; + INT32 DM11:3; + INT32 _PAD11:1; + INT32 DM12:3; + INT32 _PAD12:1; + INT32 DM13:3; + INT32 _PAD13:1; + INT32 DM20:3; + INT32 _PAD20:1; + INT32 DM21:3; + INT32 _PAD21:1; + INT32 DM22:3; + INT32 _PAD22:1; + INT32 DM23:3; + INT32 _PAD23:1; + INT32 DM30:3; + INT32 _PAD30:1; + INT32 DM31:3; + INT32 _PAD31:1; + INT32 DM32:3; + INT32 _PAD32:1; + INT32 DM33:3; + INT32 _PAD33:1; REG_END REG64_(GIFReg, DTHE) diff --git a/plugins/GSdx/GSDrawScanline.cpp b/plugins/GSdx/GSDrawScanline.cpp index 2f6d19063c..ff9ab080aa 100644 --- a/plugins/GSdx/GSDrawScanline.cpp +++ b/plugins/GSdx/GSDrawScanline.cpp @@ -32,6 +32,12 @@ GSDrawScanline::GSDrawScanline(GSState* state, int id) GSDrawScanline::~GSDrawScanline() { + POSITION pos = m_dscg.GetHeadPosition(); + + while(pos) + { + delete m_dscg.GetNextValue(pos); + } } void GSDrawScanline::BeginDraw(const GSRasterizerData* data, Functions* f) @@ -60,6 +66,7 @@ void GSDrawScanline::BeginDraw(const GSRasterizerData* data, Functions* f) m_env.afix2 = m_env.afix.yywwlh().sll16(7); m_env.frb = GSVector4i((int)env.FOGCOL.ai32[0] & 0x00ff00ff); m_env.fga = GSVector4i((int)(env.FOGCOL.ai32[0] >> 8) & 0x00ff00ff); + m_env.dimx = env.dimx; if(m_env.sel.fpsm == 1) { @@ -163,7 +170,7 @@ void GSDrawScanline::BeginDraw(const GSRasterizerData* data, Functions* f) // - f->sl = m_ds.Lookup(m_env.sel); + f->sl = (DrawScanlinePtr)&GSDrawScanline::DrawScanline; // m_ds.Lookup(m_env.sel); // @@ -186,16 +193,31 @@ void GSDrawScanline::BeginDraw(const GSRasterizerData* data, Functions* f) } f->sp = m_sp.Lookup(sel); + + // + + GSDrawScanlineCodeGenerator* cg = NULL; + + if(!m_dscg.Lookup(m_env.sel, cg)) + { + cg = new GSDrawScanlineCodeGenerator(m_env); + + m_dscg.SetAt(m_env.sel, cg); + } + + m_dsf = (DrawScanlineStaticPtr)cg->getCode(); } void GSDrawScanline::EndDraw(const GSRasterizerStats& stats) { - m_ds.UpdateStats(stats, m_state->m_perfmon.GetFrame()); + // m_ds.UpdateStats(stats, m_state->m_perfmon.GetFrame()); } template void GSDrawScanline::SetupPrim(const GSVertexSW* vertices, const GSVertexSW& dscan) { + // TODO: clean up unused parts + // p GSVector4 p = dscan.p; @@ -311,47 +333,28 @@ void GSDrawScanline::SetupPrim(const GSVertexSW* vertices, const GSVertexSW& dsc } else { - GSVector4i rgba = GSVector4i(vertices[0].c); + GSVector4i c = GSVector4i(vertices[0].c); - GSVector4i rbga = rgba.upl16(rgba.zwxy()); + c = c.upl16(c.zwxy()); if(tme == 0) { - rbga = rbga.srl16(7); - - DWORD abe = m_env.sel.abe & 0x3f; // a, b, c - - DWORD abea = m_env.sel.abea; - DWORD abeb = m_env.sel.abeb; - DWORD abec = m_env.sel.abec; - DWORD abed = m_env.sel.abed; - - if(fge == 0 && abe != 0x3f && !(abe & 0x15) && abea != abeb) // 0x15 = 010101b => a, b, c != 1 - { - GSVector4i c[4]; - - c[0] = rbga; - c[1] = rgba.zzzzh().zzzz(); - c[2] = GSVector4i::zero(); - c[3] = m_env.afix2; - - GSVector4i cc = GSVector4i::lerp16<1>(c[abea], c[abeb], c[abec + 1]); - - if(abed == 0) - { - cc = cc.add16(c[0]); - } - - m_env.c2.rb = cc.xxxx(); - m_env.c2.ga = cc.zzzz().mix16(c[1].srl16(7)); - } + c = c.srl16(7); } - m_env.c.rb = rbga.xxxx(); - m_env.c.ga = rbga.zzzz(); + m_env.c.rb = c.xxxx(); + m_env.c.ga = c.zzzz(); } } +void GSDrawScanline::DrawScanline(int top, int left, int right, const GSVertexSW& v) +{ + // TODO: call this directly from rasterizer + + m_dsf(top, left, right, v); +} + +/* GSVector4i GSDrawScanline::Wrap(const GSVector4i& t) { GSVector4i clamp = t.sat_i16(m_env.t.min, m_env.t.max); @@ -1133,7 +1136,7 @@ void GSDrawScanline::DrawScanlineEx(int top, int left, int right, const GSVertex GSVector4i rb, ga; - if(tfx == TFX_NONE && fge == 0 && abea != 1 && abeb != 1 && abec != 1 && abea != abeb) + if(!iip && tfx == TFX_NONE && !fge && abea != 1 && abeb != 1 && abec != 1 && abea != abeb) { c[0] = m_env.c2.rb; c[1] = m_env.c2.ga; @@ -1236,15 +1239,9 @@ void GSDrawScanline::DrawScanlineEx(int top, int left, int right, const GSVertex } } } - +*/ void GSDrawScanline::DrawSolidRect(const GSVector4i& r, const GSVertexSW& v) { -/* -static FILE* s_fp = NULL; -if(!s_fp) s_fp = fopen("c:\\log2.txt", "w"); -__int64 start = __rdtsc(); -int size = (r.z - r.x) * (r.w - r.y); -*/ ASSERT(r.y >= 0); ASSERT(r.w >= 0); @@ -1318,10 +1315,6 @@ int size = (r.z - r.x) * (r.w - r.y); } } } -/* -__int64 stop = __rdtsc(); -fprintf(s_fp, "%I64d => %I64d = %I64d (%d,%d - %d,%d) %d\n", start, stop, stop - start, r.x, r.y, r.z, r.w, size); -*/ } template @@ -1396,7 +1389,7 @@ void GSDrawScanline::FillBlock(const GSVector4i* row, int* col, const GSVector4i } } } - +/* // GSDrawScanline::GSDrawScanlineMap::GSDrawScanlineMap() @@ -2736,11 +2729,11 @@ GSDrawScanline::GSDrawScanlineMap::GSDrawScanlineMap() #endif } -IDrawScanline::DrawScanlinePtr GSDrawScanline::GSDrawScanlineMap::GetDefaultFunction(DWORD dw) +IDrawScanline::DrawScanlinePtr GSDrawScanline::GSDrawScanlineMap::GetDefaultFunction(DWORD key) { GSScanlineSelector sel; - sel.dw = dw; + sel.key = key; return m_default[sel.fpsm][sel.zpsm][sel.ztst][sel.iip]; } @@ -2755,19 +2748,19 @@ void GSDrawScanline::GSDrawScanlineMap::PrintStats() while(pos) { - DWORD dw; + DWORD key; ActivePtr* p; - m_map_active.GetNextAssoc(pos, dw, p); + m_map_active.GetNextAssoc(pos, key, p); - if(m_map.Lookup(dw)) + if(m_map.Lookup(key)) { continue; } GSScanlineSelector sel; - sel.dw = dw; + sel.key = key; if(p->frames > 30 && !sel.IsSolidRect()) { @@ -2775,7 +2768,7 @@ void GSDrawScanline::GSDrawScanlineMap::PrintStats() if(tpf >= 500) { - _ftprintf(fp, _T("InitDS_Sel(0x%08x); // %6.2f%%\n"), sel.dw, (float)tpf / 100); + _ftprintf(fp, _T("InitDS_Sel(0x%08x); // %6.2f%%\n"), (DWORD)sel, (float)tpf / 100); } } } @@ -2785,7 +2778,7 @@ void GSDrawScanline::GSDrawScanlineMap::PrintStats() } // - +*/ GSDrawScanline::GSSetupPrimMap::GSSetupPrimMap() { #define InitSP_IIP(zbe, fge, tme, fst, iip) \ @@ -2811,13 +2804,13 @@ GSDrawScanline::GSSetupPrimMap::GSSetupPrimMap() InitSP_ZBE(1); } -IDrawScanline::SetupPrimPtr GSDrawScanline::GSSetupPrimMap::GetDefaultFunction(DWORD dw) +IDrawScanline::SetupPrimPtr GSDrawScanline::GSSetupPrimMap::GetDefaultFunction(DWORD key) { - DWORD zbe = (dw >> 0) & 1; - DWORD fge = (dw >> 1) & 1; - DWORD tme = (dw >> 2) & 1; - DWORD fst = (dw >> 3) & 1; - DWORD iip = (dw >> 4) & 1; + DWORD zbe = (key >> 0) & 1; + DWORD fge = (key >> 1) & 1; + DWORD tme = (key >> 2) & 1; + DWORD fst = (key >> 3) & 1; + DWORD iip = (key >> 4) & 1; return m_default[zbe][fge][tme][fst][iip]; } @@ -2831,7 +2824,7 @@ const GSVector4 GSDrawScanline::m_shift[4] = GSVector4(-2.0f, -1.0f, 0.0f, 1.0f), GSVector4(-3.0f, -2.0f, -1.0f, 0.0f), }; - +/* const GSVector4i GSDrawScanline::m_test[8] = { GSVector4i::zero(), @@ -2843,3 +2836,4 @@ const GSVector4i GSDrawScanline::m_test[8] = GSVector4i(0x00000000, 0x00000000, 0x00000000, 0xffffffff), GSVector4i::zero(), }; +*/ diff --git a/plugins/GSdx/GSDrawScanline.h b/plugins/GSdx/GSDrawScanline.h index 5e84bf371c..c5a01db43a 100644 --- a/plugins/GSdx/GSDrawScanline.h +++ b/plugins/GSdx/GSDrawScanline.h @@ -23,150 +23,61 @@ #include "GSState.h" #include "GSRasterizer.h" +#include "GSScanlineEnvironment.h" +#include "GSDrawScanlineCodeGenerator.h" #include "GSAlignedClass.h" -union GSScanlineSelector -{ - struct - { - DWORD fpsm:2; // 0 - DWORD zpsm:2; // 2 - DWORD ztst:2; // 4 (0: off, 1: write, 2: test (ge), 3: test (g)) - DWORD atst:3; // 6 - DWORD afail:2; // 9 - DWORD iip:1; // 11 - DWORD tfx:3; // 12 - DWORD tcc:1; // 15 - DWORD fst:1; // 16 - DWORD ltf:1; // 17 - DWORD tlu:1; // 18 - DWORD fge:1; // 19 - DWORD date:1; // 20 - DWORD abea:2; // 21 - DWORD abeb:2; // 23 - DWORD abec:2; // 25 - DWORD abed:2; // 27 - DWORD pabe:1; // 29 - DWORD rfb:1; // 30 - DWORD sprite:1; // 31 - }; - - struct - { - DWORD _pad1:21; - DWORD abe:8; - DWORD _pad2:3; - }; - - DWORD dw; - - operator DWORD() {return dw;} - - bool IsSolidRect() - { - return sprite - && iip == 0 - && tfx == TFX_NONE - && abe == 255 - && ztst <= 1 - && atst <= 1 - && date == 0 - && fge == 0; - } -}; - -__declspec(align(16)) struct GSScanlineEnvironment -{ - GSScanlineSelector sel; - - void* vm; - const void* tex; - const DWORD* clut; - DWORD tw; - - GSVector4i* fbr; - GSVector4i* zbr; - int** fbc; - int** zbc; - GSVector2i* fzbr; - GSVector2i* fzbc; - - GSVector4i fm, zm; - struct {GSVector4i min, max, mask;} t; // [u] x 4 [v] x 4 - GSVector4i datm; - GSVector4i colclamp; - GSVector4i fba; - GSVector4i aref; - GSVector4i afix, afix2; - GSVector4i frb, fga; - - struct {GSVector4 z, s, t, q; GSVector4i rb, ga, f, si, ti, _pad[3];} d[4]; - struct {GSVector4 z, stq; GSVector4i c, f, st;} d4; - struct {GSVector4i rb, ga;} c; - struct {GSVector4i z, f;} p; - struct {GSVector4i rb, ga;} c2; -}; - -__declspec(align(16)) struct GSScanlineParam -{ - GSScanlineSelector sel; - - void* vm; - const void* tex; - const DWORD* clut; - DWORD tw; - - GSLocalMemory::Offset* fbo; - GSLocalMemory::Offset* zbo; - GSLocalMemory::Offset4* fzbo; - - DWORD fm, zm; -}; - class GSDrawScanline : public GSAlignedClass<16>, public IDrawScanline { GSScanlineEnvironment m_env; static const GSVector4 m_shift[4]; - static const GSVector4i m_test[8]; +/* static const GSVector4i m_test[8]; // - class GSDrawScanlineMap : public GSFunctionMap + class GSDrawScanlineMap : public GSFunctionMap { DrawScanlinePtr m_default[4][4][4][2]; public: GSDrawScanlineMap(); - DrawScanlinePtr GetDefaultFunction(DWORD dw); + DrawScanlinePtr GetDefaultFunction(DWORD key); void PrintStats(); }; GSDrawScanlineMap m_ds; - +*/ // - class GSSetupPrimMap : public GSFunctionMap + class GSSetupPrimMap : public GSFunctionMap { SetupPrimPtr m_default[2][2][2][2][2]; public: GSSetupPrimMap(); - SetupPrimPtr GetDefaultFunction(DWORD dw); + SetupPrimPtr GetDefaultFunction(DWORD key); }; GSSetupPrimMap m_sp; - // - template void SetupPrim(const GSVertexSW* vertices, const GSVertexSW& dscan); // + CRBMap m_dscg; + + DrawScanlineStaticPtr m_dsf; + + void DrawScanline(int top, int left, int right, const GSVertexSW& v); + +/* + // + __forceinline GSVector4i Wrap(const GSVector4i& t); __forceinline void SampleTexture(DWORD ltf, DWORD tlu, const GSVector4i& u, const GSVector4i& v, GSVector4i* c); @@ -187,7 +98,7 @@ class GSDrawScanline : public GSAlignedClass<16>, public IDrawScanline template void DrawScanlineEx(int top, int left, int right, const GSVertexSW& v); - +*/ // void DrawSolidRect(const GSVector4i& r, const GSVertexSW& v); @@ -213,5 +124,5 @@ public: void BeginDraw(const GSRasterizerData* data, Functions* f); void EndDraw(const GSRasterizerStats& stats); - void PrintStats() {m_ds.PrintStats();} + void PrintStats() {/*m_ds.PrintStats();*/} }; diff --git a/plugins/GSdx/GSDrawScanlineCodeGenerator.cpp b/plugins/GSdx/GSDrawScanlineCodeGenerator.cpp new file mode 100644 index 0000000000..cbe6fda70d --- /dev/null +++ b/plugins/GSdx/GSDrawScanlineCodeGenerator.cpp @@ -0,0 +1,1975 @@ +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * This Program 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 2, or (at your option) + * any later version. + * + * This Program 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +// TODO: test without sse41 +// TODO: x64 + +#include "StdAfx.h" +#include "GSDrawScanlineCodeGenerator.h" + +GSDrawScanlineCodeGenerator::GSDrawScanlineCodeGenerator(GSScanlineEnvironment& env) + : CodeGenerator(DEFAULT_MAX_CODE_SIZE, 0) + , m_env(env) +{ + #if _M_AMD64 + #error TODO + #endif + + Generate(); +} + +void GSDrawScanlineCodeGenerator::Generate() +{ + push(ebx); + push(esi); + push(edi); + push(ebp); + + const int params = 16; + + Init(params); + + align(16); + +L("@@"); + + // ecx = steps + // esi = fzbr + // edi = fzbc + // xmm0 = z/zi + // xmm2 = s/si (tme) + // xmm3 = t/ti (tme) + // xmm4 = q (tme) + // xmm5 = rb (!tme) + // xmm6 = ga (!tme) + // xmm7 = test + + TestZ(xmm1, m_env.sel.tfx != TFX_NONE ? xmm6 : xmm4); + + // ecx = steps + // esi = fzbr + // edi = fzbc + // ebp = za + // - xmm0 + // xmm2 = s/si (tme) + // xmm3 = t/ti (tme) + // xmm4 = q (tme) + // xmm5 = rb (!tme) + // xmm6 = ga (!tme) + // xmm7 = test + + SampleTexture(); + + // ecx = steps + // esi = fzbr + // edi = fzbc + // ebp = za + // - xmm2 + // - xmm3 + // - xmm4 + // xmm5 = rb + // xmm6 = ga + // xmm7 = test + + AlphaTFX(); + + // ecx = steps + // esi = fzbr + // edi = fzbc + // ebp = za + // xmm2 = gaf (TFX_HIGHLIGHT || TFX_HIGHLIGHT2 && !tcc) + // xmm5 = rb + // xmm6 = ga + // xmm7 = test + + if(m_env.sel.fb) + { + movdqa(xmm3, xmmword[&m_env.fm]); + } + + if(m_env.sel.zb) + { + movdqa(xmm4, xmmword[&m_env.zm]); + } + + // ecx = steps + // esi = fzbr + // edi = fzbc + // ebp = za + // xmm2 = gaf (TFX_HIGHLIGHT || TFX_HIGHLIGHT2 && !tcc) + // xmm3 = fm + // xmm4 = zm + // xmm5 = rb + // xmm6 = ga + // xmm7 = test + + TestAlpha(); + + // ecx = steps + // esi = fzbr + // edi = fzbc + // ebp = za + // xmm2 = gaf (TFX_HIGHLIGHT || TFX_HIGHLIGHT2 && !tcc) + // xmm3 = fm + // xmm4 = zm + // xmm5 = rb + // xmm6 = ga + // xmm7 = test + + ColorTFX(); + + // ecx = steps + // esi = fzbr + // edi = fzbc + // ebp = za + // xmm3 = fm + // xmm4 = zm + // xmm5 = rb + // xmm6 = ga + // xmm7 = test + + Fog(); + + // ecx = steps + // esi = fzbr + // edi = fzbc + // ebp = za + // xmm3 = fm + // xmm4 = zm + // xmm5 = rb + // xmm6 = ga + // xmm7 = test + + ReadFrame(); + + // ecx = steps + // esi = fzbr + // edi = fzbc + // ebp = za + //xmm2 = fd + // xmm3 = fm + // xmm4 = zm + // xmm5 = rb + // xmm6 = ga + // xmm7 = test + + TestDestAlpha(); + + // fm |= test; + // zm |= test; + + if(m_env.sel.fb || m_env.sel.ztest) + { + por(xmm3, xmm7); + } + + if(m_env.sel.zb) + { + por(xmm4, xmm7); + } + + // ebx = fa + // ecx = steps + // esi = fzbr + // edi = fzbc + // ebp = za + // xmm2 = fd + // xmm3 = fm + // xmm4 = zm + // xmm5 = rb + // xmm6 = ga + + // int fzm = ~(fm == GSVector4i::xffffffff()).ps32(zm == GSVector4i::xffffffff()).ps32().mask(); + + if(m_env.sel.fb && m_env.sel.zb) + { + pcmpeqd(xmm0, xmm0); + movdqa(xmm1, xmm0); + pcmpeqd(xmm0, xmm3); + pcmpeqd(xmm1, xmm4); + } + else if(m_env.sel.fb) + { + pcmpeqd(xmm0, xmm0); + pcmpeqd(xmm0, xmm3); + pxor(xmm1, xmm1); + } + else if(m_env.sel.zb) + { + pxor(xmm0, xmm0); + pcmpeqd(xmm1, xmm1); + pcmpeqd(xmm1, xmm4); + } + + packssdw(xmm0, xmm1); + packssdw(xmm0, xmm0); // TODO: not really needed... + pmovmskb(edx, xmm0); + not(edx); + + // ebx = fa + // ecx = steps + // edx = fzm + // esi = fzbr + // edi = fzbc + // ebp = za + // xmm2 = fd + // xmm3 = fm + // xmm4 = zm + // xmm5 = rb + // xmm6 = ga + + WriteZBuf(); + + // ebx = fa + // ecx = steps + // edx = fzm + // esi = fzbr + // edi = fzbc + // - ebp + // xmm2 = fd + // xmm3 = fm + // - xmm4 + // xmm5 = rb + // xmm6 = ga + + AlphaBlend(); + + // ebx = fa + // ecx = steps + // edx = fzm + // esi = fzbr + // edi = fzbc + // xmm2 = fd + // xmm3 = fm + // xmm5 = rb + // xmm6 = ga + + WriteFrame(params); + +L("step"); + + // if(steps <= 0) break; + + test(ecx, ecx); + jle("@f", T_NEAR); + + Step(); + + jmp("@b", T_NEAR); + +L("@@"); + + pop(ebp); + pop(edi); + pop(esi); + pop(ebx); + + ret(); +} + +void GSDrawScanlineCodeGenerator::Init(int params) +{ + const int _top = params + 4; + const int _left = params + 8; + const int _right = params + 12; + const int _v = params + 16; + + // int skip = left & 3; + + mov(eax, dword[esp + _left]); + mov(ebx, eax); + and(eax, 3); + + // left -= skip; + + sub(ebx, eax); + + // int steps = right - left - 4; + + mov(ecx, dword[esp + _right]); + sub(ecx, ebx); + sub(ecx, 4); + + // GSVector4i test = m_test[skip] | m_test[7 + (steps & (steps >> 31))]; + + shl(eax, 4); + + movdqa(xmm7, xmmword[eax + (size_t)&m_test[0]]); + + mov(edx, ecx); + sar(edx, 31); + and(edx, ecx); + shl(edx, 4); + + por(xmm7, xmmword[edx + (size_t)&m_test[7]]); + + // GSVector2i* fza_base = &m_env.fzbr[top]; + + mov(esi, dword[esp + _top]); + lea(esi, ptr[esi * 8]); + add(esi, dword[&m_env.fzbr]); + + // GSVector2i* fza_offset = &m_env.fzbc[left >> 2]; + + lea(edi, ptr[ebx * 2]); + add(edi, dword[&m_env.fzbc]); + + if(!m_env.sel.sprite && (m_env.sel.fwrite && m_env.sel.fge || m_env.sel.zb) || m_env.sel.fb && (m_env.sel.tfx != TFX_NONE || m_env.sel.iip)) + { + // eax = &m_env.d[skip] + + shl(eax, 4); + lea(eax, ptr[eax + (size_t)m_env.d]); + + // ebx = &v + + mov(ebx, dword[esp + _v]); + } + + if(!m_env.sel.sprite) + { + if(m_env.sel.fwrite && m_env.sel.fge || m_env.sel.zb) + { + movaps(xmm0, xmmword[ebx + 16]); // v.p + + if(m_env.sel.fwrite && m_env.sel.fge) + { + // f = GSVector4i(vp).zzzzh().zzzz().add16(m_env.d[skip].f); + + cvttps2dq(xmm1, xmm0); + pshufhw(xmm1, xmm1, _MM_SHUFFLE(2, 2, 2, 2)); + pshufd(xmm1, xmm1, _MM_SHUFFLE(2, 2, 2, 2)); + paddw(xmm1, xmmword[eax + 16 * 6]); + + movdqa(xmmword[&m_env.temp.f], xmm1); + } + + if(m_env.sel.zb) + { + // z = vp.zzzz() + m_env.d[skip].z; + + shufps(xmm0, xmm0, _MM_SHUFFLE(2, 2, 2, 2)); + addps(xmm0, xmmword[eax]); + + movaps(xmmword[&m_env.temp.z], xmm0); + } + } + } + else + { + if(m_env.sel.ztest) + { + movdqa(xmm0, xmmword[&m_env.p.z]); + } + } + + if(m_env.sel.fb) + { + if(m_env.sel.tfx != TFX_NONE) + { + movaps(xmm4, xmmword[ebx + 32]); // v.t + + if(m_env.sel.fst) + { + // GSVector4i vti(vt); + + cvttps2dq(xmm4, xmm4); + + // si = vti.xxxx() + m_env.d[skip].si; + // ti = vti.yyyy(); if(!sprite) ti += m_env.d[skip].ti; + + pshufd(xmm2, xmm4, _MM_SHUFFLE(0, 0, 0, 0)); + pshufd(xmm3, xmm4, _MM_SHUFFLE(1, 1, 1, 1)); + + paddd(xmm2, xmmword[eax + 16 * 7]); + + if(!m_env.sel.sprite) + { + paddd(xmm3, xmmword[eax + 16 * 8]); + } + else + { + movdqa(xmm4, xmm3); + pshuflw(xmm4, xmm4, _MM_SHUFFLE(2, 2, 0, 0)); + pshufhw(xmm4, xmm4, _MM_SHUFFLE(2, 2, 0, 0)); + psrlw(xmm4, 1); + movdqa(xmmword[&m_env.temp.vf], xmm4); + } + + movdqa(xmmword[&m_env.temp.s], xmm2); + movdqa(xmmword[&m_env.temp.t], xmm3); + } + else + { + // s = vt.xxxx() + m_env.d[skip].s; + // t = vt.yyyy() + m_env.d[skip].t; + // q = vt.zzzz() + m_env.d[skip].q; + + movaps(xmm2, xmm4); + movaps(xmm3, xmm4); + + shufps(xmm2, xmm2, _MM_SHUFFLE(0, 0, 0, 0)); + shufps(xmm3, xmm3, _MM_SHUFFLE(1, 1, 1, 1)); + shufps(xmm4, xmm4, _MM_SHUFFLE(2, 2, 2, 2)); + + addps(xmm2, xmmword[eax + 16 * 1]); + addps(xmm3, xmmword[eax + 16 * 2]); + addps(xmm4, xmmword[eax + 16 * 3]); + + movaps(xmmword[&m_env.temp.s], xmm2); + movaps(xmmword[&m_env.temp.t], xmm3); + movaps(xmmword[&m_env.temp.q], xmm4); + } + } + + if(m_env.sel.iip) + { + // GSVector4i vc = GSVector4i(v.c); + + cvttps2dq(xmm6, xmmword[ebx]); // v.c + + // vc = vc.upl16(vc.zwxy()); + + pshufd(xmm5, xmm6, _MM_SHUFFLE(1, 0, 3, 2)); + punpcklwd(xmm6, xmm5); + + // rb = vc.xxxx().add16(m_env.d[skip].rb); + // ga = vc.zzzz().add16(m_env.d[skip].ga); + + pshufd(xmm5, xmm6, _MM_SHUFFLE(0, 0, 0, 0)); + pshufd(xmm6, xmm6, _MM_SHUFFLE(2, 2, 2, 2)); + + paddw(xmm5, xmmword[eax + 16 * 4]); + paddw(xmm6, xmmword[eax + 16 * 5]); + + movdqa(xmmword[&m_env.temp.rb], xmm5); + movdqa(xmmword[&m_env.temp.ga], xmm6); + } + else + { + if(m_env.sel.tfx == TFX_NONE) + { + movdqa(xmm5, xmmword[&m_env.c.rb]); + movdqa(xmm6, xmmword[&m_env.c.ga]); + } + } + } +} + +void GSDrawScanlineCodeGenerator::Step() +{ + // steps -= 4; + + sub(ecx, 4); + + // fza_offset++; + + add(edi, 8); + + if(!m_env.sel.sprite) + { + // z += m_env.d4.z; + + if(m_env.sel.zb) + { + movaps(xmm0, xmmword[&m_env.temp.z]); + addps(xmm0, xmmword[&m_env.d4.z]); + movaps(xmmword[&m_env.temp.z], xmm0); + } + + // f = f.add16(m_env.d4.f); + + if(m_env.sel.fwrite && m_env.sel.fge) + { + movdqa(xmm1, xmmword[&m_env.temp.f]); + paddw(xmm1, xmmword[&m_env.d4.f]); + movdqa(xmmword[&m_env.temp.f], xmm1); + } + } + else + { + if(m_env.sel.ztest) + { + movdqa(xmm0, xmmword[&m_env.p.z]); + } + } + + if(m_env.sel.fb) + { + if(m_env.sel.tfx != TFX_NONE) + { + if(m_env.sel.fst) + { + // GSVector4i st = m_env.d4.st; + + // si += st.xxxx(); + // if(!sprite) ti += st.yyyy(); + + movdqa(xmm4, xmmword[&m_env.d4.st]); + + pshufd(xmm2, xmm4, _MM_SHUFFLE(0, 0, 0, 0)); + paddd(xmm2, xmmword[&m_env.temp.s]); + movdqa(xmmword[&m_env.temp.s], xmm2); + + if(!m_env.sel.sprite) + { + pshufd(xmm3, xmm4, _MM_SHUFFLE(1, 1, 1, 1)); + paddd(xmm3, xmmword[&m_env.temp.t]); + movdqa(xmmword[&m_env.temp.t], xmm3); + } + else + { + movdqa(xmm3, xmmword[&m_env.temp.t]); + } + } + else + { + // GSVector4 stq = m_env.d4.stq; + + // s += stq.xxxx(); + // t += stq.yyyy(); + // q += stq.zzzz(); + + movaps(xmm2, xmmword[&m_env.d4.stq]); + movaps(xmm3, xmm2); + movaps(xmm4, xmm2); + + shufps(xmm2, xmm2, _MM_SHUFFLE(0, 0, 0, 0)); + shufps(xmm3, xmm3, _MM_SHUFFLE(1, 1, 1, 1)); + shufps(xmm4, xmm4, _MM_SHUFFLE(2, 2, 2, 2)); + + addps(xmm2, xmmword[&m_env.temp.s]); + addps(xmm3, xmmword[&m_env.temp.t]); + addps(xmm4, xmmword[&m_env.temp.q]); + + movaps(xmmword[&m_env.temp.s], xmm2); + movaps(xmmword[&m_env.temp.t], xmm3); + movaps(xmmword[&m_env.temp.q], xmm4); + } + } + + if(m_env.sel.iip) + { + // GSVector4i c = m_env.d4.c; + + // rb = rb.add16(c.xxxx()); + // ga = ga.add16(c.yyyy()); + + movdqa(xmm7, xmmword[&m_env.d4.c]); + + pshufd(xmm5, xmm7, _MM_SHUFFLE(0, 0, 0, 0)); + pshufd(xmm6, xmm7, _MM_SHUFFLE(1, 1, 1, 1)); + + paddw(xmm5, xmmword[&m_env.temp.rb]); + paddw(xmm6, xmmword[&m_env.temp.ga]); + + movdqa(xmmword[&m_env.temp.rb], xmm5); + movdqa(xmmword[&m_env.temp.ga], xmm6); + } + else + { + if(m_env.sel.tfx == TFX_NONE) + { + movdqa(xmm5, xmmword[&m_env.c.rb]); + movdqa(xmm6, xmmword[&m_env.c.ga]); + } + } + } + + // test = m_test[7 + (steps & (steps >> 31))]; + + mov(edx, ecx); + sar(edx, 31); + and(edx, ecx); + shl(edx, 4); + + movdqa(xmm7, xmmword[edx + (size_t)&m_test[7]]); +} + +void GSDrawScanlineCodeGenerator::TestZ(const Xmm& temp1, const Xmm& temp2) +{ + if(!m_env.sel.zb) + { + return; + } + + // int za = fza_base.y + fza_offset->y; + + mov(ebp, dword[esi + 4]); + add(ebp, dword[edi + 4]); + + // GSVector4i zs = sprite ? zi : (GSVector4i(z * 0.5f) << 1) | (GSVector4i(z) & GSVector4i::x00000001()); + + if(!m_env.sel.sprite) + { + static float half = 0.5f; + + movss(temp1, dword[&half]); + shufps(temp1, temp1, _MM_SHUFFLE(0, 0, 0, 0)); + mulps(temp1, xmm0); + cvttps2dq(temp1, temp1); + + cvttps2dq(xmm0, xmm0); + pcmpeqd(temp1, temp1); + psrld(temp1, 31); + pand(temp1, xmm0); + + por(xmm0, temp1); + + if(m_env.sel.zwrite) + { + movdqa(xmmword[&m_env.temp.zs], xmm0); + } + } + + if(m_env.sel.ztest) + { + ReadPixel(temp1, ebp); + + if(m_env.sel.zwrite && m_env.sel.zpsm < 2) + { + movdqa(xmmword[&m_env.temp.zd], temp1); + } + + // GSVector4i o = GSVector4i::x80000000(); + + pcmpeqd(temp2, temp2); + pslld(temp2, 31); + + // GSVector4i zso = zs - o; + + psubd(xmm0, temp2); + + // zpsm == 0: GSVector4i zdo = zd - o; + // zpsm == 1: GSVector4i zdo = (zd & GSVector4i::x00ffffff()) - o; + // zpsm == 2: GSVector4i zdo = (zd & GSVector4i::x0000ffff()) - o; + + if(m_env.sel.zpsm) + { + pslld(xmm1, m_env.sel.zpsm * 8); + psrld(xmm1, m_env.sel.zpsm * 8); + } + + psubd(temp1, temp2); + + switch(m_env.sel.ztst) + { + case ZTST_GEQUAL: + // test |= zso < zdo; + pcmpgtd(temp1, xmm0); + por(xmm7, temp1); + break; + + case ZTST_GREATER: + // test |= zso <= zdo; + movdqa(temp2, temp1); + pcmpgtd(temp1, xmm0); + por(xmm7, temp1); + pcmpeqd(temp2, xmm0); + por(xmm7, temp1); + break; + } + + alltrue(xmm7, eax, "step"); + } +} + +void GSDrawScanlineCodeGenerator::SampleTexture() +{ + if(!m_env.sel.fb || m_env.sel.tfx == TFX_NONE) + { + return; + } + + mov(ebx, dword[&m_env.tex]); + + if(!m_env.sel.fst) + { + // GSVector4 w = q.rcp(); + + rcpps(xmm4, xmm4); + + // u = GSVector4i(s * w); + // v = GSVector4i(t * w); + + mulps(xmm2, xmm4); + mulps(xmm3, xmm4); + + cvttps2dq(xmm2, xmm2); + cvttps2dq(xmm3, xmm3); + + if(m_env.sel.ltf) + { + // u -= 0x8000; + // v -= 0x8000; + + mov(eax, 0x8000); + movd(xmm4, eax); + pshufd(xmm4, xmm4, _MM_SHUFFLE(0, 0, 0, 0)); + psubd(xmm2, xmm4); + psubd(xmm3, xmm4); + } + } + + // xmm2 = u + // xmm3 = v + + if(m_env.sel.ltf) + { + // GSVector4i uf = u.xxzzlh().srl16(1); + + movdqa(xmm0, xmm2); + pshuflw(xmm0, xmm0, _MM_SHUFFLE(2, 2, 0, 0)); + pshufhw(xmm0, xmm0, _MM_SHUFFLE(2, 2, 0, 0)); + psrlw(xmm0, 1); + movdqa(xmmword[&m_env.temp.uf], xmm0); + + if(!m_env.sel.sprite) + { + // GSVector4i vf = v.xxzzlh().srl16(1); + + movdqa(xmm1, xmm3); + pshuflw(xmm1, xmm1, _MM_SHUFFLE(2, 2, 0, 0)); + pshufhw(xmm1, xmm1, _MM_SHUFFLE(2, 2, 0, 0)); + psrlw(xmm1, 1); + movdqa(xmmword[&m_env.temp.vf], xmm1); + } + } + + // GSVector4i uv0 = u.sra32(16).ps32(v.sra32(16)); + + psrad(xmm2, 16); + psrad(xmm3, 16); + packssdw(xmm2, xmm3); + + if(m_env.sel.ltf) + { + // GSVector4i uv1 = uv0.add16(GSVector4i::x0001()); + + movdqa(xmm3, xmm2); + pcmpeqd(xmm1, xmm1); + psrlw(xmm1, 15); + paddw(xmm3, xmm1); + } + + // uv0 = Wrap(uv0); + + Wrap(xmm2, xmm1); + + if(m_env.sel.ltf) + { + // uv1 = Wrap(uv1); + + Wrap(xmm3, xmm1); + } + + // xmm2 = uv0 + // xmm3 = uv1 (ltf) + // xmm0, xmm1, xmm4, xmm5, xmm6 = free + // xmm7 = used + + // GSVector4i y0 = uv0.uph16() << tw; + // GSVector4i x0 = uv0.upl16(); + + pxor(xmm0, xmm0); + movd(xmm1, dword[&m_env.tw]); + + movdqa(xmm4, xmm2); + punpckhwd(xmm2, xmm0); + punpcklwd(xmm4, xmm0); + pslld(xmm2, xmm1); + + // xmm0 = 0 + // xmm1 = tw + // xmm2 = y0 + // xmm3 = uv1 (ltf) + // xmm4 = x0 + // xmm5, xmm6 = free + // xmm7 = used + + if(m_env.sel.ltf) + { + // GSVector4i y1 = uv1.uph16() << tw; + // GSVector4i x1 = uv1.upl16(); + + movdqa(xmm5, xmm3); + punpckhwd(xmm3, xmm0); + punpcklwd(xmm5, xmm0); + pslld(xmm3, xmm1); + + // xmm2 = y0 + // xmm3 = y1 + // xmm4 = x0 + // xmm5 = x1 + // xmm0, xmm1, xmm6 = free + // xmm7 = used + + // GSVector4i addr00 = y0 + x0; + // GSVector4i addr01 = y0 + x1; + // GSVector4i addr10 = y1 + x0; + // GSVector4i addr11 = y1 + x1; + + movdqa(xmm0, xmm2); + paddd(xmm2, xmm5); + paddd(xmm0, xmm4); + + movdqa(xmm1, xmm3); + paddd(xmm3, xmm5); + paddd(xmm1, xmm4); + + // xmm0 = addr00 + // xmm2 = addr01 + // xmm1 = addr10 + // xmm3 = addr11 + // xmm4, xmm5, xmm6 = free + // xmm7 = used + + // c00 = addr00.gather32_32((const DWORD/BYTE*)tex[, clut]); + // c01 = addr01.gather32_32((const DWORD/BYTE*)tex[, clut]); + // c10 = addr10.gather32_32((const DWORD/BYTE*)tex[, clut]); + // c11 = addr11.gather32_32((const DWORD/BYTE*)tex[, clut]); + + ReadTexel(xmm5, xmm0, ebx, xmm4, xmm6); + + // xmm0, xmm4, xmm6 = free + + ReadTexel(xmm6, xmm2, ebx, xmm0, xmm4); + + // xmm0, xmm2, xmm4 = free + + ReadTexel(xmm4, xmm1, ebx, xmm2, xmm0); + + // xmm0, xmm1, xmm2 = free + + ReadTexel(xmm0, xmm3, ebx, xmm1, xmm2); + + // xmm5 = c00 + // xmm6 = c01 + // xmm4 = c10 + // xmm0 = c11 + // xmm1, xmm2, xmm3 = free + // xmm7 = used + + movdqa(xmm1, xmmword[&m_env.temp.uf]); + + // GSVector4i rb00 = c00 & mask; + // GSVector4i ga00 = (c00 >> 8) & mask; + + movdqa(xmm2, xmm5); + psllw(xmm2, 8); + psrlw(xmm2, 8); + psrlw(xmm5, 8); + + // GSVector4i rb01 = c01 & mask; + // GSVector4i ga01 = (c01 >> 8) & mask; + + movdqa(xmm3, xmm6); + psllw(xmm3, 8); + psrlw(xmm3, 8); + psrlw(xmm6, 8); + + // xmm1 = uf + // xmm2 = rb00 + // xmm3 = rb01 + // xmm5 = ga00 + // xmm6 = ga01 + // xmm4 = c10 + // xmm0 = c11 + // xmm7 = used + + // rb00 = rb00.lerp16<0>(rb01, uf); + // ga00 = ga00.lerp16<0>(ga01, uf); + + lerp16<0>(xmm3, xmm2, xmm1); + lerp16<0>(xmm6, xmm5, xmm1); + + // xmm1 = uf + // xmm3 = rb00 + // xmm6 = ga00 + // xmm4 = c10 + // xmm0 = c11 + // xmm2, xmm5 = free + // xmm7 = used + + // GSVector4i rb10 = c10 & mask; + // GSVector4i rb11 = c11 & mask; + + movdqa(xmm2, xmm4); + psllw(xmm4, 8); + psrlw(xmm4, 8); + psrlw(xmm2, 8); + + // GSVector4i ga10 = (c10 >> 8) & mask; + // GSVector4i ga11 = (c11 >> 8) & mask; + + movdqa(xmm5, xmm0); + psllw(xmm0, 8); + psrlw(xmm0, 8); + psrlw(xmm5, 8); + + // xmm1 = uf + // xmm3 = rb00 + // xmm6 = ga00 + // xmm4 = rb10 + // xmm0 = rb11 + // xmm2 = ga10 + // xmm5 = ga11 + // xmm7 = used + + // rb10 = rb10.lerp16<0>(rb11, uf); + // ga10 = ga10.lerp16<0>(ga11, uf); + + lerp16<0>(xmm0, xmm4, xmm1); + lerp16<0>(xmm5, xmm2, xmm1); + + // xmm3 = rb00 + // xmm6 = ga00 + // xmm0 = rb10 + // xmm5 = ga10 + // xmm1, xmm2, xmm4 = free + // xmm7 = used + + // rb00 = rb00.lerp16<0>(rb10, vf); + // ga00 = ga00.lerp16<0>(ga10, vf); + + movdqa(xmm1, xmmword[&m_env.temp.vf]); + + lerp16<0>(xmm0, xmm3, xmm1); + lerp16<0>(xmm5, xmm6, xmm1); + + // TODO: make rb/ga end up in xmm5/xmm6 + + movdqa(xmm6, xmm5); + movdqa(xmm5, xmm0); + } + else + { + // GSVector4i addr00 = y0 + x0; + + paddd(xmm2, xmm4); + + // c00 = addr00.gather32_32((const DWORD/BYTE*)tex[, clut]); + + ReadTexel(xmm5, xmm2, ebx, xmm0, xmm1); + + // GSVector4i mask = GSVector4i::x00ff(); + + // c[0] = c00 & mask; + // c[1] = (c00 >> 8) & mask; + + movdqa(xmm6, xmm5); + + psllw(xmm5, 8); + psrlw(xmm5, 8); + psrlw(xmm6, 8); + } +} + +void GSDrawScanlineCodeGenerator::AlphaTFX() +{ + if(!m_env.sel.fb) + { + return; + } + + switch(m_env.sel.tfx) + { + case TFX_MODULATE: + + // GSVector4i ga = iip ? gaf : m_env.c.ga; + + movdqa(xmm4, xmmword[m_env.sel.iip ? &m_env.temp.ga : &m_env.c.ga]); + + // gat = gat.modulate16<1>(ga).clamp8(); + + modulate16<1>(xmm6, xmm4); + + clamp16(xmm6, xmm3); + + // if(!tcc) gat = gat.mix16(ga.srl16(7)); + + if(!m_env.sel.tcc) + { + psrlw(xmm4, 7); + + mix16(xmm6, xmm4, xmm3); + } + + break; + + case TFX_DECAL: + + break; + + case TFX_HIGHLIGHT: + + // GSVector4i ga = iip ? gaf : m_env.c.ga; + + movdqa(xmm4, xmmword[m_env.sel.iip ? &m_env.temp.ga : &m_env.c.ga]); + movdqa(xmm2, xmm4); + + // gat = gat.mix16(!tcc ? ga.srl16(7) : gat.addus8(ga.srl16(7))); + + psrlw(xmm4, 7); + + if(m_env.sel.tcc) + { + paddusb(xmm4, xmm6); + } + + mix16(xmm6, xmm4, xmm3); + + break; + + case TFX_HIGHLIGHT2: + + // if(!tcc) gat = gat.mix16(ga.srl16(7)); + + if(!m_env.sel.tcc) + { + // GSVector4i ga = iip ? gaf : m_env.c.ga; + + movdqa(xmm4, xmmword[m_env.sel.iip ? &m_env.temp.ga : &m_env.c.ga]); + movdqa(xmm2, xmm4); + + psrlw(xmm4, 7); + + mix16(xmm6, xmm4, xmm3); + } + + break; + + case TFX_NONE: + + // gat = iip ? ga.srl16(7) : ga; + + if(m_env.sel.iip) + { + psrlw(xmm6, 7); + } + + break; + } +} + +void GSDrawScanlineCodeGenerator::TestAlpha() +{ + switch(m_env.sel.afail) + { + case AFAIL_FB_ONLY: + if(!m_env.sel.zwrite) return; + break; + + case AFAIL_ZB_ONLY: + if(!m_env.sel.fwrite) return; + break; + + case AFAIL_RGB_ONLY: + if(!m_env.sel.zwrite && m_env.sel.fpsm == 1) return; + break; + } + + switch(m_env.sel.atst) + { + case ATST_NEVER: + // t = GSVector4i::xffffffff(); + pcmpeqd(xmm1, xmm1); + break; + + case ATST_ALWAYS: + return; + + case ATST_LESS: + case ATST_LEQUAL: + // t = (ga >> 16) > m_env.aref; + movdqa(xmm1, xmm6); + psrld(xmm1, 16); + pcmpgtd(xmm1, xmmword[&m_env.aref]); + break; + + case ATST_EQUAL: + // t = (ga >> 16) != m_env.aref; + movdqa(xmm1, xmm6); + psrld(xmm1, 16); + pcmpeqd(xmm1, xmmword[&m_env.aref]); + pcmpeqd(xmm0, xmm0); + pxor(xmm1, xmm0); + break; + + case ATST_GEQUAL: + case ATST_GREATER: + // t = (ga >> 16) < m_env.aref; + movdqa(xmm0, xmm6); + psrld(xmm0, 16); + movdqa(xmm1, xmmword[&m_env.aref]); + pcmpgtd(xmm1, xmm0); + break; + + case ATST_NOTEQUAL: + // t = (ga >> 16) == m_env.aref; + movdqa(xmm1, xmm6); + psrld(xmm1, 16); + pcmpeqd(xmm1, xmmword[&m_env.aref]); + break; + } + + switch(m_env.sel.afail) + { + case AFAIL_KEEP: + // test |= t; + por(xmm7, xmm1); + alltrue(xmm7, eax, "step"); + break; + + case AFAIL_FB_ONLY: + // zm |= t; + por(xmm4, xmm1); + break; + + case AFAIL_ZB_ONLY: + // fm |= t; + por(xmm3, xmm1); + break; + + case AFAIL_RGB_ONLY: + // zm |= t; + por(xmm4, xmm1); + // fm |= t & GSVector4i::xff000000(); + psrld(xmm1, 24); + pslld(xmm1, 24); + por(xmm3, xmm1); + break; + } +} + +void GSDrawScanlineCodeGenerator::ColorTFX() +{ + if(!m_env.sel.fwrite) + { + return; + } + + switch(m_env.sel.tfx) + { + case TFX_MODULATE: + + // GSVector4i rb = iip ? rbf : m_env.c.rb; + + // rbt = rbt.modulate16<1>(rb).clamp8(); + + modulate16<1>(xmm5, xmmword[m_env.sel.iip ? &m_env.temp.rb : &m_env.c.rb]); + + clamp16(xmm5, xmm1); + + break; + + case TFX_DECAL: + + break; + + case TFX_HIGHLIGHT: + case TFX_HIGHLIGHT2: + + if(m_env.sel.tfx == TFX_HIGHLIGHT2 && m_env.sel.tcc) + { + // GSVector4i ga = iip ? gaf : m_env.c.ga; + + movdqa(xmm2, xmmword[m_env.sel.iip ? &m_env.temp.ga : &m_env.c.ga]); + } + + // gat = gat.modulate16<1>(ga).add16(af).clamp8().mix16(gat); + + movdqa(xmm1, xmm6); + + modulate16<1>(xmm6, xmm2); + + pshuflw(xmm2, xmm2, _MM_SHUFFLE(3, 3, 1, 1)); + pshufhw(xmm2, xmm2, _MM_SHUFFLE(3, 3, 1, 1)); + psrlw(xmm2, 7); + + paddw(xmm6, xmm2); + + clamp16(xmm6, xmm0); + + mix16(xmm6, xmm1, xmm0); + + // GSVector4i rb = iip ? rbf : m_env.c.rb; + + // rbt = rbt.modulate16<1>(rb).add16(af).clamp8(); + + modulate16<1>(xmm5, xmmword[m_env.sel.iip ? &m_env.temp.rb : &m_env.c.rb]); + + paddw(xmm5, xmm2); + + clamp16(xmm5, xmm0); + + break; + + case TFX_NONE: + + // rbt = iip ? rb.srl16(7) : rb; + + if(m_env.sel.iip) + { + psrlw(xmm5, 7); + } + + break; + } +} + +void GSDrawScanlineCodeGenerator::Fog() +{ + if(!m_env.sel.fwrite || !m_env.sel.fge) + { + return; + } + + // rb = m_env.frb.lerp16<0>(rb, f); + // ga = m_env.fga.lerp16<0>(ga, f).mix16(ga); + + movdqa(xmm0, xmmword[!m_env.sel.sprite ? &m_env.temp.f : &m_env.p.f]); + movdqa(xmm1, xmm6); + + movdqa(xmm2, xmmword[&m_env.frb]); + lerp16<0>(xmm5, xmm2, xmm0); + + movdqa(xmm2, xmmword[&m_env.fga]); + lerp16<0>(xmm6, xmm2, xmm0); + + mix16(xmm6, xmm1, xmm0); +} + +void GSDrawScanlineCodeGenerator::ReadFrame() +{ + if(!m_env.sel.fb) + { + return; + } + + // int fa = fza_base.x + fza_offset->x; + + mov(ebx, dword[esi]); + add(ebx, dword[edi]); + + if(!m_env.sel.rfb) + { + return; + } + + ReadPixel(xmm2, ebx); +} + +void GSDrawScanlineCodeGenerator::TestDestAlpha() +{ + if(!m_env.sel.date || m_env.sel.fpsm != 0 && m_env.sel.fpsm != 2) + { + return; + } + + // test |= ((fd [<< 16]) ^ m_env.datm).sra32(31); + + movdqa(xmm1, xmm2); + if(m_env.sel.fpsm == 2) pslld(xmm1, 16); + pxor(xmm1, xmmword[&m_env.datm]); + psrad(xmm1, 31); + por(xmm7, xmm1); + + alltrue(xmm7, eax, "step"); +} + +void GSDrawScanlineCodeGenerator::WriteZBuf() +{ + if(!m_env.sel.zwrite) + { + return; + } + + movdqa(xmm1, xmmword[!m_env.sel.sprite ? &m_env.temp.zs : &m_env.p.z]); + + if(m_env.sel.ztest && m_env.sel.zpsm < 2) + { + // zs = zs.blend8(zd, zm); + + movdqa(xmm0, xmm4); + movdqa(xmm7, xmmword[&m_env.temp.zd]); + blend8(xmm1, xmm7); + + // if(fzm & 0x30) GSVector4i::storel(&vm16[addr + 0], zs); + // if(fzm & 0xc0) GSVector4i::storeh(&vm16[addr + 8], zs); + + test(dl, 0x30); + je("wz30"); + movq(qword[ebp * 2 + (size_t)m_env.vm], xmm1); + L("wz30"); + + test(dl, 0xc0); + je("wzc0"); + movhps(qword[ebp * 2 + (size_t)m_env.vm + 8 * 2], xmm1); + L("wzc0"); + } + else + { + // if(fzm & 0x10) WritePixel(zpsm, &vm16[addr + 0], zs.extract32<0>()); + // if(fzm & 0x20) WritePixel(zpsm, &vm16[addr + 2], zs.extract32<1>()); + // if(fzm & 0x40) WritePixel(zpsm, &vm16[addr + 8], zs.extract32<2>()); + // if(fzm & 0x80) WritePixel(zpsm, &vm16[addr + 10], zs.extract32<3>()); + + test(dl, 0x10); + je("wz10"); + WritePixel(xmm1, xmm0, ebp, 0, m_env.sel.zpsm); + L("wz10"); + + test(dl, 0x20); + je("wz20"); + WritePixel(xmm1, xmm0, ebp, 1, m_env.sel.zpsm); + L("wz20"); + + test(dl, 0x40); + je("wz40"); + WritePixel(xmm1, xmm0, ebp, 2, m_env.sel.zpsm); + L("wz40"); + + test(dl, 0x80); + je("wz80"); + WritePixel(xmm1, xmm0, ebp, 3, m_env.sel.zpsm); + L("wz80"); + } +} + +void GSDrawScanlineCodeGenerator::AlphaBlend() +{ + if(!m_env.sel.fwrite || m_env.sel.abe == 255) + { + return; + } + + if((m_env.sel.abea != m_env.sel.abeb) && (m_env.sel.abea == 1 || m_env.sel.abeb == 1 || m_env.sel.abec == 1) || m_env.sel.abed == 1) + { + switch(m_env.sel.fpsm) + { + case 0: + case 1: + + // c[2] = fd & mask; + // c[3] = (fd >> 8) & mask; + + movdqa(xmm0, xmm2); + movdqa(xmm1, xmm2); + + psllw(xmm0, 8); + psrlw(xmm0, 8); + psrlw(xmm1, 8); + + break; + + case 2: + + // c[2] = ((fd & 0x7c00) << 9) | ((fd & 0x001f) << 3); + // c[3] = ((fd & 0x8000) << 8) | ((fd & 0x03e0) >> 2); + + movdqa(xmm0, xmm2); + movdqa(xmm1, xmm2); + movdqa(xmm4, xmm2); + + mov(eax, 0x1f); + movd(xmm7, eax); + pshufd(xmm7, xmm7, _MM_SHUFFLE(0, 0, 0, 0)); // 0x001f + pand(xmm0, xmm7); + pslld(xmm0, 3); + + psllw(xmm7, 10); // 0x7c00 + pand(xmm4, xmm7); + pslld(xmm4, 9); + + por(xmm0, xmm4); + + movdqa(xmm4, xmm1); + + psrlw(xmm7, 5); // 0x03e0 + pand(xmm1, xmm7); + psrld(xmm1, 2); + + psllw(xmm7, 10); // 0x8000 + pand(xmm4, xmm7); + pslld(xmm4, 8); + + por(xmm1, xmm4); + + break; + } + } + + // xmm5, xmm6 = src rb, ga + // xmm0, xmm1 = dst rb, ga + // xmm2, xmm3 = used + // xmm4, xmm7 = free + + if(m_env.sel.pabe || (m_env.sel.abea != m_env.sel.abeb) && (m_env.sel.abeb == 0 || m_env.sel.abed == 0)) + { + movdqa(xmm4, xmm5); + } + + if(m_env.sel.abea != m_env.sel.abeb) + { + // rb = c[abea * 2 + 0]; + + switch(m_env.sel.abea) + { + case 0: break; + case 1: movdqa(xmm5, xmm0); break; + case 2: pxor(xmm5, xmm5); break; + } + + // rb = rb.sub16(c[abeb * 2 + 0]); + + switch(m_env.sel.abeb) + { + case 0: psubw(xmm5, xmm4); break; + case 1: psubw(xmm5, xmm0); break; + case 2: break; + } + + if(!(m_env.sel.fpsm == 1 && m_env.sel.abec == 1)) + { + // GSVector4i a = abec < 2 ? c[abec * 2 + 1].yywwlh().sll16(7) : m_env.afix2; + + switch(m_env.sel.abec) + { + case 0: + case 1: + movdqa(xmm7, m_env.sel.abec ? xmm1 : xmm6); + pshuflw(xmm7, xmm7, _MM_SHUFFLE(3, 3, 1, 1)); + pshufhw(xmm7, xmm7, _MM_SHUFFLE(3, 3, 1, 1)); + psllw(xmm7, 7); + break; + case 2: + movdqa(xmm7, xmmword[&m_env.afix2]); + break; + } + + // rb = rb.modulate16<1>(a); + + modulate16<1>(xmm5, xmm7); + } + + // rb = rb.add16(c[abed * 2 + 0]); + + switch(m_env.sel.abed) + { + case 0: paddw(xmm5, xmm4); break; + case 1: paddw(xmm5, xmm0); break; + case 2: break; + } + } + else + { + // rb = c[abed * 2 + 0]; + + switch(m_env.sel.abed) + { + case 0: break; + case 1: movdqa(xmm5, xmm0); break; + case 2: pxor(xmm5, xmm5); break; + } + } + + if(0)//m_env.sel.pabe) + { + // mask = (c[1] << 8).sra32(31); + + movdqa(xmm0, xmm6); + pslld(xmm0, 8); + psrad(xmm0, 31); + + // rb = c[0].blend8(rb, mask); + + blend8r(xmm5, xmm4); + } + + // xmm6 = src ga + // xmm1 = dst ga + // xmm5 = rb + // xmm7 = a + // xmm2, xmm3 = used + // xmm0, xmm4 = free + + movdqa(xmm4, xmm6); + + if(m_env.sel.abea != m_env.sel.abeb) + { + // ga = c[abea * 2 + 1]; + + switch(m_env.sel.abea) + { + case 0: break; + case 1: movdqa(xmm6, xmm1); break; + case 2: pxor(xmm6, xmm6); break; + } + + // ga = ga.sub16(c[abeb * 2 + 1]); + + switch(m_env.sel.abeb) + { + case 0: psubw(xmm6, xmm4); break; + case 1: psubw(xmm6, xmm1); break; + case 2: break; + } + + if(!(m_env.sel.fpsm == 1 && m_env.sel.abec == 1)) + { + // ga = ga.modulate16<1>(a); + + modulate16<1>(xmm6, xmm7); + } + + // ga = ga.add16(c[abed * 2 + 1]); + + switch(m_env.sel.abed) + { + case 0: paddw(xmm6, xmm4); break; + case 1: paddw(xmm6, xmm1); break; + case 2: break; + } + } + else + { + // ga = c[abed * 2 + 1]; + + switch(m_env.sel.abed) + { + case 0: break; + case 1: movdqa(xmm6, xmm1); break; + case 2: pxor(xmm6, xmm6); break; + } + } + + if(0)//m_env.sel.pabe) + { + if(!m_cpu.has(util::Cpu::tSSE41)) + { + // doh, previous blend8r overwrote xmm0 (sse41 uses pblendvb) + + movdqa(xmm0, xmm4); + pslld(xmm0, 8); + psrad(xmm0, 31); + } + + psrld(xmm0, 16); // zero out high words to select the source alpha in blend (so it also does mix16) + + // ga = c[1].blend8(ga, mask).mix16(c[1]); + + blend8r(xmm6, xmm4); + } + else + { + mix16(xmm6, xmm4, xmm7); + } + + if(m_env.sel.pabe) + { + printf("PABE\n"); + Sleep(1000); + MessageBeep(-1); + } +} + +void GSDrawScanlineCodeGenerator::WriteFrame(int params) +{ + const int _top = params + 4; + + if(!m_env.sel.fwrite) + { + return; + } + + if(m_env.sel.colclamp == 0) + { + // c[0] &= m_env.colclamp; + // c[1] &= m_env.colclamp; + + pcmpeqd(xmm7, xmm7); + psrlw(xmm7, 8); + pand(xmm5, xmm7); + pand(xmm6, xmm7); + } + + if(m_env.sel.fpsm == 2 && m_env.sel.dthe) + { + mov(eax, dword[esp + _top]); + and(eax, 3); + shl(eax, 5); + paddw(xmm5, xmmword[eax + (size_t)&m_env.dimx[0]]); + paddw(xmm6, xmmword[eax + (size_t)&m_env.dimx[1]]); + } + + // GSVector4i fs = c[0].upl16(c[1]).pu16(c[0].uph16(c[1])); + + movdqa(xmm7, xmm5); + punpcklwd(xmm5, xmm6); + punpckhwd(xmm7, xmm6); + packuswb(xmm5, xmm7); + + if(m_env.sel.fba && m_env.sel.fpsm != 1) + { + // fs |= m_env.fba; + + pcmpeqd(xmm7, xmm7); + pslld(xmm7, 31); + por(xmm5, xmm7); + } + + if(m_env.sel.fpsm == 2) + { + // GSVector4i rb = fs & 0x00f800f8; + // GSVector4i ga = fs & 0x8000f800; + + mov(eax, 0x00f800f8); + movd(xmm6, eax); + pshufd(xmm6, xmm6, _MM_SHUFFLE(0, 0, 0, 0)); + + mov(eax, 0x8000f800); + movd(xmm7, eax); + pshufd(xmm7, xmm7, _MM_SHUFFLE(0, 0, 0, 0)); + + movdqa(xmm4, xmm5); + pand(xmm4, xmm6); + pand(xmm5, xmm7); + + // fs = (ga >> 16) | (rb >> 9) | (ga >> 6) | (rb >> 3); + + movdqa(xmm6, xmm4); + movdqa(xmm7, xmm5); + + psrld(xmm4, 3); + psrld(xmm6, 9); + psrld(xmm5, 6); + psrld(xmm7, 16); + + por(xmm5, xmm4); + por(xmm7, xmm6); + por(xmm5, xmm7); + } + + if(m_env.sel.rfb) + { + // fs = fs.blend(fd, fm); + + blend(xmm5, xmm2, xmm3); // TODO: could be skipped in certain cases, depending on fpsm and fm + } + + if(m_env.sel.rfb && m_env.sel.fpsm < 2) + { + // if(fzm & 0x03) GSVector4i::storel(&vm16[addr + 0], fs); + // if(fzm & 0x0c) GSVector4i::storeh(&vm16[addr + 8], fs); + + test(dl, 0x03); + je("wf03"); + movq(qword[ebx * 2 + (size_t)m_env.vm], xmm5); + L("wf03"); + + test(dl, 0x0c); + je("wf0c"); + movhps(qword[ebx * 2 + (size_t)m_env.vm + 8 * 2], xmm5); + L("wf0c"); + } + else + { + // if(fzm & 0x01) WritePixel(fpsm, &vm16[addr + 0], fs.extract32<0>()); + // if(fzm & 0x02) WritePixel(fpsm, &vm16[addr + 2], fs.extract32<1>()); + // if(fzm & 0x04) WritePixel(fpsm, &vm16[addr + 8], fs.extract32<2>()); + // if(fzm & 0x08) WritePixel(fpsm, &vm16[addr + 10], fs.extract32<3>()); + + test(dl, 0x01); + je("wf01"); + WritePixel(xmm5, xmm0, ebx, 0, m_env.sel.fpsm); + L("wf01"); + + test(dl, 0x02); + je("wf02"); + WritePixel(xmm5, xmm0, ebx, 1, m_env.sel.fpsm); + L("wf02"); + + test(dl, 0x04); + je("wf04"); + WritePixel(xmm5, xmm0, ebx, 2, m_env.sel.fpsm); + L("wf04"); + + test(dl, 0x08); + je("wf08"); + WritePixel(xmm5, xmm0, ebx, 3, m_env.sel.fpsm); + L("wf08"); + } +} + +void GSDrawScanlineCodeGenerator::ReadPixel(const Xmm& dst, const Reg32& addr) +{ + movq(dst, qword[addr * 2 + (size_t)m_env.vm]); + movhps(dst, qword[addr * 2 + (size_t)m_env.vm + 8 * 2]); +} + +void GSDrawScanlineCodeGenerator::WritePixel(const Xmm& src, const Xmm& temp, const Reg32& addr, uint8 i, int psm) +{ + static const int offsets[4] = {0, 2, 8, 10}; + + Address dst = ptr[addr * 2 + (size_t)m_env.vm + offsets[i] * 2]; + + if(m_cpu.has(util::Cpu::tSSE41)) + { + switch(psm) + { + case 0: + if(i == 0) movd(dst, src); + else pextrd(dst, src, i); + break; + case 1: + if(i == 0) movd(eax, src); + else pextrd(eax, src, i); + xor(eax, dst); + and(eax, 0xffffff); + xor(dst, eax); + break; + case 2: + pextrw(eax, src, i * 2); + mov(dst, ax); + break; + } + } + else + { + switch(psm) + { + case 0: + if(i == 0) movd(dst, src); + else {pshufd(temp, src, _MM_SHUFFLE(i, i, i, i)); movd(dst, temp);} + break; + case 1: + if(i == 0) movd(eax, src); + else {pshufd(temp, src, _MM_SHUFFLE(i, i, i, i)); movd(eax, temp);} + xor(eax, dst); + and(eax, 0xffffff); + xor(dst, eax); + break; + case 2: + pextrw(eax, src, i * 2); + mov(dst, ax); + break; + } + } +} + +void GSDrawScanlineCodeGenerator::ReadTexel(const Xmm& dst, const Xmm& addr, const Reg32& base, const Xmm& temp1, const Xmm& temp2) +{ + if(m_cpu.has(util::Cpu::tSSE41)) + { + ReadTexel(dst, addr, base, 0); + ReadTexel(dst, addr, base, 1); + ReadTexel(dst, addr, base, 2); + ReadTexel(dst, addr, base, 3); + } + else + { + ReadTexel(dst, addr, base, 0); + psrldq(addr, 4); // shuffle instead? (1 2 3 0 ~ rotation) + ReadTexel(temp1, addr, base, 0); + psrldq(addr, 4); + punpckldq(dst, temp1); + + ReadTexel(temp1, addr, base, 0); + psrldq(addr, 4); + ReadTexel(temp2, addr, base, 0); + // psrldq(addr, 4); + punpckldq(temp1, temp2); + + punpcklqdq(dst, temp1); + } +} + +void GSDrawScanlineCodeGenerator::ReadTexel(const Xmm& dst, const Xmm& addr, const Reg32& base, uint8 i) +{ + if(!m_cpu.has(util::Cpu::tSSE41) && i > 0) + { + ASSERT(0); + } + + if(i == 0) movd(eax, addr); + else pextrd(eax, addr, i); + + const Address& src = m_env.sel.tlu + ? dword[eax * 4 + (size_t)m_env.clut] + : dword[base + eax * 4]; + + if(m_env.sel.tlu) + { + movzx(eax, byte[base + eax]); + } + + if(i == 0) movd(dst, src); + else pinsrd(dst, src, i); +} + +void GSDrawScanlineCodeGenerator::Wrap(const Xmm& uv, const Xmm& temp) +{ + if(m_env.sel.wms == m_env.sel.wmt) + { + if(m_env.sel.wms) + { + pmaxsw(uv, xmmword[&m_env.t.min]); + pminsw(uv, xmmword[&m_env.t.max]); + } + else + { + pand(uv, xmmword[&m_env.t.min]); + por(uv, xmmword[&m_env.t.max]); + } + } + else + { + movdqa(temp, uv); + + // GSVector4i clamp = t.sat_i16(m_env.t.min, m_env.t.max); + + pmaxsw(uv, xmmword[&m_env.t.min]); + pminsw(uv, xmmword[&m_env.t.max]); + + // GSVector4i repeat = (t & m_env.t.min) | m_env.t.max; + + pand(temp, xmmword[&m_env.t.min]); + por(temp, xmmword[&m_env.t.max]); + + // clamp.blend8(repeat, m_env.t.mask); + + movdqa(xmm0, xmmword[&m_env.t.mask]); + blend8(uv, temp); + } +} + +template +void GSDrawScanlineCodeGenerator::modulate16(const Xmm& a, const Operand& f) +{ + if(shift == 0 && m_cpu.has(util::Cpu::tSSSE3)) + { + pmulhrsw(a, f); + } + else + { + pslld(a, shift + 1); + pmulhw(a, f); + } +} + +template +void GSDrawScanlineCodeGenerator::lerp16(const Xmm& a, const Xmm& b, const Xmm& f) +{ + psubw(a, b); + modulate16(a, f); + paddw(a, b); +} + +void GSDrawScanlineCodeGenerator::mix16(const Xmm& a, const Xmm& b, const Xmm& temp) +{ + if(m_cpu.has(util::Cpu::tSSE41)) + { + pblendw(a, b, 0xaa); + } + else + { + pcmpeqd(temp, temp); + psrld(temp, 16); + pand(a, temp); + pandn(temp, b); + por(a, temp); + } +} + +void GSDrawScanlineCodeGenerator::clamp16(const Xmm& a, const Xmm& temp) +{ + packuswb(a, a); + + if(m_cpu.has(util::Cpu::tSSE41)) + { + pmovzxbw(a, a); + } + else + { + pxor(temp, temp); + punpcklbw(a, temp); + } +} + +void GSDrawScanlineCodeGenerator::alltrue(const Xmm& a, const Reg32& temp, LPCTSTR label) +{ + pmovmskb(temp, a); + cmp(temp, 0xffff); + je(label, T_NEAR); +} + +void GSDrawScanlineCodeGenerator::blend8(const Xmm& a, const Xmm& b) +{ + if(m_cpu.has(util::Cpu::tSSE41)) + { + pblendvb(a, b); + } + else + { + blend(a, b, xmm0); + } +} + +void GSDrawScanlineCodeGenerator::blend(const Xmm& a, const Xmm& b, const Xmm& mask) +{ + pand(b, mask); + pandn(mask, a); + por(b, mask); + movdqa(a, b); +} + +void GSDrawScanlineCodeGenerator::blend8r(const Xmm& b, const Xmm& a) +{ + if(m_cpu.has(util::Cpu::tSSE41)) + { + pblendvb(a, b); + movdqa(b, a); + } + else + { + blendr(b, a, xmm0); + } +} + +void GSDrawScanlineCodeGenerator::blendr(const Xmm& b, const Xmm& a, const Xmm& mask) +{ + pand(b, mask); + pandn(mask, a); + por(b, mask); +} + +const GSVector4i GSDrawScanlineCodeGenerator::m_test[8] = +{ + GSVector4i::zero(), + GSVector4i(0xffffffff, 0x00000000, 0x00000000, 0x00000000), + GSVector4i(0xffffffff, 0xffffffff, 0x00000000, 0x00000000), + GSVector4i(0xffffffff, 0xffffffff, 0xffffffff, 0x00000000), + GSVector4i(0x00000000, 0xffffffff, 0xffffffff, 0xffffffff), + GSVector4i(0x00000000, 0x00000000, 0xffffffff, 0xffffffff), + GSVector4i(0x00000000, 0x00000000, 0x00000000, 0xffffffff), + GSVector4i::zero(), +}; diff --git a/plugins/GSdx/GSDrawScanlineCodeGenerator.h b/plugins/GSdx/GSDrawScanlineCodeGenerator.h new file mode 100644 index 0000000000..0bf01fd506 --- /dev/null +++ b/plugins/GSdx/GSDrawScanlineCodeGenerator.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * This Program 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 2, or (at your option) + * any later version. + * + * This Program 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSScanlineEnvironment.h" +#include "xbyak/xbyak.h" +#include "xbyak/xbyak_util.h" + +using namespace Xbyak; + +class GSDrawScanlineCodeGenerator : public CodeGenerator +{ + void operator = (const GSDrawScanlineCodeGenerator&); + + static const GSVector4i m_test[8]; + + util::Cpu m_cpu; + + GSScanlineEnvironment& m_env; + + void Generate(); + + void Init(int params); + void Step(); + void TestZ(const Xmm& temp1, const Xmm& temp2); + void SampleTexture(); + void AlphaTFX(); + void TestAlpha(); + void ColorTFX(); + void Fog(); + void ReadFrame(); + void TestDestAlpha(); + void WriteZBuf(); + void AlphaBlend(); + void WriteFrame(int params); + + void ReadPixel(const Xmm& dst, const Reg32& addr); + void WritePixel(const Xmm& src, const Xmm& temp, const Reg32& addr, uint8 i, int psm); + void ReadTexel(const Xmm& dst, const Xmm& addr, const Reg32& base, const Xmm& temp1, const Xmm& temp2); + void ReadTexel(const Xmm& dst, const Xmm& addr, const Reg32& base, uint8 i); + void Wrap(const Xmm& uv, const Xmm& temp); + + template void modulate16(const Xmm& a, const Operand& f); + template void lerp16(const Xmm& a, const Xmm& b, const Xmm& f); + void mix16(const Xmm& a, const Xmm& b, const Xmm& temp); + void clamp16(const Xmm& a, const Xmm& temp); + void alltrue(const Xmm& a, const Reg32& temp, LPCTSTR label); + void blend8(const Xmm& a, const Xmm& b); + void blend(const Xmm& a, const Xmm& b, const Xmm& mask); + void blend8r(const Xmm& b, const Xmm& a); + void blendr(const Xmm& b, const Xmm& a, const Xmm& mask); + +public: + GSDrawScanlineCodeGenerator(GSScanlineEnvironment& env); +}; \ No newline at end of file diff --git a/plugins/GSdx/GSDrawingEnvironment.h b/plugins/GSdx/GSDrawingEnvironment.h index 604d95ac4d..f88a2a98c7 100644 --- a/plugins/GSdx/GSDrawingEnvironment.h +++ b/plugins/GSdx/GSDrawingEnvironment.h @@ -71,6 +71,22 @@ public: CTXT[0].Reset(); CTXT[1].Reset(); + + memset(dimx, 0, sizeof(dimx)); + } + + GSVector4i dimx[8]; + + void UpdateDIMX() + { + dimx[1] = GSVector4i(DIMX.DM00, 0, DIMX.DM01, 0, DIMX.DM02, 0, DIMX.DM03, 0); + dimx[0] = dimx[1].xxzzlh(); + dimx[3] = GSVector4i(DIMX.DM10, 0, DIMX.DM11, 0, DIMX.DM12, 0, DIMX.DM13, 0), + dimx[2] = dimx[2].xxzzlh(); + dimx[5] = GSVector4i(DIMX.DM20, 0, DIMX.DM21, 0, DIMX.DM22, 0, DIMX.DM23, 0), + dimx[4] = dimx[4].xxzzlh(); + dimx[7] = GSVector4i(DIMX.DM30, 0, DIMX.DM31, 0, DIMX.DM32, 0, DIMX.DM33, 0), + dimx[6] = dimx[7].xxzzlh(); } }; diff --git a/plugins/GSdx/GSFunctionMap.h b/plugins/GSdx/GSFunctionMap.h index 48e8133196..ca5634c843 100644 --- a/plugins/GSdx/GSFunctionMap.h +++ b/plugins/GSdx/GSFunctionMap.h @@ -40,21 +40,21 @@ struct GSRasterizerStats } }; -template class GSFunctionMap +template class GSFunctionMap { protected: struct ActivePtr { UINT64 frame, frames; __int64 ticks, pixels; - T f; + VALUE f; }; - CRBMap m_map; - CRBMap m_map_active; + CRBMap m_map; + CRBMap m_map_active; ActivePtr* m_active; - virtual T GetDefaultFunction(DWORD sel) = 0; + virtual VALUE GetDefaultFunction(KEY key) = 0; public: GSFunctionMap() @@ -74,18 +74,18 @@ public: m_map_active.RemoveAll(); } - void SetAt(DWORD sel, T f) + void SetAt(KEY key, VALUE f) { - m_map.SetAt(sel, f); + m_map.SetAt(key, f); } - T Lookup(DWORD sel) + VALUE Lookup(KEY key) { m_active = NULL; - if(!m_map_active.Lookup(sel, m_active)) + if(!m_map_active.Lookup(key, m_active)) { - CRBMap::CPair* pair = m_map.Lookup(sel); + CRBMap::CPair* pair = m_map.Lookup(key); ActivePtr* p = new ActivePtr(); @@ -93,9 +93,9 @@ public: p->frame = (UINT64)-1; - p->f = pair ? pair->m_value : GetDefaultFunction(sel); + p->f = pair ? pair->m_value : GetDefaultFunction(key); - m_map_active.SetAt(sel, p); + m_map_active.SetAt(key, p); m_active = p; } @@ -138,10 +138,10 @@ public: while(pos) { - DWORD sel; + KEY key; ActivePtr* p; - m_map_active.GetNextAssoc(pos, sel, p); + m_map_active.GetNextAssoc(pos, key, p); if(p->frames > 0) { @@ -150,7 +150,7 @@ public: __int64 ppf = p->frames > 0 ? p->pixels / p->frames : 0; printf("[%08x]%c %6.2f%% | %5.2f%% | f %4I64d | p %10I64d | tpp %4I64d | tpf %9I64d | ppf %7I64d\n", - sel, !m_map.Lookup(sel) ? '*' : ' ', + key, !m_map.Lookup(key) ? '*' : ' ', (float)(tpf * 10000 / 50000000) / 100, (float)(tpf * 10000 / ttpf) / 100, p->frames, p->pixels, diff --git a/plugins/GSdx/GSRasterizer.h b/plugins/GSdx/GSRasterizer.h index f0ba3f0d06..345f41d10b 100644 --- a/plugins/GSdx/GSRasterizer.h +++ b/plugins/GSdx/GSRasterizer.h @@ -54,6 +54,7 @@ public: typedef void (IDrawScanline::*DrawScanlinePtr)(int top, int left, int right, const GSVertexSW& v); typedef void (IDrawScanline::*DrawSolidRectPtr)(const GSVector4i& r, const GSVertexSW& v); typedef void (IDrawScanline::*SetupPrimPtr)(const GSVertexSW* vertices, const GSVertexSW& dscan); + typedef void (*DrawScanlineStaticPtr)(int top, int left, int right, const GSVertexSW& v); struct Functions { diff --git a/plugins/GSdx/GSRendererSW.h b/plugins/GSdx/GSRendererSW.h index e00af9d88f..521e0fce7b 100644 --- a/plugins/GSdx/GSRendererSW.h +++ b/plugins/GSdx/GSRendererSW.h @@ -256,7 +256,7 @@ protected: p.zbo = m_mem.GetOffset(context->ZBUF.Block(), context->FRAME.FBW, context->ZBUF.PSM); p.fzbo = m_mem.GetOffset4(context->FRAME, context->ZBUF); - p.sel.dw = 0; + p.sel.key = 0; p.sel.fpsm = 3; p.sel.zpsm = 3; @@ -291,6 +291,9 @@ protected: bool fwrite = p.fm != 0xffffffff; bool ftest = p.sel.atst != ATST_ALWAYS || context->TEST.DATE && context->FRAME.PSM != PSM_PSMCT24; + p.sel.fwrite = fwrite; + p.sel.ftest = ftest; + if(fwrite || ftest) { p.sel.fpsm = GSUtil::EncodePSM(context->FRAME.PSM); @@ -307,6 +310,8 @@ protected: p.sel.fst = PRIM->FST; p.sel.ltf = context->TEX1.IsLinear(); p.sel.tlu = GSLocalMemory::m_psm[context->TEX0.PSM].pal > 0; + p.sel.wms = ((context->CLAMP.WMS + 1) >> 1) & 1; + p.sel.wmt = ((context->CLAMP.WMT + 1) >> 1) & 1; if(p.sel.iip == 0 && p.sel.tfx == TFX_MODULATE && p.sel.tcc) { @@ -466,11 +471,18 @@ protected: { p.sel.rfb = 1; } + + p.sel.colclamp = env.COLCLAMP.CLAMP; + p.sel.fba = context->FBA.FBA; + p.sel.dthe = env.DTHE.DTHE; } bool zwrite = p.zm != 0xffffffff; bool ztest = context->TEST.ZTE && context->TEST.ZTST > 1; + p.sel.zwrite = zwrite; + p.sel.ztest = ztest; + if(zwrite || ztest) { p.sel.zpsm = GSUtil::EncodePSM(context->ZBUF.PSM); diff --git a/plugins/GSdx/GSScanlineEnvironment.h b/plugins/GSdx/GSScanlineEnvironment.h new file mode 100644 index 0000000000..b88e7d1eb2 --- /dev/null +++ b/plugins/GSdx/GSScanlineEnvironment.h @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * This Program 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 2, or (at your option) + * any later version. + * + * This Program 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSLocalMemory.h" +#include "GSVector.h" + +union GSScanlineSelector +{ + struct + { + DWORD fpsm:2; // 0 + DWORD zpsm:2; // 2 + DWORD ztst:2; // 4 (0: off, 1: write, 2: test (ge), 3: test (g)) + DWORD atst:3; // 6 + DWORD afail:2; // 9 + DWORD iip:1; // 11 + DWORD tfx:3; // 12 + DWORD tcc:1; // 15 + DWORD fst:1; // 16 + DWORD ltf:1; // 17 + DWORD tlu:1; // 18 + DWORD fge:1; // 19 + DWORD date:1; // 20 + DWORD abea:2; // 21 + DWORD abeb:2; // 23 + DWORD abec:2; // 25 + DWORD abed:2; // 27 + DWORD pabe:1; // 29 + DWORD rfb:1; // 30 + DWORD sprite:1; // 31 + + DWORD fwrite:1; // 32 + DWORD ftest:1; // 33 + DWORD zwrite:1; // 34 + DWORD ztest:1; // 35 + DWORD wms:1; // 36 (0: repeat, 1: clamp) + DWORD wmt:1; // 37 + DWORD colclamp:1; // 38 + DWORD fba:1; // 39 + DWORD dthe:1; // 40 + }; + + struct + { + DWORD _pad1:21; + DWORD abe:8; + DWORD _pad2:3; + DWORD fb:2; + DWORD zb:2; + }; + + struct + { + DWORD lo; + DWORD hi; + }; + + UINT64 key; + + operator DWORD() {return lo;} + operator UINT64() {return key;} + + bool IsSolidRect() + { + return sprite + && iip == 0 + && tfx == TFX_NONE + && abe == 255 + && ztst <= 1 + && atst <= 1 + && date == 0 + && fge == 0; + } +}; + +__declspec(align(16)) struct GSScanlineParam +{ + GSScanlineSelector sel; + + void* vm; + const void* tex; + const DWORD* clut; + DWORD tw; + + GSLocalMemory::Offset* fbo; + GSLocalMemory::Offset* zbo; + GSLocalMemory::Offset4* fzbo; + + DWORD fm, zm; +}; + +__declspec(align(16)) struct GSScanlineEnvironment +{ + GSScanlineSelector sel; + + void* vm; + const void* tex; + const DWORD* clut; + DWORD tw; + + GSVector4i* fbr; + GSVector4i* zbr; + int** fbc; + int** zbc; + GSVector2i* fzbr; + GSVector2i* fzbc; + + GSVector4i* dimx; + + GSVector4i fm, zm; + struct {GSVector4i min, max, mask;} t; // [u] x 4 [v] x 4 + GSVector4i datm; + GSVector4i colclamp; + GSVector4i fba; + GSVector4i aref; + GSVector4i afix, afix2; + GSVector4i frb, fga; + + struct {GSVector4 z, s, t, q; GSVector4i rb, ga, f, si, ti, _pad[7];} d[4]; + struct {GSVector4 z, stq; GSVector4i c, f, st;} d4; + struct {GSVector4i rb, ga;} c; + struct {GSVector4i z, f;} p; + struct {GSVector4i z, f, s, t, q, rb, ga, zs, zd, uf, vf;} temp; +}; diff --git a/plugins/GSdx/GSState.cpp b/plugins/GSdx/GSState.cpp index ed3d181157..f90b34c781 100644 --- a/plugins/GSdx/GSState.cpp +++ b/plugins/GSdx/GSState.cpp @@ -798,12 +798,21 @@ template void GSState::GIFRegHandlerALPHA(GIFReg* r) void GSState::GIFRegHandlerDIMX(GIFReg* r) { + bool update = false; + if(!(m_env.DIMX == (GSVector4i)r->DIMX).alltrue()) { Flush(); + + update = true; } m_env.DIMX = (GSVector4i)r->DIMX; + + if(update) + { + m_env.UpdateDIMX(); + } } void GSState::GIFRegHandlerDTHE(GIFReg* r) @@ -1573,6 +1582,8 @@ int GSState::Defrost(const GSFreezeData* fd) UpdateVertexKick(); + m_env.UpdateDIMX(); + m_env.CTXT[0].UpdateScissor(); m_env.CTXT[1].UpdateScissor(); diff --git a/plugins/GSdx/GSdx_vs2008.vcproj b/plugins/GSdx/GSdx_vs2008.vcproj index 545a8735c8..0cec269a7b 100644 --- a/plugins/GSdx/GSdx_vs2008.vcproj +++ b/plugins/GSdx/GSdx_vs2008.vcproj @@ -1,7 +1,7 @@ @@ -86,7 +86,7 @@ @@ -150,7 +150,7 @@ @@ -344,7 +344,7 @@ @@ -727,7 +727,7 @@ @@ -789,7 +789,7 @@ @@ -853,7 +853,7 @@ @@ -916,7 +916,7 @@ + + @@ -1669,6 +1673,10 @@ RelativePath=".\GSDrawScanline.h" > + + @@ -1717,6 +1725,10 @@ RelativePath=".\GSRendererSW.h" > + + @@ -5044,6 +5056,26 @@ > + + + + + + + + + + // for debug print +#include +#include +#include +#ifdef __GNUC__ +#include +#include +#endif + +#ifdef __x86_64__ + #define XBYAK64_GCC +#elif defined(_WIN64) + #define XBYAK64_WIN +#endif +#if !defined(XBYAK64) && !defined(XBYAK32) + #if defined(XBYAK64_GCC) || defined(XBYAK64_WIN) + #define XBYAK64 + #else + #define XBYAK32 + #endif +#endif + +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable : 4514) /* remove inline function */ + #pragma warning(disable : 4786) /* identifier is too long */ + #pragma warning(disable : 4503) /* name is too long */ + #pragma warning(disable : 4127) /* constant expresison */ + #if (_MSC_VER <= 1200) + #ifndef for + #define for if(0);else for + #pragma warning(disable : 4127) /* condition is constant(for "if" trick) */ + #endif + #endif + #include +#endif + +#ifndef NUM_OF_ARRAY +// template +// size_t num_of_array(const T (&)[N]) { return N; } + #define NUM_OF_ARRAY(x) (sizeof(x) / sizeof(*x)) +#endif + +namespace Xbyak { + +#include "xbyak_bin2hex.h" + +enum { + DEFAULT_MAX_CODE_SIZE = 2048, + VERSION = 0x2070, /* 0xABCD = A.BC(D) */ +}; + +#ifndef MIE_DEFINED_UINT32 + #define MIE_DEFINED_UINT32 + #ifdef _MSC_VER + typedef unsigned __int64 uint64; + #else + typedef unsigned long long uint64; + #endif + typedef unsigned int uint32; + typedef unsigned short uint16; + typedef unsigned char uint8; + #ifndef MIE_ALIGN + #ifdef _MSC_VER + #define MIE_ALIGN(x) __declspec(align(x)) + #else + #define MIE_ALIGN(x) __attribute__((aligned(x))) + #endif + #endif +#endif + +enum Error { + ERR_NONE = 0, + ERR_BAD_ADDRESSING, + ERR_CODE_IS_TOO_BIG, + ERR_BAD_SCALE, + ERR_ESP_CANT_BE_INDEX, + ERR_BAD_COMBINATION, + ERR_BAD_SIZE_OF_REGISTER, + ERR_IMM_IS_TOO_BIG, + ERR_BAD_ALIGN, + ERR_LABEL_IS_REDEFINED, + ERR_LABEL_IS_TOO_FAR, + ERR_LABEL_IS_NOT_FOUND, + ERR_CODE_ISNOT_COPYABLE, + ERR_BAD_PARAMETER, + ERR_CANT_PROTECT, + ERR_CANT_USE_64BIT_DISP, + ERR_OFFSET_IS_TOO_BIG, + ERR_MEM_SIZE_IS_NOT_SPECIFIED, + ERR_INTERNAL +}; + +static inline const char *ConvertErrorToString(Error err) +{ + static const char errTbl[][40] = { + "none", + "bad addressing", + "code is too big", + "bad scale", + "esp can't be index", + "bad combination", + "bad size of register", + "imm is too big", + "bad align", + "label is redefined", + "label is too far", + "label is not found", + "code is not copyable", + "bad parameter", + "can't protect", + "can't use 64bit disp(use (void*))", + "offset is too big", + "MEM size is not specified", + "internal error", + }; + if (err < 0 || err > ERR_INTERNAL) return 0; + return errTbl[err]; +} + +namespace inner { + +enum { debug = 1 }; + +static inline uint32 GetPtrDist(const void *p1, const void *p2 = 0) +{ + uint64 diff = static_cast(p1) - static_cast(p2); +#ifdef XBYAK64 + if (0x7FFFFFFFULL < diff && diff < 0xFFFFFFFF80000000ULL) throw ERR_OFFSET_IS_TOO_BIG; +#endif + return static_cast(diff); +} + +static inline bool IsInDisp8(uint32 x) { return 0xFFFFFF80 <= x || x <= 0x7F; } + +} + +class Operand { +private: + const uint8 idx_; + const uint8 kind_; + const uint8 bit_; + const uint8 ext8bit_; // 1 if spl/bpl/sil/dil, otherwise 0 + void operator=(Operand&); +public: + enum Kind { + NONE = 0, + MEM = 1 << 1, + IMM = 1 << 2, + REG = 1 << 3, + MMX = 1 << 4, + XMM = 1 << 5, + FPU = 1 << 6 + }; + enum Code { +#ifdef XBYAK64 + RAX = 0, RCX, RDX, RBX, RSP, RBP, RSI, RDI, R8, R9, R10, R11, R12, R13, R14, R15, + R8D = 8, R9D, R10D, R11D, R12D, R13D, R14D, R15D, + R8W = 8, R9W, R10W, R11W, R12W, R13W, R14W, R15W, + R8B = 8, R9B, R10B, R11B, R12B, R13B, R14B, R15B, + SPL = 4, BPL, SIL, DIL, +#endif + EAX = 0, ECX, EDX, EBX, ESP, EBP, ESI, EDI, + AX = 0, CX, DX, BX, SP, BP, SI, DI, + AL = 0, CL, DL, BL, AH, CH, DH, BH + }; + Operand() : idx_(0), kind_(0), bit_(0), ext8bit_(0) { } + Operand(int idx, Kind kind, int bit, int ext8bit = 0) + : idx_(static_cast(idx)) + , kind_(static_cast(kind)) + , bit_(static_cast(bit)) + , ext8bit_(static_cast(ext8bit)) + { + assert((bit_ & (bit_ - 1)) == 0); // bit must be power of two + } + Kind getKind() const { return static_cast(kind_); } + int getIdx() const { return idx_; } + bool isNone() const { return kind_ == 0; } + bool isMMX() const { return is(MMX); } + bool isXMM() const { return is(XMM); } + bool isREG(int bit = 0) const { return is(REG, bit); } + bool isMEM(int bit = 0) const { return is(MEM, bit); } + bool isExt8bit() const { return ext8bit_ != 0; } + Operand changeBit(int bit) const { return Operand(idx_, static_cast(kind_), bit, ext8bit_); } + // any bit is accetable if bit == 0 + bool is(int kind, uint32 bit = 0) const + { + return (kind_ & kind) && (bit == 0 || (bit_ & bit)); // cf. you can set (8|16) + } + bool isBit(uint32 bit) const { return (bit_ & bit) != 0; } + uint32 getBit() const { return bit_; } + const char *toString() const + { + if (kind_ == REG) { + if (ext8bit_) { + static const char tbl[4][4] = { "spl", "bpl", "sil", "dil" }; + return tbl[idx_ - 4]; + } + static const char tbl[4][16][5] = { + { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh", "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" }, + { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" }, + { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" }, + { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" }, + }; + return tbl[bit_ == 8 ? 0 : bit_ == 16 ? 1 : bit_ == 32 ? 2 : 3][idx_]; + } else if (isMMX()) { + static const char tbl[8][4] = { "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7" }; + return tbl[idx_]; + } else if (isXMM()) { + static const char tbl[16][5] = { "xm0", "xm1", "xm2", "xm3", "xm4", "xm5", "xm6", "xm7", "xm8", "xm9", "xm10", "xm11", "xm12", "xm13", "xm14", "xm15" }; + return tbl[idx_]; + } + throw ERR_INTERNAL; + } +}; + +class Reg : public Operand { + void operator=(const Reg&); +public: + Reg() { } + Reg(int idx, Kind kind, int bit = 0, int ext8bit = 0) : Operand(idx, kind, bit, ext8bit) { } + // reg = this + uint8 getRex(const Reg& index = Reg(), const Reg& base = Reg()) const + { + if ((!isExt8bit() && !index.isExt8bit() && !base.isExt8bit()) && (getIdx() | index.getIdx() | base.getIdx()) < 8) return 0; + return uint8(0x40 | ((getIdx() >> 3) << 2)| ((index.getIdx() >> 3) << 1) | (base.getIdx() >> 3)); + } +}; + +class Reg8 : public Reg { + void operator=(const Reg8&); +public: + explicit Reg8(int idx, int ext8bit = 0) : Reg(idx, Operand::REG, 8, ext8bit) { } +}; + +class Reg16 : public Reg { + void operator=(const Reg16&); +public: + explicit Reg16(int idx) : Reg(idx, Operand::REG, 16) { } +}; + +class Mmx : public Reg { + void operator=(const Mmx&); +public: + explicit Mmx(int idx, Kind kind = Operand::MMX, int bit = 64) : Reg(idx, kind, bit) { } +}; + +class Xmm : public Mmx { + void operator=(const Xmm&); +public: + explicit Xmm(int idx) : Mmx(idx, Operand::XMM, 128) { } +}; + +// register for addressing(32bit or 64bit) +class Reg32e : public Reg { +public: + // [base_(this) + index_ * scale_ + disp_] + const Reg index_; + const int scale_; // 0(index is none), 1, 2, 4, 8 + const uint32 disp_; +private: + friend class Address; + friend Reg32e operator+(const Reg32e& a, const Reg32e& b) + { + if (a.scale_ == 0) { + if (b.scale_ == 0) { // base + base + if (b.getIdx() == Operand::ESP) { // [reg + esp] => [esp + reg] + return Reg32e(b, a, 1, a.disp_ + b.disp_); + } else { + return Reg32e(a, b, 1, a.disp_ + b.disp_); + } + } else if (b.isNone()) { // base + index + return Reg32e(a, b.index_, b.scale_, a.disp_ + b.disp_); + } + } + throw ERR_BAD_ADDRESSING; + } + friend Reg32e operator*(const Reg32e& r, int scale) + { + if (r.scale_ == 0) { + if (scale == 1) { + return r; + } else if (scale == 2 || scale == 4 || scale == 8) { + return Reg32e(Reg(), r, scale, r.disp_); + } + } + throw ERR_BAD_SCALE; + } + friend Reg32e operator+(const Reg32e& r, unsigned int disp) + { + return Reg32e(r, r.index_, r.scale_, r.disp_ + disp); + } + friend Reg32e operator-(const Reg32e& r, unsigned int disp) + { + return operator+(r, -static_cast(disp)); + } + void operator=(const Reg32e&); // don't call +public: + explicit Reg32e(int idx, int bit) + : Reg(idx, REG, bit) + , index_() + , scale_(0) + , disp_(0) + { + } + Reg32e(const Reg& base, const Reg& index, int scale, unsigned int disp) + : Reg(base) + , index_(index) + , scale_(scale) + , disp_(disp) + { + if (scale != 0 && scale != 1 && scale != 2 && scale != 4 && scale != 8) throw ERR_BAD_SCALE; + if (!base.isNone() && !index.isNone() && base.getBit() != index.getBit()) throw ERR_BAD_COMBINATION; + if (index.getIdx() == Operand::ESP) throw ERR_ESP_CANT_BE_INDEX; + } + Reg32e optimize() const // select smaller size + { + // [reg * 2] => [reg + reg] + if (isNone() && !index_.isNone() && scale_ == 2) { + const Reg index(index_.getIdx(), Operand::REG, index_.getBit()); + return Reg32e(index, index, 1, disp_); + } + return *this; + } +}; + +struct Reg32 : public Reg32e { + explicit Reg32(int idx) : Reg32e(idx, 32) {} +private: + void operator=(const Reg32&); +}; +#ifdef XBYAK64 +struct Reg64 : public Reg32e { + explicit Reg64(int idx) : Reg32e(idx, 64) {} +private: + void operator=(const Reg64&); +}; +struct RegRip { + uint32 disp_; + RegRip(unsigned int disp = 0) : disp_(disp) {} + friend const RegRip operator+(const RegRip& r, unsigned int disp) { + return RegRip(r.disp_ + disp); + } + friend const RegRip operator-(const RegRip& r, unsigned int disp) { + return RegRip(r.disp_ - disp); + } +}; +#endif + +class CodeArray { + enum { + ALIGN_SIZE = 16, + MAX_FIXED_BUF_SIZE = 8 + }; + enum Type { + FIXED_BUF, // use buf_(non alignment, non protect) + USER_BUF, // use userPtr(non alignment, non protect) + ALLOC_BUF // use new(alignment, protect) + }; + void operator=(const CodeArray&); + Type type_; + uint8 *const allocPtr_; // for ALLOC_BUF + uint8 buf_[MAX_FIXED_BUF_SIZE]; // for FIXED_BUF +protected: + const size_t maxSize_; + uint8 *const top_; + size_t size_; +public: + CodeArray(size_t maxSize = MAX_FIXED_BUF_SIZE, void *userPtr = 0) + : type_(userPtr ? USER_BUF : maxSize <= MAX_FIXED_BUF_SIZE ? FIXED_BUF : ALLOC_BUF) + , allocPtr_(type_ == ALLOC_BUF ? new uint8[maxSize + ALIGN_SIZE] : 0) + , maxSize_(maxSize) + , top_(type_ == ALLOC_BUF ? getAlignedAddress(allocPtr_) : type_ == USER_BUF ? reinterpret_cast(userPtr) : buf_) + , size_(0) + { + if (type_ == ALLOC_BUF && !protect(top_, maxSize, true)) { +// fprintf(stderr, "can't protect (addr=%p, size=%u, canExec=%d)\n", addr, size, canExec); + throw ERR_CANT_PROTECT; + } + } + virtual ~CodeArray() + { + if (type_ == ALLOC_BUF) { + protect(top_, maxSize_, false); + delete[] allocPtr_; + } + } + CodeArray(const CodeArray& rhs) + : type_(rhs.type_) + , allocPtr_(0) + , maxSize_(rhs.maxSize_) + , top_(buf_) + , size_(rhs.size_) + { + if (type_ != FIXED_BUF) throw ERR_CODE_ISNOT_COPYABLE; + for (size_t i = 0; i < size_; i++) top_[i] = rhs.top_[i]; + } + void db(int code) + { + if (size_ >= maxSize_) throw ERR_CODE_IS_TOO_BIG; + top_[size_++] = static_cast(code); + } + void db(const uint8 *code, int codeSize) + { + for (int i = 0; i < codeSize; i++) db(code[i]); + } + void db(uint64 code, int codeSize) + { + if (codeSize > 8) throw ERR_BAD_PARAMETER; + for (int i = 0; i < codeSize; i++) db(static_cast(code >> (i * 8))); + } + void dw(uint32 code) { db(code, 2); } + void dd(uint32 code) { db(code, 4); } + const uint8 *getCode() const { return top_; } + const uint8 *getCurr() const { return &top_[size_]; } + size_t getSize() const { return size_; } + void dump() const + { + const uint8 *p = getCode(); + size_t bufSize = getSize(); + size_t remain = bufSize; + for (int i = 0; i < 4; i++) { + size_t disp = 16; + if (remain < 16) { + disp = remain; + } + for (size_t j = 0; j < 16; j++) { + if (j < disp) { + printf("%02X", p[i * 16 + j]); + } + } + putchar('\n'); + remain -= disp; + if (remain <= 0) { + break; + } + } + } + /* + @param data [in] address of jmp data + @param disp [in] offset from the next of jmp + @param isShort [in] true if short jmp + */ + void rewrite(uint8 *data, uint32 disp, bool isShort) + { + if (isShort) { + data[0] = static_cast(disp); + } else { + data[0] = static_cast(disp); + data[1] = static_cast(disp >> 8); + data[2] = static_cast(disp >> 16); + data[3] = static_cast(disp >> 24); + } + } + /** + change exec permission of memory + @param addr [in] buffer address + @param size [in] buffer size + @param canExec [in] true(enable to exec), false(disable to exec) + @return true(success), false(failure) + */ + static inline bool protect(const void *addr, size_t size, bool canExec) + { +#ifdef __GNUC__ + size_t pageSize = sysconf(_SC_PAGESIZE); + size_t iaddr = reinterpret_cast(addr); + size_t roundAddr = iaddr & ~(pageSize - static_cast(1)); + int mode = PROT_READ | PROT_WRITE | (canExec ? PROT_EXEC : 0); + return mprotect(reinterpret_cast(roundAddr), size + (iaddr - roundAddr), mode) == 0; +#elif defined(_WIN32) + DWORD oldProtect; + return VirtualProtect(const_cast(addr), size, canExec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &oldProtect) != 0; +#else + return true; +#endif + } + /** + get aligned memory pointer + @param addr [in] address + @param alingedSize [in] power of two + @return aligned addr by alingedSize + */ + static inline uint8 *getAlignedAddress(uint8 *addr, size_t alignedSize = ALIGN_SIZE) + { + return reinterpret_cast((reinterpret_cast(addr) + alignedSize - 1) & ~(alignedSize - static_cast(1))); + } +}; + +class Address : public Operand, public CodeArray { + void operator=(const Address&); + uint64 disp_; + bool isOnlyDisp_; + bool is64bitDisp_; + uint8 rex_; +public: + const bool is32bit_; + Address(uint32 sizeBit, bool isOnlyDisp, uint64 disp, bool is32bit, bool is64bitDisp = false) + : Operand(0, MEM, sizeBit) + , CodeArray(6) // 6 = 1(ModRM) + 1(SIB) + 4(disp) + , disp_(disp) + , isOnlyDisp_(isOnlyDisp) + , is64bitDisp_(is64bitDisp) + , rex_(0) + , is32bit_(is32bit) + { + } + bool isOnlyDisp() const { return isOnlyDisp_; } // for mov eax + uint64 getDisp() const { return disp_; } + uint8 getRex() const { return rex_; } + bool is64bitDisp() const { return is64bitDisp_; } // for moffset +#ifdef XBYAK64 + void setRex(uint8 rex) { rex_ = rex; } +#else + void setRex(uint8) { } +#endif +}; + +class AddressFrame { +private: + void operator=(const AddressFrame&); +public: + const uint32 bit_; + explicit AddressFrame(uint32 bit) : bit_(bit) { } + Address operator[](const void *disp) const + { + Reg32e r(Reg(), Reg(), 0, inner::GetPtrDist(disp)); + return operator[](r); + } +#ifdef XBYAK64 + Address operator[](uint64 disp) const + { + return Address(64, true, disp, false, true); + } + Address operator[](const RegRip& addr) const + { + Address frame(64, true, addr.disp_, false); + frame.db(B00000101); + frame.dd(addr.disp_); + return frame; + } +#endif + Address operator[](const Reg32e& in) const + { + const Reg32e& r = in.optimize(); + Address frame(bit_, (r.isNone() && r.index_.isNone()), r.disp_, r.isBit(32) || r.index_.isBit(32)); + enum { + mod00 = 0, mod01 = 1, mod10 = 2 + }; + int mod; + if (r.isNone() || ((r.getIdx() & 7) != Operand::EBP && r.disp_ == 0)) { + mod = mod00; + } else if (inner::IsInDisp8(r.disp_)) { + mod = mod01; + } else { + mod = mod10; + } + const int base = r.isNone() ? Operand::EBP : (r.getIdx() & 7); + /* ModR/M = [2:3:3] = [Mod:reg/code:R/M] */ + bool hasSIB = !r.index_.isNone() || (r.getIdx() & 7) == Operand::ESP; +#ifdef XBYAK64 + if (r.isNone() && r.index_.isNone()) hasSIB = true; +#endif + if (!hasSIB) { + frame.db((mod << 6) | base); + } else { + frame.db((mod << 6) | Operand::ESP); + /* SIB = [2:3:3] = [SS:index:base(=rm)] */ + int index = r.index_.isNone() ? Operand::ESP : (r.index_.getIdx() & 7); + int ss = (r.scale_ == 8) ? 3 : (r.scale_ == 4) ? 2 : (r.scale_ == 2) ? 1 : 0; + frame.db((ss << 6) | (index << 3) | base); + } + if (mod == mod01) { + frame.db(r.disp_); + } else if (mod == mod10 || (mod == mod00 && r.isNone())) { + frame.dd(r.disp_); + } + frame.setRex(Reg().getRex(r.index_, r)); + return frame; + } +}; + +struct JmpLabel { + uint8 *endOfJmp; /* end address of jmp */ + bool isShort; +}; + +class Label { + CodeArray *base_; + int anonymousCount_; // for @@, @f, @b + int localCount_; // for .*** + typedef std::map DefinedList; + typedef std::multimap UndefinedList; + DefinedList definedList_; + UndefinedList undefinedList_; + + /* + @@ --> @@. + @b --> @@. + @f --> @@. + .*** -> .***. + */ + std::string convertLabel(const char *label) const + { + std::string newLabel(label); + if (newLabel == "@f" || newLabel == "@F") { + newLabel = std::string("@@") + toStr(anonymousCount_ + 1); + } else if (newLabel == "@b" || newLabel == "@B") { + newLabel = std::string("@@") + toStr(anonymousCount_); + } else if (*label == '.') { + newLabel += toStr(localCount_); + } + return newLabel; + } +public: + Label() + : base_(0) + , anonymousCount_(0) + , localCount_(0) + { + } + void incLocalCount() { localCount_++; } + void decLocalCount() { localCount_--; } + void set(CodeArray *base) + { + base_ = base; + } + void define(const char *label, const uint8 *address) + { + std::string newLabel(label); + if (newLabel == "@@") { + newLabel += toStr(++anonymousCount_); + } else if (*label == '.') { + newLabel += toStr(localCount_); + } + label = newLabel.c_str(); + // add label + DefinedList::value_type item(label, address); + std::pair ret = definedList_.insert(item); + if (!ret.second) throw ERR_LABEL_IS_REDEFINED; + // search undefined label + for (;;) { + UndefinedList::iterator itr = undefinedList_.find(label); + if (itr == undefinedList_.end()) break; + const JmpLabel *jmp = &itr->second; + uint32 disp = inner::GetPtrDist(address, jmp->endOfJmp); + if (jmp->isShort && !inner::IsInDisp8(disp)) throw ERR_LABEL_IS_TOO_FAR; + uint8 *data = jmp->endOfJmp - (jmp->isShort ? 1 : 4); + base_->rewrite(data, disp, jmp->isShort); + undefinedList_.erase(itr); + } + } + const uint8 *getAddress(const char *label) const + { + std::string newLabel = convertLabel(label); + DefinedList::const_iterator itr = definedList_.find(newLabel); + if (itr != definedList_.end()) { + return itr->second; + } else { + return 0; + } + } + void addUndefinedLabel(const char *label, const JmpLabel& jmp) + { + std::string newLabel = convertLabel(label); + undefinedList_.insert(UndefinedList::value_type(newLabel, jmp)); + } + bool hasUndefinedLabel() const + { + if (inner::debug) { + for (UndefinedList::const_iterator i = undefinedList_.begin(); i != undefinedList_.end(); ++i) { + fprintf(stderr, "undefined label:%s\n", i->first.c_str()); + } + } + return !undefinedList_.empty(); + } + static inline std::string toStr(int num) + { + char buf[16]; + static const char fmt[] = ".%08x"; +#ifdef _WIN32 + #if _MSC_VER < 1400 + _snprintf(buf, sizeof(buf), fmt, num); + #else + _snprintf_s(buf, sizeof(buf), fmt, num); + #endif +#else + snprintf(buf, sizeof(buf), fmt, num); +#endif + return buf; + } +}; + +class CodeGenerator : public CodeArray { +protected: + enum LabelType { + T_SHORT, + T_NEAR, + T_AUTO // T_SHORT if possible + }; +private: + CodeGenerator operator=(const CodeGenerator&); // don't call +#ifdef XBYAK64 + enum { i32e = 32 | 64, BIT = 64 }; +#else + enum { i32e = 32, BIT = 32 }; +#endif + // (XMM, XMM|MEM) + static inline bool isXMM_XMMorMEM(const Operand& op1, const Operand& op2) + { + return op1.isXMM() && (op2.isXMM() || op2.isMEM()); + } + // (MMX, MMX|MEM) or (XMM, XMM|MEM) + static inline bool isXMMorMMX_MEM(const Operand& op1, const Operand& op2) + { + return (op1.isMMX() && (op2.isMMX() || op2.isMEM())) || isXMM_XMMorMEM(op1, op2); + } + // (XMM, MMX|MEM) + static inline bool isXMM_MMXorMEM(const Operand& op1, const Operand& op2) + { + return op1.isXMM() && (op2.isMMX() || op2.isMEM()); + } + // (MMX, XMM|MEM) + static inline bool isMMX_XMMorMEM(const Operand& op1, const Operand& op2) + { + return op1.isMMX() && (op2.isXMM() || op2.isMEM()); + } + // (XMM, REG32|MEM) + static inline bool isXMM_REG32orMEM(const Operand& op1, const Operand& op2) + { + return op1.isXMM() && (op2.isREG(i32e) || op2.isMEM()); + } + // (REG32, XMM|MEM) + static inline bool isREG32_XMMorMEM(const Operand& op1, const Operand& op2) + { + return op1.isREG(i32e) && (op2.isXMM() || op2.isMEM()); + } + void if16bit(const Operand& reg1, const Operand& reg2) + { + // except movsx(16bit, 32/64bit) + if ((reg1.isBit(16) && !reg2.isBit(i32e)) || (reg2.isBit(16) && !reg1.isBit(i32e))) db(0x66); + } + void rexAddr(const Address& addr, const Reg& reg = Reg()) + { +#ifdef XBYAK64 + if (addr.is32bit_) db(0x67); +#endif + if16bit(reg, addr); + uint32 rex = addr.getRex() | reg.getRex(); + if (reg.isREG(64)) rex |= 0x48; + if (rex) db(rex); + } + void rex(const Operand& op1, const Operand& op2 = Operand()) + { + if (op1.isMEM()) { + rexAddr(static_cast(op1), static_cast(op2)); + } else if (op2.isMEM()) { + rexAddr(static_cast(op2), static_cast(op1)); + } else { + const Reg& reg1 = static_cast(op1); + const Reg& reg2 = static_cast(op2); + // ModRM(reg, base); + if16bit(reg1, reg2); + uint8 rex = reg2.getRex(Reg(), reg1); + if (reg1.isREG(64) || reg2.isREG(64)) rex |= 0x48; + if (rex) db(rex); + } + } + Label label_; + bool isInDisp16(uint32 x) const { return 0xFFFF8000 <= x || x <= 0x7FFF; } + uint8 getModRM(int mod, int r1, int r2) const { return static_cast((mod << 6) | ((r1 & 7) << 3) | (r2 & 7)); } + void opModR(const Reg& reg1, const Reg& reg2, int code0, int code1 = NONE, int code2 = NONE) + { + rex(reg2, reg1); + db(code0 | (reg1.isBit(8) ? 0 : 1)); if (code1 != NONE) db(code1); if (code2 != NONE) db(code2); + db(getModRM(3, reg1.getIdx(), reg2.getIdx())); + } + void opModM(const Address& addr, const Reg& reg, int code0, int code1 = NONE, int code2 = NONE) + { + if (addr.is64bitDisp()) throw ERR_CANT_USE_64BIT_DISP; + rex(addr, reg); + db(code0 | (reg.isBit(8) ? 0 : 1)); if (code1 != NONE) db(code1); if (code2 != NONE) db(code2); + uint8 t = *addr.getCode(); + assert((t & ~0xC7) == 0); /* 0b11000111 */ + db(t | ((reg.getIdx() & 7) << 3)); // update reg field + db(addr.getCode() + 1, static_cast(addr.getSize()) - 1); + } + void opJmp(const char *label, LabelType type, uint8 shortCode, uint8 longCode, uint8 longPref) + { + const uint8 *address = label_.getAddress(label); + if (address) { /* label exists */ + opJmp(address, type, shortCode, longCode, longPref); + } else { + const int shortHeaderSize = 1; + const int shortJmpSize = shortHeaderSize + 1; /* +1 means 8-bit displacement */ + const int longHeaderSize = longPref ? 2 : 1; + const int longJmpSize = longHeaderSize + 4; /* +4 means 32-bit displacement */ + uint8 *top = const_cast(getCurr()); + bool isShort = (type != T_NEAR); + JmpLabel jmp; + jmp.endOfJmp = top + (isShort ? shortJmpSize : longJmpSize); + jmp.isShort = isShort; + if (isShort) { + db(shortCode); + db(0); + } else { + if (longPref) db(longPref); + db(longCode); + dd(0); + } + label_.addUndefinedLabel(label, jmp); + } + } + void opJmp(const void *addr, LabelType type, uint8 shortCode, uint8 longCode, uint8 longPref) + { + const int shortHeaderSize = 1; + const int shortJmpSize = shortHeaderSize + 1; /* +1 means 8-bit displacement */ + const int longHeaderSize = longPref ? 2 : 1; + const int longJmpSize = longHeaderSize + 4; /* +4 means 32-bit displacement */ + + uint8 *top = const_cast(getCurr()); + uint32 disp = inner::GetPtrDist(addr, top); + if (type != T_NEAR && inner::IsInDisp8(disp - shortJmpSize)) { + db(shortCode); + db(0); + rewrite(top + shortHeaderSize, disp - shortJmpSize, true); + } else { + if (type == T_SHORT) throw ERR_LABEL_IS_TOO_FAR; + if (longPref) db(longPref); + db(longCode); + dd(0); + rewrite(top + longHeaderSize, disp - longJmpSize, false); + } + } + /* preCode is for SSSE3/SSE4 */ + void opGen(const Operand& reg, const Operand& op, int code, int pref, bool isValid(const Operand&, const Operand&), int imm8 = NONE, int preCode = NONE) + { + if (isValid && !isValid(reg, op)) throw ERR_BAD_COMBINATION; + if (pref != NONE) db(pref); + if (op.isMEM()) { + opModM(static_cast(op), static_cast(reg), 0x0F, preCode, code); + } else { + opModR(static_cast(reg), static_cast(op), 0x0F, preCode, code); + } + if (imm8 != NONE) db(imm8); + } + void opMMX_IMM(const Mmx& mmx, int imm8, int code, int ext) + { + if (mmx.isXMM()) db(0x66); + opModR(Reg32(ext), mmx, 0x0F, code); + db(imm8); + } + void opMMX(const Mmx& mmx, const Operand& op, int code, int pref = 0x66, int imm8 = NONE, int preCode = NONE) + { + pref = mmx.isXMM() ? pref : NONE; + opGen(mmx, op, code, pref, isXMMorMMX_MEM, imm8, preCode); + } + void opMovXMM(const Operand& op1, const Operand& op2, int code, int pref) + { + if (pref != NONE) db(pref); + if (op1.isXMM() && op2.isMEM()) { + opModM(static_cast(op2), static_cast(op1), 0x0F, code); + } else if (op1.isMEM() && op2.isXMM()) { + opModM(static_cast(op1), static_cast(op2), 0x0F, code | 1); + } else { + throw ERR_BAD_COMBINATION; + } + } + void opExt(const Operand& op, const Mmx& mmx, int code, int imm, bool hasMMX2 = false) + { + if (hasMMX2 && op.isREG(i32e)) { /* pextrw is special */ + if (mmx.isXMM()) db(0x66); + opModR(static_cast(op), mmx, 0x0F, B11000101); db(imm); + } else { + opGen(mmx, op, code, 0x66, isXMM_REG32orMEM, imm, B00111010); + } + } + void opR_ModM(const Operand& op, int bit, uint8 mod, int ext, int code0, int code1 = NONE, int code2 = NONE) + { + if (op.isREG(bit)) { + rex(op); + db(code0 | (op.isBit(8) ? 0 : 1)); if (code1 != NONE) db(code1); if (code2 != NONE) db(code2); + db(getModRM(mod, ext, op.getIdx())); + } else if (op.isMEM()) { + opModM(static_cast(op), Reg(ext, Operand::REG, op.getBit()), code0, code1, code2); + } else { + throw ERR_BAD_COMBINATION; + } + } + void opShift(const Operand& op, int imm, int ext) + { + verifyMemHasSize(op); + opR_ModM(op, 0, 3, ext, (B11000000 | ((imm == 1 ? 1 : 0) << 4))); + if (imm != 1) db(imm); + } + void opShift(const Operand& op, const Reg8& cl, int ext) + { + if (cl.getIdx() != Operand::CL) throw ERR_BAD_COMBINATION; + opR_ModM(op, 0, 3, ext, B11010010); + } + void opModRM(const Operand& op1, const Operand& op2, bool condR, bool condM, int code0, int code1 = NONE, int code2 = NONE) + { + if (condR) { + opModR(static_cast(op1), static_cast(op2), code0, code1, code2); + } else if (condM) { + opModM(static_cast(op2), static_cast(op1), code0, code1, code2); + } else { + throw ERR_BAD_COMBINATION; + } + } + void opShxd(const Operand& op, const Reg& reg, uint8 imm, int code, const Reg8 *cl = 0) + { + if (cl && cl->getIdx() != Operand::CL) throw ERR_BAD_COMBINATION; + opModRM(reg, op, (op.isREG(16 | i32e) && op.getBit() == reg.getBit()), op.isMEM() && (reg.isREG(16 | i32e)), 0x0F, code | (cl ? 1 : 0)); + if (!cl) db(imm); + } + // (REG, REG|MEM), (MEM, REG) + void opRM_RM(const Operand& op1, const Operand& op2, int code) + { + if (op1.isREG() && op2.isMEM()) { + opModM(static_cast(op2), static_cast(op1), code | 2); + } else { + opModRM(op2, op1, op1.isREG() && op1.getKind() == op2.getKind(), op1.isMEM() && op2.isREG(), code); + } + } + // (REG|MEM, IMM) + void opRM_I(const Operand& op, uint32 imm, int code, int ext) + { + verifyMemHasSize(op); + uint32 immBit = inner::IsInDisp8(imm) ? 8 : isInDisp16(imm) ? 16 : 32; + if (op.getBit() < immBit) throw ERR_IMM_IS_TOO_BIG; + if (op.isREG()) { + if (immBit == 16 && op.isBit(32)) immBit = 32; /* don't use MEM16 if 32bit mode */ + } + if (op.isREG() && op.getIdx() == 0 && (op.getBit() == immBit || (op.isBit(64) && immBit == 32))) { // rax, eax, ax, al + rex(op); + db(code | 4 | (immBit == 8 ? 0 : 1)); + } else { + int tmp = (op.getBit() > immBit && 32 > immBit) ? 2 : 0; + opR_ModM(op, 0, 3, ext, B10000000 | tmp); + } + db(imm, immBit / 8); + } + void opIncDec(const Operand& op, int code, int ext) + { +#ifndef XBYAK64 + if (op.isREG() && !op.isBit(8)) { + rex(op); db(code | op.getIdx()); + return; + } +#endif + code = B11111110; + if (op.isREG()) { + opModR(Reg(ext, Operand::REG, op.getBit()), static_cast(op), code); + } else if (op.isMEM() && op.getBit() > 0) { + opModM(static_cast(op), Reg(ext, Operand::REG, op.getBit()), code); + } else { + throw ERR_BAD_COMBINATION; + } + } + void opPushPop(const Operand& op, int code, int ext, int alt) + { + if (op.isREG()) { +#ifdef XBYAK64 + if (op.isBit(16)) db(0x66); + if (static_cast(op).getIdx() >= 8) db(0x41); +#else + rex(op); +#endif + db(alt | (op.getIdx() & 7)); + } else if (op.isMEM()) { + opModM(static_cast(op), Reg(ext, Operand::REG, op.getBit()), code); + } else { + throw ERR_BAD_COMBINATION; + } + } + void verifyMemHasSize(const Operand& op) const + { + if (op.isMEM() && op.getBit() == 0) throw ERR_MEM_SIZE_IS_NOT_SPECIFIED; + } +protected: + unsigned int getVersion() const { return VERSION; } + using CodeArray::db; + const Mmx mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7; + const Xmm xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7; + const Xmm &xm0, &xm1, &xm2, &xm3, &xm4, &xm5, &xm6, &xm7; + const Reg32 eax, ecx, edx, ebx, esp, ebp, esi, edi; + const Reg16 ax, cx, dx, bx, sp, bp, si, di; + const Reg8 al, cl, dl, bl, ah, ch, dh, bh; + const AddressFrame ptr, byte, word, dword, qword, xmmword; +#ifdef XBYAK64 + const Reg64 rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15; + const Reg32 r8d, r9d, r10d, r11d, r12d, r13d, r14d, r15d; + const Reg16 r8w, r9w, r10w, r11w, r12w, r13w, r14w, r15w; + const Reg8 r8b, r9b, r10b, r11b, r12b, r13b, r14b, r15b; + const Reg8 spl, bpl, sil, dil; + const Xmm xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15; + const Xmm &xm8, &xm9, &xm10, &xm11, &xm12, &xm13, &xm14, &xm15; + const RegRip rip; +#endif + + void L(const char *label) + { + label_.define(label, getCurr()); + } + void inLocalLabel() { label_.incLocalCount(); } + void outLocalLabel() { label_.decLocalCount(); } + void jmp(const char *label, LabelType type = T_AUTO) + { + opJmp(label, type, B11101011, B11101001, 0); + } + void jmp(const void *addr, LabelType type = T_AUTO) + { + opJmp(addr, type, B11101011, B11101001, 0); + } + void jmp(const Operand& op) + { + opR_ModM(op, i32e, 3, 4, 0xFF); + } + // (REG|MEM, REG) + void test(const Operand& op, const Reg& reg) + { + opModRM(reg, op, op.isREG() && (op.getKind() == reg.getKind()), op.isMEM(), B10000100); + } + // (REG|MEM, IMM) + void test(const Operand& op, uint32 imm) + { + verifyMemHasSize(op); + if (op.isREG() && op.getIdx() == 0) { // al, ax, eax + rex(op); + db(B10101000 | (op.isBit(8) ? 0 : 1)); + } else { + opR_ModM(op, 0, 3, 0, B11110110); + } + int size = op.getBit() / 8; if (size > 4) size = 4; + db(imm, size); + } + void ret(int imm = 0) + { + if (imm) { + db(B11000010); dw(imm); + } else { + db(B11000011); + } + } + // (REG16|REG32, REG16|REG32|MEM) + void imul(const Reg& reg, const Operand& op) + { + opModRM(reg, op, op.isREG() && (reg.getKind() == op.getKind()), op.isMEM(), 0x0F, B10101111); + } + void imul(const Reg& reg, const Operand& op, int imm) + { + int s = inner::IsInDisp8(imm) ? 1 : 0; + opModRM(reg, op, op.isREG() && (reg.getKind() == op.getKind()), op.isMEM(), B01101001 | (s << 1)); + int size = s ? 1 : reg.isREG(16) ? 2 : 4; + db(imm, size); + } + void pop(const Operand& op) + { + opPushPop(op, B10001111, 0, B01011000); + } + void push(const Operand& op) + { + opPushPop(op, B11111111, 6, B01010000); + } + void push(const AddressFrame& af, uint32 imm) + { + if (af.bit_ == 8 && inner::IsInDisp8(imm)) { + db(B01101010); db(imm); + } else if (af.bit_ == 16 && isInDisp16(imm)) { + db(0x66); db(B01101000); dw(imm); + } else { + db(B01101000); dd(imm); + } + } + /* use "push(word, 4)" if you want "push word 4" */ + void push(uint32 imm) + { + if (inner::IsInDisp8(imm)) { + push(byte, imm); + } else { + push(dword, imm); + } + } + void bswap(const Reg32e& reg) + { + opModR(Reg32(1), reg, 0x0F); + } + void mov(const Operand& reg1, const Operand& reg2) + { + const Reg *reg = 0; + const Address *addr = 0; + uint8 code = 0; + if (reg1.isREG() && reg1.getIdx() == 0 && reg2.isMEM()) { // mov eax|ax|al, [disp] + reg = &static_cast(reg1); + addr= &static_cast(reg2); + code = B10100000; + } else + if (reg1.isMEM() && reg2.isREG() && reg2.getIdx() == 0) { // mov [disp], eax|ax|al + reg = &static_cast(reg2); + addr= &static_cast(reg1); + code = B10100010; + } +#ifdef XBYAK64 + if (addr && addr->is64bitDisp()) { + if (code) { + rex(*reg); + db(reg1.isREG(8) ? 0xA0 : reg1.isREG() ? 0xA1 : reg2.isREG(8) ? 0xA2 : 0xA3); + db(addr->getDisp(), 8); + } else { + throw ERR_BAD_COMBINATION; + } + } else +#else + if (code && addr->isOnlyDisp()) { + rex(*reg, *addr); + db(code | (reg->isBit(8) ? 0 : 1)); + dd(static_cast(addr->getDisp())); + } else +#endif + { + opRM_RM(reg1, reg2, B10001000); + } + } + void mov(const Operand& op, uint64 imm) + { + verifyMemHasSize(op); + if (op.isREG()) { + int w = op.isBit(8) ? 0 : 1; + rex(op); db(B10110000 | (w << 3) | (op.getIdx() & 7)); + } else if (op.isMEM()) { + opModM(static_cast(op), Reg(0, Operand::REG, op.getBit()), B11000110); + } else { + throw ERR_BAD_COMBINATION; + } + db(imm, op.getBit() / 8); + } + void opMovxx(const Reg& reg, const Operand& op, uint8 code) + { + int w = op.isBit(16); + bool cond = reg.isREG() && (reg.getBit() > op.getBit()); + opModRM(reg, op, cond && op.isREG(), cond && op.isMEM(), 0x0F, code | w); + } + void cmpxchg8b(const Address& addr) { opModM(addr, Reg32(1), 0x0F, B11000111); } +#ifdef XBYAK64 + void cmpxchg16b(const Address& addr) { opModM(addr, Reg64(1), 0x0F, B11000111); } +#endif + void xadd(const Operand& op, const Reg& reg) + { + opModRM(reg, op, (op.isREG() && reg.isREG() && op.getBit() == reg.getBit()), op.isMEM(), 0x0F, B11000000 | (reg.isBit(8) ? 0 : 1)); + } + void xchg(const Operand& op1, const Operand& op2) + { + const Operand *p1 = &op1, *p2 = &op2; + if (p1->isMEM() || (p2->isREG(16 | i32e) && p2->getIdx() == 0)) { + p1 = &op2; p2 = &op1; + } + if (p1->isMEM()) throw ERR_BAD_COMBINATION; + if (p2->isREG() && (p1->isREG(16 | i32e) && p1->getIdx() == 0) +#ifdef XBYAK64 + && (p2->getIdx() != 0 || !p1->isREG(32)) +#endif + ) { + rex(*p2, *p1); db(0x90 | (p2->getIdx() & 7)); + return; + } + opModRM(*p1, *p2, (p1->isREG() && p2->isREG() && (p1->getBit() == p2->getBit())), p2->isMEM(), B10000110 | (p1->isBit(8) ? 0 : 1)); + } + void call(const char *label) + { + opJmp(label, T_NEAR, 0, B10011010, 0); + } + void call(const void *addr) + { + opJmp(addr, T_NEAR, 0, B11101000, 0); + } + void call(const Operand& op) + { + opR_ModM(op, 16 | i32e, 3, 2, B11111111); + } + // special case + void movd(const Address& addr, const Mmx& mmx) + { + opModM(addr, Reg(mmx.getIdx(), Operand::REG, mmx.getBit() / 8), 0x0F, B01111110); + } + void movd(const Reg32& reg, const Mmx& mmx) + { + if (mmx.isXMM()) db(0x66); + opModR(mmx, reg, 0x0F, B01111110); + } + void movd(const Mmx& mmx, const Address& addr) + { + if (mmx.isXMM()) db(0x66); + opModM(addr, Reg(mmx.getIdx(), Operand::REG, mmx.getBit() / 8), 0x0F, B01101110); + } + void movd(const Mmx& mmx, const Reg32& reg) + { + if (mmx.isXMM()) db(0x66); + opModR(mmx, reg, 0x0F, B01101110); + } + void movq2dq(const Xmm& xmm, const Mmx& mmx) + { + db(0xF3); opModR(xmm, mmx, 0x0F, B11010110); + } + void movdq2q(const Mmx& mmx, const Xmm& xmm) + { + db(0xF2); opModR(mmx, xmm, 0x0F, B11010110); + } + void movq(const Mmx& mmx, const Operand& op) + { + if (mmx.isXMM()) db(0xF3); + opModRM(mmx, op, (mmx.getKind() == op.getKind()), op.isMEM(), 0x0F, mmx.isXMM() ? B01111110 : B01101111); + } + void movq(const Address& addr, const Mmx& mmx) + { + opModM(addr, Reg(mmx.getIdx(), Operand::REG, mmx.getBit() / 8), 0x0F, mmx.isXMM() ? B11010110 : B01111111); + } + // MMX2 : pextrw : reg, mmx/xmm, imm + // SSE4 : pextrw, pextrb, pextrd, extractps : reg/mem, mmx/xmm, imm + void pextrw(const Operand& op, const Mmx& xmm, uint8 imm) { opExt(op, xmm, 0x15, imm, true); } + void pextrb(const Operand& op, const Xmm& xmm, uint8 imm) { opExt(op, xmm, 0x14, imm); } + void pextrd(const Operand& op, const Xmm& xmm, uint8 imm) { opExt(op, xmm, 0x16, imm); } + void extractps(const Operand& op, const Xmm& xmm, uint8 imm) { opExt(op, xmm, 0x17, imm); } + void pinsrw(const Mmx& mmx, const Operand& op, int imm) + { + if (!op.isREG(32) && !op.isMEM()) throw ERR_BAD_COMBINATION; + opGen(mmx, op, B11000100, mmx.isXMM() ? 0x66 : NONE, 0, imm); + } + void insertps(const Xmm& xmm, const Operand& op, uint8 imm) { opGen(xmm, op, 0x21, 0x66, isXMM_XMMorMEM, imm, B00111010); } + void pinsrb(const Xmm& xmm, const Operand& op, uint8 imm) { opGen(xmm, op, 0x20, 0x66, isXMM_REG32orMEM, imm, B00111010); } + void pinsrd(const Xmm& xmm, const Operand& op, uint8 imm) { opGen(xmm, op, 0x22, 0x66, isXMM_REG32orMEM, imm, B00111010); } + + void pmovmskb(const Reg32e& reg, const Mmx& mmx) + { + if (mmx.isXMM()) db(0x66); + opModR(reg, mmx, 0x0F, B11010111); + } + void maskmovq(const Mmx& reg1, const Mmx& reg2) + { + if (!reg1.isMMX() || !reg2.isMMX()) throw ERR_BAD_COMBINATION; + opModR(reg1, reg2, 0x0F, B11110111); + } + void lea(const Reg32e& reg, const Address& addr) { opModM(addr, reg, B10001101); } + + void movmskps(const Reg32e& reg, const Xmm& xmm) { opModR(reg, xmm, 0x0F, B01010000); } + void movmskpd(const Reg32e& reg, const Xmm& xmm) { db(0x66); movmskps(reg, xmm); } + void movntps(const Address& addr, const Xmm& xmm) { opModM(addr, Mmx(xmm.getIdx()), 0x0F, B00101011); } + void movntdqa(const Xmm& xmm, const Address& addr) { db(0x66); opModM(addr, xmm, 0x0F, 0x38, 0x2A); } + void lddqu(const Xmm& xmm, const Address& addr) { db(0xF2); opModM(addr, xmm, 0x0F, B11110000); } + void movnti(const Address& addr, const Reg32e& reg) { opModM(addr, reg, 0x0F, B11000011); } + void movntq(const Address& addr, const Mmx& mmx) + { + if (!mmx.isMMX()) throw ERR_BAD_COMBINATION; + opModM(addr, mmx, 0x0F, B11100111); + } + void popcnt(const Reg& reg, const Operand& op) + { + bool is16bit = reg.isREG(16) && (op.isREG(16) || op.isMEM()); + if (!is16bit && !(reg.isREG(i32e) && (op.isREG(i32e) || op.isMEM()))) throw ERR_BAD_COMBINATION; + if (is16bit) db(0x66); + db(0xF3); opModRM(Reg(reg.getIdx(), Operand::REG, i32e == 32 ? 32 : reg.getBit()), op, op.isREG(), true, 0x0F, 0xB8); + } + void crc32(const Reg32e& reg, const Operand& op) + { + if (reg.isBit(32) && op.isBit(16)) db(0x66); + db(0xF2); + opModRM(reg, op, op.isREG(), op.isMEM(), 0x0F, 0x38, 0xF0 | (op.isBit(8) ? 0 : 1)); + } +public: + enum { NONE = 256 }; + CodeGenerator(size_t maxSize = DEFAULT_MAX_CODE_SIZE, void *userPtr = 0) + : CodeArray(maxSize, userPtr) + , mm0(0), mm1(1), mm2(2), mm3(3), mm4(4), mm5(5), mm6(6), mm7(7) + , xmm0(0), xmm1(1), xmm2(2), xmm3(3), xmm4(4), xmm5(5), xmm6(6), xmm7(7) + , xm0(xmm0), xm1(xmm1), xm2(xmm2), xm3(xmm3), xm4(xmm4), xm5(xmm5), xm6(xmm6), xm7(xmm7) // for my convenience + , eax(Operand::EAX), ecx(Operand::ECX), edx(Operand::EDX), ebx(Operand::EBX), esp(Operand::ESP), ebp(Operand::EBP), esi(Operand::ESI), edi(Operand::EDI) + , ax(Operand::EAX), cx(Operand::ECX), dx(Operand::EDX), bx(Operand::EBX), sp(Operand::ESP), bp(Operand::EBP), si(Operand::ESI), di(Operand::EDI) + , al(Operand::AL), cl(Operand::CL), dl(Operand::DL), bl(Operand::BL), ah(Operand::AH), ch(Operand::CH), dh(Operand::DH), bh(Operand::BH) + , ptr(0), byte(8), word(16), dword(32), qword(64), xmmword(128) +#ifdef XBYAK64 + , rax(Operand::RAX), rcx(Operand::RCX), rdx(Operand::RDX), rbx(Operand::RBX), rsp(Operand::RSP), rbp(Operand::RBP), rsi(Operand::RSI), rdi(Operand::RDI), r8(Operand::R8), r9(Operand::R9), r10(Operand::R10), r11(Operand::R11), r12(Operand::R12), r13(Operand::R13), r14(Operand::R14), r15(Operand::R15) + , r8d(Operand::R8D), r9d(Operand::R9D), r10d(Operand::R10D), r11d(Operand::R11D), r12d(Operand::R12D), r13d(Operand::R13D), r14d(Operand::R14D), r15d(Operand::R15D) + , r8w(Operand::R8W), r9w(Operand::R9W), r10w(Operand::R10W), r11w(Operand::R11W), r12w(Operand::R12W), r13w(Operand::R13W), r14w(Operand::R14W), r15w(Operand::R15W) + , r8b(Operand::R8B), r9b(Operand::R9B), r10b(Operand::R10B), r11b(Operand::R11B), r12b(Operand::R12B), r13b(Operand::R13B), r14b(Operand::R14B), r15b(Operand::R15B) + , spl(Operand::SPL, 1), bpl(Operand::BPL, 1), sil(Operand::SIL, 1), dil(Operand::DIL, 1) + , xmm8(8), xmm9(9), xmm10(10), xmm11(11), xmm12(12), xmm13(13), xmm14(14), xmm15(15) + , xm8(xmm8), xm9(xmm9), xm10(xmm10), xm11(xmm11), xm12(xmm12), xm13(xmm13), xm14(xmm14), xm15(xmm15) // for my convenience + , rip() +#endif + { + label_.set(this); + } + bool hasUndefinedLabel() const { return label_.hasUndefinedLabel(); } + const uint8 *getCode() const + { + assert(!hasUndefinedLabel()); +// if (hasUndefinedLabel()) throw ERR_LABEL_IS_NOT_FOUND; + return top_; + } +#ifdef TEST_NM + void dump(bool doClear = true) + { + CodeArray::dump(); + if (doClear) size_ = 0; + } +#endif + +#ifndef XBYAK_DONT_READ_LIST +#include "xbyak_mnemonic.h" + void align(int x = 16) + { + if (x != 4 && x != 8 && x != 16 && x != 32) throw ERR_BAD_ALIGN; + while (inner::GetPtrDist(getCurr()) % x) { + nop(); + } + } +#endif +}; + +#ifdef _MSC_VER + #pragma warning(pop) +#endif + +} // end of namespace + +#endif // XBYAK_H_ diff --git a/plugins/GSdx/xbyak/xbyak_bin2hex.h b/plugins/GSdx/xbyak/xbyak_bin2hex.h new file mode 100644 index 0000000000..8c75029af3 --- /dev/null +++ b/plugins/GSdx/xbyak/xbyak_bin2hex.h @@ -0,0 +1,258 @@ +enum { + B00000000= 0, + B00000001= 1, + B00000010= 2, + B00000011= 3, + B00000100= 4, + B00000101= 5, + B00000110= 6, + B00000111= 7, + B00001000= 8, + B00001001= 9, + B00001010= 10, + B00001011= 11, + B00001100= 12, + B00001101= 13, + B00001110= 14, + B00001111= 15, + B00010000= 16, + B00010001= 17, + B00010010= 18, + B00010011= 19, + B00010100= 20, + B00010101= 21, + B00010110= 22, + B00010111= 23, + B00011000= 24, + B00011001= 25, + B00011010= 26, + B00011011= 27, + B00011100= 28, + B00011101= 29, + B00011110= 30, + B00011111= 31, + B00100000= 32, + B00100001= 33, + B00100010= 34, + B00100011= 35, + B00100100= 36, + B00100101= 37, + B00100110= 38, + B00100111= 39, + B00101000= 40, + B00101001= 41, + B00101010= 42, + B00101011= 43, + B00101100= 44, + B00101101= 45, + B00101110= 46, + B00101111= 47, + B00110000= 48, + B00110001= 49, + B00110010= 50, + B00110011= 51, + B00110100= 52, + B00110101= 53, + B00110110= 54, + B00110111= 55, + B00111000= 56, + B00111001= 57, + B00111010= 58, + B00111011= 59, + B00111100= 60, + B00111101= 61, + B00111110= 62, + B00111111= 63, + B01000000= 64, + B01000001= 65, + B01000010= 66, + B01000011= 67, + B01000100= 68, + B01000101= 69, + B01000110= 70, + B01000111= 71, + B01001000= 72, + B01001001= 73, + B01001010= 74, + B01001011= 75, + B01001100= 76, + B01001101= 77, + B01001110= 78, + B01001111= 79, + B01010000= 80, + B01010001= 81, + B01010010= 82, + B01010011= 83, + B01010100= 84, + B01010101= 85, + B01010110= 86, + B01010111= 87, + B01011000= 88, + B01011001= 89, + B01011010= 90, + B01011011= 91, + B01011100= 92, + B01011101= 93, + B01011110= 94, + B01011111= 95, + B01100000= 96, + B01100001= 97, + B01100010= 98, + B01100011= 99, + B01100100= 100, + B01100101= 101, + B01100110= 102, + B01100111= 103, + B01101000= 104, + B01101001= 105, + B01101010= 106, + B01101011= 107, + B01101100= 108, + B01101101= 109, + B01101110= 110, + B01101111= 111, + B01110000= 112, + B01110001= 113, + B01110010= 114, + B01110011= 115, + B01110100= 116, + B01110101= 117, + B01110110= 118, + B01110111= 119, + B01111000= 120, + B01111001= 121, + B01111010= 122, + B01111011= 123, + B01111100= 124, + B01111101= 125, + B01111110= 126, + B01111111= 127, + B10000000= 128, + B10000001= 129, + B10000010= 130, + B10000011= 131, + B10000100= 132, + B10000101= 133, + B10000110= 134, + B10000111= 135, + B10001000= 136, + B10001001= 137, + B10001010= 138, + B10001011= 139, + B10001100= 140, + B10001101= 141, + B10001110= 142, + B10001111= 143, + B10010000= 144, + B10010001= 145, + B10010010= 146, + B10010011= 147, + B10010100= 148, + B10010101= 149, + B10010110= 150, + B10010111= 151, + B10011000= 152, + B10011001= 153, + B10011010= 154, + B10011011= 155, + B10011100= 156, + B10011101= 157, + B10011110= 158, + B10011111= 159, + B10100000= 160, + B10100001= 161, + B10100010= 162, + B10100011= 163, + B10100100= 164, + B10100101= 165, + B10100110= 166, + B10100111= 167, + B10101000= 168, + B10101001= 169, + B10101010= 170, + B10101011= 171, + B10101100= 172, + B10101101= 173, + B10101110= 174, + B10101111= 175, + B10110000= 176, + B10110001= 177, + B10110010= 178, + B10110011= 179, + B10110100= 180, + B10110101= 181, + B10110110= 182, + B10110111= 183, + B10111000= 184, + B10111001= 185, + B10111010= 186, + B10111011= 187, + B10111100= 188, + B10111101= 189, + B10111110= 190, + B10111111= 191, + B11000000= 192, + B11000001= 193, + B11000010= 194, + B11000011= 195, + B11000100= 196, + B11000101= 197, + B11000110= 198, + B11000111= 199, + B11001000= 200, + B11001001= 201, + B11001010= 202, + B11001011= 203, + B11001100= 204, + B11001101= 205, + B11001110= 206, + B11001111= 207, + B11010000= 208, + B11010001= 209, + B11010010= 210, + B11010011= 211, + B11010100= 212, + B11010101= 213, + B11010110= 214, + B11010111= 215, + B11011000= 216, + B11011001= 217, + B11011010= 218, + B11011011= 219, + B11011100= 220, + B11011101= 221, + B11011110= 222, + B11011111= 223, + B11100000= 224, + B11100001= 225, + B11100010= 226, + B11100011= 227, + B11100100= 228, + B11100101= 229, + B11100110= 230, + B11100111= 231, + B11101000= 232, + B11101001= 233, + B11101010= 234, + B11101011= 235, + B11101100= 236, + B11101101= 237, + B11101110= 238, + B11101111= 239, + B11110000= 240, + B11110001= 241, + B11110010= 242, + B11110011= 243, + B11110100= 244, + B11110101= 245, + B11110110= 246, + B11110111= 247, + B11111000= 248, + B11111001= 249, + B11111010= 250, + B11111011= 251, + B11111100= 252, + B11111101= 253, + B11111110= 254, + B11111111= 255 +}; diff --git a/plugins/GSdx/xbyak/xbyak_mnemonic.h b/plugins/GSdx/xbyak/xbyak_mnemonic.h new file mode 100644 index 0000000000..2ae7a4ee19 --- /dev/null +++ b/plugins/GSdx/xbyak/xbyak_mnemonic.h @@ -0,0 +1,429 @@ +const char *getVersionString() const { return "2.07"; } +void packssdw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x6B); } +void packsswb(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x63); } +void packuswb(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x67); } +void pand(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xDB); } +void pandn(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xDF); } +void pmaddwd(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xF5); } +void pmulhuw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xE4); } +void pmulhw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xE5); } +void pmullw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xD5); } +void por(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xEB); } +void punpckhbw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x68); } +void punpckhwd(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x69); } +void punpckhdq(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x6A); } +void punpcklbw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x60); } +void punpcklwd(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x61); } +void punpckldq(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x62); } +void pxor(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xEF); } +void pavgb(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xE0); } +void pavgw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xE3); } +void pmaxsw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xEE); } +void pmaxub(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xDE); } +void pminsw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xEA); } +void pminub(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xDA); } +void psadbw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xF6); } +void paddq(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xD4); } +void pmuludq(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xF4); } +void psubq(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xFB); } +void paddb(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xFC); } +void paddw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xFD); } +void paddd(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xFE); } +void paddsb(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xEC); } +void paddsw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xED); } +void paddusb(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xDC); } +void paddusw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xDD); } +void pcmpeqb(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x74); } +void pcmpeqw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x75); } +void pcmpeqd(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x76); } +void pcmpgtb(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x64); } +void pcmpgtw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x65); } +void pcmpgtd(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x66); } +void psllw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xF1); } +void pslld(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xF2); } +void psllq(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xF3); } +void psraw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xE1); } +void psrad(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xE2); } +void psrlw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xD1); } +void psrld(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xD2); } +void psrlq(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xD3); } +void psubb(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xF8); } +void psubw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xF9); } +void psubd(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xFA); } +void psubsb(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xE8); } +void psubsw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xE9); } +void psubusb(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xD8); } +void psubusw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xD9); } +void psllw(const Mmx& mmx, int imm8) { opMMX_IMM(mmx, imm8, 0x71, 6); } +void pslld(const Mmx& mmx, int imm8) { opMMX_IMM(mmx, imm8, 0x72, 6); } +void psllq(const Mmx& mmx, int imm8) { opMMX_IMM(mmx, imm8, 0x73, 6); } +void psraw(const Mmx& mmx, int imm8) { opMMX_IMM(mmx, imm8, 0x71, 4); } +void psrad(const Mmx& mmx, int imm8) { opMMX_IMM(mmx, imm8, 0x72, 4); } +void psrlw(const Mmx& mmx, int imm8) { opMMX_IMM(mmx, imm8, 0x71, 2); } +void psrld(const Mmx& mmx, int imm8) { opMMX_IMM(mmx, imm8, 0x72, 2); } +void psrlq(const Mmx& mmx, int imm8) { opMMX_IMM(mmx, imm8, 0x73, 2); } +void pslldq(const Xmm& xmm, int imm8) { opMMX_IMM(xmm, imm8, 0x73, 7); } +void psrldq(const Xmm& xmm, int imm8) { opMMX_IMM(xmm, imm8, 0x73, 3); } +void pshufw(const Mmx& mmx, const Operand& op, uint8 imm8) { opMMX(mmx, op, 0x70, 0x00, imm8); } +void pshuflw(const Mmx& mmx, const Operand& op, uint8 imm8) { opMMX(mmx, op, 0x70, 0xF2, imm8); } +void pshufhw(const Mmx& mmx, const Operand& op, uint8 imm8) { opMMX(mmx, op, 0x70, 0xF3, imm8); } +void pshufd(const Mmx& mmx, const Operand& op, uint8 imm8) { opMMX(mmx, op, 0x70, 0x66, imm8); } +void movdqa(const Xmm& xmm, const Operand& op) { opMMX(xmm, op, 0x6F, 0x66); } +void movdqa(const Address& addr, const Xmm& xmm) { db(0x66); opModM(addr, xmm, 0x0F, 0x7F); } +void movdqu(const Xmm& xmm, const Operand& op) { opMMX(xmm, op, 0x6F, 0xF3); } +void movdqu(const Address& addr, const Xmm& xmm) { db(0xF3); opModM(addr, xmm, 0x0F, 0x7F); } +void movaps(const Xmm& xmm, const Operand& op) { opMMX(xmm, op, 0x28, 0x100); } +void movaps(const Address& addr, const Xmm& xmm) { opModM(addr, xmm, 0x0F, 0x29); } +void movss(const Xmm& xmm, const Operand& op) { opMMX(xmm, op, 0x10, 0xF3); } +void movss(const Address& addr, const Xmm& xmm) { db(0xF3); opModM(addr, xmm, 0x0F, 0x11); } +void movups(const Xmm& xmm, const Operand& op) { opMMX(xmm, op, 0x10, 0x100); } +void movups(const Address& addr, const Xmm& xmm) { opModM(addr, xmm, 0x0F, 0x11); } +void movapd(const Xmm& xmm, const Operand& op) { opMMX(xmm, op, 0x28, 0x66); } +void movapd(const Address& addr, const Xmm& xmm) { db(0x66); opModM(addr, xmm, 0x0F, 0x29); } +void movsd(const Xmm& xmm, const Operand& op) { opMMX(xmm, op, 0x10, 0xF2); } +void movsd(const Address& addr, const Xmm& xmm) { db(0xF2); opModM(addr, xmm, 0x0F, 0x11); } +void movupd(const Xmm& xmm, const Operand& op) { opMMX(xmm, op, 0x10, 0x66); } +void movupd(const Address& addr, const Xmm& xmm) { db(0x66); opModM(addr, xmm, 0x0F, 0x11); } +void addps(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x58, 0x100, isXMM_XMMorMEM); } +void addss(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x58, 0xF3, isXMM_XMMorMEM); } +void addpd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x58, 0x66, isXMM_XMMorMEM); } +void addsd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x58, 0xF2, isXMM_XMMorMEM); } +void andnps(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x55, 0x100, isXMM_XMMorMEM); } +void andnpd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x55, 0x66, isXMM_XMMorMEM); } +void andps(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x54, 0x100, isXMM_XMMorMEM); } +void andpd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x54, 0x66, isXMM_XMMorMEM); } +void cmpps(const Xmm& xmm, const Operand& op, uint8 imm8) { opGen(xmm, op, 0xC2, 0x100, isXMM_XMMorMEM, imm8); } +void cmpss(const Xmm& xmm, const Operand& op, uint8 imm8) { opGen(xmm, op, 0xC2, 0xF3, isXMM_XMMorMEM, imm8); } +void cmppd(const Xmm& xmm, const Operand& op, uint8 imm8) { opGen(xmm, op, 0xC2, 0x66, isXMM_XMMorMEM, imm8); } +void cmpsd(const Xmm& xmm, const Operand& op, uint8 imm8) { opGen(xmm, op, 0xC2, 0xF2, isXMM_XMMorMEM, imm8); } +void divps(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x5E, 0x100, isXMM_XMMorMEM); } +void divss(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x5E, 0xF3, isXMM_XMMorMEM); } +void divpd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x5E, 0x66, isXMM_XMMorMEM); } +void divsd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x5E, 0xF2, isXMM_XMMorMEM); } +void maxps(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x5F, 0x100, isXMM_XMMorMEM); } +void maxss(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x5F, 0xF3, isXMM_XMMorMEM); } +void maxpd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x5F, 0x66, isXMM_XMMorMEM); } +void maxsd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x5F, 0xF2, isXMM_XMMorMEM); } +void minps(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x5D, 0x100, isXMM_XMMorMEM); } +void minss(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x5D, 0xF3, isXMM_XMMorMEM); } +void minpd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x5D, 0x66, isXMM_XMMorMEM); } +void minsd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x5D, 0xF2, isXMM_XMMorMEM); } +void mulps(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x59, 0x100, isXMM_XMMorMEM); } +void mulss(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x59, 0xF3, isXMM_XMMorMEM); } +void mulpd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x59, 0x66, isXMM_XMMorMEM); } +void mulsd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x59, 0xF2, isXMM_XMMorMEM); } +void orps(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x56, 0x100, isXMM_XMMorMEM); } +void orpd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x56, 0x66, isXMM_XMMorMEM); } +void rcpps(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x53, 0x100, isXMM_XMMorMEM); } +void rcpss(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x53, 0xF3, isXMM_XMMorMEM); } +void rsqrtps(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x52, 0x100, isXMM_XMMorMEM); } +void rsqrtss(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x52, 0xF3, isXMM_XMMorMEM); } +void shufps(const Xmm& xmm, const Operand& op, uint8 imm8) { opGen(xmm, op, 0xC6, 0x100, isXMM_XMMorMEM, imm8); } +void shufpd(const Xmm& xmm, const Operand& op, uint8 imm8) { opGen(xmm, op, 0xC6, 0x66, isXMM_XMMorMEM, imm8); } +void sqrtps(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x51, 0x100, isXMM_XMMorMEM); } +void sqrtss(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x51, 0xF3, isXMM_XMMorMEM); } +void sqrtpd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x51, 0x66, isXMM_XMMorMEM); } +void sqrtsd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x51, 0xF2, isXMM_XMMorMEM); } +void subps(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x5C, 0x100, isXMM_XMMorMEM); } +void subss(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x5C, 0xF3, isXMM_XMMorMEM); } +void subpd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x5C, 0x66, isXMM_XMMorMEM); } +void subsd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x5C, 0xF2, isXMM_XMMorMEM); } +void unpckhps(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x15, 0x100, isXMM_XMMorMEM); } +void unpckhpd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x15, 0x66, isXMM_XMMorMEM); } +void unpcklps(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x14, 0x100, isXMM_XMMorMEM); } +void unpcklpd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x14, 0x66, isXMM_XMMorMEM); } +void xorps(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x57, 0x100, isXMM_XMMorMEM); } +void xorpd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x57, 0x66, isXMM_XMMorMEM); } +void maskmovdqu(const Xmm& reg1, const Xmm& reg2) { db(0x66); opModR(reg1, reg2, 0x0F, 0xF7); } +void movhlps(const Xmm& reg1, const Xmm& reg2) { opModR(reg1, reg2, 0x0F, 0x12); } +void movlhps(const Xmm& reg1, const Xmm& reg2) { opModR(reg1, reg2, 0x0F, 0x16); } +void punpckhqdq(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x6D, 0x66, isXMM_XMMorMEM); } +void punpcklqdq(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x6C, 0x66, isXMM_XMMorMEM); } +void comiss(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x2F, 0x100, isXMM_XMMorMEM); } +void ucomiss(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x2E, 0x100, isXMM_XMMorMEM); } +void comisd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x2F, 0x66, isXMM_XMMorMEM); } +void ucomisd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x2E, 0x66, isXMM_XMMorMEM); } +void cvtpd2ps(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x5A, 0x66, isXMM_XMMorMEM); } +void cvtps2pd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x5A, 0x100, isXMM_XMMorMEM); } +void cvtsd2ss(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x5A, 0xF2, isXMM_XMMorMEM); } +void cvtss2sd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x5A, 0xF3, isXMM_XMMorMEM); } +void cvtpd2dq(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0xE6, 0xF2, isXMM_XMMorMEM); } +void cvttpd2dq(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0xE6, 0x66, isXMM_XMMorMEM); } +void cvtdq2pd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0xE6, 0xF3, isXMM_XMMorMEM); } +void cvtps2dq(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x5B, 0x66, isXMM_XMMorMEM); } +void cvttps2dq(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x5B, 0xF3, isXMM_XMMorMEM); } +void cvtdq2ps(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x5B, 0x100, isXMM_XMMorMEM); } +void addsubpd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0xD0, 0x66, isXMM_XMMorMEM); } +void addsubps(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0xD0, 0xF2, isXMM_XMMorMEM); } +void haddpd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x7C, 0x66, isXMM_XMMorMEM); } +void haddps(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x7C, 0xF2, isXMM_XMMorMEM); } +void hsubpd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x7D, 0x66, isXMM_XMMorMEM); } +void hsubps(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x7D, 0xF2, isXMM_XMMorMEM); } +void movddup(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x12, 0xF2, isXMM_XMMorMEM); } +void movshdup(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x16, 0xF3, isXMM_XMMorMEM); } +void movsldup(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x12, 0xF3, isXMM_XMMorMEM); } +void cvtpi2ps(const Operand& reg, const Operand& op) { opGen(reg, op, 0x2A, 0x100, isXMM_MMXorMEM); } +void cvtps2pi(const Operand& reg, const Operand& op) { opGen(reg, op, 0x2D, 0x100, isMMX_XMMorMEM); } +void cvtsi2ss(const Operand& reg, const Operand& op) { opGen(reg, op, 0x2A, 0xF3, isXMM_REG32orMEM); } +void cvtss2si(const Operand& reg, const Operand& op) { opGen(reg, op, 0x2D, 0xF3, isREG32_XMMorMEM); } +void cvttps2pi(const Operand& reg, const Operand& op) { opGen(reg, op, 0x2C, 0x100, isMMX_XMMorMEM); } +void cvttss2si(const Operand& reg, const Operand& op) { opGen(reg, op, 0x2C, 0xF3, isREG32_XMMorMEM); } +void cvtpi2pd(const Operand& reg, const Operand& op) { opGen(reg, op, 0x2A, 0x66, isXMM_MMXorMEM); } +void cvtpd2pi(const Operand& reg, const Operand& op) { opGen(reg, op, 0x2D, 0x66, isMMX_XMMorMEM); } +void cvtsi2sd(const Operand& reg, const Operand& op) { opGen(reg, op, 0x2A, 0xF2, isXMM_REG32orMEM); } +void cvtsd2si(const Operand& reg, const Operand& op) { opGen(reg, op, 0x2D, 0xF2, isREG32_XMMorMEM); } +void cvttpd2pi(const Operand& reg, const Operand& op) { opGen(reg, op, 0x2C, 0x66, isMMX_XMMorMEM); } +void cvttsd2si(const Operand& reg, const Operand& op) { opGen(reg, op, 0x2C, 0xF2, isREG32_XMMorMEM); } +void prefetcht0(const Address& addr) { opModM(addr, Reg32(1), 0x0F, B00011000); } +void prefetcht1(const Address& addr) { opModM(addr, Reg32(2), 0x0F, B00011000); } +void prefetcht2(const Address& addr) { opModM(addr, Reg32(3), 0x0F, B00011000); } +void prefetchnta(const Address& addr) { opModM(addr, Reg32(0), 0x0F, B00011000); } +void movhps(const Operand& op1, const Operand& op2) { opMovXMM(op1, op2, 0x16, 0x100); } +void movlps(const Operand& op1, const Operand& op2) { opMovXMM(op1, op2, 0x12, 0x100); } +void movhpd(const Operand& op1, const Operand& op2) { opMovXMM(op1, op2, 0x16, 0x66); } +void movlpd(const Operand& op1, const Operand& op2) { opMovXMM(op1, op2, 0x12, 0x66); } +void cmovo(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 0); } +void jo(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x70, 0x80, 0x0F); } +void seto(const Operand& op) { opR_ModM(op, 8, 3, 0, 0x0F, B10010000 | 0); } +void cmovno(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 1); } +void jno(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x71, 0x81, 0x0F); } +void setno(const Operand& op) { opR_ModM(op, 8, 3, 0, 0x0F, B10010000 | 1); } +void cmovb(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 2); } +void jb(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x72, 0x82, 0x0F); } +void setb(const Operand& op) { opR_ModM(op, 8, 3, 0, 0x0F, B10010000 | 2); } +void cmovnae(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 2); } +void jnae(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x72, 0x82, 0x0F); } +void setnae(const Operand& op) { opR_ModM(op, 8, 3, 0, 0x0F, B10010000 | 2); } +void cmovnb(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 3); } +void jnb(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x73, 0x83, 0x0F); } +void setnb(const Operand& op) { opR_ModM(op, 8, 3, 0, 0x0F, B10010000 | 3); } +void cmovae(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 3); } +void jae(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x73, 0x83, 0x0F); } +void setae(const Operand& op) { opR_ModM(op, 8, 3, 0, 0x0F, B10010000 | 3); } +void cmove(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 4); } +void je(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x74, 0x84, 0x0F); } +void sete(const Operand& op) { opR_ModM(op, 8, 3, 0, 0x0F, B10010000 | 4); } +void cmovz(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 4); } +void jz(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x74, 0x84, 0x0F); } +void setz(const Operand& op) { opR_ModM(op, 8, 3, 0, 0x0F, B10010000 | 4); } +void cmovne(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 5); } +void jne(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x75, 0x85, 0x0F); } +void setne(const Operand& op) { opR_ModM(op, 8, 3, 0, 0x0F, B10010000 | 5); } +void cmovnz(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 5); } +void jnz(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x75, 0x85, 0x0F); } +void setnz(const Operand& op) { opR_ModM(op, 8, 3, 0, 0x0F, B10010000 | 5); } +void cmovbe(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 6); } +void jbe(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x76, 0x86, 0x0F); } +void setbe(const Operand& op) { opR_ModM(op, 8, 3, 0, 0x0F, B10010000 | 6); } +void cmovna(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 6); } +void jna(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x76, 0x86, 0x0F); } +void setna(const Operand& op) { opR_ModM(op, 8, 3, 0, 0x0F, B10010000 | 6); } +void cmovnbe(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 7); } +void jnbe(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x77, 0x87, 0x0F); } +void setnbe(const Operand& op) { opR_ModM(op, 8, 3, 0, 0x0F, B10010000 | 7); } +void cmova(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 7); } +void ja(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x77, 0x87, 0x0F); } +void seta(const Operand& op) { opR_ModM(op, 8, 3, 0, 0x0F, B10010000 | 7); } +void cmovs(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 8); } +void js(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x78, 0x88, 0x0F); } +void sets(const Operand& op) { opR_ModM(op, 8, 3, 0, 0x0F, B10010000 | 8); } +void cmovns(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 9); } +void jns(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x79, 0x89, 0x0F); } +void setns(const Operand& op) { opR_ModM(op, 8, 3, 0, 0x0F, B10010000 | 9); } +void cmovp(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 10); } +void jp(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x7A, 0x8A, 0x0F); } +void setp(const Operand& op) { opR_ModM(op, 8, 3, 0, 0x0F, B10010000 | 10); } +void cmovpe(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 10); } +void jpe(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x7A, 0x8A, 0x0F); } +void setpe(const Operand& op) { opR_ModM(op, 8, 3, 0, 0x0F, B10010000 | 10); } +void cmovnp(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 11); } +void jnp(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x7B, 0x8B, 0x0F); } +void setnp(const Operand& op) { opR_ModM(op, 8, 3, 0, 0x0F, B10010000 | 11); } +void cmovpo(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 11); } +void jpo(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x7B, 0x8B, 0x0F); } +void setpo(const Operand& op) { opR_ModM(op, 8, 3, 0, 0x0F, B10010000 | 11); } +void cmovl(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 12); } +void jl(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x7C, 0x8C, 0x0F); } +void setl(const Operand& op) { opR_ModM(op, 8, 3, 0, 0x0F, B10010000 | 12); } +void cmovnge(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 12); } +void jnge(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x7C, 0x8C, 0x0F); } +void setnge(const Operand& op) { opR_ModM(op, 8, 3, 0, 0x0F, B10010000 | 12); } +void cmovnl(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 13); } +void jnl(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x7D, 0x8D, 0x0F); } +void setnl(const Operand& op) { opR_ModM(op, 8, 3, 0, 0x0F, B10010000 | 13); } +void cmovge(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 13); } +void jge(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x7D, 0x8D, 0x0F); } +void setge(const Operand& op) { opR_ModM(op, 8, 3, 0, 0x0F, B10010000 | 13); } +void cmovle(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 14); } +void jle(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x7E, 0x8E, 0x0F); } +void setle(const Operand& op) { opR_ModM(op, 8, 3, 0, 0x0F, B10010000 | 14); } +void cmovng(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 14); } +void jng(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x7E, 0x8E, 0x0F); } +void setng(const Operand& op) { opR_ModM(op, 8, 3, 0, 0x0F, B10010000 | 14); } +void cmovnle(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 15); } +void jnle(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x7F, 0x8F, 0x0F); } +void setnle(const Operand& op) { opR_ModM(op, 8, 3, 0, 0x0F, B10010000 | 15); } +void cmovg(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 15); } +void jg(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x7F, 0x8F, 0x0F); } +void setg(const Operand& op) { opR_ModM(op, 8, 3, 0, 0x0F, B10010000 | 15); } +#ifdef XBYAK64 +void cdqe() { db(0x48); db(0x98); } +#else +void aaa() { db(0x37); } +void aad() { db(0xD5); db(0x0A); } +void aam() { db(0xD4); db(0x0A); } +void aas() { db(0x3F); } +void daa() { db(0x27); } +void das() { db(0x2F); } +void popad() { db(0x61); } +void popfd() { db(0x9D); } +void pusha() { db(0x60); } +void pushad() { db(0x60); } +void pushfd() { db(0x9C); } +void popa() { db(0x61); } +#endif +void cbw() { db(0x66); db(0x98); } +void cdq() { db(0x99); } +void clc() { db(0xF8); } +void cld() { db(0xFC); } +void cli() { db(0xFA); } +void cmc() { db(0xF5); } +void cpuid() { db(0x0F); db(0xA2); } +void cwd() { db(0x66); db(0x99); } +void cwde() { db(0x98); } +void lahf() { db(0x9F); } +void lock() { db(0xF0); } +void nop() { db(0x90); } +void sahf() { db(0x9E); } +void stc() { db(0xF9); } +void std() { db(0xFD); } +void sti() { db(0xFB); } +void emms() { db(0x0F); db(0x77); } +void pause() { db(0xF3); db(0x90); } +void sfence() { db(0x0F); db(0xAE); db(0xF8); } +void lfence() { db(0x0F); db(0xAE); db(0xE8); } +void mfence() { db(0x0F); db(0xAE); db(0xF0); } +void monitor() { db(0x0F); db(0x01); db(0xC8); } +void mwait() { db(0x0F); db(0x01); db(0xC9); } +void rdmsr() { db(0x0F); db(0x32); } +void rdpmc() { db(0x0F); db(0x33); } +void rdtsc() { db(0x0F); db(0x31); } +void wait() { db(0x9B); } +void wbinvd() { db(0x0F); db(0x09); } +void wrmsr() { db(0x0F); db(0x30); } +void xlatb() { db(0xD7); } +void popf() { db(0x9D); } +void pushf() { db(0x9C); } +void adc(const Operand& op1, const Operand& op2) { opRM_RM(op1, op2, 0x10); } +void adc(const Operand& op, uint32 imm) { opRM_I(op, imm, 0x10, 2); } +void add(const Operand& op1, const Operand& op2) { opRM_RM(op1, op2, 0x00); } +void add(const Operand& op, uint32 imm) { opRM_I(op, imm, 0x00, 0); } +void and(const Operand& op1, const Operand& op2) { opRM_RM(op1, op2, 0x20); } +void and(const Operand& op, uint32 imm) { opRM_I(op, imm, 0x20, 4); } +void cmp(const Operand& op1, const Operand& op2) { opRM_RM(op1, op2, 0x38); } +void cmp(const Operand& op, uint32 imm) { opRM_I(op, imm, 0x38, 7); } +void or(const Operand& op1, const Operand& op2) { opRM_RM(op1, op2, 0x08); } +void or(const Operand& op, uint32 imm) { opRM_I(op, imm, 0x08, 1); } +void sbb(const Operand& op1, const Operand& op2) { opRM_RM(op1, op2, 0x18); } +void sbb(const Operand& op, uint32 imm) { opRM_I(op, imm, 0x18, 3); } +void sub(const Operand& op1, const Operand& op2) { opRM_RM(op1, op2, 0x28); } +void sub(const Operand& op, uint32 imm) { opRM_I(op, imm, 0x28, 5); } +void xor(const Operand& op1, const Operand& op2) { opRM_RM(op1, op2, 0x30); } +void xor(const Operand& op, uint32 imm) { opRM_I(op, imm, 0x30, 6); } +void dec(const Operand& op) { opIncDec(op, 0x48, 1); } +void inc(const Operand& op) { opIncDec(op, 0x40, 0); } +void div(const Operand& op) { opR_ModM(op, 0, 3, 6, 0xF6); } +void idiv(const Operand& op) { opR_ModM(op, 0, 3, 7, 0xF6); } +void imul(const Operand& op) { opR_ModM(op, 0, 3, 5, 0xF6); } +void mul(const Operand& op) { opR_ModM(op, 0, 3, 4, 0xF6); } +void neg(const Operand& op) { opR_ModM(op, 0, 3, 3, 0xF6); } +void not(const Operand& op) { opR_ModM(op, 0, 3, 2, 0xF6); } +void rcl(const Operand& op, int imm) { opShift(op, imm, 2); } +void rcl(const Operand& op, const Reg8& cl) { opShift(op, cl, 2); } +void rcr(const Operand& op, int imm) { opShift(op, imm, 3); } +void rcr(const Operand& op, const Reg8& cl) { opShift(op, cl, 3); } +void rol(const Operand& op, int imm) { opShift(op, imm, 0); } +void rol(const Operand& op, const Reg8& cl) { opShift(op, cl, 0); } +void ror(const Operand& op, int imm) { opShift(op, imm, 1); } +void ror(const Operand& op, const Reg8& cl) { opShift(op, cl, 1); } +void sar(const Operand& op, int imm) { opShift(op, imm, 7); } +void sar(const Operand& op, const Reg8& cl) { opShift(op, cl, 7); } +void shl(const Operand& op, int imm) { opShift(op, imm, 4); } +void shl(const Operand& op, const Reg8& cl) { opShift(op, cl, 4); } +void shr(const Operand& op, int imm) { opShift(op, imm, 5); } +void shr(const Operand& op, const Reg8& cl) { opShift(op, cl, 5); } +void sal(const Operand& op, int imm) { opShift(op, imm, 4); } +void sal(const Operand& op, const Reg8& cl) { opShift(op, cl, 4); } +void shld(const Operand& op, const Reg& reg, uint8 imm) { opShxd(op, reg, imm, 0xA4); } +void shld(const Operand& op, const Reg& reg, const Reg8& cl) { opShxd(op, reg, 0, 0xA4, &cl); } +void shrd(const Operand& op, const Reg& reg, uint8 imm) { opShxd(op, reg, imm, 0xAC); } +void shrd(const Operand& op, const Reg& reg, const Reg8& cl) { opShxd(op, reg, 0, 0xAC, &cl); } +void bsf(const Reg®, const Operand& op) { opModRM(reg, op, op.isREG(16 | i32e), op.isMEM(), 0x0F, 0xBC); } +void bsr(const Reg®, const Operand& op) { opModRM(reg, op, op.isREG(16 | i32e), op.isMEM(), 0x0F, 0xBD); } +void pshufb(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x00, 0x66, 256, 0x38); } +void phaddw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x01, 0x66, 256, 0x38); } +void phaddd(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x02, 0x66, 256, 0x38); } +void phaddsw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x03, 0x66, 256, 0x38); } +void pmaddubsw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x04, 0x66, 256, 0x38); } +void phsubw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x05, 0x66, 256, 0x38); } +void phsubd(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x06, 0x66, 256, 0x38); } +void phsubsw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x07, 0x66, 256, 0x38); } +void psignb(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x08, 0x66, 256, 0x38); } +void psignw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x09, 0x66, 256, 0x38); } +void psignd(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x0A, 0x66, 256, 0x38); } +void pmulhrsw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x0B, 0x66, 256, 0x38); } +void pabsb(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x1C, 0x66, 256, 0x38); } +void pabsw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x1D, 0x66, 256, 0x38); } +void pabsd(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x1E, 0x66, 256, 0x38); } +void palignr(const Mmx& mmx, const Operand& op, int imm) { opMMX(mmx, op, 0x0f, 0x66, static_cast(imm), 0x3a); } +void blendvpd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x15, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void blendvps(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x14, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void packusdw(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x2B, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void pblendvb(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x10, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void pcmpeqq(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x29, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void ptest(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x17, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void pmovsxbw(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x20, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void pmovsxbd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x21, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void pmovsxbq(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x22, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void pmovsxwd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x23, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void pmovsxwq(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x24, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void pmovsxdq(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x25, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void pmovzxbw(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x30, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void pmovzxbd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x31, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void pmovzxbq(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x32, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void pmovzxwd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x33, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void pmovzxwq(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x34, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void pmovzxdq(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x35, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void pminsb(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x38, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void pminsd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x39, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void pminuw(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x3A, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void pminud(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x3B, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void pmaxsb(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x3C, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void pmaxsd(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x3D, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void pmaxuw(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x3E, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void pmaxud(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x3F, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void pmuldq(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x28, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void pmulld(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x40, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void phminposuw(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x41, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void pcmpgtq(const Xmm& xmm, const Operand& op) { opGen(xmm, op, 0x37, 0x66, isXMM_XMMorMEM, 256, 0x38); } +void blendpd(const Xmm& xmm, const Operand& op, int imm) { opGen(xmm, op, 0x0D, 0x66, isXMM_XMMorMEM, static_cast(imm), 0x3A); } +void blendps(const Xmm& xmm, const Operand& op, int imm) { opGen(xmm, op, 0x0C, 0x66, isXMM_XMMorMEM, static_cast(imm), 0x3A); } +void dppd(const Xmm& xmm, const Operand& op, int imm) { opGen(xmm, op, 0x41, 0x66, isXMM_XMMorMEM, static_cast(imm), 0x3A); } +void dpps(const Xmm& xmm, const Operand& op, int imm) { opGen(xmm, op, 0x40, 0x66, isXMM_XMMorMEM, static_cast(imm), 0x3A); } +void mpsadbw(const Xmm& xmm, const Operand& op, int imm) { opGen(xmm, op, 0x42, 0x66, isXMM_XMMorMEM, static_cast(imm), 0x3A); } +void pblendw(const Xmm& xmm, const Operand& op, int imm) { opGen(xmm, op, 0x0E, 0x66, isXMM_XMMorMEM, static_cast(imm), 0x3A); } +void roundps(const Xmm& xmm, const Operand& op, int imm) { opGen(xmm, op, 0x08, 0x66, isXMM_XMMorMEM, static_cast(imm), 0x3A); } +void roundpd(const Xmm& xmm, const Operand& op, int imm) { opGen(xmm, op, 0x09, 0x66, isXMM_XMMorMEM, static_cast(imm), 0x3A); } +void roundss(const Xmm& xmm, const Operand& op, int imm) { opGen(xmm, op, 0x0A, 0x66, isXMM_XMMorMEM, static_cast(imm), 0x3A); } +void roundsd(const Xmm& xmm, const Operand& op, int imm) { opGen(xmm, op, 0x0B, 0x66, isXMM_XMMorMEM, static_cast(imm), 0x3A); } +void pcmpestrm(const Xmm& xmm, const Operand& op, int imm) { opGen(xmm, op, 0x60, 0x66, isXMM_XMMorMEM, static_cast(imm), 0x3A); } +void pcmpestri(const Xmm& xmm, const Operand& op, int imm) { opGen(xmm, op, 0x61, 0x66, isXMM_XMMorMEM, static_cast(imm), 0x3A); } +void pcmpistrm(const Xmm& xmm, const Operand& op, int imm) { opGen(xmm, op, 0x62, 0x66, isXMM_XMMorMEM, static_cast(imm), 0x3A); } +void pcmpistri(const Xmm& xmm, const Operand& op, int imm) { opGen(xmm, op, 0x63, 0x66, isXMM_XMMorMEM, static_cast(imm), 0x3A); } +void ldmxcsr(const Address& addr) { opModM(addr, Reg32(2), 0x0F, 0xAE); } +void stmxcsr(const Address& addr) { opModM(addr, Reg32(3), 0x0F, 0xAE); } +void clflush(const Address& addr) { opModM(addr, Reg32(7), 0x0F, 0xAE); } +void movntpd(const Address& addr, const Xmm& reg) { opModM(addr, Reg16(reg.getIdx()), 0x0F, 0x2B); } +void movntdq(const Address& addr, const Xmm& reg) { opModM(addr, Reg16(reg.getIdx()), 0x0F, 0xE7); } +void movsx(const Reg& reg, const Operand& op) { opMovxx(reg, op, 0xBE); } +void movzx(const Reg& reg, const Operand& op) { opMovxx(reg, op, 0xB6); } diff --git a/plugins/GSdx/xbyak/xbyak_util.h b/plugins/GSdx/xbyak/xbyak_util.h new file mode 100644 index 0000000000..8eb2a8e952 --- /dev/null +++ b/plugins/GSdx/xbyak/xbyak_util.h @@ -0,0 +1,185 @@ +#ifndef XBYAK_XBYAK_UTIL_H_ +#define XBYAK_XBYAK_UTIL_H_ + +/** + utility class for Xbyak + @note this header is under construction +*/ + +#ifdef _WIN32 + #if (_MSC_VER < 1400) && defined(XBYAK32) + static inline __declspec(naked) void __cpuid(int[4], int) + { + __asm { + push ebx + push esi + mov eax, dword ptr [esp + 4 * 2 + 8] // eaxIn + cpuid + mov esi, dword ptr [esp + 4 * 2 + 4] // data + mov dword ptr [esi], eax + mov dword ptr [esi + 4], ebx + mov dword ptr [esi + 8], ecx + mov dword ptr [esi + 12], edx + pop esi + pop ebx + ret + } + } + #else + #include // for __cpuid + #endif +#else + #if __GNUC_PREREQ(4, 3) + #include + #else + #define __cpuid(eaxIn, a, b, c, d) __asm__("cpuid\n" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(eaxIn)) + #endif +#endif + +namespace Xbyak { namespace util { + +/** + CPU detection class +*/ +class Cpu { + unsigned int type_; +public: + static inline void getCpuid(unsigned int eaxIn, unsigned int data[4]) + { +#ifdef _WIN32 + __cpuid(reinterpret_cast(data), eaxIn); +#else + __cpuid(eaxIn, data[0], data[1], data[2], data[3]); +#endif + } + enum Type { + NONE = 0, + tMMX = 1 << 0, + tMMX2 = 1 << 1, + tCMOV = 1 << 2, + tSSE = 1 << 3, + tSSE2 = 1 << 4, + tSSE3 = 1 << 5, + tSSSE3 = 1 << 6, + tSSE41 = 1 << 7, + tSSE42 = 1 << 8, + tPOPCNT = 1 << 9, + + t3DN = 1 << 16, + tE3DN = 1 << 17, + tSSE4a = 1 << 18, + tSSE5 = 1 << 11, + + tINTEL = 1 << 24, + tAMD = 1 << 25 + }; + Cpu() + : type_(NONE) + { + unsigned int data[4]; + getCpuid(0, data); + static const char intel[] = "ntel"; + static const char amd[] = "cAMD"; + if (data[2] == *reinterpret_cast(amd)) { + type_ |= tAMD; + getCpuid(0x80000001, data); + if (data[3] & (1 << 31)) type_ |= t3DN; + if (data[3] & (1 << 15)) type_ |= tCMOV; + if (data[3] & (1 << 30)) type_ |= tE3DN; + if (data[3] & (1 << 22)) type_ |= tMMX2; + } + if (data[2] == *reinterpret_cast(intel)) { + type_ |= tINTEL; + } + getCpuid(1, data); + if (data[2] & (1 << 0)) type_ |= tSSE3; + if (data[2] & (1 << 9)) type_ |= tSSSE3; + if (data[2] & (1 << 19)) type_ |= tSSE41; + if (data[2] & (1 << 20)) type_ |= tSSE42; + if (data[2] & (1 << 23)) type_ |= tPOPCNT; + + if (data[3] & (1 << 15)) type_ |= tCMOV; + if (data[3] & (1 << 23)) type_ |= tMMX; + if (data[3] & (1 << 25)) type_ |= tMMX2 | tSSE; + if (data[3] & (1 << 26)) type_ |= tSSE2; + } + bool has(Type type) const + { + return (type & type_) != 0; + } +}; + +#ifdef XBYAK32 + +namespace local { +#ifdef _WIN32 + #define XBYAK_LOCAL_DEFINE_SET_EIP_TO_REG(x) static inline __declspec(naked) void set_eip_to_ ## x() { \ + __asm { mov x, dword ptr [esp] } __asm { ret } \ + } +#else + #define XBYAK_LOCAL_DEFINE_SET_EIP_TO_REG(x) static inline void set_eip_to_ ## x() { \ + __asm__ volatile("movl (%esp), %" #x); \ + } +#endif + +XBYAK_LOCAL_DEFINE_SET_EIP_TO_REG(eax) +XBYAK_LOCAL_DEFINE_SET_EIP_TO_REG(ecx) +XBYAK_LOCAL_DEFINE_SET_EIP_TO_REG(edx) +XBYAK_LOCAL_DEFINE_SET_EIP_TO_REG(ebx) +XBYAK_LOCAL_DEFINE_SET_EIP_TO_REG(esi) +XBYAK_LOCAL_DEFINE_SET_EIP_TO_REG(edi) +XBYAK_LOCAL_DEFINE_SET_EIP_TO_REG(ebp) + +#undef XBYAK_LOCAL_DEFINE_SET_EIP_TO_REG +} // end of local + +template +struct EnableSetEip : public Gen { + EnableSetEip(size_t maxSize = DEFAULT_MAX_CODE_SIZE, void *userPtr = 0) + : Gen(maxSize, userPtr) + { + } + /** + get pid to out register + @note out = eax or ecx or edx + */ + void setEipTo(const Xbyak::Reg32& out) + { +#if 0 + Gen::call(Gen::getCurr() + 5); + Gen::pop(out); +#else + int idx = out.getIdx(); + switch (idx) { + case Xbyak::Operand::EAX: + Gen::call((void*)local::set_eip_to_eax); + break; + case Xbyak::Operand::ECX: + Gen::call((void*)local::set_eip_to_ecx); + break; + case Xbyak::Operand::EDX: + Gen::call((void*)local::set_eip_to_edx); + break; + case Xbyak::Operand::EBX: + Gen::call((void*)local::set_eip_to_ebx); + break; + case Xbyak::Operand::ESI: + Gen::call((void*)local::set_eip_to_esi); + break; + case Xbyak::Operand::EDI: + Gen::call((void*)local::set_eip_to_esi); + break; + case Xbyak::Operand::EBP: + Gen::call((void*)local::set_eip_to_ebp); + break; + default: + assert(0); + } +#endif + } +}; +#endif + +} } // end of util +#endif +