123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675 |
- #include <assert.h>
- #include <math.h>
- #include <stdbool.h>
- #include <stdint.h>
- #include <stdlib.h>
- #include "arith.h"
- #include "const.h"
- #include "cpu.h"
- #include "fpu.h"
- #include "global_pointers.h"
- #include "instructions.h"
- #include "instructions_0f.h"
- #include "js_imports.h"
- #include "log.h"
- #include "memory.h"
- #include "misc_instr.h"
- #include "sse_instr.h"
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wunused-parameter"
- bool* const apic_enabled;
- void instr_0F00_0_mem(int32_t addr) {
- // sldt
- if(!protected_mode[0] || vm86_mode()) trigger_ud();
- safe_write16(addr, sreg[LDTR]);
- }
- void instr_0F00_0_reg(int32_t r) {
- if(!protected_mode[0] || vm86_mode()) trigger_ud();
- write_reg_osize(r, sreg[LDTR]);
- }
- void instr_0F00_1_mem(int32_t addr) {
- // str
- if(!protected_mode[0] || vm86_mode()) trigger_ud();
- safe_write16(addr, sreg[TR]);
- }
- void instr_0F00_1_reg(int32_t r) {
- if(!protected_mode[0] || vm86_mode()) trigger_ud();
- write_reg_osize(r, sreg[TR]);
- }
- void instr_0F00_2_mem(int32_t addr) {
- // lldt
- if(!protected_mode[0] || vm86_mode()) trigger_ud();
- if(cpl[0]) trigger_gp(0);
- load_ldt(safe_read16(addr));
- }
- void instr_0F00_2_reg(int32_t r) {
- if(!protected_mode[0] || vm86_mode()) trigger_ud();
- if(cpl[0]) trigger_gp(0);
- load_ldt(read_reg16(r));
- }
- void instr_0F00_3_mem(int32_t addr) {
- // ltr
- if(!protected_mode[0] || vm86_mode()) trigger_ud();
- if(cpl[0]) trigger_gp(0);
- load_tr(safe_read16(addr));
- }
- void instr_0F00_3_reg(int32_t r) {
- if(!protected_mode[0] || vm86_mode()) trigger_ud();
- if(cpl[0]) trigger_gp(0);
- load_tr(read_reg16(r));
- }
- void instr_0F00_4_mem(int32_t addr) {
- if(!protected_mode[0] || vm86_mode()) trigger_ud();
- verr(safe_read16(addr));
- }
- void instr_0F00_4_reg(int32_t r) {
- if(!protected_mode[0] || vm86_mode()) trigger_ud();
- verr(read_reg16(r));
- }
- void instr_0F00_5_mem(int32_t addr) {
- if(!protected_mode[0] || vm86_mode()) trigger_ud();
- verw(safe_read16(addr));
- }
- void instr_0F00_5_reg(int32_t r) {
- if(!protected_mode[0] || vm86_mode()) trigger_ud();
- verw(read_reg16(r));
- }
- void instr_0F01_0_reg(int32_t r) { trigger_ud(); }
- void instr_0F01_0_mem(int32_t addr) {
- // sgdt
- writable_or_pagefault(addr, 6);
- int32_t mask = is_osize_32() ? -1 : 0x00FFFFFF;
- safe_write16(addr, gdtr_size[0]);
- safe_write32(addr + 2, gdtr_offset[0] & mask);
- }
- void instr_0F01_1_reg(int32_t r) { trigger_ud(); }
- void instr_0F01_1_mem(int32_t addr) {
- // sidt
- writable_or_pagefault(addr, 6);
- int32_t mask = is_osize_32() ? -1 : 0x00FFFFFF;
- safe_write16(addr, idtr_size[0]);
- safe_write32(addr + 2, idtr_offset[0] & mask);
- }
- void instr_0F01_2_reg(int32_t r) { trigger_ud(); }
- void instr_0F01_2_mem(int32_t addr) {
- // lgdt
- if(cpl[0]) trigger_gp(0);
- int32_t size = safe_read16(addr);
- int32_t offset = safe_read32s(addr + 2);
- int32_t mask = is_osize_32() ? -1 : 0x00FFFFFF;
- gdtr_size[0] = size;
- gdtr_offset[0] = offset & mask;
- }
- void instr_0F01_3_reg(int32_t r) { trigger_ud(); }
- void instr_0F01_3_mem(int32_t addr) {
- // lidt
- if(cpl[0]) trigger_gp(0);
- int32_t size = safe_read16(addr);
- int32_t offset = safe_read32s(addr + 2);
- int32_t mask = is_osize_32() ? -1 : 0x00FFFFFF;
- idtr_size[0] = size;
- idtr_offset[0] = offset & mask;
- }
- void instr_0F01_4_reg(int32_t r) {
- // smsw
- write_reg_osize(r, cr[0]);
- }
- void instr_0F01_4_mem(int32_t addr) {
- safe_write16(addr, cr[0] & 0xFFFF);
- }
- void lmsw(int32_t new_cr0) {
- new_cr0 = (cr[0] & ~0xF) | (new_cr0 & 0xF);
- if(protected_mode[0])
- {
- // lmsw cannot be used to switch back
- new_cr0 |= CR0_PE;
- }
- set_cr0(new_cr0);
- }
- void instr_0F01_6_reg(int32_t r) {
- if(cpl[0]) trigger_gp(0);
- lmsw(read_reg16(r));
- }
- void instr_0F01_6_mem(int32_t addr) {
- if(cpl[0]) trigger_gp(0);
- lmsw(safe_read16(addr));
- }
- void instr_0F01_7_reg(int32_t r) { trigger_ud(); }
- void instr_0F01_7_mem(int32_t addr) {
- // invlpg
- if(cpl[0]) trigger_gp(0);
- invlpg(addr);
- }
- DEFINE_MODRM_INSTR_READ16(instr16_0F02, write_reg16(r, lar(___, read_reg16(r))))
- DEFINE_MODRM_INSTR_READ16(instr32_0F02, write_reg32(r, lar(___, read_reg32(r))))
- DEFINE_MODRM_INSTR_READ16(instr16_0F03, write_reg16(r, lsl(___, read_reg16(r))))
- DEFINE_MODRM_INSTR_READ16(instr32_0F03, write_reg32(r, lsl(___, read_reg32(r))))
- void instr_0F04() { undefined_instruction(); }
- void instr_0F05() { undefined_instruction(); }
- void instr_0F06() {
- // clts
- if(cpl[0])
- {
- dbg_log("clts #gp");
- trigger_gp(0);
- }
- else
- {
- //dbg_log("clts");
- cr[0] &= ~CR0_TS;
- }
- }
- void instr_0F07() { undefined_instruction(); }
- void instr_0F08() {
- // invd
- todo();
- }
- void instr_0F09() {
- if(cpl[0])
- {
- dbg_log("wbinvd #gp");
- trigger_gp(0);
- }
- // wbinvd
- }
- void instr_0F0A() { undefined_instruction(); }
- void instr_0F0B() {
- // UD2
- trigger_ud();
- }
- void instr_0F0C() { undefined_instruction(); }
- void instr_0F0D() {
- // nop
- todo();
- }
- void instr_0F0E() { undefined_instruction(); }
- void instr_0F0F() { undefined_instruction(); }
- void instr_0F10(union reg128 source, int32_t r) {
- // movups xmm, xmm/m128
- mov_rm_r128(source, r);
- }
- DEFINE_SSE_SPLIT(instr_0F10, safe_read128s, read_xmm128s)
- void instr_F30F10_reg(int32_t r1, int32_t r2) {
- // movss xmm, xmm/m32
- task_switch_test_mmx();
- union reg128 data = read_xmm128s(r1);
- union reg128 orig = read_xmm128s(r2);
- write_xmm128(r2, data.u32[0], orig.u32[1], orig.u32[2], orig.u32[3]);
- }
- void instr_F30F10_mem(int32_t addr, int32_t r) {
- // movss xmm, xmm/m32
- task_switch_test_mmx();
- int32_t data = safe_read32s(addr);
- write_xmm128(r, data, 0, 0, 0);
- }
- void instr_660F10(union reg128 source, int32_t r) {
- // movupd xmm, xmm/m128
- mov_rm_r128(source, r);
- }
- DEFINE_SSE_SPLIT(instr_660F10, safe_read128s, read_xmm128s)
- void instr_F20F10_reg(int32_t r1, int32_t r2) {
- // movsd xmm, xmm/m64
- task_switch_test_mmx();
- union reg128 data = read_xmm128s(r1);
- union reg128 orig = read_xmm128s(r2);
- write_xmm128(r2, data.u32[0], data.u32[1], orig.u32[2], orig.u32[3]);
- }
- void instr_F20F10_mem(int32_t addr, int32_t r) {
- // movsd xmm, xmm/m64
- task_switch_test_mmx();
- union reg64 data = safe_read64s(addr);
- write_xmm128(r, data.u32[0], data.u32[1], 0, 0);
- }
- void instr_0F11_reg(int32_t r1, int32_t r2) {
- // movups xmm/m128, xmm
- mov_r_r128(r1, r2);
- }
- void instr_0F11_mem(int32_t addr, int32_t r) {
- // movups xmm/m128, xmm
- mov_r_m128(addr, r);
- }
- void instr_F30F11_reg(int32_t rm_dest, int32_t reg_src) {
- // movss xmm/m32, xmm
- task_switch_test_mmx();
- union reg128 data = read_xmm128s(reg_src);
- union reg128 orig = read_xmm128s(rm_dest);
- write_xmm128(rm_dest, data.u32[0], orig.u32[1], orig.u32[2], orig.u32[3]);
- }
- void instr_F30F11_mem(int32_t addr, int32_t r) {
- // movss xmm/m32, xmm
- task_switch_test_mmx();
- union reg128 data = read_xmm128s(r);
- safe_write32(addr, data.u32[0]);
- }
- void instr_660F11_reg(int32_t r1, int32_t r2) {
- // movupd xmm/m128, xmm
- mov_r_r128(r1, r2);
- }
- void instr_660F11_mem(int32_t addr, int32_t r) {
- // movupd xmm/m128, xmm
- mov_r_m128(addr, r);
- }
- void instr_F20F11_reg(int32_t r1, int32_t r2) {
- // movsd xmm/m64, xmm
- task_switch_test_mmx();
- union reg128 data = read_xmm128s(r2);
- union reg128 orig = read_xmm128s(r1);
- write_xmm128(r1, data.u32[0], data.u32[1], orig.u32[2], orig.u32[3]);
- }
- void instr_F20F11_mem(int32_t addr, int32_t r) {
- // movsd xmm/m64, xmm
- task_switch_test_mmx();
- union reg64 data = read_xmm64s(r);
- safe_write64(addr, data.u64[0]);
- }
- void instr_0F12_mem(int32_t addr, int32_t r) {
- // movlps xmm, m64
- task_switch_test_mmx();
- union reg64 data = safe_read64s(addr);
- union reg128 orig = read_xmm128s(r);
- write_xmm128(r, data.u32[0], data.u32[1], orig.u32[2], orig.u32[3]);
- }
- void instr_0F12_reg(int32_t r1, int32_t r2) {
- // movhlps xmm, xmm
- task_switch_test_mmx();
- union reg128 data = read_xmm128s(r1);
- union reg128 orig = read_xmm128s(r2);
- write_xmm128(r2, data.u32[2], data.u32[3], orig.u32[2], orig.u32[3]);
- }
- void instr_660F12_reg(int32_t r1, int32_t r) { trigger_ud(); }
- void instr_660F12_mem(int32_t addr, int32_t r) {
- // movlpd xmm, m64
- task_switch_test_mmx();
- union reg64 data = safe_read64s(addr);
- write_xmm64(r, data);
- }
- void instr_F20F12_mem(int32_t addr, int32_t r) { unimplemented_sse(); }
- void instr_F20F12_reg(int32_t r1, int32_t r2) { unimplemented_sse(); }
- void instr_F30F12_mem(int32_t addr, int32_t r) { unimplemented_sse(); }
- void instr_F30F12_reg(int32_t r1, int32_t r2) { unimplemented_sse(); }
- void instr_0F13_mem(int32_t addr, int32_t r) {
- // movlps m64, xmm
- movl_r128_m64(addr, r);
- }
- void instr_0F13_reg(int32_t r1, int32_t r2) { unimplemented_sse(); }
- void instr_660F13_reg(int32_t r1, int32_t r) { trigger_ud(); }
- void instr_660F13_mem(int32_t addr, int32_t r) {
- // movlpd xmm/m64, xmm
- movl_r128_m64(addr, r);
- }
- void instr_0F14(union reg64 source, int32_t r) {
- // unpcklps xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg64 destination = read_xmm64s(r);
- write_xmm128(
- r,
- destination.u32[0],
- source.u32[0],
- destination.u32[1],
- source.u32[1]
- );
- }
- DEFINE_SSE_SPLIT(instr_0F14, safe_read64s, read_xmm64s)
- void instr_660F14(union reg64 source, int32_t r) {
- // unpcklpd xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg64 destination = read_xmm64s(r);
- write_xmm128(
- r,
- destination.u32[0],
- destination.u32[1],
- source.u32[0],
- source.u32[1]
- );
- }
- DEFINE_SSE_SPLIT(instr_660F14, safe_read64s, read_xmm64s)
- void instr_0F15(union reg128 source, int32_t r) {
- // unpckhps xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- write_xmm128(
- r,
- destination.u32[2],
- source.u32[2],
- destination.u32[3],
- source.u32[3]
- );
- }
- DEFINE_SSE_SPLIT(instr_0F15, safe_read128s, read_xmm128s)
- void instr_660F15(union reg128 source, int32_t r) {
- // unpckhpd xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- write_xmm128(
- r,
- destination.u32[2],
- destination.u32[3],
- source.u32[2],
- source.u32[3]
- );
- }
- DEFINE_SSE_SPLIT(instr_660F15, safe_read128s, read_xmm128s)
- void instr_0F16_mem(int32_t addr, int32_t r) {
- // movhps xmm, m64
- movh_m64_r128(addr, r);
- }
- void instr_0F16_reg(int32_t r1, int32_t r2) {
- // movlhps xmm, xmm
- task_switch_test_mmx();
- union reg128 data = read_xmm128s(r1);
- union reg128 orig = read_xmm128s(r2);
- write_xmm128(r2, orig.u32[0], orig.u32[1], data.u32[0], data.u32[1]);
- }
- void instr_660F16_mem(int32_t addr, int32_t r) {
- // movhpd xmm, m64
- movh_m64_r128(addr, r);
- }
- void instr_660F16_reg(int32_t r1, int32_t r2) { trigger_ud(); }
- void instr_0F17_mem(int32_t addr, int32_t r) {
- // movhps m64, xmm
- movh_r128_m64(addr, r);
- }
- void instr_0F17_reg(int32_t r1, int32_t r2) { trigger_ud(); }
- void instr_660F17_mem(int32_t addr, int32_t r) {
- // movhpd m64, xmm
- movh_r128_m64(addr, r);
- }
- void instr_660F17_reg(int32_t r1, int32_t r2) { trigger_ud(); }
- void instr_0F18_reg(int32_t r1, int32_t r2) { trigger_ud(); }
- void instr_0F18_mem(int32_t addr, int32_t r) {
- // prefetch
- // nop for us
- }
- void instr_0F19() { unimplemented_sse(); }
- void instr_0F1A() { unimplemented_sse(); }
- void instr_0F1B() { unimplemented_sse(); }
- void instr_0F1C() { unimplemented_sse(); }
- void instr_0F1D() { unimplemented_sse(); }
- void instr_0F1E() { unimplemented_sse(); }
- void instr_0F1F_reg(int32_t r1, int32_t r2) {
- // multi-byte nop
- }
- void instr_0F1F_mem(int32_t addr, int32_t r) {
- // multi-byte nop
- }
- void instr_0F20(int32_t r, int32_t creg) {
- if(cpl[0])
- {
- trigger_gp(0);
- }
- switch(creg)
- {
- case 0:
- write_reg32(r, cr[0]);
- break;
- case 2:
- write_reg32(r, cr[2]);
- break;
- case 3:
- write_reg32(r, cr[3]);
- break;
- case 4:
- write_reg32(r, cr[4]);
- break;
- default:
- dbg_log("%d", creg);
- todo();
- trigger_ud();
- }
- }
- void instr_0F21(int32_t r, int32_t dreg_index) {
- if(cpl[0])
- {
- trigger_gp(0);
- }
- if(dreg_index == 4 || dreg_index == 5)
- {
- if(cr[4] & CR4_DE)
- {
- dbg_log("#ud mov dreg 4/5 with cr4.DE set");
- trigger_ud();
- }
- else
- {
- // DR4 and DR5 refer to DR6 and DR7 respectively
- dreg_index += 2;
- }
- }
- write_reg32(r, dreg[dreg_index]);
- //dbg_log("read dr%d: %x", dreg_index, dreg[dreg_index]);
- }
- void instr_0F22(int32_t r, int32_t creg) {
- if(cpl[0])
- {
- trigger_gp(0);
- }
- int32_t data = read_reg32(r);
- // mov cr, addr
- switch(creg)
- {
- case 0:
- //dbg_log("cr0 <- %x", data);
- set_cr0(data);
- break;
- case 2:
- dbg_log("cr2 <- %x", data);
- cr[2] = data;
- break;
- case 3:
- //dbg_log("cr3 <- %x", data);
- data &= ~0b111111100111;
- dbg_assert_message((data & 0xFFF) == 0, "TODO");
- cr[3] = data;
- clear_tlb();
- //dump_page_directory();
- break;
- case 4:
- dbg_log("cr4 <- %d", cr[4]);
- if(data & (1 << 11 | 1 << 12 | 1 << 15 | 1 << 16 | 1 << 19 | 0xFFC00000))
- {
- trigger_gp(0);
- }
- if((cr[4] ^ data) & CR4_PGE)
- {
- if(data & CR4_PGE)
- {
- // The PGE bit has been enabled. The global TLB is
- // still empty, so we only have to copy it over
- clear_tlb();
- }
- else
- {
- // Clear the global TLB
- full_clear_tlb();
- }
- }
- cr[4] = data;
- page_size_extensions[0] = (cr[4] & CR4_PSE) ? PSE_ENABLED : 0;
- if(cr[4] & CR4_PAE)
- {
- //throw debug.unimpl("PAE");
- assert(false);
- }
- break;
- default:
- dbg_log("%d", creg);
- todo();
- trigger_ud();
- }
- }
- void instr_0F23(int32_t r, int32_t dreg_index) {
- if(cpl[0])
- {
- trigger_gp(0);
- }
- if(dreg_index == 4 || dreg_index == 5)
- {
- if(cr[4] & CR4_DE)
- {
- dbg_log("#ud mov dreg 4/5 with cr4.DE set");
- trigger_ud();
- }
- else
- {
- // DR4 and DR5 refer to DR6 and DR7 respectively
- dreg_index += 2;
- }
- }
- dreg[dreg_index] = read_reg32(r);
- //dbg_log("write dr%d: %x", dreg_index, dreg[dreg_index]);
- }
- void instr_0F24() { undefined_instruction(); }
- void instr_0F25() { undefined_instruction(); }
- void instr_0F26() { undefined_instruction(); }
- void instr_0F27() { undefined_instruction(); }
- void instr_0F28(union reg128 source, int32_t r) {
- // movaps xmm, xmm/m128
- // XXX: Aligned read or #gp
- mov_rm_r128(source, r);
- }
- DEFINE_SSE_SPLIT(instr_0F28, safe_read128s, read_xmm128s)
- void instr_660F28(union reg128 source, int32_t r) {
- // movapd xmm, xmm/m128
- // XXX: Aligned read or #gp
- // Note: Same as movdqa (660F6F)
- mov_rm_r128(source, r);
- }
- DEFINE_SSE_SPLIT(instr_660F28, safe_read128s, read_xmm128s)
- void instr_0F29_mem(int32_t addr, int32_t r) {
- // movaps m128, xmm
- task_switch_test_mmx();
- union reg128 data = read_xmm128s(r);
- // XXX: Aligned write or #gp
- safe_write128(addr, data);
- }
- void instr_0F29_reg(int32_t r1, int32_t r2) {
- // movaps xmm, xmm
- mov_r_r128(r1, r2);
- }
- void instr_660F29_mem(int32_t addr, int32_t r) {
- // movapd m128, xmm
- task_switch_test_mmx();
- union reg128 data = read_xmm128s(r);
- // XXX: Aligned write or #gp
- safe_write128(addr, data);
- }
- void instr_660F29_reg(int32_t r1, int32_t r2) {
- // movapd xmm, xmm
- mov_r_r128(r1, r2);
- }
- void instr_0F2A() { unimplemented_sse(); }
- void instr_0F2B_reg(int32_t r1, int32_t r2) { trigger_ud(); }
- void instr_0F2B_mem(int32_t addr, int32_t r) {
- // movntps m128, xmm
- // XXX: Aligned write or #gp
- mov_r_m128(addr, r);
- }
- void instr_660F2B_reg(int32_t r1, int32_t r2) { trigger_ud(); }
- void instr_660F2B_mem(int32_t addr, int32_t r) {
- // movntpd m128, xmm
- // XXX: Aligned write or #gp
- mov_r_m128(addr, r);
- }
- void instr_0F2C_mem(int32_t addr, int32_t r) { unimplemented_sse(); }
- void instr_0F2C_reg(int32_t r1, int32_t r2) { unimplemented_sse(); }
- void instr_660F2C_mem(int32_t addr, int32_t r) { unimplemented_sse(); }
- void instr_660F2C_reg(int32_t r1, int32_t r2) { unimplemented_sse(); }
- void instr_F20F2C(union reg64 source, int32_t r) {
- // cvttsd2si r32, xmm/m64
- // emscripten bug causes this ported instruction to throw "integer result unpresentable"
- // https://github.com/kripken/emscripten/issues/5433
- task_switch_test_mmx();
- #if 0
- union reg64 source = read_xmm_mem64s();
- double f = source.f64[0];
- if(f <= 0x7FFFFFFF && f >= -0x80000000)
- {
- int32_t si = (int32_t) f;
- write_g32(si);
- }
- else
- {
- write_g32(0x80000000);
- }
- #else
- write_reg32(r, convert_f64_to_i32(source.f64[0]));
- #endif
- }
- DEFINE_SSE_SPLIT(instr_F20F2C, safe_read64s, read_xmm64s)
- void instr_F30F2C_mem(int32_t addr, int32_t r) { unimplemented_sse(); }
- void instr_F30F2C_reg(int32_t r1, int32_t r2) { unimplemented_sse(); }
- void instr_0F2D() { unimplemented_sse(); }
- void instr_0F2E() { unimplemented_sse(); }
- void instr_0F2F() { unimplemented_sse(); }
- // wrmsr
- void instr_0F30() {
- // wrmsr - write maschine specific register
- if(cpl[0])
- {
- trigger_gp(0);
- }
- int32_t index = reg32s[ECX];
- int32_t low = reg32s[EAX];
- int32_t high = reg32s[EDX];
- if(index != IA32_SYSENTER_ESP)
- {
- dbg_log("wrmsr ecx=%x data=%x:%x", index, high, low);
- }
- switch(index)
- {
- case IA32_SYSENTER_CS:
- sysenter_cs[0] = low & 0xFFFF;
- break;
- case IA32_SYSENTER_EIP:
- sysenter_eip[0] = low;
- break;
- case IA32_SYSENTER_ESP:
- sysenter_esp[0] = low;
- break;
- case IA32_APIC_BASE_MSR:
- {
- dbg_assert_message(high == 0, "Changing APIC address (high 32 bits) not supported");
- int32_t address = low & ~(IA32_APIC_BASE_BSP | IA32_APIC_BASE_EXTD | IA32_APIC_BASE_EN);
- dbg_assert_message(address == APIC_ADDRESS, "Changing APIC address not supported");
- dbg_assert_message((low & IA32_APIC_BASE_EXTD) == 0, "x2apic not supported");
- *apic_enabled = (low & IA32_APIC_BASE_EN) == IA32_APIC_BASE_EN;
- }
- break;
- case IA32_TIME_STAMP_COUNTER:
- set_tsc(low, high);
- break;
- case IA32_BIOS_SIGN_ID:
- break;
- case MSR_MISC_FEATURE_ENABLES:
- // Linux 4, see: https://patchwork.kernel.org/patch/9528279/
- break;
- case IA32_MISC_ENABLE: // Enable Misc. Processor Features
- break;
- case IA32_MCG_CAP:
- // netbsd
- break;
- case IA32_KERNEL_GS_BASE:
- // Only used in 64 bit mode (by SWAPGS), but set by kvm-unit-test
- dbg_log("GS Base written");
- break;
- default:
- dbg_log("Unknown msr: %x", index);
- assert(false);
- }
- }
- void instr_0F31() {
- // rdtsc - read timestamp counter
- if(!cpl[0] || !(cr[4] & CR4_TSD))
- {
- uint64_t tsc = read_tsc();
- reg32s[EAX] = tsc;
- reg32s[EDX] = tsc >> 32;
- //dbg_log("rdtsc edx:eax=%x:%x", reg32s[EDX], reg32s[EAX]);
- }
- else
- {
- trigger_gp(0);
- }
- }
- void instr_0F32() {
- // rdmsr - read maschine specific register
- if(cpl[0])
- {
- trigger_gp(0);
- }
- int32_t index = reg32s[ECX];
- dbg_log("rdmsr ecx=%x", index);
- int32_t low = 0;
- int32_t high = 0;
- switch(index)
- {
- case IA32_SYSENTER_CS:
- low = sysenter_cs[0];
- break;
- case IA32_SYSENTER_EIP:
- low = sysenter_eip[0];
- break;
- case IA32_SYSENTER_ESP:
- low = sysenter_esp[0];
- break;
- case IA32_TIME_STAMP_COUNTER:
- {
- uint64_t tsc = read_tsc();
- low = tsc;
- high = tsc >> 32;
- }
- break;
- case IA32_PLATFORM_ID:
- break;
- case IA32_APIC_BASE_MSR:
- if(ENABLE_ACPI)
- {
- low = APIC_ADDRESS;
- if(*apic_enabled)
- {
- low |= IA32_APIC_BASE_EN;
- }
- }
- break;
- case IA32_BIOS_SIGN_ID:
- break;
- case MSR_PLATFORM_INFO:
- low = 1 << 8;
- break;
- case MSR_MISC_FEATURE_ENABLES:
- break;
- case IA32_MISC_ENABLE: // Enable Misc. Processor Features
- low = 1 << 0; // fast string
- break;
- case IA32_RTIT_CTL:
- // linux4
- break;
- case MSR_SMI_COUNT:
- break;
- case IA32_MCG_CAP:
- // netbsd
- break;
- case MSR_PKG_C2_RESIDENCY:
- break;
- default:
- dbg_log("Unknown msr: %x", index);
- assert(false);
- }
- reg32s[EAX] = low;
- reg32s[EDX] = high;
- }
- void instr_0F33() {
- // rdpmc
- todo();
- }
- void instr_0F34() {
- // sysenter
- int32_t seg = sysenter_cs[0] & 0xFFFC;
- if(!protected_mode[0] || seg == 0)
- {
- trigger_gp(0);
- }
- if(CPU_LOG_VERBOSE)
- {
- //dbg_log("sysenter cs:eip=" + h(seg , 4) + ":" + h(sysenter_eip[0], 8) +
- // " ss:esp=" + h(seg + 8, 4) + ":" + h(sysenter_esp[0], 8));
- }
- flags[0] &= ~FLAG_VM & ~FLAG_INTERRUPT;
- instruction_pointer[0] = sysenter_eip[0];
- reg32s[ESP] = sysenter_esp[0];
- sreg[CS] = seg;
- segment_is_null[CS] = 0;
- segment_limits[CS] = -1;
- segment_offsets[CS] = 0;
- update_cs_size(true);
- cpl[0] = 0;
- cpl_changed();
- sreg[SS] = seg + 8;
- segment_is_null[SS] = 0;
- segment_limits[SS] = -1;
- segment_offsets[SS] = 0;
- stack_size_32[0] = true;
- }
- void instr_0F35() {
- // sysexit
- int32_t seg = sysenter_cs[0] & 0xFFFC;
- if(!protected_mode[0] || cpl[0] || seg == 0)
- {
- trigger_gp(0);
- }
- if(CPU_LOG_VERBOSE)
- {
- //dbg_log("sysexit cs:eip=" + h(seg + 16, 4) + ":" + h(reg32s[EDX], 8) +
- // " ss:esp=" + h(seg + 24, 4) + ":" + h(reg32s[ECX], 8));
- }
- instruction_pointer[0] = reg32s[EDX];
- reg32s[ESP] = reg32s[ECX];
- sreg[CS] = seg + 16 | 3;
- segment_is_null[CS] = 0;
- segment_limits[CS] = -1;
- segment_offsets[CS] = 0;
- update_cs_size(true);
- cpl[0] = 3;
- cpl_changed();
- sreg[SS] = seg + 24 | 3;
- segment_is_null[SS] = 0;
- segment_limits[SS] = -1;
- segment_offsets[SS] = 0;
- stack_size_32[0] = true;
- }
- void instr_0F36() { undefined_instruction(); }
- void instr_0F37() {
- // getsec
- todo();
- }
- // sse3+
- void instr_0F38() { unimplemented_sse(); }
- void instr_0F39() { unimplemented_sse(); }
- void instr_0F3A() { unimplemented_sse(); }
- void instr_0F3B() { unimplemented_sse(); }
- void instr_0F3C() { unimplemented_sse(); }
- void instr_0F3D() { unimplemented_sse(); }
- void instr_0F3E() { unimplemented_sse(); }
- void instr_0F3F() { unimplemented_sse(); }
- // cmov
- DEFINE_MODRM_INSTR_READ16(instr16_0F40, cmovcc16( test_o(), ___, r))
- DEFINE_MODRM_INSTR_READ32(instr32_0F40, cmovcc32( test_o(), ___, r))
- DEFINE_MODRM_INSTR_READ16(instr16_0F41, cmovcc16(!test_o(), ___, r))
- DEFINE_MODRM_INSTR_READ32(instr32_0F41, cmovcc32(!test_o(), ___, r))
- DEFINE_MODRM_INSTR_READ16(instr16_0F42, cmovcc16( test_b(), ___, r))
- DEFINE_MODRM_INSTR_READ32(instr32_0F42, cmovcc32( test_b(), ___, r))
- DEFINE_MODRM_INSTR_READ16(instr16_0F43, cmovcc16(!test_b(), ___, r))
- DEFINE_MODRM_INSTR_READ32(instr32_0F43, cmovcc32(!test_b(), ___, r))
- DEFINE_MODRM_INSTR_READ16(instr16_0F44, cmovcc16( test_z(), ___, r))
- DEFINE_MODRM_INSTR_READ32(instr32_0F44, cmovcc32( test_z(), ___, r))
- DEFINE_MODRM_INSTR_READ16(instr16_0F45, cmovcc16(!test_z(), ___, r))
- DEFINE_MODRM_INSTR_READ32(instr32_0F45, cmovcc32(!test_z(), ___, r))
- DEFINE_MODRM_INSTR_READ16(instr16_0F46, cmovcc16( test_be(), ___, r))
- DEFINE_MODRM_INSTR_READ32(instr32_0F46, cmovcc32( test_be(), ___, r))
- DEFINE_MODRM_INSTR_READ16(instr16_0F47, cmovcc16(!test_be(), ___, r))
- DEFINE_MODRM_INSTR_READ32(instr32_0F47, cmovcc32(!test_be(), ___, r))
- DEFINE_MODRM_INSTR_READ16(instr16_0F48, cmovcc16( test_s(), ___, r))
- DEFINE_MODRM_INSTR_READ32(instr32_0F48, cmovcc32( test_s(), ___, r))
- DEFINE_MODRM_INSTR_READ16(instr16_0F49, cmovcc16(!test_s(), ___, r))
- DEFINE_MODRM_INSTR_READ32(instr32_0F49, cmovcc32(!test_s(), ___, r))
- DEFINE_MODRM_INSTR_READ16(instr16_0F4A, cmovcc16( test_p(), ___, r))
- DEFINE_MODRM_INSTR_READ32(instr32_0F4A, cmovcc32( test_p(), ___, r))
- DEFINE_MODRM_INSTR_READ16(instr16_0F4B, cmovcc16(!test_p(), ___, r))
- DEFINE_MODRM_INSTR_READ32(instr32_0F4B, cmovcc32(!test_p(), ___, r))
- DEFINE_MODRM_INSTR_READ16(instr16_0F4C, cmovcc16( test_l(), ___, r))
- DEFINE_MODRM_INSTR_READ32(instr32_0F4C, cmovcc32( test_l(), ___, r))
- DEFINE_MODRM_INSTR_READ16(instr16_0F4D, cmovcc16(!test_l(), ___, r))
- DEFINE_MODRM_INSTR_READ32(instr32_0F4D, cmovcc32(!test_l(), ___, r))
- DEFINE_MODRM_INSTR_READ16(instr16_0F4E, cmovcc16( test_le(), ___, r))
- DEFINE_MODRM_INSTR_READ32(instr32_0F4E, cmovcc32( test_le(), ___, r))
- DEFINE_MODRM_INSTR_READ16(instr16_0F4F, cmovcc16(!test_le(), ___, r))
- DEFINE_MODRM_INSTR_READ32(instr32_0F4F, cmovcc32(!test_le(), ___, r))
- void instr_0F50_reg(int32_t r1, int32_t r2) {
- // movmskps r, xmm
- task_switch_test_mmx();
- union reg128 source = read_xmm128s(r1);
- int32_t data = source.u32[0] >> 31 | (source.u32[1] >> 31) << 1 |
- (source.u32[2] >> 31) << 2 | (source.u32[3] >> 31) << 3;
- write_reg32(r2, data);
- }
- void instr_0F50_mem(int32_t addr, int32_t r1) { trigger_ud(); }
- void instr_660F50_reg(int32_t r1, int32_t r2) {
- // movmskpd r, xmm
- task_switch_test_mmx();
- union reg128 source = read_xmm128s(r1);
- int32_t data = (source.u32[1] >> 31) | (source.u32[3] >> 31) << 1;
- write_reg32(r2, data);
- }
- void instr_660F50_mem(int32_t addr, int32_t r1) { trigger_ud(); }
- void instr_0F51() { unimplemented_sse(); }
- void instr_0F52() { unimplemented_sse(); }
- void instr_0F53() { unimplemented_sse(); }
- void instr_0F54(union reg128 source, int32_t r) {
- // andps xmm, xmm/mem128
- // XXX: Aligned access or #gp
- pand_r128(source, r);
- }
- DEFINE_SSE_SPLIT(instr_0F54, safe_read128s, read_xmm128s)
- void instr_660F54(union reg128 source, int32_t r) {
- // andpd xmm, xmm/mem128
- // XXX: Aligned access or #gp
- pand_r128(source, r);
- }
- DEFINE_SSE_SPLIT(instr_660F54, safe_read128s, read_xmm128s)
- void instr_0F55(union reg128 source, int32_t r) {
- // andnps xmm, xmm/mem128
- // XXX: Aligned access or #gp
- pandn_r128(source, r);
- }
- DEFINE_SSE_SPLIT(instr_0F55, safe_read128s, read_xmm128s)
- void instr_660F55(union reg128 source, int32_t r) {
- // andnpd xmm, xmm/mem128
- // XXX: Aligned access or #gp
- pandn_r128(source, r);
- }
- DEFINE_SSE_SPLIT(instr_660F55, safe_read128s, read_xmm128s)
- void instr_0F56(union reg128 source, int32_t r) {
- // orps xmm, xmm/mem128
- // XXX: Aligned access or #gp
- por_r128(source, r);
- }
- DEFINE_SSE_SPLIT(instr_0F56, safe_read128s, read_xmm128s)
- void instr_660F56(union reg128 source, int32_t r) {
- // orpd xmm, xmm/mem128
- // XXX: Aligned access or #gp
- por_r128(source, r);
- }
- DEFINE_SSE_SPLIT(instr_660F56, safe_read128s, read_xmm128s)
- void instr_0F57(union reg128 source, int32_t r) {
- // xorps xmm, xmm/mem128
- // XXX: Aligned access or #gp
- pxor_r128(source, r);
- }
- DEFINE_SSE_SPLIT(instr_0F57, safe_read128s, read_xmm128s)
- void instr_660F57(union reg128 source, int32_t r) {
- // xorpd xmm, xmm/mem128
- // XXX: Aligned access or #gp
- pxor_r128(source, r);
- }
- DEFINE_SSE_SPLIT(instr_660F57, safe_read128s, read_xmm128s)
- void instr_0F58() { unimplemented_sse(); }
- void instr_0F59() { unimplemented_sse(); }
- void instr_0F5A() { unimplemented_sse(); }
- void instr_0F5B() { unimplemented_sse(); }
- void instr_0F5C() { unimplemented_sse(); }
- void instr_0F5D() { unimplemented_sse(); }
- void instr_0F5E() { unimplemented_sse(); }
- void instr_0F5F() { unimplemented_sse(); }
- void instr_0F60(int32_t source, int32_t r) {
- // punpcklbw mm, mm/m32
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- int32_t byte0 = destination.u8[0];
- int32_t byte1 = source & 0xFF;
- int32_t byte2 = destination.u8[1];
- int32_t byte3 = (source >> 8) & 0xFF;
- int32_t byte4 = destination.u8[2];
- int32_t byte5 = (source >> 16) & 0xFF;
- int32_t byte6 = destination.u8[3];
- int32_t byte7 = source >> 24;
- int32_t low = byte0 | byte1 << 8 | byte2 << 16 | byte3 << 24;
- int32_t high = byte4 | byte5 << 8 | byte6 << 16 | byte7 << 24;
- write_mmx64(r, low, high);
- }
- DEFINE_SSE_SPLIT(instr_0F60, safe_read32s, read_mmx32s)
- void instr_660F60(union reg64 source, int32_t r) {
- // punpcklbw xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg64 destination = read_xmm64s(r);
- write_xmm128(
- r,
- destination.u8[0] | source.u8[0] << 8 | destination.u8[1] << 16 | source.u8[1] << 24,
- destination.u8[2] | source.u8[2] << 8 | destination.u8[3] << 16 | source.u8[3] << 24,
- destination.u8[4] | source.u8[4] << 8 | destination.u8[5] << 16 | source.u8[5] << 24,
- destination.u8[6] | source.u8[6] << 8 | destination.u8[7] << 16 | source.u8[7] << 24
- );
- }
- DEFINE_SSE_SPLIT(instr_660F60, safe_read64s, read_xmm64s)
- void instr_0F61(int32_t source, int32_t r) {
- // punpcklwd mm, mm/m32
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- int32_t word0 = destination.u16[0];
- int32_t word1 = source & 0xFFFF;
- int32_t word2 = destination.u16[1];
- int32_t word3 = source >> 16;
- int32_t low = word0 | word1 << 16;
- int32_t high = word2 | word3 << 16;
- write_mmx64(r, low, high);
- }
- DEFINE_SSE_SPLIT(instr_0F61, safe_read32s, read_mmx32s)
- void instr_660F61(union reg64 source, int32_t r) {
- // punpcklwd xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg64 destination = read_xmm64s(r);
- write_xmm128(
- r,
- destination.u16[0] | source.u16[0] << 16,
- destination.u16[1] | source.u16[1] << 16,
- destination.u16[2] | source.u16[2] << 16,
- destination.u16[3] | source.u16[3] << 16
- );
- }
- DEFINE_SSE_SPLIT(instr_660F61, safe_read64s, read_xmm64s)
- void instr_0F62(int32_t source, int32_t r) {
- // punpckldq mm, mm/m32
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- write_mmx64(r, destination.u32[0], source);
- }
- DEFINE_SSE_SPLIT(instr_0F62, safe_read32s, read_mmx32s)
- void instr_660F62(union reg128 source, int32_t r) {
- // punpckldq xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- write_xmm128(
- r,
- destination.u32[0],
- source.u32[0],
- destination.u32[1],
- source.u32[1]
- );
- }
- DEFINE_SSE_SPLIT(instr_660F62, safe_read128s, read_xmm128s)
- void instr_0F63(union reg64 source, int32_t r) {
- // packsswb mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- int32_t low = saturate_sw_to_sb(destination.u16[0]) |
- saturate_sw_to_sb(destination.u16[1]) << 8 |
- saturate_sw_to_sb(destination.u16[2]) << 16 |
- saturate_sw_to_sb(destination.u16[3]) << 24;
- int32_t high = saturate_sw_to_sb(source.u16[0]) |
- saturate_sw_to_sb(source.u16[1]) << 8 |
- saturate_sw_to_sb(source.u16[2]) << 16 |
- saturate_sw_to_sb(source.u16[3]) << 24;
- write_mmx64(r, low, high);
- }
- DEFINE_SSE_SPLIT(instr_0F63, safe_read64s, read_mmx64s)
- void instr_660F63(union reg128 source, int32_t r) {
- // packsswb xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- int32_t dword0 = saturate_sw_to_sb(destination.u16[0]) |
- saturate_sw_to_sb(destination.u16[1]) << 8 |
- saturate_sw_to_sb(destination.u16[2]) << 16 |
- saturate_sw_to_sb(destination.u16[3]) << 24;
- int32_t dword1 = saturate_sw_to_sb(destination.u16[4]) |
- saturate_sw_to_sb(destination.u16[5]) << 8 |
- saturate_sw_to_sb(destination.u16[6]) << 16 |
- saturate_sw_to_sb(destination.u16[7]) << 24;
- int32_t dword2 = saturate_sw_to_sb(source.u16[0]) |
- saturate_sw_to_sb(source.u16[1]) << 8 |
- saturate_sw_to_sb(source.u16[2]) << 16 |
- saturate_sw_to_sb(source.u16[3]) << 24;
- int32_t dword3 = saturate_sw_to_sb(source.u16[4]) |
- saturate_sw_to_sb(source.u16[5]) << 8 |
- saturate_sw_to_sb(source.u16[6]) << 16 |
- saturate_sw_to_sb(source.u16[7]) << 24;
- write_xmm128(r, dword0, dword1, dword2, dword3);
- }
- DEFINE_SSE_SPLIT(instr_660F63, safe_read128s, read_xmm128s)
- void instr_0F64(union reg64 source, int32_t r) {
- // pcmpgtb mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- union reg64 result = { { 0 } };
- for(uint32_t i = 0; i < 8; i++)
- {
- result.u8[i] = destination.i8[i] > source.i8[i] ? 0xFF : 0;
- }
- write_mmx_reg64(r, result);
- }
- DEFINE_SSE_SPLIT(instr_0F64, safe_read64s, read_mmx64s)
- void instr_660F64(union reg128 source, int32_t r) {
- // pcmpgtb xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- union reg128 result = { { 0 } };
- for(int32_t i = 0; i < 16; i++)
- {
- result.i8[i] = destination.i8[i] > source.i8[i] ? 0xFF : 0;
- }
- write_xmm_reg128(r, result);
- }
- DEFINE_SSE_SPLIT(instr_660F64, safe_read128s, read_xmm128s)
- void instr_0F65(union reg64 source, int32_t r) {
- // pcmpgtw mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- int32_t word0 = destination.i16[0] > source.i16[0] ? 0xFFFF : 0;
- int32_t word1 = destination.i16[1] > source.i16[1] ? 0xFFFF : 0;
- int32_t word2 = destination.i16[2] > source.i16[2] ? 0xFFFF : 0;
- int32_t word3 = destination.i16[3] > source.i16[3] ? 0xFFFF : 0;
- int32_t low = word0 | word1 << 16;
- int32_t high = word2 | word3 << 16;
- write_mmx64(r, low, high);
- }
- DEFINE_SSE_SPLIT(instr_0F65, safe_read64s, read_mmx64s)
- void instr_660F65(union reg128 source, int32_t r) {
- // pcmpgtw xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- union reg128 result = { { 0 } };
- for(int32_t i = 0; i < 8; i++)
- {
- result.u16[i] = destination.i16[i] > source.i16[i] ? 0xFFFF : 0;
- }
- write_xmm_reg128(r, result);
- }
- DEFINE_SSE_SPLIT(instr_660F65, safe_read128s, read_xmm128s)
- void instr_0F66(union reg64 source, int32_t r) {
- // pcmpgtd mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- int32_t low = destination.i32[0] > source.i32[0] ? -1 : 0;
- int32_t high = destination.i32[1] > source.i32[1] ? -1 : 0;
- write_mmx64(r, low, high);
- }
- DEFINE_SSE_SPLIT(instr_0F66, safe_read64s, read_mmx64s)
- void instr_660F66(union reg128 source, int32_t r) {
- // pcmpgtd xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- write_xmm128(
- r,
- destination.i32[0] > source.i32[0] ? -1 : 0,
- destination.i32[1] > source.i32[1] ? -1 : 0,
- destination.i32[2] > source.i32[2] ? -1 : 0,
- destination.i32[3] > source.i32[3] ? -1 : 0
- );
- }
- DEFINE_SSE_SPLIT(instr_660F66, safe_read128s, read_xmm128s)
- void instr_0F67(union reg64 source, int32_t r) {
- // packuswb mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- uint32_t low = saturate_sw_to_ub(destination.u16[0]) |
- saturate_sw_to_ub(destination.u16[1]) << 8 |
- saturate_sw_to_ub(destination.u16[2]) << 16 |
- saturate_sw_to_ub(destination.u16[3]) << 24;
- uint32_t high = saturate_sw_to_ub(source.u16[0]) |
- saturate_sw_to_ub(source.u16[1]) << 8 |
- saturate_sw_to_ub(source.u16[2]) << 16 |
- saturate_sw_to_ub(source.u16[3]) << 24;
- write_mmx64(r, low, high);
- }
- DEFINE_SSE_SPLIT(instr_0F67, safe_read64s, read_mmx64s)
- void instr_660F67(union reg128 source, int32_t r) {
- // packuswb xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- union reg128 result;
- for(int32_t i = 0; i < 8; i++)
- {
- result.u8[i] = saturate_sw_to_ub(destination.u16[i]);
- result.u8[i | 8] = saturate_sw_to_ub(source.u16[i]);
- }
- write_xmm_reg128(r, result);
- }
- DEFINE_SSE_SPLIT(instr_660F67, safe_read128s, read_xmm128s)
- void instr_0F68(union reg64 source, int32_t r) {
- // punpckhbw mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- int32_t byte0 = destination.u8[4];
- int32_t byte1 = source.u8[4];
- int32_t byte2 = destination.u8[5];
- int32_t byte3 = source.u8[5];
- int32_t byte4 = destination.u8[6];
- int32_t byte5 = source.u8[6];
- int32_t byte6 = destination.u8[7];
- int32_t byte7 = source.u8[7];
- int32_t low = byte0 | byte1 << 8 | byte2 << 16 | byte3 << 24;
- int32_t high = byte4 | byte5 << 8 | byte6 << 16 | byte7 << 24;
- write_mmx64(r, low, high);
- }
- DEFINE_SSE_SPLIT(instr_0F68, safe_read64s, read_mmx64s)
- void instr_660F68(union reg128 source, int32_t r) {
- // punpckhbw xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- write_xmm128(
- r,
- destination.u8[ 8] | source.u8[ 8] << 8 | destination.u8[ 9] << 16 | source.u8[ 9] << 24,
- destination.u8[10] | source.u8[10] << 8 | destination.u8[11] << 16 | source.u8[11] << 24,
- destination.u8[12] | source.u8[12] << 8 | destination.u8[13] << 16 | source.u8[13] << 24,
- destination.u8[14] | source.u8[14] << 8 | destination.u8[15] << 16 | source.u8[15] << 24
- );
- }
- DEFINE_SSE_SPLIT(instr_660F68, safe_read128s, read_xmm128s)
- void instr_0F69(union reg64 source, int32_t r) {
- // punpckhwd mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- int32_t word0 = destination.u16[2];
- int32_t word1 = source.u16[2];
- int32_t word2 = destination.u16[3];
- int32_t word3 = source.u16[3];
- int32_t low = word0 | word1 << 16;
- int32_t high = word2 | word3 << 16;
- write_mmx64(r, low, high);
- }
- DEFINE_SSE_SPLIT(instr_0F69, safe_read64s, read_mmx64s)
- void instr_660F69(union reg128 source, int32_t r) {
- // punpckhwd xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- int32_t dword0 = destination.u16[4] | source.u16[4] << 16;
- int32_t dword1 = destination.u16[5] | source.u16[5] << 16;
- int32_t dword2 = destination.u16[6] | source.u16[6] << 16;
- int32_t dword3 = destination.u16[7] | source.u16[7] << 16;
- write_xmm128(r, dword0, dword1, dword2, dword3);
- }
- DEFINE_SSE_SPLIT(instr_660F69, safe_read128s, read_xmm128s)
- void instr_0F6A(union reg64 source, int32_t r) {
- // punpckhdq mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- write_mmx64(r, destination.u32[1], source.u32[1]);
- }
- DEFINE_SSE_SPLIT(instr_0F6A, safe_read64s, read_mmx64s)
- void instr_660F6A(union reg128 source, int32_t r) {
- // punpckhdq xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- write_xmm128(r, destination.u32[2], source.u32[2], destination.u32[3], source.u32[3]);
- }
- DEFINE_SSE_SPLIT(instr_660F6A, safe_read128s, read_xmm128s)
- void instr_0F6B(union reg64 source, int32_t r) {
- // packssdw mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- int32_t low = saturate_sd_to_sw(destination.u32[0]) |
- saturate_sd_to_sw(destination.u32[1]) << 16;
- int32_t high = saturate_sd_to_sw(source.u32[0]) |
- saturate_sd_to_sw(source.u32[1]) << 16;
- write_mmx64(r, low, high);
- }
- DEFINE_SSE_SPLIT(instr_0F6B, safe_read64s, read_mmx64s)
- void instr_660F6B(union reg128 source, int32_t r) {
- // packssdw xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- int32_t dword0 = saturate_sd_to_sw(destination.u32[0]) |
- saturate_sd_to_sw(destination.u32[1]) << 16;
- int32_t dword1 = saturate_sd_to_sw(destination.u32[2]) |
- saturate_sd_to_sw(destination.u32[3]) << 16;
- int32_t dword2 = saturate_sd_to_sw(source.u32[0]) |
- saturate_sd_to_sw(source.u32[1]) << 16;
- int32_t dword3 = saturate_sd_to_sw(source.u32[2]) |
- saturate_sd_to_sw(source.u32[3]) << 16;
- write_xmm128(r, dword0, dword1, dword2, dword3);
- }
- DEFINE_SSE_SPLIT(instr_660F6B, safe_read128s, read_xmm128s)
- void instr_0F6C_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_0F6C_reg(int32_t r1, int32_t r2) { trigger_ud(); }
- void instr_660F6C(union reg128 source, int32_t r) {
- // punpcklqdq xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- write_xmm128(r, destination.u32[0], destination.u32[1], source.u32[0], source.u32[1]);
- }
- DEFINE_SSE_SPLIT(instr_660F6C, safe_read128s, read_xmm128s)
- void instr_0F6D_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_0F6D_reg(int32_t r1, int32_t r2) { trigger_ud(); }
- void instr_660F6D(union reg128 source, int32_t r) {
- // punpckhqdq xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- write_xmm128(r, destination.u32[2], destination.u32[3], source.u32[2], source.u32[3]);
- }
- DEFINE_SSE_SPLIT(instr_660F6D, safe_read128s, read_xmm128s)
- void instr_0F6E(int32_t source, int32_t r) {
- // movd mm, r/m32
- task_switch_test_mmx();
- write_mmx64(r, source, 0);
- }
- DEFINE_SSE_SPLIT(instr_0F6E, safe_read32s, read_reg32)
- void instr_660F6E(int32_t source, int32_t r) {
- // movd mm, r/m32
- task_switch_test_mmx();
- write_xmm128(r, source, 0, 0, 0);
- }
- DEFINE_SSE_SPLIT(instr_660F6E, safe_read32s, read_reg32)
- void instr_0F6F(union reg64 source, int32_t r) {
- // movq mm, mm/m64
- task_switch_test_mmx();
- write_mmx64(r, source.u32[0], source.u32[1]);
- }
- DEFINE_SSE_SPLIT(instr_0F6F, safe_read64s, read_mmx64s)
- void instr_660F6F(union reg128 source, int32_t r) {
- // movdqa xmm, xmm/mem128
- // XXX: Aligned access or #gp
- // XXX: Aligned read or #gp
- mov_rm_r128(source, r);
- }
- DEFINE_SSE_SPLIT(instr_660F6F, safe_read128s, read_xmm128s)
- void instr_F30F6F(union reg128 source, int32_t r) {
- // movdqu xmm, xmm/m128
- mov_rm_r128(source, r);
- }
- DEFINE_SSE_SPLIT(instr_F30F6F, safe_read128s, read_xmm128s)
- void instr_0F70(union reg64 source, int32_t r, int32_t imm8) {
- // pshufw mm1, mm2/m64, imm8
- task_switch_test_mmx();
- int32_t word0_shift = imm8 & 0b11;
- uint32_t word0 = source.u32[word0_shift >> 1] >> ((word0_shift & 1) << 4) & 0xFFFF;
- int32_t word1_shift = (imm8 >> 2) & 0b11;
- uint32_t word1 = source.u32[word1_shift >> 1] >> ((word1_shift & 1) << 4);
- int32_t low = word0 | word1 << 16;
- int32_t word2_shift = (imm8 >> 4) & 0b11;
- uint32_t word2 = source.u32[word2_shift >> 1] >> ((word2_shift & 1) << 4) & 0xFFFF;
- uint32_t word3_shift = (imm8 >> 6);
- uint32_t word3 = source.u32[word3_shift >> 1] >> ((word3_shift & 1) << 4);
- int32_t high = word2 | word3 << 16;
- write_mmx64(r, low, high);
- }
- DEFINE_SSE_SPLIT_IMM(instr_0F70, safe_read64s, read_mmx64s)
- void instr_660F70(union reg128 source, int32_t r, int32_t imm8) {
- // pshufd xmm, xmm/mem128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- write_xmm128(
- r,
- source.u32[imm8 & 3],
- source.u32[imm8 >> 2 & 3],
- source.u32[imm8 >> 4 & 3],
- source.u32[imm8 >> 6 & 3]
- );
- }
- DEFINE_SSE_SPLIT_IMM(instr_660F70, safe_read128s, read_xmm128s)
- void instr_F20F70(union reg128 source, int32_t r, int32_t imm8) {
- // pshuflw xmm, xmm/m128, imm8
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- write_xmm128(
- r,
- source.u16[imm8 & 3] | source.u16[imm8 >> 2 & 3] << 16,
- source.u16[imm8 >> 4 & 3] | source.u16[imm8 >> 6 & 3] << 16,
- source.u32[2],
- source.u32[3]
- );
- }
- DEFINE_SSE_SPLIT_IMM(instr_F20F70, safe_read128s, read_xmm128s)
- void instr_F30F70(union reg128 source, int32_t r, int32_t imm8) {
- // pshufhw xmm, xmm/m128, imm8
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- write_xmm128(
- r,
- source.u32[0],
- source.u32[1],
- source.u16[imm8 & 3 | 4] | source.u16[imm8 >> 2 & 3 | 4] << 16,
- source.u16[imm8 >> 4 & 3 | 4] | source.u16[imm8 >> 6 & 3 | 4] << 16
- );
- }
- DEFINE_SSE_SPLIT_IMM(instr_F30F70, safe_read128s, read_xmm128s)
- void instr_0F71_2_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_0F71_4_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_0F71_6_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_0F71_2_reg(int32_t r, int32_t imm8) {
- // psrlw mm, imm8
- psrlw_r64(r, imm8);
- }
- void instr_0F71_4_reg(int32_t r, int32_t imm8) {
- // psraw mm, imm8
- psraw_r64(r, imm8);
- }
- void instr_0F71_6_reg(int32_t r, int32_t imm8) {
- // psllw mm, imm8
- psllw_r64(r, imm8);
- }
- void instr_660F71_2_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_660F71_4_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_660F71_6_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_660F71_2_reg(int32_t r, int32_t imm8) {
- // psrlw xmm, imm8
- psrlw_r128(r, imm8);
- }
- void instr_660F71_4_reg(int32_t r, int32_t imm8) {
- // psraw xmm, imm8
- psraw_r128(r, imm8);
- }
- void instr_660F71_6_reg(int32_t r, int32_t imm8) {
- // psllw xmm, imm8
- psllw_r128(r, imm8);
- }
- void instr_0F72_2_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_0F72_4_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_0F72_6_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_0F72_2_reg(int32_t r, int32_t imm8) {
- // psrld mm, imm8
- psrld_r64(r, imm8);
- }
- void instr_0F72_4_reg(int32_t r, int32_t imm8) {
- // psrad mm, imm8
- psrad_r64(r, imm8);
- }
- void instr_0F72_6_reg(int32_t r, int32_t imm8) {
- // pslld mm, imm8
- pslld_r64(r, imm8);
- }
- void instr_660F72_2_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_660F72_4_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_660F72_6_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_660F72_2_reg(int32_t r, int32_t imm8) {
- // psrld xmm, imm8
- psrld_r128(r, imm8);
- }
- void instr_660F72_4_reg(int32_t r, int32_t imm8) {
- // psrad xmm, imm8
- psrad_r128(r, imm8);
- }
- void instr_660F72_6_reg(int32_t r, int32_t imm8) {
- // pslld xmm, imm8
- pslld_r128(r, imm8);
- }
- void instr_0F73_2_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_0F73_3_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_0F73_3_reg(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_0F73_6_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_0F73_7_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_0F73_7_reg(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_0F73_2_reg(int32_t r, int32_t imm8) {
- // psrlq mm, imm8
- psrlq_r64(r, imm8);
- }
- void instr_0F73_6_reg(int32_t r, int32_t imm8) {
- // psllq mm, imm8
- psllq_r64(r, imm8);
- }
- void instr_660F73_2_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_660F73_3_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_660F73_6_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_660F73_7_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_660F73_2_reg(int32_t r, int32_t imm8) {
- // psrlq xmm, imm8
- psrlq_r128(r, imm8);
- }
- void instr_660F73_3_reg(int32_t r, int32_t imm8) {
- // psrldq xmm, imm8
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- if(imm8 == 0)
- {
- return;
- }
- union reg128 result = { { 0 } };
- uint32_t shift = imm8 > 15 ? 128 : imm8 << 3;
- if(shift <= 63)
- {
- result.u64[0] = destination.u64[0] >> shift | destination.u64[1] >> (64 - shift);
- result.u64[1] = destination.u64[1] >> shift;
- }
- else if(shift <= 127)
- {
- result.u64[0] = destination.u64[1] >> (shift - 64);
- result.u64[1] = 0;
- }
- write_xmm_reg128(r, result);
- }
- void instr_660F73_6_reg(int32_t r, int32_t imm8) {
- // psllq xmm, imm8
- psllq_r128(r, imm8);
- }
- void instr_660F73_7_reg(int32_t r, int32_t imm8) {
- // pslldq xmm, imm8
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- if(imm8 == 0)
- {
- return;
- }
- union reg128 result = { { 0 } };
- uint32_t shift = imm8 > 15 ? 128 : imm8 << 3;
- if(shift <= 63)
- {
- result.u64[0] = destination.u64[0] << shift;
- result.u64[1] = destination.u64[1] << shift | destination.u64[0] >> (64 - shift);
- }
- else if(shift <= 127)
- {
- result.u64[0] = 0;
- result.u64[1] = destination.u64[0] << (shift - 64);
- }
- write_xmm_reg128(r, result);
- }
- void instr_0F74(union reg64 source, int32_t r) {
- // pcmpeqb mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- union reg64 result = { { 0 } };
- for(uint32_t i = 0; i < 8; i++)
- {
- result.u8[i] = destination.i8[i] == source.i8[i] ? 0xFF : 0;
- }
- write_mmx_reg64(r, result);
- }
- DEFINE_SSE_SPLIT(instr_0F74, safe_read64s, read_mmx64s)
- void instr_660F74(union reg128 source, int32_t r) {
- // pcmpeqb xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- union reg128 result;
- for(int32_t i = 0; i < 16; i++)
- {
- result.u8[i] = source.u8[i] == destination.u8[i] ? 0xFF : 0;
- }
- write_xmm_reg128(r, result);
- }
- DEFINE_SSE_SPLIT(instr_660F74, safe_read128s, read_xmm128s)
- void instr_0F75(union reg64 source, int32_t r) {
- // pcmpeqw mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- int32_t word0 = destination.u16[0] == source.u16[0] ? 0xFFFF : 0;
- int32_t word1 = destination.u16[1] == source.u16[1] ? 0xFFFF : 0;
- int32_t word2 = destination.u16[2] == source.u16[2] ? 0xFFFF : 0;
- int32_t word3 = destination.u16[3] == source.u16[3] ? 0xFFFF : 0;
- int32_t low = word0 | word1 << 16;
- int32_t high = word2 | word3 << 16;
- write_mmx64(r, low, high);
- }
- DEFINE_SSE_SPLIT(instr_0F75, safe_read64s, read_mmx64s)
- void instr_660F75(union reg128 source, int32_t r) {
- // pcmpeqw xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- union reg128 result;
- for(int32_t i = 0; i < 8; i++)
- {
- result.u16[i] = source.u16[i] == destination.u16[i] ? 0xFFFF : 0;
- }
- write_xmm_reg128(r, result);
- }
- DEFINE_SSE_SPLIT(instr_660F75, safe_read128s, read_xmm128s)
- void instr_0F76(union reg64 source, int32_t r) {
- // pcmpeqd mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- int32_t low = destination.u32[0] == source.u32[0] ? -1 : 0;
- int32_t high = destination.u32[1] == source.u32[1] ? -1 : 0;
- write_mmx64(r, low, high);
- }
- DEFINE_SSE_SPLIT(instr_0F76, safe_read64s, read_mmx64s)
- void instr_660F76(union reg128 source, int32_t r) {
- // pcmpeqd xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- write_xmm128(
- r,
- source.u32[0] == destination.u32[0] ? -1 : 0,
- source.u32[1] == destination.u32[1] ? -1 : 0,
- source.u32[2] == destination.u32[2] ? -1 : 0,
- source.u32[3] == destination.u32[3] ? -1 : 0
- );
- }
- DEFINE_SSE_SPLIT(instr_660F76, safe_read128s, read_xmm128s)
- void instr_0F77() {
- // emms
- if(cr[0] & (CR0_EM | CR0_TS)) {
- if(cr[0] & CR0_TS) {
- trigger_nm();
- }
- else {
- trigger_ud();
- }
- }
- fpu_set_tag_word(0xFFFF);
- }
- void instr_0F78() { unimplemented_sse(); }
- void instr_0F79() { unimplemented_sse(); }
- void instr_0F7A() { unimplemented_sse(); }
- void instr_0F7B() { unimplemented_sse(); }
- void instr_0F7C() { unimplemented_sse(); }
- void instr_0F7D() { unimplemented_sse(); }
- int32_t instr_0F7E(int32_t r) {
- // movd r/m32, mm
- task_switch_test_mmx();
- union reg64 data = read_mmx64s(r);
- return data.u32[0];
- }
- DEFINE_SSE_SPLIT_WRITE(instr_0F7E, safe_write32, write_reg32)
- int32_t instr_660F7E(int32_t r) {
- // movd r/m32, xmm
- task_switch_test_mmx();
- union reg64 data = read_xmm64s(r);
- return data.u32[0];
- }
- DEFINE_SSE_SPLIT_WRITE(instr_660F7E, safe_write32, write_reg32)
- void instr_F30F7E_mem(int32_t addr, int32_t r) {
- // movq xmm, xmm/mem64
- task_switch_test_mmx();
- union reg64 data = safe_read64s(addr);
- write_xmm128(r, data.u32[0], data.u32[1], 0, 0);
- }
- void instr_F30F7E_reg(int32_t r1, int32_t r2) {
- // movq xmm, xmm/mem64
- task_switch_test_mmx();
- union reg64 data = read_xmm64s(r1);
- write_xmm128(r2, data.u32[0], data.u32[1], 0, 0);
- }
- void instr_0F7F_mem(int32_t addr, int32_t r) {
- // movq mm/m64, mm
- mov_r_m64(addr, r);
- }
- void instr_0F7F_reg(int32_t r1, int32_t r2) {
- // movq mm/m64, mm
- task_switch_test_mmx();
- union reg64 data = read_mmx64s(r2);
- write_mmx64(r1, data.u32[0], data.u32[1]);
- }
- void instr_660F7F_mem(int32_t addr, int32_t r) {
- // movdqa xmm/m128, xmm
- // XXX: Aligned write or #gp
- mov_r_m128(addr, r);
- }
- void instr_660F7F_reg(int32_t r1, int32_t r2) {
- // movdqa xmm/m128, xmm
- // XXX: Aligned access or #gp
- mov_r_r128(r1, r2);
- }
- void instr_F30F7F_mem(int32_t addr, int32_t r) {
- // movdqu xmm/m128, xmm
- mov_r_m128(addr, r);
- }
- void instr_F30F7F_reg(int32_t r1, int32_t r2) {
- // movdqu xmm/m128, xmm
- mov_r_r128(r1, r2);
- }
- // jmpcc
- void instr16_0F80(int32_t imm) { jmpcc16( test_o(), imm); }
- void instr32_0F80(int32_t imm) { jmpcc32( test_o(), imm); }
- void instr16_0F81(int32_t imm) { jmpcc16(!test_o(), imm); }
- void instr32_0F81(int32_t imm) { jmpcc32(!test_o(), imm); }
- void instr16_0F82(int32_t imm) { jmpcc16( test_b(), imm); }
- void instr32_0F82(int32_t imm) { jmpcc32( test_b(), imm); }
- void instr16_0F83(int32_t imm) { jmpcc16(!test_b(), imm); }
- void instr32_0F83(int32_t imm) { jmpcc32(!test_b(), imm); }
- void instr16_0F84(int32_t imm) { jmpcc16( test_z(), imm); }
- void instr32_0F84(int32_t imm) { jmpcc32( test_z(), imm); }
- void instr16_0F85(int32_t imm) { jmpcc16(!test_z(), imm); }
- void instr32_0F85(int32_t imm) { jmpcc32(!test_z(), imm); }
- void instr16_0F86(int32_t imm) { jmpcc16( test_be(), imm); }
- void instr32_0F86(int32_t imm) { jmpcc32( test_be(), imm); }
- void instr16_0F87(int32_t imm) { jmpcc16(!test_be(), imm); }
- void instr32_0F87(int32_t imm) { jmpcc32(!test_be(), imm); }
- void instr16_0F88(int32_t imm) { jmpcc16( test_s(), imm); }
- void instr32_0F88(int32_t imm) { jmpcc32( test_s(), imm); }
- void instr16_0F89(int32_t imm) { jmpcc16(!test_s(), imm); }
- void instr32_0F89(int32_t imm) { jmpcc32(!test_s(), imm); }
- void instr16_0F8A(int32_t imm) { jmpcc16( test_p(), imm); }
- void instr32_0F8A(int32_t imm) { jmpcc32( test_p(), imm); }
- void instr16_0F8B(int32_t imm) { jmpcc16(!test_p(), imm); }
- void instr32_0F8B(int32_t imm) { jmpcc32(!test_p(), imm); }
- void instr16_0F8C(int32_t imm) { jmpcc16( test_l(), imm); }
- void instr32_0F8C(int32_t imm) { jmpcc32( test_l(), imm); }
- void instr16_0F8D(int32_t imm) { jmpcc16(!test_l(), imm); }
- void instr32_0F8D(int32_t imm) { jmpcc32(!test_l(), imm); }
- void instr16_0F8E(int32_t imm) { jmpcc16( test_le(), imm); }
- void instr32_0F8E(int32_t imm) { jmpcc32( test_le(), imm); }
- void instr16_0F8F(int32_t imm) { jmpcc16(!test_le(), imm); }
- void instr32_0F8F(int32_t imm) { jmpcc32(!test_le(), imm); }
- // setcc
- void instr_0F90_reg(int32_t r, int32_t unused) { setcc_reg( test_o(), r); }
- void instr_0F91_reg(int32_t r, int32_t unused) { setcc_reg(!test_o(), r); }
- void instr_0F92_reg(int32_t r, int32_t unused) { setcc_reg( test_b(), r); }
- void instr_0F93_reg(int32_t r, int32_t unused) { setcc_reg(!test_b(), r); }
- void instr_0F94_reg(int32_t r, int32_t unused) { setcc_reg( test_z(), r); }
- void instr_0F95_reg(int32_t r, int32_t unused) { setcc_reg(!test_z(), r); }
- void instr_0F96_reg(int32_t r, int32_t unused) { setcc_reg( test_be(), r); }
- void instr_0F97_reg(int32_t r, int32_t unused) { setcc_reg(!test_be(), r); }
- void instr_0F98_reg(int32_t r, int32_t unused) { setcc_reg( test_s(), r); }
- void instr_0F99_reg(int32_t r, int32_t unused) { setcc_reg(!test_s(), r); }
- void instr_0F9A_reg(int32_t r, int32_t unused) { setcc_reg( test_p(), r); }
- void instr_0F9B_reg(int32_t r, int32_t unused) { setcc_reg(!test_p(), r); }
- void instr_0F9C_reg(int32_t r, int32_t unused) { setcc_reg( test_l(), r); }
- void instr_0F9D_reg(int32_t r, int32_t unused) { setcc_reg(!test_l(), r); }
- void instr_0F9E_reg(int32_t r, int32_t unused) { setcc_reg( test_le(), r); }
- void instr_0F9F_reg(int32_t r, int32_t unused) { setcc_reg(!test_le(), r); }
- void instr_0F90_mem(int32_t addr, int32_t unused) { setcc_mem( test_o(), addr); }
- void instr_0F91_mem(int32_t addr, int32_t unused) { setcc_mem(!test_o(), addr); }
- void instr_0F92_mem(int32_t addr, int32_t unused) { setcc_mem( test_b(), addr); }
- void instr_0F93_mem(int32_t addr, int32_t unused) { setcc_mem(!test_b(), addr); }
- void instr_0F94_mem(int32_t addr, int32_t unused) { setcc_mem( test_z(), addr); }
- void instr_0F95_mem(int32_t addr, int32_t unused) { setcc_mem(!test_z(), addr); }
- void instr_0F96_mem(int32_t addr, int32_t unused) { setcc_mem( test_be(), addr); }
- void instr_0F97_mem(int32_t addr, int32_t unused) { setcc_mem(!test_be(), addr); }
- void instr_0F98_mem(int32_t addr, int32_t unused) { setcc_mem( test_s(), addr); }
- void instr_0F99_mem(int32_t addr, int32_t unused) { setcc_mem(!test_s(), addr); }
- void instr_0F9A_mem(int32_t addr, int32_t unused) { setcc_mem( test_p(), addr); }
- void instr_0F9B_mem(int32_t addr, int32_t unused) { setcc_mem(!test_p(), addr); }
- void instr_0F9C_mem(int32_t addr, int32_t unused) { setcc_mem( test_l(), addr); }
- void instr_0F9D_mem(int32_t addr, int32_t unused) { setcc_mem(!test_l(), addr); }
- void instr_0F9E_mem(int32_t addr, int32_t unused) { setcc_mem( test_le(), addr); }
- void instr_0F9F_mem(int32_t addr, int32_t unused) { setcc_mem(!test_le(), addr); }
- void instr16_0FA0() { push16(sreg[FS]); }
- void instr32_0FA0() { push32(sreg[FS]); }
- void instr16_0FA1() {
- switch_seg(FS, safe_read16(get_stack_pointer(0)));
- adjust_stack_reg(2);
- }
- void instr32_0FA1() {
- switch_seg(FS, safe_read32s(get_stack_pointer(0)) & 0xFFFF);
- adjust_stack_reg(4);
- }
- void instr_0FA2() { cpuid(); }
- void instr16_0FA3_reg(int32_t r1, int32_t r2) { bt_reg(read_reg16(r1), read_reg16(r2) & 15); }
- void instr16_0FA3_mem(int32_t addr, int32_t r) { bt_mem(addr, read_reg16(r) << 16 >> 16); }
- void instr32_0FA3_reg(int32_t r1, int32_t r2) { bt_reg(read_reg32(r1), read_reg32(r2) & 31); }
- void instr32_0FA3_mem(int32_t addr, int32_t r) { bt_mem(addr, read_reg32(r)); }
- DEFINE_MODRM_INSTR_IMM_READ_WRITE_16(instr16_0FA4, shld16(___, read_reg16(r), imm & 31))
- DEFINE_MODRM_INSTR_IMM_READ_WRITE_32(instr32_0FA4, shld32(___, read_reg32(r), imm & 31))
- DEFINE_MODRM_INSTR_READ_WRITE_16(instr16_0FA5, shld16(___, read_reg16(r), reg8[CL] & 31))
- DEFINE_MODRM_INSTR_READ_WRITE_32(instr32_0FA5, shld32(___, read_reg32(r), reg8[CL] & 31))
- void instr_0FA6() {
- // obsolete cmpxchg (os/2)
- trigger_ud();
- }
- void instr_0FA7() { undefined_instruction(); }
- void instr16_0FA8() { push16(sreg[GS]); }
- void instr32_0FA8() { push32(sreg[GS]); }
- void instr16_0FA9() {
- switch_seg(GS, safe_read16(get_stack_pointer(0)));
- adjust_stack_reg(2);
- }
- void instr32_0FA9() {
- switch_seg(GS, safe_read32s(get_stack_pointer(0)) & 0xFFFF);
- adjust_stack_reg(4);
- }
- void instr_0FAA() {
- // rsm
- todo();
- }
- void instr16_0FAB_reg(int32_t r1, int32_t r2) { write_reg16(r1, bts_reg(read_reg16(r1), read_reg16(r2) & 15)); }
- void instr16_0FAB_mem(int32_t addr, int32_t r) { bts_mem(addr, read_reg16(r) << 16 >> 16); }
- void instr32_0FAB_reg(int32_t r1, int32_t r2) { write_reg32(r1, bts_reg(read_reg32(r1), read_reg32(r2) & 31)); }
- void instr32_0FAB_mem(int32_t addr, int32_t r) { bts_mem(addr, read_reg32(r)); }
- DEFINE_MODRM_INSTR_IMM_READ_WRITE_16(instr16_0FAC, shrd16(___, read_reg16(r), imm & 31))
- DEFINE_MODRM_INSTR_IMM_READ_WRITE_32(instr32_0FAC, shrd32(___, read_reg32(r), imm & 31))
- DEFINE_MODRM_INSTR_READ_WRITE_16(instr16_0FAD, shrd16(___, read_reg16(r), reg8[CL] & 31))
- DEFINE_MODRM_INSTR_READ_WRITE_32(instr32_0FAD, shrd32(___, read_reg32(r), reg8[CL] & 31))
- void instr_0FAE_0_reg(int32_t r) { trigger_ud(); }
- void instr_0FAE_0_mem(int32_t addr) {
- fxsave(addr);
- }
- void instr_0FAE_1_reg(int32_t r) { trigger_ud(); }
- void instr_0FAE_1_mem(int32_t addr) {
- fxrstor(addr);
- }
- void instr_0FAE_2_reg(int32_t r) { trigger_ud(); }
- void instr_0FAE_2_mem(int32_t addr) {
- // ldmxcsr
- int32_t new_mxcsr = safe_read32s(addr);
- if(new_mxcsr & ~MXCSR_MASK)
- {
- dbg_log("Invalid mxcsr bits: %x", (new_mxcsr & ~MXCSR_MASK));
- assert(false);
- trigger_gp(0);
- }
- *mxcsr = new_mxcsr;
- }
- void instr_0FAE_3_reg(int32_t r) { trigger_ud(); }
- void instr_0FAE_3_mem(int32_t addr) {
- // stmxcsr
- safe_write32(addr, *mxcsr);
- }
- void instr_0FAE_4_reg(int32_t r) { trigger_ud(); }
- void instr_0FAE_4_mem(int32_t addr) {
- // xsave
- todo();
- }
- void instr_0FAE_5_reg(int32_t r) {
- // lfence
- dbg_assert_message(r == 0, "Unexpected lfence encoding");
- }
- void instr_0FAE_5_mem(int32_t addr) {
- // xrstor
- todo();
- }
- void instr_0FAE_6_reg(int32_t r) {
- // mfence
- dbg_assert_message(r == 0, "Unexpected mfence encoding");
- }
- void instr_0FAE_6_mem(int32_t addr) {
- dbg_assert_message(false, "0fae/5 #ud");
- trigger_ud();
- }
- void instr_0FAE_7_reg(int32_t r) {
- // sfence
- dbg_assert_message(r == 0, "Unexpected sfence encoding");
- }
- void instr_0FAE_7_mem(int32_t addr) {
- // clflush
- todo();
- }
- DEFINE_MODRM_INSTR_READ16(instr16_0FAF, write_reg16(r, imul_reg16(read_reg16(r) << 16 >> 16, ___ << 16 >> 16)))
- DEFINE_MODRM_INSTR_READ32(instr32_0FAF, write_reg32(r, imul_reg32(read_reg32(r), ___)))
- void instr_0FB0_reg(int32_t r1, int32_t r2) {
- // cmpxchg8
- int32_t data = read_reg8(r1);
- cmp8(reg8[AL], data);
- if(getzf())
- {
- write_reg8(r1, read_reg8(r2));
- }
- else
- {
- reg8[AL] = data;
- }
- }
- void instr_0FB0_mem(int32_t addr, int32_t r) {
- // cmpxchg8
- writable_or_pagefault(addr, 1);
- int32_t data = safe_read8(addr);
- cmp8(reg8[AL], data);
- if(getzf())
- {
- safe_write8(addr, read_reg8(r));
- }
- else
- {
- safe_write8(addr, data);
- reg8[AL] = data;
- }
- }
- void instr16_0FB1_reg(int32_t r1, int32_t r2) {
- // cmpxchg16
- int32_t data = read_reg16(r1);
- cmp16(reg16[AX], data);
- if(getzf())
- {
- write_reg16(r1, read_reg16(r2));
- }
- else
- {
- reg16[AX] = data;
- }
- }
- void instr16_0FB1_mem(int32_t addr, int32_t r) {
- // cmpxchg16
- writable_or_pagefault(addr, 2);
- int32_t data = safe_read16(addr);
- cmp16(reg16[AX], data);
- if(getzf())
- {
- safe_write16(addr, read_reg16(r));
- }
- else
- {
- safe_write16(addr, data);
- reg16[AX] = data;
- }
- }
- void instr32_0FB1_reg(int32_t r1, int32_t r2) {
- // cmpxchg32
- int32_t data = read_reg32(r1);
- cmp32(reg32s[EAX], data);
- if(getzf())
- {
- write_reg32(r1, read_reg32(r2));
- }
- else
- {
- reg32s[EAX] = data;
- }
- }
- void instr32_0FB1_mem(int32_t addr, int32_t r) {
- // cmpxchg32
- writable_or_pagefault(addr, 4);
- int32_t data = safe_read32s(addr);
- cmp32(reg32s[EAX], data);
- if(getzf())
- {
- safe_write32(addr, read_reg32(r));
- }
- else
- {
- safe_write32(addr, data);
- reg32s[EAX] = data;
- }
- }
- // lss
- void instr16_0FB2_reg(int32_t unused, int32_t unused2) { trigger_ud(); }
- void instr16_0FB2_mem(int32_t addr, int32_t r) {
- lss16(addr, get_reg16_index(r), SS);
- }
- void instr32_0FB2_reg(int32_t unused, int32_t unused2) { trigger_ud(); }
- void instr32_0FB2_mem(int32_t addr, int32_t r) {
- lss32(addr, r, SS);
- }
- void instr16_0FB3_reg(int32_t r1, int32_t r2) { write_reg16(r1, btr_reg(read_reg16(r1), read_reg16(r2) & 15)); }
- void instr16_0FB3_mem(int32_t addr, int32_t r) { btr_mem(addr, read_reg16(r) << 16 >> 16); }
- void instr32_0FB3_reg(int32_t r1, int32_t r2) { write_reg32(r1, btr_reg(read_reg32(r1), read_reg32(r2) & 31)); }
- void instr32_0FB3_mem(int32_t addr, int32_t r) { btr_mem(addr, read_reg32(r)); }
- // lfs, lgs
- void instr16_0FB4_reg(int32_t unused, int32_t unused2) { trigger_ud(); }
- void instr16_0FB4_mem(int32_t addr, int32_t r) {
- lss16(addr, get_reg16_index(r), FS);
- }
- void instr32_0FB4_reg(int32_t unused, int32_t unused2) { trigger_ud(); }
- void instr32_0FB4_mem(int32_t addr, int32_t r) {
- lss32(addr, r, FS);
- }
- void instr16_0FB5_reg(int32_t unused, int32_t unused2) { trigger_ud(); }
- void instr16_0FB5_mem(int32_t addr, int32_t r) {
- lss16(addr, get_reg16_index(r), GS);
- }
- void instr32_0FB5_reg(int32_t unused, int32_t unused2) { trigger_ud(); }
- void instr32_0FB5_mem(int32_t addr, int32_t r) {
- lss32(addr, r, GS);
- }
- // movzx
- DEFINE_MODRM_INSTR_READ8(instr16_0FB6, write_reg16(r, ___))
- DEFINE_MODRM_INSTR_READ8(instr32_0FB6, write_reg32(r, ___))
- DEFINE_MODRM_INSTR_READ16(instr16_0FB7, write_reg16(r, ___))
- DEFINE_MODRM_INSTR_READ16(instr32_0FB7, write_reg32(r, ___))
- void instr16_0FB8_reg(int32_t r1, int32_t r2) { trigger_ud(); }
- void instr16_0FB8_mem(int32_t addr, int32_t r) { trigger_ud(); }
- DEFINE_MODRM_INSTR_READ16(instr16_F30FB8, write_reg16(r, popcnt(___)))
- void instr32_0FB8_reg(int32_t r1, int32_t r2) { trigger_ud(); }
- void instr32_0FB8_mem(int32_t addr, int32_t r) { trigger_ud(); }
- DEFINE_MODRM_INSTR_READ32(instr32_F30FB8, write_reg32(r, popcnt(___)))
- void instr_0FB9() {
- // UD2
- trigger_ud();
- }
- void instr16_0FBA_4_reg(int32_t r, int32_t imm) {
- bt_reg(read_reg16(r), imm & 15);
- }
- void instr16_0FBA_4_mem(int32_t addr, int32_t imm) {
- bt_mem(addr, imm & 15);
- }
- void instr16_0FBA_5_reg(int32_t r, int32_t imm) {
- write_reg16(r, bts_reg(read_reg16(r), imm & 15));
- }
- void instr16_0FBA_5_mem(int32_t addr, int32_t imm) {
- bts_mem(addr, imm & 15);
- }
- void instr16_0FBA_6_reg(int32_t r, int32_t imm) {
- write_reg16(r, btr_reg(read_reg16(r), imm & 15));
- }
- void instr16_0FBA_6_mem(int32_t addr, int32_t imm) {
- btr_mem(addr, imm & 15);
- }
- void instr16_0FBA_7_reg(int32_t r, int32_t imm) {
- write_reg16(r, btc_reg(read_reg16(r), imm & 15));
- }
- void instr16_0FBA_7_mem(int32_t addr, int32_t imm) {
- btc_mem(addr, imm & 15);
- }
- void instr32_0FBA_4_reg(int32_t r, int32_t imm) {
- bt_reg(read_reg32(r), imm & 31);
- }
- void instr32_0FBA_4_mem(int32_t addr, int32_t imm) {
- bt_mem(addr, imm & 31);
- }
- void instr32_0FBA_5_reg(int32_t r, int32_t imm) {
- write_reg32(r, bts_reg(read_reg32(r), imm & 31));
- }
- void instr32_0FBA_5_mem(int32_t addr, int32_t imm) {
- bts_mem(addr, imm & 31);
- }
- void instr32_0FBA_6_reg(int32_t r, int32_t imm) {
- write_reg32(r, btr_reg(read_reg32(r), imm & 31));
- }
- void instr32_0FBA_6_mem(int32_t addr, int32_t imm) {
- btr_mem(addr, imm & 31);
- }
- void instr32_0FBA_7_reg(int32_t r, int32_t imm) {
- write_reg32(r, btc_reg(read_reg32(r), imm & 31));
- }
- void instr32_0FBA_7_mem(int32_t addr, int32_t imm) {
- btc_mem(addr, imm & 31);
- }
- void instr16_0FBB_reg(int32_t r1, int32_t r2) { write_reg16(r1, btc_reg(read_reg16(r1), read_reg16(r2) & 15)); }
- void instr16_0FBB_mem(int32_t addr, int32_t r) { btc_mem(addr, read_reg16(r) << 16 >> 16); }
- void instr32_0FBB_reg(int32_t r1, int32_t r2) { write_reg32(r1, btc_reg(read_reg32(r1), read_reg32(r2) & 31)); }
- void instr32_0FBB_mem(int32_t addr, int32_t r) { btc_mem(addr, read_reg32(r)); }
- DEFINE_MODRM_INSTR_READ16(instr16_0FBC, write_reg16(r, bsf16(read_reg16(r), ___)))
- DEFINE_MODRM_INSTR_READ32(instr32_0FBC, write_reg32(r, bsf32(read_reg32(r), ___)))
- DEFINE_MODRM_INSTR_READ16(instr16_0FBD, write_reg16(r, bsr16(read_reg16(r), ___)))
- DEFINE_MODRM_INSTR_READ32(instr32_0FBD, write_reg32(r, bsr32(read_reg32(r), ___)))
- // movsx
- DEFINE_MODRM_INSTR_READ8(instr16_0FBE, write_reg16(r, ___ << 24 >> 24))
- DEFINE_MODRM_INSTR_READ8(instr32_0FBE, write_reg32(r, ___ << 24 >> 24))
- DEFINE_MODRM_INSTR_READ16(instr16_0FBF, write_reg16(r, ___ << 16 >> 16))
- DEFINE_MODRM_INSTR_READ16(instr32_0FBF, write_reg32(r, ___ << 16 >> 16))
- DEFINE_MODRM_INSTR_READ_WRITE_8(instr_0FC0, xadd8(___, get_reg8_index(r)))
- DEFINE_MODRM_INSTR_READ_WRITE_16(instr16_0FC1, xadd16(___, get_reg16_index(r)))
- DEFINE_MODRM_INSTR_READ_WRITE_32(instr32_0FC1, xadd32(___, r))
- void instr_0FC2() { unimplemented_sse(); }
- void instr_0FC3_reg(int32_t r1, int32_t r2) { trigger_ud(); }
- void instr_0FC3_mem(int32_t addr, int32_t r) {
- // movnti
- safe_write32(addr, read_reg32(r));
- }
- void instr_0FC4(int32_t source, int32_t r, int32_t imm8) {
- // pinsrw mm, r32/m16, imm8
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- uint32_t index = imm8 & 3;
- destination.u16[index] = source & 0xffff;
- write_mmx_reg64(r, destination);
- }
- DEFINE_SSE_SPLIT_IMM(instr_0FC4, read16, read_reg32)
- void instr_660FC4(int32_t source, int32_t r, int32_t imm8) {
- // pinsrw xmm, r32/m16, imm8
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- uint32_t index = imm8 & 7;
- destination.u16[index] = source & 0xffff;
- write_xmm_reg128(r, destination);
- }
- DEFINE_SSE_SPLIT_IMM(instr_660FC4, read16, read_reg32)
- void instr_0FC5_mem(int32_t addr, int32_t r, int32_t imm8) { trigger_ud(); }
- void instr_0FC5_reg(int32_t r1, int32_t r2, int32_t imm8) {
- // pextrw r32, mm, imm8
- task_switch_test_mmx();
- union reg64 data = read_mmx64s(r1);
- uint32_t index = imm8 & 3;
- uint32_t result = data.u16[index];
- write_reg32(r2, result);
- }
- void instr_660FC5_mem(int32_t addr, int32_t r, int32_t imm8) { trigger_ud(); }
- void instr_660FC5_reg(int32_t r1, int32_t r2, int32_t imm8) {
- // pextrw r32, xmm, imm8
- task_switch_test_mmx();
- union reg128 data = read_xmm128s(r1);
- uint32_t index = imm8 & 7;
- uint32_t result = data.u16[index];
- write_reg32(r2, result);
- }
- void instr_0FC6() { unimplemented_sse(); }
- void instr_0FC7_1_reg(int32_t r) { trigger_ud(); }
- void instr_0FC7_1_mem(int32_t addr) {
- // cmpxchg8b
- writable_or_pagefault(addr, 8);
- int32_t m64_low = safe_read32s(addr);
- int32_t m64_high = safe_read32s(addr + 4);
- if(reg32s[EAX] == m64_low &&
- reg32s[EDX] == m64_high)
- {
- flags[0] |= FLAG_ZERO;
- safe_write32(addr, reg32s[EBX]);
- safe_write32(addr + 4, reg32s[ECX]);
- }
- else
- {
- flags[0] &= ~FLAG_ZERO;
- reg32s[EAX] = m64_low;
- reg32s[EDX] = m64_high;
- safe_write32(addr, m64_low);
- safe_write32(addr + 4, m64_high);
- }
- flags_changed[0] &= ~FLAG_ZERO;
- }
- void instr_0FC7_6_reg(int32_t r) {
- // rdrand
- int32_t has_rand = has_rand_int();
- int32_t rand = 0;
- if(has_rand)
- {
- rand = get_rand_int();
- }
- write_reg_osize(r, rand);
- flags[0] &= ~FLAGS_ALL;
- flags[0] |= has_rand;
- flags_changed[0] = 0;
- }
- void instr_0FC7_6_mem(int32_t addr) {
- todo();
- trigger_ud();
- }
- void instr_0FC8() { bswap(EAX); }
- void instr_0FC9() { bswap(ECX); }
- void instr_0FCA() { bswap(EDX); }
- void instr_0FCB() { bswap(EBX); }
- void instr_0FCC() { bswap(ESP); }
- void instr_0FCD() { bswap(EBP); }
- void instr_0FCE() { bswap(ESI); }
- void instr_0FCF() { bswap(EDI); }
- void instr_0FD0() { unimplemented_sse(); }
- void instr_0FD1(union reg64 source, int32_t r) {
- // psrlw mm, mm/m64
- psrlw_r64(r, source.u32[0]);
- }
- DEFINE_SSE_SPLIT(instr_0FD1, safe_read64s, read_mmx64s)
- void instr_660FD1(union reg128 source, int32_t r) {
- // psrlw xmm, xmm/m128
- // XXX: Aligned access or #gp
- psrlw_r128(r, source.u32[0]);
- }
- DEFINE_SSE_SPLIT(instr_660FD1, safe_read128s, read_xmm128s)
- void instr_0FD2(union reg64 source, int32_t r) {
- // psrld mm, mm/m64
- psrld_r64(r, source.u32[0]);
- }
- DEFINE_SSE_SPLIT(instr_0FD2, safe_read64s, read_mmx64s)
- void instr_660FD2(union reg128 source, int32_t r) {
- // psrld xmm, xmm/m128
- // XXX: Aligned access or #gp
- psrld_r128(r, source.u32[0]);
- }
- DEFINE_SSE_SPLIT(instr_660FD2, safe_read128s, read_xmm128s)
- void instr_0FD3(union reg64 source, int32_t r) {
- // psrlq mm, mm/m64
- psrlq_r64(r, source.u32[0]);
- }
- DEFINE_SSE_SPLIT(instr_0FD3, safe_read64s, read_mmx64s)
- void instr_660FD3(union reg128 source, int32_t r) {
- // psrlq xmm, mm/m64
- psrlq_r128(r, source.u32[0]);
- }
- DEFINE_SSE_SPLIT(instr_660FD3, safe_read128s, read_xmm128s)
- void instr_0FD4(union reg64 source, int32_t r) {
- // paddq mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- destination.u64[0] += source.u64[0];
- write_mmx_reg64(r, destination);
- }
- DEFINE_SSE_SPLIT(instr_0FD4, safe_read64s, read_mmx64s)
- void instr_660FD4(union reg128 source, int32_t r) {
- // paddq xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- destination.u64[0] += source.u64[0];
- destination.u64[1] += source.u64[1];
- write_xmm_reg128(r, destination);
- }
- DEFINE_SSE_SPLIT(instr_660FD4, safe_read128s, read_xmm128s)
- void instr_0FD5(union reg64 source, int32_t r) {
- // pmullw mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- int32_t word0 = (destination.u16[0] * source.u16[0]) & 0xFFFF;
- int32_t word1 = (destination.u16[1] * source.u16[1]) & 0xFFFF;
- int32_t word2 = (destination.u16[2] * source.u16[2]) & 0xFFFF;
- int32_t word3 = (destination.u16[3] * source.u16[3]) & 0xFFFF;
- int32_t low = word0 | word1 << 16;
- int32_t high = word2 | word3 << 16;
- write_mmx64(r, low, high);
- }
- DEFINE_SSE_SPLIT(instr_0FD5, safe_read64s, read_mmx64s)
- void instr_660FD5(union reg128 source, int32_t r) {
- // pmullw xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- write_xmm128(
- r,
- source.u16[0] * destination.u16[0] & 0xFFFF | source.u16[1] * destination.u16[1] << 16,
- source.u16[2] * destination.u16[2] & 0xFFFF | source.u16[3] * destination.u16[3] << 16,
- source.u16[4] * destination.u16[4] & 0xFFFF | source.u16[5] * destination.u16[5] << 16,
- source.u16[6] * destination.u16[6] & 0xFFFF | source.u16[7] * destination.u16[7] << 16
- );
- }
- DEFINE_SSE_SPLIT(instr_660FD5, safe_read128s, read_xmm128s)
- void instr_0FD6_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_0FD6_reg(int32_t r1, int32_t r2) { trigger_ud(); }
- void instr_660FD6_mem(int32_t addr, int32_t r) {
- // movq xmm/m64, xmm
- movl_r128_m64(addr, r);
- }
- void instr_660FD6_reg(int32_t r1, int32_t r2) {
- // movq xmm/m64, xmm
- task_switch_test_mmx();
- union reg64 data = read_xmm64s(r2);
- write_xmm128(r1, data.u32[0], data.u32[1], 0, 0);
- }
- void instr_F20FD6_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_F20FD6_reg(int32_t r1, int32_t r2) {
- // movdq2q mm, xmm
- task_switch_test_mmx();
- union reg128 source = read_xmm128s(r1);
- write_mmx64(r2, source.u32[0], source.u32[1]);
- }
- void instr_F30FD6_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_F30FD6_reg(int32_t r1, int32_t r2) {
- // movq2dq xmm, mm
- task_switch_test_mmx();
- union reg64 source = read_mmx64s(r1);
- write_xmm128(r2, source.u32[0], source.u32[1], 0, 0);
- }
- void instr_0FD7_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_0FD7_reg(int32_t r1, int32_t r2) {
- // pmovmskb r, mm
- task_switch_test_mmx();
- union reg64 x = read_mmx64s(r1);
- uint32_t result =
- x.u8[0] >> 7 << 0 | x.u8[1] >> 7 << 1 | x.u8[2] >> 7 << 2 | x.u8[3] >> 7 << 3 |
- x.u8[4] >> 7 << 4 | x.u8[5] >> 7 << 5 | x.u8[6] >> 7 << 6 | x.u8[7] >> 7 << 7;
- write_reg32(r2, result);
- }
- void instr_660FD7_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_660FD7_reg(int32_t r1, int32_t r2) {
- // pmovmskb reg, xmm
- task_switch_test_mmx();
- union reg128 x = read_xmm128s(r1);
- int32_t result =
- x.u8[0] >> 7 << 0 | x.u8[1] >> 7 << 1 | x.u8[2] >> 7 << 2 | x.u8[3] >> 7 << 3 |
- x.u8[4] >> 7 << 4 | x.u8[5] >> 7 << 5 | x.u8[6] >> 7 << 6 | x.u8[7] >> 7 << 7 |
- x.u8[8] >> 7 << 8 | x.u8[9] >> 7 << 9 | x.u8[10] >> 7 << 10 | x.u8[11] >> 7 << 11 |
- x.u8[12] >> 7 << 12 | x.u8[13] >> 7 << 13 | x.u8[14] >> 7 << 14 | x.u8[15] >> 7 << 15;
- write_reg32(r2, result);
- }
- void instr_0FD8(union reg64 source, int32_t r) {
- // psubusb mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- union reg64 result = { { 0 } };
- for(uint32_t i = 0; i < 8; i++)
- {
- result.u8[i] = saturate_sd_to_ub(destination.u8[i] - source.u8[i]);
- }
- write_mmx_reg64(r, result);
- }
- DEFINE_SSE_SPLIT(instr_0FD8, safe_read64s, read_mmx64s)
- void instr_660FD8(union reg128 source, int32_t r) {
- // psubusb xmm, xmm/m128
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- union reg128 result;
- for(uint32_t i = 0; i < 16; i++)
- {
- result.u8[i] = saturate_sd_to_ub(destination.u8[i] - source.u8[i]);
- }
- write_xmm_reg128(r, result);
- }
- DEFINE_SSE_SPLIT(instr_660FD8, safe_read128s, read_xmm128s)
- void instr_0FD9(union reg64 source, int32_t r) {
- // psubusw mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- int32_t word0 = saturate_uw(destination.u16[0] - source.u16[0]);
- int32_t word1 = saturate_uw(destination.u16[1] - source.u16[1]);
- int32_t word2 = saturate_uw(destination.u16[2] - source.u16[2]);
- int32_t word3 = saturate_uw(destination.u16[3] - source.u16[3]);
- int32_t low = word0 | word1 << 16;
- int32_t high = word2 | word3 << 16;
- write_mmx64(r, low, high);
- }
- DEFINE_SSE_SPLIT(instr_0FD9, safe_read64s, read_mmx64s)
- void instr_660FD9(union reg128 source, int32_t r) {
- // psubusw xmm, xmm/m128
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- union reg128 result;
- for(uint32_t i = 0; i < 8; i++)
- {
- result.u16[i] = saturate_uw(destination.u16[i] - source.u16[i]);
- }
- write_xmm_reg128(r, result);
- }
- DEFINE_SSE_SPLIT(instr_660FD9, safe_read128s, read_xmm128s)
- void instr_0FDA(union reg64 source, int32_t r) {
- // pminub mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- union reg64 result;
- for(uint32_t i = 0; i < 8; i++)
- {
- result.u8[i] = source.u8[i] < destination.u8[i] ? source.u8[i] : destination.u8[i];
- }
- write_mmx_reg64(r, result);
- }
- DEFINE_SSE_SPLIT(instr_0FDA, safe_read64s, read_mmx64s)
- void instr_660FDA(union reg128 source, int32_t r) {
- // pminub xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- union reg128 result;
- for(uint32_t i = 0; i < 16; i++)
- {
- result.u8[i] = source.u8[i] < destination.u8[i] ? source.u8[i] : destination.u8[i];
- }
- write_xmm_reg128(r, result);
- }
- DEFINE_SSE_SPLIT(instr_660FDA, safe_read128s, read_xmm128s)
- void instr_0FDB(union reg64 source, int32_t r) {
- // pand mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- union reg64 result = { { 0 } };
- result.u64[0] = source.u64[0] & destination.u64[0];
- write_mmx_reg64(r, result);
- }
- DEFINE_SSE_SPLIT(instr_0FDB, safe_read64s, read_mmx64s)
- void instr_660FDB(union reg128 source, int32_t r) {
- // pand xmm, xmm/m128
- // XXX: Aligned access or #gp
- pand_r128(source, r);
- }
- DEFINE_SSE_SPLIT(instr_660FDB, safe_read128s, read_xmm128s)
- void instr_0FDC(union reg64 source, int32_t r) {
- // paddusb mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- union reg64 result = { { 0 } };
- for(uint32_t i = 0; i < 8; i++)
- {
- result.u8[i] = saturate_ud_to_ub(destination.u8[i] + source.u8[i]);
- }
- write_mmx_reg64(r, result);
- }
- DEFINE_SSE_SPLIT(instr_0FDC, safe_read64s, read_mmx64s)
- void instr_660FDC(union reg128 source, int32_t r) {
- // paddusb xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- union reg128 result;
- for(uint32_t i = 0; i < 16; i++)
- {
- result.u8[i] = saturate_ud_to_ub(source.u8[i] + destination.u8[i]);
- }
- write_xmm_reg128(r, result);
- }
- DEFINE_SSE_SPLIT(instr_660FDC, safe_read128s, read_xmm128s)
- void instr_0FDD(union reg64 source, int32_t r) {
- // paddusw mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- int32_t word0 = saturate_uw(destination.u16[0] + source.u16[0]);
- int32_t word1 = saturate_uw(destination.u16[1] + source.u16[1]);
- int32_t word2 = saturate_uw(destination.u16[2] + source.u16[2]);
- int32_t word3 = saturate_uw(destination.u16[3] + source.u16[3]);
- int32_t low = word0 | word1 << 16;
- int32_t high = word2 | word3 << 16;
- write_mmx64(r, low, high);
- }
- DEFINE_SSE_SPLIT(instr_0FDD, safe_read64s, read_mmx64s)
- void instr_660FDD(union reg128 source, int32_t r) {
- // paddusw xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- write_xmm128(
- r,
- saturate_uw(source.u16[0] + destination.u16[0]) | saturate_uw(source.u16[1] + destination.u16[1]) << 16,
- saturate_uw(source.u16[2] + destination.u16[2]) | saturate_uw(source.u16[3] + destination.u16[3]) << 16,
- saturate_uw(source.u16[4] + destination.u16[4]) | saturate_uw(source.u16[5] + destination.u16[5]) << 16,
- saturate_uw(source.u16[6] + destination.u16[6]) | saturate_uw(source.u16[7] + destination.u16[7]) << 16
- );
- }
- DEFINE_SSE_SPLIT(instr_660FDD, safe_read128s, read_xmm128s)
- void instr_0FDE(union reg64 source, int32_t r) {
- // pmaxub mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- union reg64 result;
- for(uint32_t i = 0; i < 8; i++)
- {
- result.u8[i] = source.u8[i] > destination.u8[i] ? source.u8[i] : destination.u8[i];
- }
- write_mmx_reg64(r, result);
- }
- DEFINE_SSE_SPLIT(instr_0FDE, safe_read64s, read_mmx64s)
- void instr_660FDE(union reg128 source, int32_t r) {
- // pmaxub xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- union reg128 result;
- for(uint32_t i = 0; i < 16; i++)
- {
- result.u8[i] = source.u8[i] > destination.u8[i] ? source.u8[i] : destination.u8[i];
- }
- write_xmm_reg128(r, result);
- }
- DEFINE_SSE_SPLIT(instr_660FDE, safe_read128s, read_xmm128s)
- void instr_0FDF(union reg64 source, int32_t r) {
- // pandn mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- union reg64 result = { { 0 } };
- result.u64[0] = source.u64[0] & ~destination.u64[0];
- write_mmx_reg64(r, result);
- }
- DEFINE_SSE_SPLIT(instr_0FDF, safe_read64s, read_mmx64s)
- void instr_660FDF(union reg128 source, int32_t r) {
- // pandn xmm, xmm/m128
- // XXX: Aligned access or #gp
- pandn_r128(source, r);
- }
- DEFINE_SSE_SPLIT(instr_660FDF, safe_read128s, read_xmm128s)
- void instr_0FE0(union reg64 source, int32_t r) {
- // pavgb mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- union reg64 result = { { 0 } };
- for(uint32_t i = 0; i < 8; i++)
- {
- result.u8[i] = (destination.u8[i] + source.u8[i] + 1) >> 1;
- }
- write_mmx_reg64(r, result);
- }
- DEFINE_SSE_SPLIT(instr_0FE0, safe_read64s, read_mmx64s)
- void instr_660FE0(union reg128 source, int32_t r) {
- // pavgb xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- union reg128 result;
- for(uint32_t i = 0; i < 16; i++)
- {
- result.u8[i] = (destination.u8[i] + source.u8[i] + 1) >> 1;
- }
- write_xmm_reg128(r, result);
- }
- DEFINE_SSE_SPLIT(instr_660FE0, safe_read128s, read_xmm128s)
- void instr_0FE1(union reg64 source, int32_t r) {
- // psraw mm, mm/m64
- psraw_r64(r, source.u32[0]);
- }
- DEFINE_SSE_SPLIT(instr_0FE1, safe_read64s, read_mmx64s)
- void instr_660FE1(union reg128 source, int32_t r) {
- // psraw xmm, xmm/m128
- // XXX: Aligned access or #gp
- psraw_r128(r, source.u32[0]);
- }
- DEFINE_SSE_SPLIT(instr_660FE1, safe_read128s, read_xmm128s)
- void instr_0FE2(union reg64 source, int32_t r) {
- // psrad mm, mm/m64
- psrad_r64(r, source.u32[0]);
- }
- DEFINE_SSE_SPLIT(instr_0FE2, safe_read64s, read_mmx64s)
- void instr_660FE2(union reg128 source, int32_t r) {
- // psrad xmm, xmm/m128
- // XXX: Aligned access or #gp
- psrad_r128(r, source.u32[0]);
- }
- DEFINE_SSE_SPLIT(instr_660FE2, safe_read128s, read_xmm128s)
- void instr_0FE3(union reg64 source, int32_t r) {
- // pavgw mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- destination.u16[0] = (destination.u16[0] + source.u16[0] + 1) >> 1;
- destination.u16[1] = (destination.u16[1] + source.u16[1] + 1) >> 1;
- destination.u16[2] = (destination.u16[2] + source.u16[2] + 1) >> 1;
- destination.u16[3] = (destination.u16[3] + source.u16[3] + 1) >> 1;
- write_mmx_reg64(r, destination);
- }
- DEFINE_SSE_SPLIT(instr_0FE3, safe_read64s, read_mmx64s)
- void instr_660FE3(union reg128 source, int32_t r) {
- // pavgw xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- destination.u16[0] = (destination.u16[0] + source.u16[0] + 1) >> 1;
- destination.u16[1] = (destination.u16[1] + source.u16[1] + 1) >> 1;
- destination.u16[2] = (destination.u16[2] + source.u16[2] + 1) >> 1;
- destination.u16[3] = (destination.u16[3] + source.u16[3] + 1) >> 1;
- destination.u16[4] = (destination.u16[4] + source.u16[4] + 1) >> 1;
- destination.u16[5] = (destination.u16[5] + source.u16[5] + 1) >> 1;
- destination.u16[6] = (destination.u16[6] + source.u16[6] + 1) >> 1;
- destination.u16[7] = (destination.u16[7] + source.u16[7] + 1) >> 1;
- write_xmm_reg128(r, destination);
- }
- DEFINE_SSE_SPLIT(instr_660FE3, safe_read128s, read_xmm128s)
- void instr_0FE4(union reg64 source, int32_t r) {
- // pmulhuw mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- write_mmx64(
- r,
- (source.u16[0] * destination.u16[0] >> 16) & 0xFFFF | source.u16[1] * destination.u16[1] & 0xFFFF0000,
- (source.u16[2] * destination.u16[2] >> 16) & 0xFFFF | source.u16[3] * destination.u16[3] & 0xFFFF0000
- );
- }
- DEFINE_SSE_SPLIT(instr_0FE4, safe_read64s, read_mmx64s)
- void instr_660FE4(union reg128 source, int32_t r) {
- // pmulhuw xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- write_xmm128(
- r,
- (source.u16[0] * destination.u16[0] >> 16) & 0xFFFF | source.u16[1] * destination.u16[1] & 0xFFFF0000,
- (source.u16[2] * destination.u16[2] >> 16) & 0xFFFF | source.u16[3] * destination.u16[3] & 0xFFFF0000,
- (source.u16[4] * destination.u16[4] >> 16) & 0xFFFF | source.u16[5] * destination.u16[5] & 0xFFFF0000,
- (source.u16[6] * destination.u16[6] >> 16) & 0xFFFF | source.u16[7] * destination.u16[7] & 0xFFFF0000
- );
- }
- DEFINE_SSE_SPLIT(instr_660FE4, safe_read128s, read_xmm128s)
- void instr_0FE5(union reg64 source, int32_t r) {
- // pmulhw mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- uint32_t word0 = ((destination.i16[0] * source.i16[0]) >> 16) & 0xFFFF;
- uint32_t word1 = ((destination.i16[1] * source.i16[1]) >> 16) & 0xFFFF;
- uint32_t word2 = ((destination.i16[2] * source.i16[2]) >> 16) & 0xFFFF;
- uint32_t word3 = ((destination.i16[3] * source.i16[3]) >> 16) & 0xFFFF;
- int32_t low = word0 | (word1 << 16);
- int32_t high = word2 | (word3 << 16);
- write_mmx64(r, low, high);
- }
- DEFINE_SSE_SPLIT(instr_0FE5, safe_read64s, read_mmx64s)
- void instr_660FE5(union reg128 source, int32_t r) {
- // pmulhw xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- int32_t dword0 = ((destination.i16[0] * source.i16[0]) >> 16) & 0xFFFF |
- ((destination.i16[1] * source.i16[1]) & 0xFFFF0000);
- int32_t dword1 = ((destination.i16[2] * source.i16[2]) >> 16) & 0xFFFF |
- ((destination.i16[3] * source.i16[3]) & 0xFFFF0000);
- int32_t dword2 = ((destination.i16[4] * source.i16[4]) >> 16) & 0xFFFF |
- ((destination.i16[5] * source.i16[5]) & 0xFFFF0000);
- int32_t dword3 = ((destination.i16[6] * source.i16[6]) >> 16) & 0xFFFF |
- ((destination.i16[7] * source.i16[7]) & 0xFFFF0000);
- write_xmm128(r, dword0, dword1, dword2, dword3);
- }
- DEFINE_SSE_SPLIT(instr_660FE5, safe_read128s, read_xmm128s)
- void instr_0FE6_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_0FE6_reg(int32_t r1, int32_t r2) { trigger_ud(); }
- void instr_660FE6_mem(int32_t addr, int32_t r) { unimplemented_sse(); }
- void instr_660FE6_reg(int32_t r1, int32_t r2) { unimplemented_sse(); }
- void instr_F20FE6_mem(int32_t addr, int32_t r) { unimplemented_sse(); }
- void instr_F20FE6_reg(int32_t r1, int32_t r2) { unimplemented_sse(); }
- void instr_F30FE6_mem(int32_t addr, int32_t r) { unimplemented_sse(); }
- void instr_F30FE6_reg(int32_t r1, int32_t r2) { unimplemented_sse(); }
- void instr_0FE7_mem(int32_t addr, int32_t r) {
- // movntq m64, mm
- mov_r_m64(addr, r);
- }
- void instr_0FE7_reg(int32_t r1, int32_t r2) { trigger_ud(); }
- void instr_660FE7_reg(int32_t r1, int32_t r2) { trigger_ud(); }
- void instr_660FE7_mem(int32_t addr, int32_t r) {
- // movntdq m128, xmm
- mov_r_m128(addr, r);
- }
- void instr_0FE8(union reg64 source, int32_t r) {
- // psubsb mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- union reg64 result = { { 0 } };
- for(uint32_t i = 0; i < 8; i++)
- {
- result.u8[i] = saturate_sd_to_sb(destination.i8[i] - source.i8[i]);
- }
- write_mmx_reg64(r, result);
- }
- DEFINE_SSE_SPLIT(instr_0FE8, safe_read64s, read_mmx64s)
- void instr_660FE8(union reg128 source, int32_t r) {
- // psubsb xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- union reg128 result;
- for(uint32_t i = 0; i < 16; i++)
- {
- result.i8[i] = saturate_sd_to_sb(destination.i8[i] - source.i8[i]);
- }
- write_xmm_reg128(r, result);
- }
- DEFINE_SSE_SPLIT(instr_660FE8, safe_read128s, read_xmm128s)
- void instr_0FE9(union reg64 source, int32_t r) {
- // psubsw mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- int32_t word0 = saturate_sd_to_sw(destination.i16[0] - source.i16[0]);
- int32_t word1 = saturate_sd_to_sw(destination.i16[1] - source.i16[1]);
- int32_t word2 = saturate_sd_to_sw(destination.i16[2] - source.i16[2]);
- int32_t word3 = saturate_sd_to_sw(destination.i16[3] - source.i16[3]);
- int32_t low = word0 | word1 << 16;
- int32_t high = word2 | word3 << 16;
- write_mmx64(r, low, high);
- }
- DEFINE_SSE_SPLIT(instr_0FE9, safe_read64s, read_mmx64s)
- void instr_660FE9(union reg128 source, int32_t r) {
- // psubsw xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- int32_t dword0 = saturate_sd_to_sw(destination.i16[0] - source.i16[0]) |
- saturate_sd_to_sw(destination.i16[1] - source.i16[1]) << 16;
- int32_t dword1 = saturate_sd_to_sw(destination.i16[2] - source.i16[2]) |
- saturate_sd_to_sw(destination.i16[3] - source.i16[3]) << 16;
- int32_t dword2 = saturate_sd_to_sw(destination.i16[4] - source.i16[4]) |
- saturate_sd_to_sw(destination.i16[5] - source.i16[5]) << 16;
- int32_t dword3 = saturate_sd_to_sw(destination.i16[6] - source.i16[6]) |
- saturate_sd_to_sw(destination.i16[7] - source.i16[7]) << 16;
- write_xmm128(r, dword0, dword1, dword2, dword3);
- }
- DEFINE_SSE_SPLIT(instr_660FE9, safe_read128s, read_xmm128s)
- void instr_0FEA(union reg64 source, int32_t r) {
- // pminsw mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- union reg64 result;
- for(uint32_t i = 0; i < 4; i++)
- {
- result.i16[i] = destination.i16[i] < source.i16[i] ? destination.i16[i] : source.i16[i];
- }
- write_mmx_reg64(r, result);
- }
- DEFINE_SSE_SPLIT(instr_0FEA, safe_read64s, read_mmx64s)
- void instr_660FEA(union reg128 source, int32_t r) {
- // pminsw xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- union reg128 result;
- for(uint32_t i = 0; i < 8; i++)
- {
- result.i16[i] = destination.i16[i] < source.i16[i] ? destination.i16[i] : source.i16[i];
- }
- write_xmm_reg128(r, result);
- }
- DEFINE_SSE_SPLIT(instr_660FEA, safe_read128s, read_xmm128s)
- void instr_0FEB(union reg64 source, int32_t r) {
- // por mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- union reg64 result = { { 0 } };
- result.u64[0] = source.u64[0] | destination.u64[0];
- write_mmx_reg64(r, result);
- }
- DEFINE_SSE_SPLIT(instr_0FEB, safe_read64s, read_mmx64s)
- void instr_660FEB(union reg128 source, int32_t r) {
- // por xmm, xmm/m128
- // XXX: Aligned access or #gp
- por_r128(source, r);
- }
- DEFINE_SSE_SPLIT(instr_660FEB, safe_read128s, read_xmm128s)
- void instr_0FEC(union reg64 source, int32_t r) {
- // paddsb mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- union reg64 result = { { 0 } };
- for(uint32_t i = 0; i < 8; i++)
- {
- result.u8[i] = saturate_sd_to_sb(destination.i8[i] + source.i8[i]);
- }
- write_mmx_reg64(r, result);
- }
- DEFINE_SSE_SPLIT(instr_0FEC, safe_read64s, read_mmx64s)
- void instr_660FEC(union reg128 source, int32_t r) {
- // paddsb xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- union reg128 result;
- for(uint32_t i = 0; i < 16; i++)
- {
- result.i8[i] = saturate_sd_to_sb(destination.i8[i] + source.i8[i]);
- }
- write_xmm_reg128(r, result);
- }
- DEFINE_SSE_SPLIT(instr_660FEC, safe_read128s, read_xmm128s)
- void instr_0FED(union reg64 source, int32_t r) {
- // paddsw mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- int32_t word0 = saturate_sd_to_sw(destination.i16[0] + source.i16[0]);
- int32_t word1 = saturate_sd_to_sw(destination.i16[1] + source.i16[1]);
- int32_t word2 = saturate_sd_to_sw(destination.i16[2] + source.i16[2]);
- int32_t word3 = saturate_sd_to_sw(destination.i16[3] + source.i16[3]);
- int32_t low = word0 | word1 << 16;
- int32_t high = word2 | word3 << 16;
- write_mmx64(r, low, high);
- }
- DEFINE_SSE_SPLIT(instr_0FED, safe_read64s, read_mmx64s)
- void instr_660FED(union reg128 source, int32_t r) {
- // paddsw xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- int32_t dword0 = saturate_sd_to_sw(destination.i16[0] + source.i16[0]) |
- saturate_sd_to_sw(destination.i16[1] + source.i16[1]) << 16;
- int32_t dword1 = saturate_sd_to_sw(destination.i16[2] + source.i16[2]) |
- saturate_sd_to_sw(destination.i16[3] + source.i16[3]) << 16;
- int32_t dword2 = saturate_sd_to_sw(destination.i16[4] + source.i16[4]) |
- saturate_sd_to_sw(destination.i16[5] + source.i16[5]) << 16;
- int32_t dword3 = saturate_sd_to_sw(destination.i16[6] + source.i16[6]) |
- saturate_sd_to_sw(destination.i16[7] + source.i16[7]) << 16;
- write_xmm128(r, dword0, dword1, dword2, dword3);
- }
- DEFINE_SSE_SPLIT(instr_660FED, safe_read128s, read_xmm128s)
- void instr_0FEE(union reg64 source, int32_t r) {
- // pmaxsw mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- union reg64 result;
- for(uint32_t i = 0; i < 4; i++)
- {
- result.i16[i] = destination.i16[i] >= source.i16[i] ? destination.i16[i] : source.i16[i];
- }
- write_mmx_reg64(r, result);
- }
- DEFINE_SSE_SPLIT(instr_0FEE, safe_read64s, read_mmx64s)
- void instr_660FEE(union reg128 source, int32_t r) {
- // pmaxsw xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- union reg128 result;
- for(uint32_t i = 0; i < 8; i++)
- {
- result.i16[i] = destination.i16[i] >= source.i16[i] ? destination.i16[i] : source.i16[i];
- }
- write_xmm_reg128(r, result);
- }
- DEFINE_SSE_SPLIT(instr_660FEE, safe_read128s, read_xmm128s)
- void instr_0FEF(union reg64 source, int32_t r) {
- // pxor mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- union reg64 result = { { 0 } };
- result.u64[0] = source.u64[0] ^ destination.u64[0];
- write_mmx_reg64(r, result);
- }
- DEFINE_SSE_SPLIT(instr_0FEF, safe_read64s, read_mmx64s)
- void instr_660FEF(union reg128 source, int32_t r) {
- // pxor xmm, xmm/m128
- // XXX: Aligned access or #gp
- pxor_r128(source, r);
- }
- DEFINE_SSE_SPLIT(instr_660FEF, safe_read128s, read_xmm128s)
- void instr_0FF0() { unimplemented_sse(); }
- void instr_0FF1(union reg64 source, int32_t r) {
- // psllw mm, mm/m64
- psllw_r64(r, source.u32[0]);
- }
- DEFINE_SSE_SPLIT(instr_0FF1, safe_read64s, read_mmx64s)
- void instr_660FF1(union reg128 source, int32_t r) {
- // psllw xmm, xmm/m128
- // XXX: Aligned access or #gp
- psllw_r128(r, source.u32[0]);
- }
- DEFINE_SSE_SPLIT(instr_660FF1, safe_read128s, read_xmm128s)
- void instr_0FF2(union reg64 source, int32_t r) {
- // pslld mm, mm/m64
- pslld_r64(r, source.u32[0]);
- }
- DEFINE_SSE_SPLIT(instr_0FF2, safe_read64s, read_mmx64s)
- void instr_660FF2(union reg128 source, int32_t r) {
- // pslld xmm, xmm/m128
- // XXX: Aligned access or #gp
- pslld_r128(r, source.u32[0]);
- }
- DEFINE_SSE_SPLIT(instr_660FF2, safe_read128s, read_xmm128s)
- void instr_0FF3(union reg64 source, int32_t r) {
- // psllq mm, mm/m64
- psllq_r64(r, source.u32[0]);
- }
- DEFINE_SSE_SPLIT(instr_0FF3, safe_read64s, read_mmx64s)
- void instr_660FF3(union reg128 source, int32_t r) {
- // psllq xmm, xmm/m128
- // XXX: Aligned access or #gp
- psllq_r128(r, source.u32[0]);
- }
- DEFINE_SSE_SPLIT(instr_660FF3, safe_read128s, read_xmm128s)
- void instr_0FF4(union reg64 source, int32_t r) {
- // pmuludq mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- destination.u64[0] = (uint64_t) source.u32[0] * (uint64_t) destination.u32[0];
- write_mmx_reg64(r, destination);
- }
- DEFINE_SSE_SPLIT(instr_0FF4, safe_read64s, read_mmx64s)
- void instr_660FF4(union reg128 source, int32_t r) {
- // pmuludq xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- destination.u64[0] = (uint64_t) source.u32[0] * (uint64_t) destination.u32[0];
- destination.u64[1] = (uint64_t) source.u32[2] * (uint64_t) destination.u32[2];
- write_xmm_reg128(r, destination);
- }
- DEFINE_SSE_SPLIT(instr_660FF4, safe_read128s, read_xmm128s)
- void instr_0FF5(union reg64 source, int32_t r) {
- // pmaddwd mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- int32_t mul0 = destination.i16[0] * source.i16[0];
- int32_t mul1 = destination.i16[1] * source.i16[1];
- int32_t mul2 = destination.i16[2] * source.i16[2];
- int32_t mul3 = destination.i16[3] * source.i16[3];
- int32_t low = mul0 + mul1;
- int32_t high = mul2 + mul3;
- write_mmx64(r, low, high);
- }
- DEFINE_SSE_SPLIT(instr_0FF5, safe_read64s, read_mmx64s)
- void instr_660FF5(union reg128 source, int32_t r) {
- // pmaddwd xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- int32_t dword0 = (destination.i16[0] * source.i16[0]) +
- (destination.i16[1] * source.i16[1]);
- int32_t dword1 = (destination.i16[2] * source.i16[2]) +
- (destination.i16[3] * source.i16[3]);
- int32_t dword2 = (destination.i16[4] * source.i16[4]) +
- (destination.i16[5] * source.i16[5]);
- int32_t dword3 = (destination.i16[6] * source.i16[6]) +
- (destination.i16[7] * source.i16[7]);
- write_xmm128(r, dword0, dword1, dword2, dword3);
- }
- DEFINE_SSE_SPLIT(instr_660FF5, safe_read128s, read_xmm128s)
- void instr_0FF6(union reg64 source, int32_t r) {
- // psadbw mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- uint32_t sum = 0;
- for(uint32_t i = 0; i < 8; i++)
- {
- sum += abs(destination.u8[i] - source.u8[i]);
- }
- write_mmx64(r, sum, 0);
- }
- DEFINE_SSE_SPLIT(instr_0FF6, safe_read64s, read_mmx64s)
- void instr_660FF6(union reg128 source, int32_t r) {
- // psadbw xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- uint32_t sum0 = 0;
- uint32_t sum1 = 0;
- for(uint32_t i = 0; i < 8; i++)
- {
- sum0 += abs(destination.u8[i] - source.u8[i]);
- sum1 += abs(destination.u8[i + 8] - source.u8[i + 8]);
- }
- write_xmm128(r, sum0, 0, sum1, 0);
- }
- DEFINE_SSE_SPLIT(instr_660FF6, safe_read128s, read_xmm128s)
- void instr_0FF7_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_0FF7_reg(int32_t r1, int32_t r2) {
- // maskmovq mm, mm
- task_switch_test_mmx();
- union reg64 source = read_mmx64s(r2);
- union reg64 mask = read_mmx64s(r1);
- int32_t addr = get_seg_prefix(DS) + get_reg_asize(EDI);
- writable_or_pagefault(addr, 8);
- for(uint32_t i = 0; i < 8; i++)
- {
- if(mask.u8[i] & 0x80)
- {
- safe_write8(addr + i, source.u8[i]);
- }
- }
- }
- void instr_660FF7_mem(int32_t addr, int32_t r) { trigger_ud(); }
- void instr_660FF7_reg(int32_t r1, int32_t r2) {
- // maskmovdqu xmm, xmm
- task_switch_test_mmx();
- union reg128 source = read_xmm128s(r2);
- union reg128 mask = read_xmm128s(r1);
- int32_t addr = get_seg_prefix(DS) + get_reg_asize(EDI);
- writable_or_pagefault(addr, 16);
- for(uint32_t i = 0; i < 16; i++)
- {
- if(mask.u8[i] & 0x80)
- {
- safe_write8(addr + i, source.u8[i]);
- }
- }
- }
- void instr_0FF8(union reg64 source, int32_t r) {
- // psubb mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- union reg64 result = { { 0 } };
- for(uint32_t i = 0; i < 8; i++)
- {
- result.u8[i] = (destination.i8[i] - source.i8[i]) & 0xFF;
- }
- write_mmx_reg64(r, result);
- }
- DEFINE_SSE_SPLIT(instr_0FF8, safe_read64s, read_mmx64s)
- void instr_660FF8(union reg128 source, int32_t r) {
- // psubb xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- union reg128 result = { { 0 } };
- for(uint32_t i = 0; i < 16; i++)
- {
- result.i8[i] = (destination.i8[i] - source.i8[i]) & 0xFF;
- }
- write_xmm_reg128(r, result);
- }
- DEFINE_SSE_SPLIT(instr_660FF8, safe_read128s, read_xmm128s)
- void instr_0FF9(union reg64 source, int32_t r) {
- // psubw mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- int32_t word0 = (destination.u32[0] - source.u32[0]) & 0xFFFF;
- int32_t word1 = (((uint32_t) destination.u16[1]) - source.u16[1]) & 0xFFFF;
- int32_t low = word0 | word1 << 16;
- int32_t word2 = (destination.u32[1] - source.u32[1]) & 0xFFFF;
- int32_t word3 = (((uint32_t) destination.u16[3]) - source.u16[3]) & 0xFFFF;
- int32_t high = word2 | word3 << 16;
- write_mmx64(r, low, high);
- }
- DEFINE_SSE_SPLIT(instr_0FF9, safe_read64s, read_mmx64s)
- void instr_660FF9(union reg128 source, int32_t r) {
- // psubw xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- union reg128 result = { { 0 } };
- for(uint32_t i = 0; i < 8; i++)
- {
- result.i16[i] = (destination.i16[i] - source.i16[i]) & 0xFFFF;
- }
- write_xmm_reg128(r, result);
- }
- DEFINE_SSE_SPLIT(instr_660FF9, safe_read128s, read_xmm128s)
- void instr_0FFA(union reg64 source, int32_t r) {
- // psubd mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- write_mmx64(
- r,
- destination.u32[0] - source.u32[0],
- destination.u32[1] - source.u32[1]
- );
- }
- DEFINE_SSE_SPLIT(instr_0FFA, safe_read64s, read_mmx64s)
- void instr_660FFA(union reg128 source, int32_t r) {
- // psubd xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- write_xmm128(
- r,
- destination.u32[0] - source.u32[0],
- destination.u32[1] - source.u32[1],
- destination.u32[2] - source.u32[2],
- destination.u32[3] - source.u32[3]
- );
- }
- DEFINE_SSE_SPLIT(instr_660FFA, safe_read128s, read_xmm128s)
- void instr_0FFB(union reg64 source, int32_t r) {
- // psubq mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- destination.u64[0] = destination.u64[0] - source.u64[0];
- write_mmx_reg64(r, destination);
- }
- DEFINE_SSE_SPLIT(instr_0FFB, safe_read64s, read_mmx64s)
- void instr_660FFB(union reg128 source, int32_t r) {
- // psubq xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- destination.u64[0] = destination.u64[0] - source.u64[0];
- destination.u64[1] = destination.u64[1] - source.u64[1];
- write_xmm_reg128(r, destination);
- }
- DEFINE_SSE_SPLIT(instr_660FFB, safe_read128s, read_xmm128s)
- void instr_0FFC(union reg64 source, int32_t r) {
- // paddb mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- union reg64 result = { { 0 } };
- for(uint32_t i = 0; i < 8; i++)
- {
- result.u8[i] = (destination.u8[i] + source.u8[i]) & 0xFF;
- }
- write_mmx_reg64(r, result);
- }
- DEFINE_SSE_SPLIT(instr_0FFC, safe_read64s, read_mmx64s)
- void instr_660FFC(union reg128 source, int32_t r) {
- // paddb xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- union reg128 result = { { 0 } };
- for(uint32_t i = 0; i < 16; i++)
- {
- result.u8[i] = (destination.u8[i] + source.u8[i]) & 0xFF;
- }
- write_xmm_reg128(r, result);
- }
- DEFINE_SSE_SPLIT(instr_660FFC, safe_read128s, read_xmm128s)
- void instr_0FFD(union reg64 source, int32_t r) {
- // paddw mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- int32_t word0 = (destination.u32[0] + source.u32[0]) & 0xFFFF;
- int32_t word1 = (destination.u16[1] + source.u16[1]) & 0xFFFF;
- int32_t low = word0 | word1 << 16;
- int32_t word2 = (destination.u32[1] + source.u32[1]) & 0xFFFF;
- int32_t word3 = (destination.u16[3] + source.u16[3]) & 0xFFFF;
- int32_t high = word2 | word3 << 16;
- write_mmx64(r, low, high);
- }
- DEFINE_SSE_SPLIT(instr_0FFD, safe_read64s, read_mmx64s)
- void instr_660FFD(union reg128 source, int32_t r) {
- // paddw xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- union reg128 result = { { 0 } };
- for(uint32_t i = 0; i < 8; i++)
- {
- result.u16[i] = (destination.u16[i] + source.u16[i]) & 0xFFFF;
- }
- write_xmm_reg128(r, result);
- }
- DEFINE_SSE_SPLIT(instr_660FFD, safe_read128s, read_xmm128s)
- void instr_0FFE(union reg64 source, int32_t r) {
- // paddd mm, mm/m64
- task_switch_test_mmx();
- union reg64 destination = read_mmx64s(r);
- int32_t low = destination.u32[0] + source.u32[0];
- int32_t high = destination.u32[1] + source.u32[1];
- write_mmx64(r, low, high);
- }
- DEFINE_SSE_SPLIT(instr_0FFE, safe_read64s, read_mmx64s)
- void instr_660FFE(union reg128 source, int32_t r) {
- // paddd xmm, xmm/m128
- // XXX: Aligned access or #gp
- task_switch_test_mmx();
- union reg128 destination = read_xmm128s(r);
- int32_t dword0 = destination.u32[0] + source.u32[0];
- int32_t dword1 = destination.u32[1] + source.u32[1];
- int32_t dword2 = destination.u32[2] + source.u32[2];
- int32_t dword3 = destination.u32[3] + source.u32[3];
- write_xmm128(r, dword0, dword1, dword2, dword3);
- }
- DEFINE_SSE_SPLIT(instr_660FFE, safe_read128s, read_xmm128s)
- void instr_0FFF() {
- // Windows 98
- dbg_log("#ud: 0F FF");
- trigger_ud();
- }
- void run_instruction0f_16(int32_t opcode)
- {
- #include "../../build/interpreter0f_16.c"
- }
- void run_instruction0f_32(int32_t opcode)
- {
- #include "../../build/interpreter0f_32.c"
- }
- #pragma clang diagnostic pop
|