123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415 |
- /* $OpenBSD: x86emu.c,v 1.9 2014/06/15 11:04:49 pirofti Exp $ */
- /* $NetBSD: x86emu.c,v 1.7 2009/02/03 19:26:29 joerg Exp $ */
- /*
- *
- * Realmode X86 Emulator Library
- *
- * Copyright (C) 1996-1999 SciTech Software, Inc.
- * Copyright (C) David Mosberger-Tang
- * Copyright (C) 1999 Egbert Eich
- * Copyright (C) 2007 Joerg Sonnenberger
- *
- * ========================================================================
- *
- * Permission to use, copy, modify, distribute, and sell this software and
- * its documentation for any purpose is hereby granted without fee,
- * provided that the above copyright notice appear in all copies and that
- * both that copyright notice and this permission notice appear in
- * supporting documentation, and that the name of the authors not be used
- * in advertising or publicity pertaining to distribution of the software
- * without specific, written prior permission. The authors makes no
- * representations about the suitability of this software for any purpose.
- * It is provided "as is" without express or implied warranty.
- *
- * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
- * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- *
- */
- #include <dev/x86emu/x86emu.h>
- #include <dev/x86emu/x86emu_regs.h>
- static void x86emu_intr_raise (struct x86emu *, uint8_t type);
- static void x86emu_exec_one_byte(struct x86emu *);
- static void x86emu_exec_two_byte(struct x86emu *);
- static void fetch_decode_modrm (struct x86emu *);
- static uint8_t fetch_byte_imm (struct x86emu *);
- static uint16_t fetch_word_imm (struct x86emu *);
- static uint32_t fetch_long_imm (struct x86emu *);
- static uint8_t fetch_data_byte (struct x86emu *, uint32_t offset);
- static uint8_t fetch_byte (struct x86emu *, uint segment, uint32_t offset);
- static uint16_t fetch_data_word (struct x86emu *, uint32_t offset);
- static uint16_t fetch_word (struct x86emu *, uint32_t segment, uint32_t offset);
- static uint32_t fetch_data_long (struct x86emu *, uint32_t offset);
- static uint32_t fetch_long (struct x86emu *, uint32_t segment, uint32_t offset);
- static void store_data_byte (struct x86emu *, uint32_t offset, uint8_t val);
- static void store_byte (struct x86emu *, uint32_t segment, uint32_t offset, uint8_t val);
- static void store_data_word (struct x86emu *, uint32_t offset, uint16_t val);
- static void store_word (struct x86emu *, uint32_t segment, uint32_t offset, uint16_t val);
- static void store_data_long (struct x86emu *, uint32_t offset, uint32_t val);
- static void store_long (struct x86emu *, uint32_t segment, uint32_t offset, uint32_t val);
- static uint8_t* decode_rl_byte_register(struct x86emu *);
- static uint16_t* decode_rl_word_register(struct x86emu *);
- static uint32_t* decode_rl_long_register(struct x86emu *);
- static uint8_t* decode_rh_byte_register(struct x86emu *);
- static uint16_t* decode_rh_word_register(struct x86emu *);
- static uint32_t* decode_rh_long_register(struct x86emu *);
- static uint16_t* decode_rh_seg_register(struct x86emu *);
- static uint32_t decode_rl_address(struct x86emu *);
- static uint8_t decode_and_fetch_byte(struct x86emu *);
- static uint16_t decode_and_fetch_word(struct x86emu *);
- static uint32_t decode_and_fetch_long(struct x86emu *);
- static uint8_t decode_and_fetch_byte_imm8(struct x86emu *, uint8_t *);
- static uint16_t decode_and_fetch_word_imm8(struct x86emu *, uint8_t *);
- static uint32_t decode_and_fetch_long_imm8(struct x86emu *, uint8_t *);
- static uint16_t decode_and_fetch_word_disp(struct x86emu *, int16_t);
- static uint32_t decode_and_fetch_long_disp(struct x86emu *, int16_t);
- static void write_back_byte(struct x86emu *, uint8_t);
- static void write_back_word(struct x86emu *, uint16_t);
- static void write_back_long(struct x86emu *, uint32_t);
- static uint16_t aaa_word (struct x86emu *, uint16_t d);
- static uint16_t aas_word (struct x86emu *, uint16_t d);
- static uint16_t aad_word (struct x86emu *, uint16_t d);
- static uint16_t aam_word (struct x86emu *, uint8_t d);
- static uint8_t adc_byte (struct x86emu *, uint8_t d, uint8_t s);
- static uint16_t adc_word (struct x86emu *, uint16_t d, uint16_t s);
- static uint32_t adc_long (struct x86emu *, uint32_t d, uint32_t s);
- static uint8_t add_byte (struct x86emu *, uint8_t d, uint8_t s);
- static uint16_t add_word (struct x86emu *, uint16_t d, uint16_t s);
- static uint32_t add_long (struct x86emu *, uint32_t d, uint32_t s);
- static uint8_t and_byte (struct x86emu *, uint8_t d, uint8_t s);
- static uint16_t and_word (struct x86emu *, uint16_t d, uint16_t s);
- static uint32_t and_long (struct x86emu *, uint32_t d, uint32_t s);
- static uint8_t cmp_byte (struct x86emu *, uint8_t d, uint8_t s);
- static uint16_t cmp_word (struct x86emu *, uint16_t d, uint16_t s);
- static uint32_t cmp_long (struct x86emu *, uint32_t d, uint32_t s);
- static void cmp_byte_no_return (struct x86emu *, uint8_t d, uint8_t s);
- static void cmp_word_no_return (struct x86emu *, uint16_t d, uint16_t s);
- static void cmp_long_no_return (struct x86emu *, uint32_t d, uint32_t s);
- static uint8_t daa_byte (struct x86emu *, uint8_t d);
- static uint8_t das_byte (struct x86emu *, uint8_t d);
- static uint8_t dec_byte (struct x86emu *, uint8_t d);
- static uint16_t dec_word (struct x86emu *, uint16_t d);
- static uint32_t dec_long (struct x86emu *, uint32_t d);
- static uint8_t inc_byte (struct x86emu *, uint8_t d);
- static uint16_t inc_word (struct x86emu *, uint16_t d);
- static uint32_t inc_long (struct x86emu *, uint32_t d);
- static uint8_t or_byte (struct x86emu *, uint8_t d, uint8_t s);
- static uint16_t or_word (struct x86emu *, uint16_t d, uint16_t s);
- static uint32_t or_long (struct x86emu *, uint32_t d, uint32_t s);
- static uint8_t neg_byte (struct x86emu *, uint8_t s);
- static uint16_t neg_word (struct x86emu *, uint16_t s);
- static uint32_t neg_long (struct x86emu *, uint32_t s);
- static uint8_t rcl_byte (struct x86emu *, uint8_t d, uint8_t s);
- static uint16_t rcl_word (struct x86emu *, uint16_t d, uint8_t s);
- static uint32_t rcl_long (struct x86emu *, uint32_t d, uint8_t s);
- static uint8_t rcr_byte (struct x86emu *, uint8_t d, uint8_t s);
- static uint16_t rcr_word (struct x86emu *, uint16_t d, uint8_t s);
- static uint32_t rcr_long (struct x86emu *, uint32_t d, uint8_t s);
- static uint8_t rol_byte (struct x86emu *, uint8_t d, uint8_t s);
- static uint16_t rol_word (struct x86emu *, uint16_t d, uint8_t s);
- static uint32_t rol_long (struct x86emu *, uint32_t d, uint8_t s);
- static uint8_t ror_byte (struct x86emu *, uint8_t d, uint8_t s);
- static uint16_t ror_word (struct x86emu *, uint16_t d, uint8_t s);
- static uint32_t ror_long (struct x86emu *, uint32_t d, uint8_t s);
- static uint8_t shl_byte (struct x86emu *, uint8_t d, uint8_t s);
- static uint16_t shl_word (struct x86emu *, uint16_t d, uint8_t s);
- static uint32_t shl_long (struct x86emu *, uint32_t d, uint8_t s);
- static uint8_t shr_byte (struct x86emu *, uint8_t d, uint8_t s);
- static uint16_t shr_word (struct x86emu *, uint16_t d, uint8_t s);
- static uint32_t shr_long (struct x86emu *, uint32_t d, uint8_t s);
- static uint8_t sar_byte (struct x86emu *, uint8_t d, uint8_t s);
- static uint16_t sar_word (struct x86emu *, uint16_t d, uint8_t s);
- static uint32_t sar_long (struct x86emu *, uint32_t d, uint8_t s);
- static uint16_t shld_word (struct x86emu *, uint16_t d, uint16_t fill, uint8_t s);
- static uint32_t shld_long (struct x86emu *, uint32_t d, uint32_t fill, uint8_t s);
- static uint16_t shrd_word (struct x86emu *, uint16_t d, uint16_t fill, uint8_t s);
- static uint32_t shrd_long (struct x86emu *, uint32_t d, uint32_t fill, uint8_t s);
- static uint8_t sbb_byte (struct x86emu *, uint8_t d, uint8_t s);
- static uint16_t sbb_word (struct x86emu *, uint16_t d, uint16_t s);
- static uint32_t sbb_long (struct x86emu *, uint32_t d, uint32_t s);
- static uint8_t sub_byte (struct x86emu *, uint8_t d, uint8_t s);
- static uint16_t sub_word (struct x86emu *, uint16_t d, uint16_t s);
- static uint32_t sub_long (struct x86emu *, uint32_t d, uint32_t s);
- static void test_byte (struct x86emu *, uint8_t d, uint8_t s);
- static void test_word (struct x86emu *, uint16_t d, uint16_t s);
- static void test_long (struct x86emu *, uint32_t d, uint32_t s);
- static uint8_t xor_byte (struct x86emu *, uint8_t d, uint8_t s);
- static uint16_t xor_word (struct x86emu *, uint16_t d, uint16_t s);
- static uint32_t xor_long (struct x86emu *, uint32_t d, uint32_t s);
- static void imul_byte (struct x86emu *, uint8_t s);
- static void imul_word (struct x86emu *, uint16_t s);
- static void imul_long (struct x86emu *, uint32_t s);
- static void mul_byte (struct x86emu *, uint8_t s);
- static void mul_word (struct x86emu *, uint16_t s);
- static void mul_long (struct x86emu *, uint32_t s);
- static void idiv_byte (struct x86emu *, uint8_t s);
- static void idiv_word (struct x86emu *, uint16_t s);
- static void idiv_long (struct x86emu *, uint32_t s);
- static void div_byte (struct x86emu *, uint8_t s);
- static void div_word (struct x86emu *, uint16_t s);
- static void div_long (struct x86emu *, uint32_t s);
- static void ins (struct x86emu *, int size);
- static void outs (struct x86emu *, int size);
- static void push_word (struct x86emu *, uint16_t w);
- static void push_long (struct x86emu *, uint32_t w);
- static uint16_t pop_word (struct x86emu *);
- static uint32_t pop_long (struct x86emu *);
- /*
- * REMARKS:
- * Handles any pending asychronous interrupts.
- */
- static void
- x86emu_intr_dispatch(struct x86emu *emu, uint8_t intno)
- {
- if (emu->_x86emu_intrTab[intno]) {
- (*emu->_x86emu_intrTab[intno]) (emu, intno);
- } else {
- push_word(emu, (uint16_t) emu->x86.R_FLG);
- CLEAR_FLAG(F_IF);
- CLEAR_FLAG(F_TF);
- push_word(emu, emu->x86.R_CS);
- emu->x86.R_CS = fetch_word(emu, 0, intno * 4 + 2);
- push_word(emu, emu->x86.R_IP);
- emu->x86.R_IP = fetch_word(emu, 0, intno * 4);
- }
- }
- static void
- x86emu_intr_handle(struct x86emu *emu)
- {
- uint8_t intno;
- if (emu->x86.intr & INTR_SYNCH) {
- intno = emu->x86.intno;
- emu->x86.intr = 0;
- x86emu_intr_dispatch(emu, intno);
- }
- }
- /*
- * PARAMETERS:
- * intrnum - Interrupt number to raise
- *
- * REMARKS:
- * Raise the specified interrupt to be handled before the execution of the
- * next instruction.
- */
- void
- x86emu_intr_raise(struct x86emu *emu, uint8_t intrnum)
- {
- emu->x86.intno = intrnum;
- emu->x86.intr |= INTR_SYNCH;
- }
- /*
- * REMARKS:
- * Main execution loop for the emulator. We return from here when the system
- * halts, which is normally caused by a stack fault when we return from the
- * original real mode call.
- */
- void
- x86emu_exec(struct x86emu *emu)
- {
- emu->x86.intr = 0;
- #ifdef _KERNEL
- if (setjmp(&emu->exec_state))
- return;
- #else
- if (setjmp(emu->exec_state))
- return;
- #endif
- for (;;) {
- if (emu->x86.intr) {
- if (((emu->x86.intr & INTR_SYNCH) &&
- (emu->x86.intno == 0 || emu->x86.intno == 2)) ||
- !ACCESS_FLAG(F_IF)) {
- x86emu_intr_handle(emu);
- }
- }
- if (emu->x86.R_CS == 0 && emu->x86.R_IP == 0)
- return;
- x86emu_exec_one_byte(emu);
- ++emu->cur_cycles;
- }
- }
- void
- x86emu_exec_call(struct x86emu *emu, uint16_t seg, uint16_t off)
- {
- push_word(emu, 0);
- push_word(emu, 0);
- emu->x86.R_CS = seg;
- emu->x86.R_IP = off;
- x86emu_exec(emu);
- }
- void
- x86emu_exec_intr(struct x86emu *emu, uint8_t intr)
- {
- push_word(emu, emu->x86.R_FLG);
- CLEAR_FLAG(F_IF);
- CLEAR_FLAG(F_TF);
- push_word(emu, 0);
- push_word(emu, 0);
- emu->x86.R_CS = (*emu->emu_rdw)(emu, intr * 4 + 2);
- emu->x86.R_IP = (*emu->emu_rdw)(emu, intr * 4);
- emu->x86.intr = 0;
- x86emu_exec(emu);
- }
- /*
- * REMARKS:
- * Halts the system by setting the halted system flag.
- */
- void
- x86emu_halt_sys(struct x86emu *emu)
- {
- #ifdef _KERNEL
- longjmp(&emu->exec_state);
- #else
- longjmp(emu->exec_state, 1);
- #endif
- }
- /*
- * PARAMETERS:
- * mod - Mod value from decoded byte
- * regh - Reg h value from decoded byte
- * regl - Reg l value from decoded byte
- *
- * REMARKS:
- * Raise the specified interrupt to be handled before the execution of the
- * next instruction.
- *
- * NOTE: Do not inline this function, as (*emu->emu_rdb) is already inline!
- */
- static void
- fetch_decode_modrm(struct x86emu *emu)
- {
- int fetched;
- fetched = fetch_byte_imm(emu);
- emu->cur_mod = (fetched >> 6) & 0x03;
- emu->cur_rh = (fetched >> 3) & 0x07;
- emu->cur_rl = (fetched >> 0) & 0x07;
- }
- /*
- * RETURNS:
- * Immediate byte value read from instruction queue
- *
- * REMARKS:
- * This function returns the immediate byte from the instruction queue, and
- * moves the instruction pointer to the next value.
- *
- * NOTE: Do not inline this function, as (*emu->emu_rdb) is already inline!
- */
- static uint8_t
- fetch_byte_imm(struct x86emu *emu)
- {
- uint8_t fetched;
- fetched = fetch_byte(emu, emu->x86.R_CS, emu->x86.R_IP);
- emu->x86.R_IP++;
- return fetched;
- }
- /*
- * RETURNS:
- * Immediate word value read from instruction queue
- *
- * REMARKS:
- * This function returns the immediate byte from the instruction queue, and
- * moves the instruction pointer to the next value.
- *
- * NOTE: Do not inline this function, as (*emu->emu_rdw) is already inline!
- */
- static uint16_t
- fetch_word_imm(struct x86emu *emu)
- {
- uint16_t fetched;
- fetched = fetch_word(emu, emu->x86.R_CS, emu->x86.R_IP);
- emu->x86.R_IP += 2;
- return fetched;
- }
- /*
- * RETURNS:
- * Immediate lone value read from instruction queue
- *
- * REMARKS:
- * This function returns the immediate byte from the instruction queue, and
- * moves the instruction pointer to the next value.
- *
- * NOTE: Do not inline this function, as (*emu->emu_rdw) is already inline!
- */
- static uint32_t
- fetch_long_imm(struct x86emu *emu)
- {
- uint32_t fetched;
- fetched = fetch_long(emu, emu->x86.R_CS, emu->x86.R_IP);
- emu->x86.R_IP += 4;
- return fetched;
- }
- /*
- * RETURNS:
- * Value of the default data segment
- *
- * REMARKS:
- * Inline function that returns the default data segment for the current
- * instruction.
- *
- * On the x86 processor, the default segment is not always DS if there is
- * no segment override. Address modes such as -3[BP] or 10[BP+SI] all refer to
- * addresses relative to SS (ie: on the stack). So, at the minimum, all
- * decodings of addressing modes would have to set/clear a bit describing
- * whether the access is relative to DS or SS. That is the function of the
- * cpu-state-varible emu->x86.mode. There are several potential states:
- *
- * repe prefix seen (handled elsewhere)
- * repne prefix seen (ditto)
- *
- * cs segment override
- * ds segment override
- * es segment override
- * fs segment override
- * gs segment override
- * ss segment override
- *
- * ds/ss select (in absense of override)
- *
- * Each of the above 7 items are handled with a bit in the mode field.
- */
- static uint32_t
- get_data_segment(struct x86emu *emu)
- {
- switch (emu->x86.mode & SYSMODE_SEGMASK) {
- case 0: /* default case: use ds register */
- case SYSMODE_SEGOVR_DS:
- case SYSMODE_SEGOVR_DS | SYSMODE_SEG_DS_SS:
- return emu->x86.R_DS;
- case SYSMODE_SEG_DS_SS:/* non-overridden, use ss register */
- return emu->x86.R_SS;
- case SYSMODE_SEGOVR_CS:
- case SYSMODE_SEGOVR_CS | SYSMODE_SEG_DS_SS:
- return emu->x86.R_CS;
- case SYSMODE_SEGOVR_ES:
- case SYSMODE_SEGOVR_ES | SYSMODE_SEG_DS_SS:
- return emu->x86.R_ES;
- case SYSMODE_SEGOVR_FS:
- case SYSMODE_SEGOVR_FS | SYSMODE_SEG_DS_SS:
- return emu->x86.R_FS;
- case SYSMODE_SEGOVR_GS:
- case SYSMODE_SEGOVR_GS | SYSMODE_SEG_DS_SS:
- return emu->x86.R_GS;
- case SYSMODE_SEGOVR_SS:
- case SYSMODE_SEGOVR_SS | SYSMODE_SEG_DS_SS:
- return emu->x86.R_SS;
- }
- x86emu_halt_sys(emu);
- }
- /*
- * PARAMETERS:
- * offset - Offset to load data from
- *
- * RETURNS:
- * Byte value read from the absolute memory location.
- *
- * NOTE: Do not inline this function as (*emu->emu_rdX) is already inline!
- */
- static uint8_t
- fetch_data_byte(struct x86emu *emu, uint32_t offset)
- {
- return fetch_byte(emu, get_data_segment(emu), offset);
- }
- /*
- * PARAMETERS:
- * offset - Offset to load data from
- *
- * RETURNS:
- * Word value read from the absolute memory location.
- *
- * NOTE: Do not inline this function as (*emu->emu_rdX) is already inline!
- */
- static uint16_t
- fetch_data_word(struct x86emu *emu, uint32_t offset)
- {
- return fetch_word(emu, get_data_segment(emu), offset);
- }
- /*
- * PARAMETERS:
- * offset - Offset to load data from
- *
- * RETURNS:
- * Long value read from the absolute memory location.
- *
- * NOTE: Do not inline this function as (*emu->emu_rdX) is already inline!
- */
- static uint32_t
- fetch_data_long(struct x86emu *emu, uint32_t offset)
- {
- return fetch_long(emu, get_data_segment(emu), offset);
- }
- /*
- * PARAMETERS:
- * segment - Segment to load data from
- * offset - Offset to load data from
- *
- * RETURNS:
- * Byte value read from the absolute memory location.
- *
- * NOTE: Do not inline this function as (*emu->emu_rdX) is already inline!
- */
- static uint8_t
- fetch_byte(struct x86emu *emu, uint32_t segment, uint32_t offset)
- {
- return (*emu->emu_rdb) (emu, ((uint32_t) segment << 4) + offset);
- }
- /*
- * PARAMETERS:
- * segment - Segment to load data from
- * offset - Offset to load data from
- *
- * RETURNS:
- * Word value read from the absolute memory location.
- *
- * NOTE: Do not inline this function as (*emu->emu_rdX) is already inline!
- */
- static uint16_t
- fetch_word(struct x86emu *emu, uint32_t segment, uint32_t offset)
- {
- return (*emu->emu_rdw) (emu, ((uint32_t) segment << 4) + offset);
- }
- /*
- * PARAMETERS:
- * segment - Segment to load data from
- * offset - Offset to load data from
- *
- * RETURNS:
- * Long value read from the absolute memory location.
- *
- * NOTE: Do not inline this function as (*emu->emu_rdX) is already inline!
- */
- static uint32_t
- fetch_long(struct x86emu *emu, uint32_t segment, uint32_t offset)
- {
- return (*emu->emu_rdl) (emu, ((uint32_t) segment << 4) + offset);
- }
- /*
- * PARAMETERS:
- * offset - Offset to store data at
- * val - Value to store
- *
- * REMARKS:
- * Writes a word value to an segmented memory location. The segment used is
- * the current 'default' segment, which may have been overridden.
- *
- * NOTE: Do not inline this function as (*emu->emu_wrX) is already inline!
- */
- static void
- store_data_byte(struct x86emu *emu, uint32_t offset, uint8_t val)
- {
- store_byte(emu, get_data_segment(emu), offset, val);
- }
- /*
- * PARAMETERS:
- * offset - Offset to store data at
- * val - Value to store
- *
- * REMARKS:
- * Writes a word value to an segmented memory location. The segment used is
- * the current 'default' segment, which may have been overridden.
- *
- * NOTE: Do not inline this function as (*emu->emu_wrX) is already inline!
- */
- static void
- store_data_word(struct x86emu *emu, uint32_t offset, uint16_t val)
- {
- store_word(emu, get_data_segment(emu), offset, val);
- }
- /*
- * PARAMETERS:
- * offset - Offset to store data at
- * val - Value to store
- *
- * REMARKS:
- * Writes a long value to an segmented memory location. The segment used is
- * the current 'default' segment, which may have been overridden.
- *
- * NOTE: Do not inline this function as (*emu->emu_wrX) is already inline!
- */
- static void
- store_data_long(struct x86emu *emu, uint32_t offset, uint32_t val)
- {
- store_long(emu, get_data_segment(emu), offset, val);
- }
- /*
- * PARAMETERS:
- * segment - Segment to store data at
- * offset - Offset to store data at
- * val - Value to store
- *
- * REMARKS:
- * Writes a byte value to an absolute memory location.
- *
- * NOTE: Do not inline this function as (*emu->emu_wrX) is already inline!
- */
- static void
- store_byte(struct x86emu *emu, uint32_t segment, uint32_t offset, uint8_t val)
- {
- (*emu->emu_wrb) (emu, ((uint32_t) segment << 4) + offset, val);
- }
- /*
- * PARAMETERS:
- * segment - Segment to store data at
- * offset - Offset to store data at
- * val - Value to store
- *
- * REMARKS:
- * Writes a word value to an absolute memory location.
- *
- * NOTE: Do not inline this function as (*emu->emu_wrX) is already inline!
- */
- static void
- store_word(struct x86emu *emu, uint32_t segment, uint32_t offset, uint16_t val)
- {
- (*emu->emu_wrw) (emu, ((uint32_t) segment << 4) + offset, val);
- }
- /*
- * PARAMETERS:
- * segment - Segment to store data at
- * offset - Offset to store data at
- * val - Value to store
- *
- * REMARKS:
- * Writes a long value to an absolute memory location.
- *
- * NOTE: Do not inline this function as (*emu->emu_wrX) is already inline!
- */
- static void
- store_long(struct x86emu *emu, uint32_t segment, uint32_t offset, uint32_t val)
- {
- (*emu->emu_wrl) (emu, ((uint32_t) segment << 4) + offset, val);
- }
- /*
- * PARAMETERS:
- * reg - Register to decode
- *
- * RETURNS:
- * Pointer to the appropriate register
- *
- * REMARKS:
- * Return a pointer to the register given by the R/RM field of the
- * modrm byte, for byte operands. Also enables the decoding of instructions.
- */
- static uint8_t *
- decode_rm_byte_register(struct x86emu *emu, int reg)
- {
- switch (reg) {
- case 0:
- return &emu->x86.R_AL;
- case 1:
- return &emu->x86.R_CL;
- case 2:
- return &emu->x86.R_DL;
- case 3:
- return &emu->x86.R_BL;
- case 4:
- return &emu->x86.R_AH;
- case 5:
- return &emu->x86.R_CH;
- case 6:
- return &emu->x86.R_DH;
- case 7:
- return &emu->x86.R_BH;
- default:
- x86emu_halt_sys(emu);
- }
- }
- static uint8_t *
- decode_rl_byte_register(struct x86emu *emu)
- {
- return decode_rm_byte_register(emu, emu->cur_rl);
- }
- static uint8_t *
- decode_rh_byte_register(struct x86emu *emu)
- {
- return decode_rm_byte_register(emu, emu->cur_rh);
- }
- /*
- * PARAMETERS:
- * reg - Register to decode
- *
- * RETURNS:
- * Pointer to the appropriate register
- *
- * REMARKS:
- * Return a pointer to the register given by the R/RM field of the
- * modrm byte, for word operands. Also enables the decoding of instructions.
- */
- static uint16_t *
- decode_rm_word_register(struct x86emu *emu, int reg)
- {
- switch (reg) {
- case 0:
- return &emu->x86.R_AX;
- case 1:
- return &emu->x86.R_CX;
- case 2:
- return &emu->x86.R_DX;
- case 3:
- return &emu->x86.R_BX;
- case 4:
- return &emu->x86.R_SP;
- case 5:
- return &emu->x86.R_BP;
- case 6:
- return &emu->x86.R_SI;
- case 7:
- return &emu->x86.R_DI;
- default:
- x86emu_halt_sys(emu);
- }
- }
- static uint16_t *
- decode_rl_word_register(struct x86emu *emu)
- {
- return decode_rm_word_register(emu, emu->cur_rl);
- }
- static uint16_t *
- decode_rh_word_register(struct x86emu *emu)
- {
- return decode_rm_word_register(emu, emu->cur_rh);
- }
- /*
- * PARAMETERS:
- * reg - Register to decode
- *
- * RETURNS:
- * Pointer to the appropriate register
- *
- * REMARKS:
- * Return a pointer to the register given by the R/RM field of the
- * modrm byte, for dword operands. Also enables the decoding of instructions.
- */
- static uint32_t *
- decode_rm_long_register(struct x86emu *emu, int reg)
- {
- switch (reg) {
- case 0:
- return &emu->x86.R_EAX;
- case 1:
- return &emu->x86.R_ECX;
- case 2:
- return &emu->x86.R_EDX;
- case 3:
- return &emu->x86.R_EBX;
- case 4:
- return &emu->x86.R_ESP;
- case 5:
- return &emu->x86.R_EBP;
- case 6:
- return &emu->x86.R_ESI;
- case 7:
- return &emu->x86.R_EDI;
- default:
- x86emu_halt_sys(emu);
- }
- }
- static uint32_t *
- decode_rl_long_register(struct x86emu *emu)
- {
- return decode_rm_long_register(emu, emu->cur_rl);
- }
- static uint32_t *
- decode_rh_long_register(struct x86emu *emu)
- {
- return decode_rm_long_register(emu, emu->cur_rh);
- }
- /*
- * PARAMETERS:
- * reg - Register to decode
- *
- * RETURNS:
- * Pointer to the appropriate register
- *
- * REMARKS:
- * Return a pointer to the register given by the R/RM field of the
- * modrm byte, for word operands, modified from above for the weirdo
- * special case of segreg operands. Also enables the decoding of instructions.
- */
- static uint16_t *
- decode_rh_seg_register(struct x86emu *emu)
- {
- switch (emu->cur_rh) {
- case 0:
- return &emu->x86.R_ES;
- case 1:
- return &emu->x86.R_CS;
- case 2:
- return &emu->x86.R_SS;
- case 3:
- return &emu->x86.R_DS;
- case 4:
- return &emu->x86.R_FS;
- case 5:
- return &emu->x86.R_GS;
- default:
- x86emu_halt_sys(emu);
- }
- }
- /*
- * Return offset from the SIB Byte.
- */
- static uint32_t
- decode_sib_address(struct x86emu *emu, int sib, int mod)
- {
- uint32_t base = 0, i = 0, scale = 1;
- switch (sib & 0x07) {
- case 0:
- base = emu->x86.R_EAX;
- break;
- case 1:
- base = emu->x86.R_ECX;
- break;
- case 2:
- base = emu->x86.R_EDX;
- break;
- case 3:
- base = emu->x86.R_EBX;
- break;
- case 4:
- base = emu->x86.R_ESP;
- emu->x86.mode |= SYSMODE_SEG_DS_SS;
- break;
- case 5:
- if (mod == 0) {
- base = fetch_long_imm(emu);
- } else {
- base = emu->x86.R_EBP;
- emu->x86.mode |= SYSMODE_SEG_DS_SS;
- }
- break;
- case 6:
- base = emu->x86.R_ESI;
- break;
- case 7:
- base = emu->x86.R_EDI;
- break;
- }
- switch ((sib >> 3) & 0x07) {
- case 0:
- i = emu->x86.R_EAX;
- break;
- case 1:
- i = emu->x86.R_ECX;
- break;
- case 2:
- i = emu->x86.R_EDX;
- break;
- case 3:
- i = emu->x86.R_EBX;
- break;
- case 4:
- i = 0;
- break;
- case 5:
- i = emu->x86.R_EBP;
- break;
- case 6:
- i = emu->x86.R_ESI;
- break;
- case 7:
- i = emu->x86.R_EDI;
- break;
- }
- scale = 1 << ((sib >> 6) & 0x03);
- return base + (i * scale);
- }
- /*
- * PARAMETERS:
- * rm - RM value to decode
- *
- * RETURNS:
- * Offset in memory for the address decoding
- *
- * REMARKS:
- * Return the offset given by mod=00, mod=01 or mod=10 addressing.
- * Also enables the decoding of instructions.
- */
- static uint32_t
- decode_rl_address(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_ADDR) {
- uint32_t offset, sib;
- /* 32-bit addressing */
- switch (emu->cur_rl) {
- case 0:
- offset = emu->x86.R_EAX;
- break;
- case 1:
- offset = emu->x86.R_ECX;
- break;
- case 2:
- offset = emu->x86.R_EDX;
- break;
- case 3:
- offset = emu->x86.R_EBX;
- break;
- case 4:
- sib = fetch_byte_imm(emu);
- offset = decode_sib_address(emu, sib, 0);
- break;
- case 5:
- if (emu->cur_mod == 0) {
- offset = fetch_long_imm(emu);
- } else {
- emu->x86.mode |= SYSMODE_SEG_DS_SS;
- offset = emu->x86.R_EBP;
- }
- break;
- case 6:
- offset = emu->x86.R_ESI;
- break;
- case 7:
- offset = emu->x86.R_EDI;
- break;
- default:
- x86emu_halt_sys(emu);
- }
- if (emu->cur_mod == 1)
- offset += (int8_t)fetch_byte_imm(emu);
- else if (emu->cur_mod == 2)
- offset += fetch_long_imm(emu);
- return offset;
- } else {
- uint16_t offset;
- /* 16-bit addressing */
- switch (emu->cur_rl) {
- case 0:
- offset = emu->x86.R_BX + emu->x86.R_SI;
- break;
- case 1:
- offset = emu->x86.R_BX + emu->x86.R_DI;
- break;
- case 2:
- emu->x86.mode |= SYSMODE_SEG_DS_SS;
- offset = emu->x86.R_BP + emu->x86.R_SI;
- break;
- case 3:
- emu->x86.mode |= SYSMODE_SEG_DS_SS;
- offset = emu->x86.R_BP + emu->x86.R_DI;
- break;
- case 4:
- offset = emu->x86.R_SI;
- break;
- case 5:
- offset = emu->x86.R_DI;
- break;
- case 6:
- if (emu->cur_mod == 0) {
- offset = fetch_word_imm(emu);
- } else {
- emu->x86.mode |= SYSMODE_SEG_DS_SS;
- offset = emu->x86.R_BP;
- }
- break;
- case 7:
- offset = emu->x86.R_BX;
- break;
- default:
- x86emu_halt_sys(emu);
- }
- if (emu->cur_mod == 1)
- offset += (int8_t)fetch_byte_imm(emu);
- else if (emu->cur_mod == 2)
- offset += fetch_word_imm(emu);
- return offset;
- }
- }
- static uint8_t
- decode_and_fetch_byte(struct x86emu *emu)
- {
- if (emu->cur_mod != 3) {
- emu->cur_offset = decode_rl_address(emu);
- return fetch_data_byte(emu, emu->cur_offset);
- } else {
- return *decode_rl_byte_register(emu);
- }
- }
- static uint16_t
- decode_and_fetch_word_disp(struct x86emu *emu, int16_t disp)
- {
- if (emu->cur_mod != 3) {
- /* TODO: A20 gate emulation */
- emu->cur_offset = decode_rl_address(emu) + disp;
- if ((emu->x86.mode & SYSMODE_PREFIX_ADDR) == 0)
- emu->cur_offset &= 0xffff;
- return fetch_data_word(emu, emu->cur_offset);
- } else {
- return *decode_rl_word_register(emu);
- }
- }
- static uint32_t
- decode_and_fetch_long_disp(struct x86emu *emu, int16_t disp)
- {
- if (emu->cur_mod != 3) {
- /* TODO: A20 gate emulation */
- emu->cur_offset = decode_rl_address(emu) + disp;
- if ((emu->x86.mode & SYSMODE_PREFIX_ADDR) == 0)
- emu->cur_offset &= 0xffff;
- return fetch_data_long(emu, emu->cur_offset);
- } else {
- return *decode_rl_long_register(emu);
- }
- }
- uint16_t
- decode_and_fetch_word(struct x86emu *emu)
- {
- return decode_and_fetch_word_disp(emu, 0);
- }
- uint32_t
- decode_and_fetch_long(struct x86emu *emu)
- {
- return decode_and_fetch_long_disp(emu, 0);
- }
- uint8_t
- decode_and_fetch_byte_imm8(struct x86emu *emu, uint8_t *imm)
- {
- if (emu->cur_mod != 3) {
- emu->cur_offset = decode_rl_address(emu);
- *imm = fetch_byte_imm(emu);
- return fetch_data_byte(emu, emu->cur_offset);
- } else {
- *imm = fetch_byte_imm(emu);
- return *decode_rl_byte_register(emu);
- }
- }
- static uint16_t
- decode_and_fetch_word_imm8(struct x86emu *emu, uint8_t *imm)
- {
- if (emu->cur_mod != 3) {
- emu->cur_offset = decode_rl_address(emu);
- *imm = fetch_byte_imm(emu);
- return fetch_data_word(emu, emu->cur_offset);
- } else {
- *imm = fetch_byte_imm(emu);
- return *decode_rl_word_register(emu);
- }
- }
- static uint32_t
- decode_and_fetch_long_imm8(struct x86emu *emu, uint8_t *imm)
- {
- if (emu->cur_mod != 3) {
- emu->cur_offset = decode_rl_address(emu);
- *imm = fetch_byte_imm(emu);
- return fetch_data_long(emu, emu->cur_offset);
- } else {
- *imm = fetch_byte_imm(emu);
- return *decode_rl_long_register(emu);
- }
- }
- static void
- write_back_byte(struct x86emu *emu, uint8_t val)
- {
- if (emu->cur_mod != 3)
- store_data_byte(emu, emu->cur_offset, val);
- else
- *decode_rl_byte_register(emu) = val;
- }
- static void
- write_back_word(struct x86emu *emu, uint16_t val)
- {
- if (emu->cur_mod != 3)
- store_data_word(emu, emu->cur_offset, val);
- else
- *decode_rl_word_register(emu) = val;
- }
- static void
- write_back_long(struct x86emu *emu, uint32_t val)
- {
- if (emu->cur_mod != 3)
- store_data_long(emu, emu->cur_offset, val);
- else
- *decode_rl_long_register(emu) = val;
- }
- static void
- common_inc_word_long(struct x86emu *emu, union x86emu_register *reg)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- reg->I32_reg.e_reg = inc_long(emu, reg->I32_reg.e_reg);
- else
- reg->I16_reg.x_reg = inc_word(emu, reg->I16_reg.x_reg);
- }
- static void
- common_dec_word_long(struct x86emu *emu, union x86emu_register *reg)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- reg->I32_reg.e_reg = dec_long(emu, reg->I32_reg.e_reg);
- else
- reg->I16_reg.x_reg = dec_word(emu, reg->I16_reg.x_reg);
- }
- static void
- common_binop_byte_rm_r(struct x86emu *emu,
- uint8_t (*binop)(struct x86emu *, uint8_t, uint8_t))
- {
- uint32_t destoffset;
- uint8_t *destreg, srcval;
- uint8_t destval;
- fetch_decode_modrm(emu);
- srcval = *decode_rh_byte_register(emu);
- if (emu->cur_mod != 3) {
- destoffset = decode_rl_address(emu);
- destval = fetch_data_byte(emu, destoffset);
- destval = (*binop)(emu, destval, srcval);
- store_data_byte(emu, destoffset, destval);
- } else {
- destreg = decode_rl_byte_register(emu);
- *destreg = (*binop)(emu, *destreg, srcval);
- }
- }
- static void
- common_binop_ns_byte_rm_r(struct x86emu *emu,
- void (*binop)(struct x86emu *, uint8_t, uint8_t))
- {
- uint32_t destoffset;
- uint8_t destval, srcval;
- fetch_decode_modrm(emu);
- srcval = *decode_rh_byte_register(emu);
- if (emu->cur_mod != 3) {
- destoffset = decode_rl_address(emu);
- destval = fetch_data_byte(emu, destoffset);
- } else {
- destval = *decode_rl_byte_register(emu);
- }
- (*binop)(emu, destval, srcval);
- }
- static void
- common_binop_word_rm_r(struct x86emu *emu,
- uint16_t (*binop)(struct x86emu *, uint16_t, uint16_t))
- {
- uint32_t destoffset;
- uint16_t destval, *destreg, srcval;
- fetch_decode_modrm(emu);
- srcval = *decode_rh_word_register(emu);
- if (emu->cur_mod != 3) {
- destoffset = decode_rl_address(emu);
- destval = fetch_data_word(emu, destoffset);
- destval = (*binop)(emu, destval, srcval);
- store_data_word(emu, destoffset, destval);
- } else {
- destreg = decode_rl_word_register(emu);
- *destreg = (*binop)(emu, *destreg, srcval);
- }
- }
- static void
- common_binop_byte_r_rm(struct x86emu *emu,
- uint8_t (*binop)(struct x86emu *, uint8_t, uint8_t))
- {
- uint8_t *destreg, srcval;
- uint32_t srcoffset;
- fetch_decode_modrm(emu);
- destreg = decode_rh_byte_register(emu);
- if (emu->cur_mod != 3) {
- srcoffset = decode_rl_address(emu);
- srcval = fetch_data_byte(emu, srcoffset);
- } else {
- srcval = *decode_rl_byte_register(emu);
- }
- *destreg = (*binop)(emu, *destreg, srcval);
- }
- static void
- common_binop_long_rm_r(struct x86emu *emu,
- uint32_t (*binop)(struct x86emu *, uint32_t, uint32_t))
- {
- uint32_t destoffset;
- uint32_t destval, *destreg, srcval;
- fetch_decode_modrm(emu);
- srcval = *decode_rh_long_register(emu);
- if (emu->cur_mod != 3) {
- destoffset = decode_rl_address(emu);
- destval = fetch_data_long(emu, destoffset);
- destval = (*binop)(emu, destval, srcval);
- store_data_long(emu, destoffset, destval);
- } else {
- destreg = decode_rl_long_register(emu);
- *destreg = (*binop)(emu, *destreg, srcval);
- }
- }
- static void
- common_binop_word_long_rm_r(struct x86emu *emu,
- uint16_t (*binop16)(struct x86emu *, uint16_t, uint16_t),
- uint32_t (*binop32)(struct x86emu *, uint32_t, uint32_t))
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- common_binop_long_rm_r(emu, binop32);
- else
- common_binop_word_rm_r(emu, binop16);
- }
- static void
- common_binop_ns_word_rm_r(struct x86emu *emu,
- void (*binop)(struct x86emu *, uint16_t, uint16_t))
- {
- uint32_t destoffset;
- uint16_t destval, srcval;
- fetch_decode_modrm(emu);
- srcval = *decode_rh_word_register(emu);
- if (emu->cur_mod != 3) {
- destoffset = decode_rl_address(emu);
- destval = fetch_data_word(emu, destoffset);
- } else {
- destval = *decode_rl_word_register(emu);
- }
- (*binop)(emu, destval, srcval);
- }
- static void
- common_binop_ns_long_rm_r(struct x86emu *emu,
- void (*binop)(struct x86emu *, uint32_t, uint32_t))
- {
- uint32_t destoffset;
- uint32_t destval, srcval;
- fetch_decode_modrm(emu);
- srcval = *decode_rh_long_register(emu);
- if (emu->cur_mod != 3) {
- destoffset = decode_rl_address(emu);
- destval = fetch_data_long(emu, destoffset);
- } else {
- destval = *decode_rl_long_register(emu);
- }
- (*binop)(emu, destval, srcval);
- }
- static void
- common_binop_ns_word_long_rm_r(struct x86emu *emu,
- void (*binop16)(struct x86emu *, uint16_t, uint16_t),
- void (*binop32)(struct x86emu *, uint32_t, uint32_t))
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- common_binop_ns_long_rm_r(emu, binop32);
- else
- common_binop_ns_word_rm_r(emu, binop16);
- }
- static void
- common_binop_long_r_rm(struct x86emu *emu,
- uint32_t (*binop)(struct x86emu *, uint32_t, uint32_t))
- {
- uint32_t srcoffset;
- uint32_t *destreg, srcval;
- fetch_decode_modrm(emu);
- destreg = decode_rh_long_register(emu);
- if (emu->cur_mod != 3) {
- srcoffset = decode_rl_address(emu);
- srcval = fetch_data_long(emu, srcoffset);
- } else {
- srcval = *decode_rl_long_register(emu);
- }
- *destreg = (*binop)(emu, *destreg, srcval);
- }
- static void
- common_binop_word_r_rm(struct x86emu *emu,
- uint16_t (*binop)(struct x86emu *, uint16_t, uint16_t))
- {
- uint32_t srcoffset;
- uint16_t *destreg, srcval;
- fetch_decode_modrm(emu);
- destreg = decode_rh_word_register(emu);
- if (emu->cur_mod != 3) {
- srcoffset = decode_rl_address(emu);
- srcval = fetch_data_word(emu, srcoffset);
- } else {
- srcval = *decode_rl_word_register(emu);
- }
- *destreg = (*binop)(emu, *destreg, srcval);
- }
- static void
- common_binop_word_long_r_rm(struct x86emu *emu,
- uint16_t (*binop16)(struct x86emu *, uint16_t, uint16_t),
- uint32_t (*binop32)(struct x86emu *, uint32_t, uint32_t))
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- common_binop_long_r_rm(emu, binop32);
- else
- common_binop_word_r_rm(emu, binop16);
- }
- static void
- common_binop_byte_imm(struct x86emu *emu,
- uint8_t (*binop)(struct x86emu *, uint8_t, uint8_t))
- {
- uint8_t srcval;
- srcval = fetch_byte_imm(emu);
- emu->x86.R_AL = (*binop)(emu, emu->x86.R_AL, srcval);
- }
- static void
- common_binop_word_long_imm(struct x86emu *emu,
- uint16_t (*binop16)(struct x86emu *, uint16_t, uint16_t),
- uint32_t (*binop32)(struct x86emu *, uint32_t, uint32_t))
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- uint32_t srcval;
- srcval = fetch_long_imm(emu);
- emu->x86.R_EAX = (*binop32)(emu, emu->x86.R_EAX, srcval);
- } else {
- uint16_t srcval;
- srcval = fetch_word_imm(emu);
- emu->x86.R_AX = (*binop16)(emu, emu->x86.R_AX, srcval);
- }
- }
- static void
- common_push_word_long(struct x86emu *emu, union x86emu_register *reg)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- push_long(emu, reg->I32_reg.e_reg);
- else
- push_word(emu, reg->I16_reg.x_reg);
- }
- static void
- common_pop_word_long(struct x86emu *emu, union x86emu_register *reg)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- reg->I32_reg.e_reg = pop_long(emu);
- else
- reg->I16_reg.x_reg = pop_word(emu);
- }
- static void
- common_imul_long_IMM(struct x86emu *emu, int byte_imm)
- {
- uint32_t srcoffset;
- uint32_t *destreg, srcval;
- int32_t imm;
- uint64_t res;
- fetch_decode_modrm(emu);
- destreg = decode_rh_long_register(emu);
- if (emu->cur_mod != 3) {
- srcoffset = decode_rl_address(emu);
- srcval = fetch_data_long(emu, srcoffset);
- } else {
- srcval = *decode_rl_long_register(emu);
- }
- if (byte_imm)
- imm = (int8_t)fetch_byte_imm(emu);
- else
- imm = fetch_long_imm(emu);
- res = (int32_t)srcval * imm;
- if (res > 0xffffffff) {
- SET_FLAG(F_CF);
- SET_FLAG(F_OF);
- } else {
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_OF);
- }
- *destreg = (uint32_t)res;
- }
- static void
- common_imul_word_IMM(struct x86emu *emu, int byte_imm)
- {
- uint32_t srcoffset;
- uint16_t *destreg, srcval;
- int16_t imm;
- uint32_t res;
- fetch_decode_modrm(emu);
- destreg = decode_rh_word_register(emu);
- if (emu->cur_mod != 3) {
- srcoffset = decode_rl_address(emu);
- srcval = fetch_data_word(emu, srcoffset);
- } else {
- srcval = *decode_rl_word_register(emu);
- }
- if (byte_imm)
- imm = (int8_t)fetch_byte_imm(emu);
- else
- imm = fetch_word_imm(emu);
- res = (int16_t)srcval * imm;
- if (res > 0xffff) {
- SET_FLAG(F_CF);
- SET_FLAG(F_OF);
- } else {
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_OF);
- }
- *destreg = (uint16_t) res;
- }
- static void
- common_imul_imm(struct x86emu *emu, int byte_imm)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- common_imul_long_IMM(emu, byte_imm);
- else
- common_imul_word_IMM(emu, byte_imm);
- }
- static void
- common_jmp_near(struct x86emu *emu, int cond)
- {
- int8_t offset;
- uint16_t target;
- offset = (int8_t) fetch_byte_imm(emu);
- target = (uint16_t) (emu->x86.R_IP + (int16_t) offset);
- if (cond)
- emu->x86.R_IP = target;
- }
- static void
- common_load_far_pointer(struct x86emu *emu, uint16_t *seg)
- {
- uint16_t *dstreg;
- uint32_t srcoffset;
- fetch_decode_modrm(emu);
- if (emu->cur_mod == 3)
- x86emu_halt_sys(emu);
- dstreg = decode_rh_word_register(emu);
- srcoffset = decode_rl_address(emu);
- *dstreg = fetch_data_word(emu, srcoffset);
- *seg = fetch_data_word(emu, srcoffset + 2);
- }
- /* Implementation */
- /*
- * REMARKS:
- * Handles opcode 0x3a
- */
- static void
- x86emuOp_cmp_byte_R_RM(struct x86emu *emu)
- {
- uint8_t *destreg, srcval;
- fetch_decode_modrm(emu);
- destreg = decode_rh_byte_register(emu);
- srcval = decode_and_fetch_byte(emu);
- cmp_byte(emu, *destreg, srcval);
- }
- /*
- * REMARKS:
- *
- * Handles opcode 0x3b
- */
- static void
- x86emuOp32_cmp_word_R_RM(struct x86emu *emu)
- {
- uint32_t srcval, *destreg;
- fetch_decode_modrm(emu);
- destreg = decode_rh_long_register(emu);
- srcval = decode_and_fetch_long(emu);
- cmp_long(emu, *destreg, srcval);
- }
- static void
- x86emuOp16_cmp_word_R_RM(struct x86emu *emu)
- {
- uint16_t srcval, *destreg;
- fetch_decode_modrm(emu);
- destreg = decode_rh_word_register(emu);
- srcval = decode_and_fetch_word(emu);
- cmp_word(emu, *destreg, srcval);
- }
- static void
- x86emuOp_cmp_word_R_RM(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- x86emuOp32_cmp_word_R_RM(emu);
- else
- x86emuOp16_cmp_word_R_RM(emu);
- }
- /*
- * REMARKS:
- * Handles opcode 0x3c
- */
- static void
- x86emuOp_cmp_byte_AL_IMM(struct x86emu *emu)
- {
- uint8_t srcval;
- srcval = fetch_byte_imm(emu);
- cmp_byte(emu, emu->x86.R_AL, srcval);
- }
- /*
- * REMARKS:
- * Handles opcode 0x3d
- */
- static void
- x86emuOp32_cmp_word_AX_IMM(struct x86emu *emu)
- {
- uint32_t srcval;
- srcval = fetch_long_imm(emu);
- cmp_long(emu, emu->x86.R_EAX, srcval);
- }
- static void
- x86emuOp16_cmp_word_AX_IMM(struct x86emu *emu)
- {
- uint16_t srcval;
- srcval = fetch_word_imm(emu);
- cmp_word(emu, emu->x86.R_AX, srcval);
- }
- static void
- x86emuOp_cmp_word_AX_IMM(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- x86emuOp32_cmp_word_AX_IMM(emu);
- else
- x86emuOp16_cmp_word_AX_IMM(emu);
- }
- /*
- * REMARKS:
- * Handles opcode 0x60
- */
- static void
- x86emuOp_push_all(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- uint32_t old_sp = emu->x86.R_ESP;
- push_long(emu, emu->x86.R_EAX);
- push_long(emu, emu->x86.R_ECX);
- push_long(emu, emu->x86.R_EDX);
- push_long(emu, emu->x86.R_EBX);
- push_long(emu, old_sp);
- push_long(emu, emu->x86.R_EBP);
- push_long(emu, emu->x86.R_ESI);
- push_long(emu, emu->x86.R_EDI);
- } else {
- uint16_t old_sp = emu->x86.R_SP;
- push_word(emu, emu->x86.R_AX);
- push_word(emu, emu->x86.R_CX);
- push_word(emu, emu->x86.R_DX);
- push_word(emu, emu->x86.R_BX);
- push_word(emu, old_sp);
- push_word(emu, emu->x86.R_BP);
- push_word(emu, emu->x86.R_SI);
- push_word(emu, emu->x86.R_DI);
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0x61
- */
- static void
- x86emuOp_pop_all(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- emu->x86.R_EDI = pop_long(emu);
- emu->x86.R_ESI = pop_long(emu);
- emu->x86.R_EBP = pop_long(emu);
- emu->x86.R_ESP += 4; /* skip ESP */
- emu->x86.R_EBX = pop_long(emu);
- emu->x86.R_EDX = pop_long(emu);
- emu->x86.R_ECX = pop_long(emu);
- emu->x86.R_EAX = pop_long(emu);
- } else {
- emu->x86.R_DI = pop_word(emu);
- emu->x86.R_SI = pop_word(emu);
- emu->x86.R_BP = pop_word(emu);
- emu->x86.R_SP += 2;/* skip SP */
- emu->x86.R_BX = pop_word(emu);
- emu->x86.R_DX = pop_word(emu);
- emu->x86.R_CX = pop_word(emu);
- emu->x86.R_AX = pop_word(emu);
- }
- }
- /*opcode 0x62 ILLEGAL OP, calls x86emuOp_illegal_op() */
- /*opcode 0x63 ILLEGAL OP, calls x86emuOp_illegal_op() */
- /*
- * REMARKS:
- * Handles opcode 0x68
- */
- static void
- x86emuOp_push_word_IMM(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- uint32_t imm;
- imm = fetch_long_imm(emu);
- push_long(emu, imm);
- } else {
- uint16_t imm;
- imm = fetch_word_imm(emu);
- push_word(emu, imm);
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0x6a
- */
- static void
- x86emuOp_push_byte_IMM(struct x86emu *emu)
- {
- int16_t imm;
- imm = (int8_t) fetch_byte_imm(emu);
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- push_long(emu, (int32_t) imm);
- } else {
- push_word(emu, imm);
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0x6c and 0x6d
- */
- static void
- x86emuOp_ins_word(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- ins(emu, 4);
- } else {
- ins(emu, 2);
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0x6f
- */
- static void
- x86emuOp_outs_word(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- outs(emu, 4);
- } else {
- outs(emu, 2);
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0x7c
- */
- static void
- x86emuOp_jump_near_L(struct x86emu *emu)
- {
- int sf, of;
- sf = ACCESS_FLAG(F_SF) != 0;
- of = ACCESS_FLAG(F_OF) != 0;
- common_jmp_near(emu, sf != of);
- }
- /*
- * REMARKS:
- * Handles opcode 0x7d
- */
- static void
- x86emuOp_jump_near_NL(struct x86emu *emu)
- {
- int sf, of;
- sf = ACCESS_FLAG(F_SF) != 0;
- of = ACCESS_FLAG(F_OF) != 0;
- common_jmp_near(emu, sf == of);
- }
- /*
- * REMARKS:
- * Handles opcode 0x7e
- */
- static void
- x86emuOp_jump_near_LE(struct x86emu *emu)
- {
- int sf, of;
- sf = ACCESS_FLAG(F_SF) != 0;
- of = ACCESS_FLAG(F_OF) != 0;
- common_jmp_near(emu, sf != of || ACCESS_FLAG(F_ZF));
- }
- /*
- * REMARKS:
- * Handles opcode 0x7f
- */
- static void
- x86emuOp_jump_near_NLE(struct x86emu *emu)
- {
- int sf, of;
- sf = ACCESS_FLAG(F_SF) != 0;
- of = ACCESS_FLAG(F_OF) != 0;
- common_jmp_near(emu, sf == of && !ACCESS_FLAG(F_ZF));
- }
- static
- uint8_t(*const opc80_byte_operation[]) (struct x86emu *, uint8_t d, uint8_t s) =
- {
- add_byte, /* 00 */
- or_byte, /* 01 */
- adc_byte, /* 02 */
- sbb_byte, /* 03 */
- and_byte, /* 04 */
- sub_byte, /* 05 */
- xor_byte, /* 06 */
- cmp_byte, /* 07 */
- };
- /*
- * REMARKS:
- * Handles opcode 0x80
- */
- static void
- x86emuOp_opc80_byte_RM_IMM(struct x86emu *emu)
- {
- uint8_t imm, destval;
- /*
- * Weirdo special case instruction format. Part of the opcode
- * held below in "RH". Doubly nested case would result, except
- * that the decoded instruction
- */
- fetch_decode_modrm(emu);
- destval = decode_and_fetch_byte(emu);
- imm = fetch_byte_imm(emu);
- destval = (*opc80_byte_operation[emu->cur_rh]) (emu, destval, imm);
- if (emu->cur_rh != 7)
- write_back_byte(emu, destval);
- }
- static
- uint16_t(* const opc81_word_operation[])
- (struct x86emu *, uint16_t d, uint16_t s) =
- {
- add_word, /* 00 */
- or_word, /* 01 */
- adc_word, /* 02 */
- sbb_word, /* 03 */
- and_word, /* 04 */
- sub_word, /* 05 */
- xor_word, /* 06 */
- cmp_word, /* 07 */
- };
- static
- uint32_t(* const opc81_long_operation[])
- (struct x86emu *, uint32_t d, uint32_t s) =
- {
- add_long, /* 00 */
- or_long, /* 01 */
- adc_long, /* 02 */
- sbb_long, /* 03 */
- and_long, /* 04 */
- sub_long, /* 05 */
- xor_long, /* 06 */
- cmp_long, /* 07 */
- };
- /*
- * REMARKS:
- * Handles opcode 0x81
- */
- static void
- x86emuOp32_opc81_word_RM_IMM(struct x86emu *emu)
- {
- uint32_t destval, imm;
- /*
- * Weirdo special case instruction format. Part of the opcode
- * held below in "RH". Doubly nested case would result, except
- * that the decoded instruction
- */
- fetch_decode_modrm(emu);
- destval = decode_and_fetch_long(emu);
- imm = fetch_long_imm(emu);
- destval = (*opc81_long_operation[emu->cur_rh]) (emu, destval, imm);
- if (emu->cur_rh != 7)
- write_back_long(emu, destval);
- }
- static void
- x86emuOp16_opc81_word_RM_IMM(struct x86emu *emu)
- {
- uint16_t destval, imm;
- /*
- * Weirdo special case instruction format. Part of the opcode
- * held below in "RH". Doubly nested case would result, except
- * that the decoded instruction
- */
- fetch_decode_modrm(emu);
- destval = decode_and_fetch_word(emu);
- imm = fetch_word_imm(emu);
- destval = (*opc81_word_operation[emu->cur_rh]) (emu, destval, imm);
- if (emu->cur_rh != 7)
- write_back_word(emu, destval);
- }
- static void
- x86emuOp_opc81_word_RM_IMM(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- x86emuOp32_opc81_word_RM_IMM(emu);
- else
- x86emuOp16_opc81_word_RM_IMM(emu);
- }
- static
- uint8_t(* const opc82_byte_operation[])
- (struct x86emu *, uint8_t s, uint8_t d) =
- {
- add_byte, /* 00 */
- or_byte, /* 01 *//* YYY UNUSED ???? */
- adc_byte, /* 02 */
- sbb_byte, /* 03 */
- and_byte, /* 04 *//* YYY UNUSED ???? */
- sub_byte, /* 05 */
- xor_byte, /* 06 *//* YYY UNUSED ???? */
- cmp_byte, /* 07 */
- };
- /*
- * REMARKS:
- * Handles opcode 0x82
- */
- static void
- x86emuOp_opc82_byte_RM_IMM(struct x86emu *emu)
- {
- uint8_t imm, destval;
- /*
- * Weirdo special case instruction format. Part of the opcode
- * held below in "RH". Doubly nested case would result, except
- * that the decoded instruction Similar to opcode 81, except that
- * the immediate byte is sign extended to a word length.
- */
- fetch_decode_modrm(emu);
- destval = decode_and_fetch_byte(emu);
- imm = fetch_byte_imm(emu);
- destval = (*opc82_byte_operation[emu->cur_rh]) (emu, destval, imm);
- if (emu->cur_rh != 7)
- write_back_byte(emu, destval);
- }
- static
- uint16_t(* const opc83_word_operation[])
- (struct x86emu *, uint16_t s, uint16_t d) =
- {
- add_word, /* 00 */
- or_word, /* 01 *//* YYY UNUSED ???? */
- adc_word, /* 02 */
- sbb_word, /* 03 */
- and_word, /* 04 *//* YYY UNUSED ???? */
- sub_word, /* 05 */
- xor_word, /* 06 *//* YYY UNUSED ???? */
- cmp_word, /* 07 */
- };
- static
- uint32_t(* const opc83_long_operation[])
- (struct x86emu *, uint32_t s, uint32_t d) =
- {
- add_long, /* 00 */
- or_long, /* 01 *//* YYY UNUSED ???? */
- adc_long, /* 02 */
- sbb_long, /* 03 */
- and_long, /* 04 *//* YYY UNUSED ???? */
- sub_long, /* 05 */
- xor_long, /* 06 *//* YYY UNUSED ???? */
- cmp_long, /* 07 */
- };
- /*
- * REMARKS:
- * Handles opcode 0x83
- */
- static void
- x86emuOp32_opc83_word_RM_IMM(struct x86emu *emu)
- {
- uint32_t destval, imm;
- fetch_decode_modrm(emu);
- destval = decode_and_fetch_long(emu);
- imm = (int8_t) fetch_byte_imm(emu);
- destval = (*opc83_long_operation[emu->cur_rh]) (emu, destval, imm);
- if (emu->cur_rh != 7)
- write_back_long(emu, destval);
- }
- static void
- x86emuOp16_opc83_word_RM_IMM(struct x86emu *emu)
- {
- uint16_t destval, imm;
- fetch_decode_modrm(emu);
- destval = decode_and_fetch_word(emu);
- imm = (int8_t) fetch_byte_imm(emu);
- destval = (*opc83_word_operation[emu->cur_rh]) (emu, destval, imm);
- if (emu->cur_rh != 7)
- write_back_word(emu, destval);
- }
- static void
- x86emuOp_opc83_word_RM_IMM(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- x86emuOp32_opc83_word_RM_IMM(emu);
- else
- x86emuOp16_opc83_word_RM_IMM(emu);
- }
- /*
- * REMARKS:
- * Handles opcode 0x86
- */
- static void
- x86emuOp_xchg_byte_RM_R(struct x86emu *emu)
- {
- uint8_t *srcreg, destval, tmp;
- fetch_decode_modrm(emu);
- destval = decode_and_fetch_byte(emu);
- srcreg = decode_rh_byte_register(emu);
- tmp = destval;
- destval = *srcreg;
- *srcreg = tmp;
- write_back_byte(emu, destval);
- }
- /*
- * REMARKS:
- * Handles opcode 0x87
- */
- static void
- x86emuOp32_xchg_word_RM_R(struct x86emu *emu)
- {
- uint32_t *srcreg, destval, tmp;
- fetch_decode_modrm(emu);
- destval = decode_and_fetch_long(emu);
- srcreg = decode_rh_long_register(emu);
- tmp = destval;
- destval = *srcreg;
- *srcreg = tmp;
- write_back_long(emu, destval);
- }
- static void
- x86emuOp16_xchg_word_RM_R(struct x86emu *emu)
- {
- uint16_t *srcreg, destval, tmp;
- fetch_decode_modrm(emu);
- destval = decode_and_fetch_word(emu);
- srcreg = decode_rh_word_register(emu);
- tmp = destval;
- destval = *srcreg;
- *srcreg = tmp;
- write_back_word(emu, destval);
- }
- static void
- x86emuOp_xchg_word_RM_R(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- x86emuOp32_xchg_word_RM_R(emu);
- else
- x86emuOp16_xchg_word_RM_R(emu);
- }
- /*
- * REMARKS:
- * Handles opcode 0x88
- */
- static void
- x86emuOp_mov_byte_RM_R(struct x86emu *emu)
- {
- uint8_t *destreg, *srcreg;
- uint32_t destoffset;
- fetch_decode_modrm(emu);
- srcreg = decode_rh_byte_register(emu);
- if (emu->cur_mod != 3) {
- destoffset = decode_rl_address(emu);
- store_data_byte(emu, destoffset, *srcreg);
- } else {
- destreg = decode_rl_byte_register(emu);
- *destreg = *srcreg;
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0x89
- */
- static void
- x86emuOp32_mov_word_RM_R(struct x86emu *emu)
- {
- uint32_t destoffset;
- uint32_t *destreg, srcval;
- fetch_decode_modrm(emu);
- srcval = *decode_rh_long_register(emu);
- if (emu->cur_mod != 3) {
- destoffset = decode_rl_address(emu);
- store_data_long(emu, destoffset, srcval);
- } else {
- destreg = decode_rl_long_register(emu);
- *destreg = srcval;
- }
- }
- static void
- x86emuOp16_mov_word_RM_R(struct x86emu *emu)
- {
- uint32_t destoffset;
- uint16_t *destreg, srcval;
- fetch_decode_modrm(emu);
- srcval = *decode_rh_word_register(emu);
- if (emu->cur_mod != 3) {
- destoffset = decode_rl_address(emu);
- store_data_word(emu, destoffset, srcval);
- } else {
- destreg = decode_rl_word_register(emu);
- *destreg = srcval;
- }
- }
- static void
- x86emuOp_mov_word_RM_R(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- x86emuOp32_mov_word_RM_R(emu);
- else
- x86emuOp16_mov_word_RM_R(emu);
- }
- /*
- * REMARKS:
- * Handles opcode 0x8a
- */
- static void
- x86emuOp_mov_byte_R_RM(struct x86emu *emu)
- {
- uint8_t *destreg;
- fetch_decode_modrm(emu);
- destreg = decode_rh_byte_register(emu);
- *destreg = decode_and_fetch_byte(emu);
- }
- /*
- * REMARKS:
- * Handles opcode 0x8b
- */
- static void
- x86emuOp_mov_word_R_RM(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- uint32_t *destreg;
- fetch_decode_modrm(emu);
- destreg = decode_rh_long_register(emu);
- *destreg = decode_and_fetch_long(emu);
- } else {
- uint16_t *destreg;
- fetch_decode_modrm(emu);
- destreg = decode_rh_word_register(emu);
- *destreg = decode_and_fetch_word(emu);
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0x8c
- */
- static void
- x86emuOp_mov_word_RM_SR(struct x86emu *emu)
- {
- uint16_t *destreg, srcval;
- uint32_t destoffset;
- fetch_decode_modrm(emu);
- srcval = *decode_rh_seg_register(emu);
- if (emu->cur_mod != 3) {
- destoffset = decode_rl_address(emu);
- store_data_word(emu, destoffset, srcval);
- } else {
- destreg = decode_rl_word_register(emu);
- *destreg = srcval;
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0x8d
- */
- static void
- x86emuOp_lea_word_R_M(struct x86emu *emu)
- {
- uint32_t destoffset;
- fetch_decode_modrm(emu);
- if (emu->cur_mod == 3)
- x86emu_halt_sys(emu);
- destoffset = decode_rl_address(emu);
- if (emu->x86.mode & SYSMODE_PREFIX_ADDR) {
- uint32_t *srcreg;
- srcreg = decode_rh_long_register(emu);
- *srcreg = (uint32_t) destoffset;
- } else {
- uint16_t *srcreg;
- srcreg = decode_rh_word_register(emu);
- *srcreg = (uint16_t) destoffset;
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0x8e
- */
- static void
- x86emuOp_mov_word_SR_RM(struct x86emu *emu)
- {
- uint16_t *destreg;
- fetch_decode_modrm(emu);
- destreg = decode_rh_seg_register(emu);
- *destreg = decode_and_fetch_word(emu);
- /*
- * Clean up, and reset all the R_xSP pointers to the correct
- * locations. This is about 3x too much overhead (doing all the
- * segreg ptrs when only one is needed, but this instruction
- * *cannot* be that common, and this isn't too much work anyway.
- */
- }
- /*
- * REMARKS:
- * Handles opcode 0x8f
- */
- static void
- x86emuOp32_pop_RM(struct x86emu *emu)
- {
- uint32_t destoffset;
- uint32_t destval, *destreg;
- fetch_decode_modrm(emu);
- if (emu->cur_mod != 3) {
- destoffset = decode_rl_address(emu);
- destval = pop_long(emu);
- store_data_long(emu, destoffset, destval);
- } else {
- destreg = decode_rl_long_register(emu);
- *destreg = pop_long(emu);
- }
- }
- static void
- x86emuOp16_pop_RM(struct x86emu *emu)
- {
- uint32_t destoffset;
- uint16_t destval, *destreg;
- fetch_decode_modrm(emu);
- if (emu->cur_mod != 3) {
- destoffset = decode_rl_address(emu);
- destval = pop_word(emu);
- store_data_word(emu, destoffset, destval);
- } else {
- destreg = decode_rl_word_register(emu);
- *destreg = pop_word(emu);
- }
- }
- static void
- x86emuOp_pop_RM(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- x86emuOp32_pop_RM(emu);
- else
- x86emuOp16_pop_RM(emu);
- }
- /*
- * REMARKS:
- * Handles opcode 0x91
- */
- static void
- x86emuOp_xchg_word_AX_CX(struct x86emu *emu)
- {
- uint32_t tmp;
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- tmp = emu->x86.R_EAX;
- emu->x86.R_EAX = emu->x86.R_ECX;
- emu->x86.R_ECX = tmp;
- } else {
- tmp = emu->x86.R_AX;
- emu->x86.R_AX = emu->x86.R_CX;
- emu->x86.R_CX = (uint16_t) tmp;
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0x92
- */
- static void
- x86emuOp_xchg_word_AX_DX(struct x86emu *emu)
- {
- uint32_t tmp;
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- tmp = emu->x86.R_EAX;
- emu->x86.R_EAX = emu->x86.R_EDX;
- emu->x86.R_EDX = tmp;
- } else {
- tmp = emu->x86.R_AX;
- emu->x86.R_AX = emu->x86.R_DX;
- emu->x86.R_DX = (uint16_t) tmp;
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0x93
- */
- static void
- x86emuOp_xchg_word_AX_BX(struct x86emu *emu)
- {
- uint32_t tmp;
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- tmp = emu->x86.R_EAX;
- emu->x86.R_EAX = emu->x86.R_EBX;
- emu->x86.R_EBX = tmp;
- } else {
- tmp = emu->x86.R_AX;
- emu->x86.R_AX = emu->x86.R_BX;
- emu->x86.R_BX = (uint16_t) tmp;
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0x94
- */
- static void
- x86emuOp_xchg_word_AX_SP(struct x86emu *emu)
- {
- uint32_t tmp;
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- tmp = emu->x86.R_EAX;
- emu->x86.R_EAX = emu->x86.R_ESP;
- emu->x86.R_ESP = tmp;
- } else {
- tmp = emu->x86.R_AX;
- emu->x86.R_AX = emu->x86.R_SP;
- emu->x86.R_SP = (uint16_t) tmp;
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0x95
- */
- static void
- x86emuOp_xchg_word_AX_BP(struct x86emu *emu)
- {
- uint32_t tmp;
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- tmp = emu->x86.R_EAX;
- emu->x86.R_EAX = emu->x86.R_EBP;
- emu->x86.R_EBP = tmp;
- } else {
- tmp = emu->x86.R_AX;
- emu->x86.R_AX = emu->x86.R_BP;
- emu->x86.R_BP = (uint16_t) tmp;
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0x96
- */
- static void
- x86emuOp_xchg_word_AX_SI(struct x86emu *emu)
- {
- uint32_t tmp;
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- tmp = emu->x86.R_EAX;
- emu->x86.R_EAX = emu->x86.R_ESI;
- emu->x86.R_ESI = tmp;
- } else {
- tmp = emu->x86.R_AX;
- emu->x86.R_AX = emu->x86.R_SI;
- emu->x86.R_SI = (uint16_t) tmp;
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0x97
- */
- static void
- x86emuOp_xchg_word_AX_DI(struct x86emu *emu)
- {
- uint32_t tmp;
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- tmp = emu->x86.R_EAX;
- emu->x86.R_EAX = emu->x86.R_EDI;
- emu->x86.R_EDI = tmp;
- } else {
- tmp = emu->x86.R_AX;
- emu->x86.R_AX = emu->x86.R_DI;
- emu->x86.R_DI = (uint16_t) tmp;
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0x98
- */
- static void
- x86emuOp_cbw(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- if (emu->x86.R_AX & 0x8000) {
- emu->x86.R_EAX |= 0xffff0000;
- } else {
- emu->x86.R_EAX &= 0x0000ffff;
- }
- } else {
- if (emu->x86.R_AL & 0x80) {
- emu->x86.R_AH = 0xff;
- } else {
- emu->x86.R_AH = 0x0;
- }
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0x99
- */
- static void
- x86emuOp_cwd(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- if (emu->x86.R_EAX & 0x80000000) {
- emu->x86.R_EDX = 0xffffffff;
- } else {
- emu->x86.R_EDX = 0x0;
- }
- } else {
- if (emu->x86.R_AX & 0x8000) {
- emu->x86.R_DX = 0xffff;
- } else {
- emu->x86.R_DX = 0x0;
- }
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0x9a
- */
- static void
- x86emuOp_call_far_IMM(struct x86emu *emu)
- {
- uint16_t farseg, faroff;
- faroff = fetch_word_imm(emu);
- farseg = fetch_word_imm(emu);
- /* XXX
- *
- * Hooked interrupt vectors calling into our "BIOS" will cause problems
- * unless all intersegment stuff is checked for BIOS access. Check
- * needed here. For moment, let it alone. */
- push_word(emu, emu->x86.R_CS);
- emu->x86.R_CS = farseg;
- push_word(emu, emu->x86.R_IP);
- emu->x86.R_IP = faroff;
- }
- /*
- * REMARKS:
- * Handles opcode 0x9c
- */
- static void
- x86emuOp_pushf_word(struct x86emu *emu)
- {
- uint32_t flags;
- /* clear out *all* bits not representing flags, and turn on real bits */
- flags = (emu->x86.R_EFLG & F_MSK) | F_ALWAYS_ON;
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- push_long(emu, flags);
- } else {
- push_word(emu, (uint16_t) flags);
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0x9d
- */
- static void
- x86emuOp_popf_word(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- emu->x86.R_EFLG = pop_long(emu);
- } else {
- emu->x86.R_FLG = pop_word(emu);
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0x9e
- */
- static void
- x86emuOp_sahf(struct x86emu *emu)
- {
- /* clear the lower bits of the flag register */
- emu->x86.R_FLG &= 0xffffff00;
- /* or in the AH register into the flags register */
- emu->x86.R_FLG |= emu->x86.R_AH;
- }
- /*
- * REMARKS:
- * Handles opcode 0x9f
- */
- static void
- x86emuOp_lahf(struct x86emu *emu)
- {
- emu->x86.R_AH = (uint8_t) (emu->x86.R_FLG & 0xff);
- /* undocumented TC++ behavior??? Nope. It's documented, but you have
- * too look real hard to notice it. */
- emu->x86.R_AH |= 0x2;
- }
- /*
- * REMARKS:
- * Handles opcode 0xa0
- */
- static void
- x86emuOp_mov_AL_M_IMM(struct x86emu *emu)
- {
- uint16_t offset;
- offset = fetch_word_imm(emu);
- emu->x86.R_AL = fetch_data_byte(emu, offset);
- }
- /*
- * REMARKS:
- * Handles opcode 0xa1
- */
- static void
- x86emuOp_mov_AX_M_IMM(struct x86emu *emu)
- {
- uint16_t offset;
- offset = fetch_word_imm(emu);
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- emu->x86.R_EAX = fetch_data_long(emu, offset);
- } else {
- emu->x86.R_AX = fetch_data_word(emu, offset);
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0xa2
- */
- static void
- x86emuOp_mov_M_AL_IMM(struct x86emu *emu)
- {
- uint16_t offset;
- offset = fetch_word_imm(emu);
- store_data_byte(emu, offset, emu->x86.R_AL);
- }
- /*
- * REMARKS:
- * Handles opcode 0xa3
- */
- static void
- x86emuOp_mov_M_AX_IMM(struct x86emu *emu)
- {
- uint16_t offset;
- offset = fetch_word_imm(emu);
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- store_data_long(emu, offset, emu->x86.R_EAX);
- } else {
- store_data_word(emu, offset, emu->x86.R_AX);
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0xa4
- */
- static void
- x86emuOp_movs_byte(struct x86emu *emu)
- {
- uint8_t val;
- uint32_t count;
- int inc;
- if (ACCESS_FLAG(F_DF)) /* down */
- inc = -1;
- else
- inc = 1;
- count = 1;
- if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
- /* dont care whether REPE or REPNE */
- /* move them until CX is ZERO. */
- count = emu->x86.R_CX;
- emu->x86.R_CX = 0;
- emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
- }
- while (count--) {
- val = fetch_data_byte(emu, emu->x86.R_SI);
- store_byte(emu, emu->x86.R_ES, emu->x86.R_DI, val);
- emu->x86.R_SI += inc;
- emu->x86.R_DI += inc;
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0xa5
- */
- static void
- x86emuOp_movs_word(struct x86emu *emu)
- {
- uint32_t val;
- int inc;
- uint32_t count;
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- inc = 4;
- else
- inc = 2;
- if (ACCESS_FLAG(F_DF)) /* down */
- inc = -inc;
- count = 1;
- if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
- /* dont care whether REPE or REPNE */
- /* move them until CX is ZERO. */
- count = emu->x86.R_CX;
- emu->x86.R_CX = 0;
- emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
- }
- while (count--) {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- val = fetch_data_long(emu, emu->x86.R_SI);
- store_long(emu, emu->x86.R_ES, emu->x86.R_DI, val);
- } else {
- val = fetch_data_word(emu, emu->x86.R_SI);
- store_word(emu, emu->x86.R_ES, emu->x86.R_DI,
- (uint16_t) val);
- }
- emu->x86.R_SI += inc;
- emu->x86.R_DI += inc;
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0xa6
- */
- static void
- x86emuOp_cmps_byte(struct x86emu *emu)
- {
- int8_t val1, val2;
- int inc;
- if (ACCESS_FLAG(F_DF)) /* down */
- inc = -1;
- else
- inc = 1;
- if (emu->x86.mode & SYSMODE_PREFIX_REPE) {
- /* REPE */
- /* move them until CX is ZERO. */
- while (emu->x86.R_CX != 0) {
- val1 = fetch_data_byte(emu, emu->x86.R_SI);
- val2 = fetch_byte(emu, emu->x86.R_ES, emu->x86.R_DI);
- cmp_byte(emu, val1, val2);
- emu->x86.R_CX -= 1;
- emu->x86.R_SI += inc;
- emu->x86.R_DI += inc;
- if (ACCESS_FLAG(F_ZF) == 0)
- break;
- }
- emu->x86.mode &= ~SYSMODE_PREFIX_REPE;
- } else if (emu->x86.mode & SYSMODE_PREFIX_REPNE) {
- /* REPNE */
- /* move them until CX is ZERO. */
- while (emu->x86.R_CX != 0) {
- val1 = fetch_data_byte(emu, emu->x86.R_SI);
- val2 = fetch_byte(emu, emu->x86.R_ES, emu->x86.R_DI);
- cmp_byte(emu, val1, val2);
- emu->x86.R_CX -= 1;
- emu->x86.R_SI += inc;
- emu->x86.R_DI += inc;
- if (ACCESS_FLAG(F_ZF))
- break; /* zero flag set means equal */
- }
- emu->x86.mode &= ~SYSMODE_PREFIX_REPNE;
- } else {
- val1 = fetch_data_byte(emu, emu->x86.R_SI);
- val2 = fetch_byte(emu, emu->x86.R_ES, emu->x86.R_DI);
- cmp_byte(emu, val1, val2);
- emu->x86.R_SI += inc;
- emu->x86.R_DI += inc;
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0xa7
- */
- static void
- x86emuOp_cmps_word(struct x86emu *emu)
- {
- uint32_t val1, val2;
- int inc;
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- if (ACCESS_FLAG(F_DF)) /* down */
- inc = -4;
- else
- inc = 4;
- } else {
- if (ACCESS_FLAG(F_DF)) /* down */
- inc = -2;
- else
- inc = 2;
- }
- if (emu->x86.mode & SYSMODE_PREFIX_REPE) {
- /* REPE */
- /* move them until CX is ZERO. */
- while (emu->x86.R_CX != 0) {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- val1 = fetch_data_long(emu, emu->x86.R_SI);
- val2 = fetch_long(emu, emu->x86.R_ES,
- emu->x86.R_DI);
- cmp_long(emu, val1, val2);
- } else {
- val1 = fetch_data_word(emu, emu->x86.R_SI);
- val2 = fetch_word(emu, emu->x86.R_ES,
- emu->x86.R_DI);
- cmp_word(emu, (uint16_t) val1, (uint16_t) val2);
- }
- emu->x86.R_CX -= 1;
- emu->x86.R_SI += inc;
- emu->x86.R_DI += inc;
- if (ACCESS_FLAG(F_ZF) == 0)
- break;
- }
- emu->x86.mode &= ~SYSMODE_PREFIX_REPE;
- } else if (emu->x86.mode & SYSMODE_PREFIX_REPNE) {
- /* REPNE */
- /* move them until CX is ZERO. */
- while (emu->x86.R_CX != 0) {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- val1 = fetch_data_long(emu, emu->x86.R_SI);
- val2 = fetch_long(emu, emu->x86.R_ES,
- emu->x86.R_DI);
- cmp_long(emu, val1, val2);
- } else {
- val1 = fetch_data_word(emu, emu->x86.R_SI);
- val2 = fetch_word(emu, emu->x86.R_ES,
- emu->x86.R_DI);
- cmp_word(emu, (uint16_t) val1, (uint16_t) val2);
- }
- emu->x86.R_CX -= 1;
- emu->x86.R_SI += inc;
- emu->x86.R_DI += inc;
- if (ACCESS_FLAG(F_ZF))
- break; /* zero flag set means equal */
- }
- emu->x86.mode &= ~SYSMODE_PREFIX_REPNE;
- } else {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- val1 = fetch_data_long(emu, emu->x86.R_SI);
- val2 = fetch_long(emu, emu->x86.R_ES, emu->x86.R_DI);
- cmp_long(emu, val1, val2);
- } else {
- val1 = fetch_data_word(emu, emu->x86.R_SI);
- val2 = fetch_word(emu, emu->x86.R_ES, emu->x86.R_DI);
- cmp_word(emu, (uint16_t) val1, (uint16_t) val2);
- }
- emu->x86.R_SI += inc;
- emu->x86.R_DI += inc;
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0xa9
- */
- static void
- x86emuOp_test_AX_IMM(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- test_long(emu, emu->x86.R_EAX, fetch_long_imm(emu));
- } else {
- test_word(emu, emu->x86.R_AX, fetch_word_imm(emu));
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0xaa
- */
- static void
- x86emuOp_stos_byte(struct x86emu *emu)
- {
- int inc;
- if (ACCESS_FLAG(F_DF)) /* down */
- inc = -1;
- else
- inc = 1;
- if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
- /* dont care whether REPE or REPNE */
- /* move them until CX is ZERO. */
- while (emu->x86.R_CX != 0) {
- store_byte(emu, emu->x86.R_ES, emu->x86.R_DI,
- emu->x86.R_AL);
- emu->x86.R_CX -= 1;
- emu->x86.R_DI += inc;
- }
- emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
- } else {
- store_byte(emu, emu->x86.R_ES, emu->x86.R_DI, emu->x86.R_AL);
- emu->x86.R_DI += inc;
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0xab
- */
- static void
- x86emuOp_stos_word(struct x86emu *emu)
- {
- int inc;
- uint32_t count;
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- inc = 4;
- else
- inc = 2;
-
- if (ACCESS_FLAG(F_DF)) /* down */
- inc = -inc;
- count = 1;
- if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
- /* dont care whether REPE or REPNE */
- /* move them until CX is ZERO. */
- count = emu->x86.R_CX;
- emu->x86.R_CX = 0;
- emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
- }
- while (count--) {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- store_long(emu, emu->x86.R_ES, emu->x86.R_DI,
- emu->x86.R_EAX);
- } else {
- store_word(emu, emu->x86.R_ES, emu->x86.R_DI,
- emu->x86.R_AX);
- }
- emu->x86.R_DI += inc;
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0xac
- */
- static void
- x86emuOp_lods_byte(struct x86emu *emu)
- {
- int inc;
- if (ACCESS_FLAG(F_DF)) /* down */
- inc = -1;
- else
- inc = 1;
- if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
- /* dont care whether REPE or REPNE */
- /* move them until CX is ZERO. */
- while (emu->x86.R_CX != 0) {
- emu->x86.R_AL = fetch_data_byte(emu, emu->x86.R_SI);
- emu->x86.R_CX -= 1;
- emu->x86.R_SI += inc;
- }
- emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
- } else {
- emu->x86.R_AL = fetch_data_byte(emu, emu->x86.R_SI);
- emu->x86.R_SI += inc;
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0xad
- */
- static void
- x86emuOp_lods_word(struct x86emu *emu)
- {
- int inc;
- uint32_t count;
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- inc = 4;
- else
- inc = 2;
- if (ACCESS_FLAG(F_DF)) /* down */
- inc = -inc;
- count = 1;
- if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
- /* dont care whether REPE or REPNE */
- /* move them until CX is ZERO. */
- count = emu->x86.R_CX;
- emu->x86.R_CX = 0;
- emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
- }
- while (count--) {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- emu->x86.R_EAX = fetch_data_long(emu, emu->x86.R_SI);
- } else {
- emu->x86.R_AX = fetch_data_word(emu, emu->x86.R_SI);
- }
- emu->x86.R_SI += inc;
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0xae
- */
- static void
- x86emuOp_scas_byte(struct x86emu *emu)
- {
- int8_t val2;
- int inc;
- if (ACCESS_FLAG(F_DF)) /* down */
- inc = -1;
- else
- inc = 1;
- if (emu->x86.mode & SYSMODE_PREFIX_REPE) {
- /* REPE */
- /* move them until CX is ZERO. */
- while (emu->x86.R_CX != 0) {
- val2 = fetch_byte(emu, emu->x86.R_ES, emu->x86.R_DI);
- cmp_byte(emu, emu->x86.R_AL, val2);
- emu->x86.R_CX -= 1;
- emu->x86.R_DI += inc;
- if (ACCESS_FLAG(F_ZF) == 0)
- break;
- }
- emu->x86.mode &= ~SYSMODE_PREFIX_REPE;
- } else if (emu->x86.mode & SYSMODE_PREFIX_REPNE) {
- /* REPNE */
- /* move them until CX is ZERO. */
- while (emu->x86.R_CX != 0) {
- val2 = fetch_byte(emu, emu->x86.R_ES, emu->x86.R_DI);
- cmp_byte(emu, emu->x86.R_AL, val2);
- emu->x86.R_CX -= 1;
- emu->x86.R_DI += inc;
- if (ACCESS_FLAG(F_ZF))
- break; /* zero flag set means equal */
- }
- emu->x86.mode &= ~SYSMODE_PREFIX_REPNE;
- } else {
- val2 = fetch_byte(emu, emu->x86.R_ES, emu->x86.R_DI);
- cmp_byte(emu, emu->x86.R_AL, val2);
- emu->x86.R_DI += inc;
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0xaf
- */
- static void
- x86emuOp_scas_word(struct x86emu *emu)
- {
- int inc;
- uint32_t val;
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- inc = 4;
- else
- inc = 2;
- if (ACCESS_FLAG(F_DF)) /* down */
- inc = -inc;
- if (emu->x86.mode & SYSMODE_PREFIX_REPE) {
- /* REPE */
- /* move them until CX is ZERO. */
- while (emu->x86.R_CX != 0) {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- val = fetch_long(emu, emu->x86.R_ES,
- emu->x86.R_DI);
- cmp_long(emu, emu->x86.R_EAX, val);
- } else {
- val = fetch_word(emu, emu->x86.R_ES,
- emu->x86.R_DI);
- cmp_word(emu, emu->x86.R_AX, (uint16_t) val);
- }
- emu->x86.R_CX -= 1;
- emu->x86.R_DI += inc;
- if (ACCESS_FLAG(F_ZF) == 0)
- break;
- }
- emu->x86.mode &= ~SYSMODE_PREFIX_REPE;
- } else if (emu->x86.mode & SYSMODE_PREFIX_REPNE) {
- /* REPNE */
- /* move them until CX is ZERO. */
- while (emu->x86.R_CX != 0) {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- val = fetch_long(emu, emu->x86.R_ES,
- emu->x86.R_DI);
- cmp_long(emu, emu->x86.R_EAX, val);
- } else {
- val = fetch_word(emu, emu->x86.R_ES,
- emu->x86.R_DI);
- cmp_word(emu, emu->x86.R_AX, (uint16_t) val);
- }
- emu->x86.R_CX -= 1;
- emu->x86.R_DI += inc;
- if (ACCESS_FLAG(F_ZF))
- break; /* zero flag set means equal */
- }
- emu->x86.mode &= ~SYSMODE_PREFIX_REPNE;
- } else {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- val = fetch_long(emu, emu->x86.R_ES, emu->x86.R_DI);
- cmp_long(emu, emu->x86.R_EAX, val);
- } else {
- val = fetch_word(emu, emu->x86.R_ES, emu->x86.R_DI);
- cmp_word(emu, emu->x86.R_AX, (uint16_t) val);
- }
- emu->x86.R_DI += inc;
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0xb8
- */
- static void
- x86emuOp_mov_word_AX_IMM(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- emu->x86.R_EAX = fetch_long_imm(emu);
- else
- emu->x86.R_AX = fetch_word_imm(emu);
- }
- /*
- * REMARKS:
- * Handles opcode 0xb9
- */
- static void
- x86emuOp_mov_word_CX_IMM(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- emu->x86.R_ECX = fetch_long_imm(emu);
- else
- emu->x86.R_CX = fetch_word_imm(emu);
- }
- /*
- * REMARKS:
- * Handles opcode 0xba
- */
- static void
- x86emuOp_mov_word_DX_IMM(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- emu->x86.R_EDX = fetch_long_imm(emu);
- else
- emu->x86.R_DX = fetch_word_imm(emu);
- }
- /*
- * REMARKS:
- * Handles opcode 0xbb
- */
- static void
- x86emuOp_mov_word_BX_IMM(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- emu->x86.R_EBX = fetch_long_imm(emu);
- else
- emu->x86.R_BX = fetch_word_imm(emu);
- }
- /*
- * REMARKS:
- * Handles opcode 0xbc
- */
- static void
- x86emuOp_mov_word_SP_IMM(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- emu->x86.R_ESP = fetch_long_imm(emu);
- else
- emu->x86.R_SP = fetch_word_imm(emu);
- }
- /*
- * REMARKS:
- * Handles opcode 0xbd
- */
- static void
- x86emuOp_mov_word_BP_IMM(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- emu->x86.R_EBP = fetch_long_imm(emu);
- else
- emu->x86.R_BP = fetch_word_imm(emu);
- }
- /*
- * REMARKS:
- * Handles opcode 0xbe
- */
- static void
- x86emuOp_mov_word_SI_IMM(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- emu->x86.R_ESI = fetch_long_imm(emu);
- else
- emu->x86.R_SI = fetch_word_imm(emu);
- }
- /*
- * REMARKS:
- * Handles opcode 0xbf
- */
- static void
- x86emuOp_mov_word_DI_IMM(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- emu->x86.R_EDI = fetch_long_imm(emu);
- else
- emu->x86.R_DI = fetch_word_imm(emu);
- }
- /* used by opcodes c0, d0, and d2. */
- static
- uint8_t(* const opcD0_byte_operation[])
- (struct x86emu *, uint8_t d, uint8_t s) =
- {
- rol_byte,
- ror_byte,
- rcl_byte,
- rcr_byte,
- shl_byte,
- shr_byte,
- shl_byte, /* sal_byte === shl_byte by definition */
- sar_byte,
- };
- /*
- * REMARKS:
- * Handles opcode 0xc0
- */
- static void
- x86emuOp_opcC0_byte_RM_MEM(struct x86emu *emu)
- {
- uint8_t destval, amt;
- /*
- * Yet another weirdo special case instruction format. Part of
- * the opcode held below in "RH". Doubly nested case would
- * result, except that the decoded instruction
- */
- fetch_decode_modrm(emu);
- /* know operation, decode the mod byte to find the addressing mode. */
- destval = decode_and_fetch_byte_imm8(emu, &amt);
- destval = (*opcD0_byte_operation[emu->cur_rh]) (emu, destval, amt);
- write_back_byte(emu, destval);
- }
- /* used by opcodes c1, d1, and d3. */
- static
- uint16_t(* const opcD1_word_operation[])
- (struct x86emu *, uint16_t s, uint8_t d) =
- {
- rol_word,
- ror_word,
- rcl_word,
- rcr_word,
- shl_word,
- shr_word,
- shl_word, /* sal_byte === shl_byte by definition */
- sar_word,
- };
- /* used by opcodes c1, d1, and d3. */
- static
- uint32_t(* const opcD1_long_operation[])
- (struct x86emu *, uint32_t s, uint8_t d) =
- {
- rol_long,
- ror_long,
- rcl_long,
- rcr_long,
- shl_long,
- shr_long,
- shl_long, /* sal_byte === shl_byte by definition */
- sar_long,
- };
- /*
- * REMARKS:
- * Handles opcode 0xc1
- */
- static void
- x86emuOp_opcC1_word_RM_MEM(struct x86emu *emu)
- {
- uint8_t amt;
- /*
- * Yet another weirdo special case instruction format. Part of
- * the opcode held below in "RH". Doubly nested case would
- * result, except that the decoded instruction
- */
- fetch_decode_modrm(emu);
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- uint32_t destval;
- destval = decode_and_fetch_long_imm8(emu, &amt);
- destval = (*opcD1_long_operation[emu->cur_rh])
- (emu, destval, amt);
- write_back_long(emu, destval);
- } else {
- uint16_t destval;
- destval = decode_and_fetch_word_imm8(emu, &amt);
- destval = (*opcD1_word_operation[emu->cur_rh])
- (emu, destval, amt);
- write_back_word(emu, destval);
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0xc2
- */
- static void
- x86emuOp_ret_near_IMM(struct x86emu *emu)
- {
- uint16_t imm;
- imm = fetch_word_imm(emu);
- emu->x86.R_IP = pop_word(emu);
- emu->x86.R_SP += imm;
- }
- /*
- * REMARKS:
- * Handles opcode 0xc6
- */
- static void
- x86emuOp_mov_byte_RM_IMM(struct x86emu *emu)
- {
- uint8_t *destreg;
- uint32_t destoffset;
- uint8_t imm;
- fetch_decode_modrm(emu);
- if (emu->cur_rh != 0)
- x86emu_halt_sys(emu);
- if (emu->cur_mod != 3) {
- destoffset = decode_rl_address(emu);
- imm = fetch_byte_imm(emu);
- store_data_byte(emu, destoffset, imm);
- } else {
- destreg = decode_rl_byte_register(emu);
- imm = fetch_byte_imm(emu);
- *destreg = imm;
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0xc7
- */
- static void
- x86emuOp32_mov_word_RM_IMM(struct x86emu *emu)
- {
- uint32_t destoffset;
- uint32_t imm, *destreg;
- fetch_decode_modrm(emu);
- if (emu->cur_rh != 0)
- x86emu_halt_sys(emu);
- if (emu->cur_mod != 3) {
- destoffset = decode_rl_address(emu);
- imm = fetch_long_imm(emu);
- store_data_long(emu, destoffset, imm);
- } else {
- destreg = decode_rl_long_register(emu);
- imm = fetch_long_imm(emu);
- *destreg = imm;
- }
- }
- static void
- x86emuOp16_mov_word_RM_IMM(struct x86emu *emu)
- {
- uint32_t destoffset;
- uint16_t imm, *destreg;
- fetch_decode_modrm(emu);
- if (emu->cur_rh != 0)
- x86emu_halt_sys(emu);
- if (emu->cur_mod != 3) {
- destoffset = decode_rl_address(emu);
- imm = fetch_word_imm(emu);
- store_data_word(emu, destoffset, imm);
- } else {
- destreg = decode_rl_word_register(emu);
- imm = fetch_word_imm(emu);
- *destreg = imm;
- }
- }
- static void
- x86emuOp_mov_word_RM_IMM(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- x86emuOp32_mov_word_RM_IMM(emu);
- else
- x86emuOp16_mov_word_RM_IMM(emu);
- }
- /*
- * REMARKS:
- * Handles opcode 0xc8
- */
- static void
- x86emuOp_enter(struct x86emu *emu)
- {
- uint16_t local, frame_pointer;
- uint8_t nesting;
- int i;
- local = fetch_word_imm(emu);
- nesting = fetch_byte_imm(emu);
- push_word(emu, emu->x86.R_BP);
- frame_pointer = emu->x86.R_SP;
- if (nesting > 0) {
- for (i = 1; i < nesting; i++) {
- emu->x86.R_BP -= 2;
- push_word(emu, fetch_word(emu, emu->x86.R_SS,
- emu->x86.R_BP));
- }
- push_word(emu, frame_pointer);
- }
- emu->x86.R_BP = frame_pointer;
- emu->x86.R_SP = (uint16_t) (emu->x86.R_SP - local);
- }
- /*
- * REMARKS:
- * Handles opcode 0xc9
- */
- static void
- x86emuOp_leave(struct x86emu *emu)
- {
- emu->x86.R_SP = emu->x86.R_BP;
- emu->x86.R_BP = pop_word(emu);
- }
- /*
- * REMARKS:
- * Handles opcode 0xca
- */
- static void
- x86emuOp_ret_far_IMM(struct x86emu *emu)
- {
- uint16_t imm;
- imm = fetch_word_imm(emu);
- emu->x86.R_IP = pop_word(emu);
- emu->x86.R_CS = pop_word(emu);
- emu->x86.R_SP += imm;
- }
- /*
- * REMARKS:
- * Handles opcode 0xcb
- */
- static void
- x86emuOp_ret_far(struct x86emu *emu)
- {
- emu->x86.R_IP = pop_word(emu);
- emu->x86.R_CS = pop_word(emu);
- }
- /*
- * REMARKS:
- * Handles opcode 0xcc
- */
- static void
- x86emuOp_int3(struct x86emu *emu)
- {
- x86emu_intr_dispatch(emu, 3);
- }
- /*
- * REMARKS:
- * Handles opcode 0xcd
- */
- static void
- x86emuOp_int_IMM(struct x86emu *emu)
- {
- uint8_t intnum;
- intnum = fetch_byte_imm(emu);
- x86emu_intr_dispatch(emu, intnum);
- }
- /*
- * REMARKS:
- * Handles opcode 0xce
- */
- static void
- x86emuOp_into(struct x86emu *emu)
- {
- if (ACCESS_FLAG(F_OF))
- x86emu_intr_dispatch(emu, 4);
- }
- /*
- * REMARKS:
- * Handles opcode 0xcf
- */
- static void
- x86emuOp_iret(struct x86emu *emu)
- {
- emu->x86.R_IP = pop_word(emu);
- emu->x86.R_CS = pop_word(emu);
- emu->x86.R_FLG = pop_word(emu);
- }
- /*
- * REMARKS:
- * Handles opcode 0xd0
- */
- static void
- x86emuOp_opcD0_byte_RM_1(struct x86emu *emu)
- {
- uint8_t destval;
- fetch_decode_modrm(emu);
- destval = decode_and_fetch_byte(emu);
- destval = (*opcD0_byte_operation[emu->cur_rh]) (emu, destval, 1);
- write_back_byte(emu, destval);
- }
- /*
- * REMARKS:
- * Handles opcode 0xd1
- */
- static void
- x86emuOp_opcD1_word_RM_1(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- uint32_t destval;
- fetch_decode_modrm(emu);
- destval = decode_and_fetch_long(emu);
- destval = (*opcD1_long_operation[emu->cur_rh])(emu, destval, 1);
- write_back_long(emu, destval);
- } else {
- uint16_t destval;
- fetch_decode_modrm(emu);
- destval = decode_and_fetch_word(emu);
- destval = (*opcD1_word_operation[emu->cur_rh])(emu, destval, 1);
- write_back_word(emu, destval);
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0xd2
- */
- static void
- x86emuOp_opcD2_byte_RM_CL(struct x86emu *emu)
- {
- uint8_t destval;
- fetch_decode_modrm(emu);
- destval = decode_and_fetch_byte(emu);
- destval = (*opcD0_byte_operation[emu->cur_rh])
- (emu, destval, emu->x86.R_CL);
- write_back_byte(emu, destval);
- }
- /*
- * REMARKS:
- * Handles opcode 0xd3
- */
- static void
- x86emuOp_opcD3_word_RM_CL(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- uint32_t destval;
- fetch_decode_modrm(emu);
- destval = decode_and_fetch_long(emu);
- destval = (*opcD1_long_operation[emu->cur_rh])
- (emu, destval, emu->x86.R_CL);
- write_back_long(emu, destval);
- } else {
- uint16_t destval;
- fetch_decode_modrm(emu);
- destval = decode_and_fetch_word(emu);
- destval = (*opcD1_word_operation[emu->cur_rh])
- (emu, destval, emu->x86.R_CL);
- write_back_word(emu, destval);
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0xd4
- */
- static void
- x86emuOp_aam(struct x86emu *emu)
- {
- uint8_t a;
- a = fetch_byte_imm(emu); /* this is a stupid encoding. */
- if (a != 10) {
- /* fix: add base decoding aam_word(uint8_t val, int base a) */
- x86emu_halt_sys(emu);
- }
- /* note the type change here --- returning AL and AH in AX. */
- emu->x86.R_AX = aam_word(emu, emu->x86.R_AL);
- }
- /*
- * REMARKS:
- * Handles opcode 0xd5
- */
- static void
- x86emuOp_aad(struct x86emu *emu)
- {
- uint8_t a;
- a = fetch_byte_imm(emu);
- if (a != 10) {
- /* fix: add base decoding aad_word(uint16_t val, int base a) */
- x86emu_halt_sys(emu);
- }
- emu->x86.R_AX = aad_word(emu, emu->x86.R_AX);
- }
- /* opcode 0xd6 ILLEGAL OPCODE */
- /*
- * REMARKS:
- * Handles opcode 0xd7
- */
- static void
- x86emuOp_xlat(struct x86emu *emu)
- {
- uint16_t addr;
- addr = (uint16_t) (emu->x86.R_BX + (uint8_t) emu->x86.R_AL);
- emu->x86.R_AL = fetch_data_byte(emu, addr);
- }
- /* opcode=0xd8 */
- static void
- x86emuOp_esc_coprocess_d8(struct x86emu *emu)
- {
- }
- /* opcode=0xd9 */
- static void
- x86emuOp_esc_coprocess_d9(struct x86emu *emu)
- {
- fetch_decode_modrm(emu);
- if (emu->cur_mod != 3)
- decode_rl_address(emu);
- }
- /* opcode=0xda */
- static void
- x86emuOp_esc_coprocess_da(struct x86emu *emu)
- {
- fetch_decode_modrm(emu);
- if (emu->cur_mod != 3)
- decode_rl_address(emu);
- }
- /* opcode=0xdb */
- static void
- x86emuOp_esc_coprocess_db(struct x86emu *emu)
- {
- fetch_decode_modrm(emu);
- if (emu->cur_mod != 3)
- decode_rl_address(emu);
- }
- /* opcode=0xdc */
- static void
- x86emuOp_esc_coprocess_dc(struct x86emu *emu)
- {
- fetch_decode_modrm(emu);
- if (emu->cur_mod != 3)
- decode_rl_address(emu);
- }
- /* opcode=0xdd */
- static void
- x86emuOp_esc_coprocess_dd(struct x86emu *emu)
- {
- fetch_decode_modrm(emu);
- if (emu->cur_mod != 3)
- decode_rl_address(emu);
- }
- /* opcode=0xde */
- static void
- x86emuOp_esc_coprocess_de(struct x86emu *emu)
- {
- fetch_decode_modrm(emu);
- if (emu->cur_mod != 3)
- decode_rl_address(emu);
- }
- /* opcode=0xdf */
- static void
- x86emuOp_esc_coprocess_df(struct x86emu *emu)
- {
- fetch_decode_modrm(emu);
- if (emu->cur_mod != 3)
- decode_rl_address(emu);
- }
- /*
- * REMARKS:
- * Handles opcode 0xe0
- */
- static void
- x86emuOp_loopne(struct x86emu *emu)
- {
- int16_t ip;
- ip = (int8_t) fetch_byte_imm(emu);
- ip += (int16_t) emu->x86.R_IP;
- emu->x86.R_CX -= 1;
- if (emu->x86.R_CX != 0 && !ACCESS_FLAG(F_ZF)) /* CX != 0 and !ZF */
- emu->x86.R_IP = ip;
- }
- /*
- * REMARKS:
- * Handles opcode 0xe1
- */
- static void
- x86emuOp_loope(struct x86emu *emu)
- {
- int16_t ip;
- ip = (int8_t) fetch_byte_imm(emu);
- ip += (int16_t) emu->x86.R_IP;
- emu->x86.R_CX -= 1;
- if (emu->x86.R_CX != 0 && ACCESS_FLAG(F_ZF)) /* CX != 0 and ZF */
- emu->x86.R_IP = ip;
- }
- /*
- * REMARKS:
- * Handles opcode 0xe2
- */
- static void
- x86emuOp_loop(struct x86emu *emu)
- {
- int16_t ip;
- ip = (int8_t) fetch_byte_imm(emu);
- ip += (int16_t) emu->x86.R_IP;
- emu->x86.R_CX -= 1;
- if (emu->x86.R_CX != 0)
- emu->x86.R_IP = ip;
- }
- /*
- * REMARKS:
- * Handles opcode 0xe3
- */
- static void
- x86emuOp_jcxz(struct x86emu *emu)
- {
- uint16_t target;
- int8_t offset;
- /* jump to byte offset if overflow flag is set */
- offset = (int8_t) fetch_byte_imm(emu);
- target = (uint16_t) (emu->x86.R_IP + offset);
- if (emu->x86.R_CX == 0)
- emu->x86.R_IP = target;
- }
- /*
- * REMARKS:
- * Handles opcode 0xe4
- */
- static void
- x86emuOp_in_byte_AL_IMM(struct x86emu *emu)
- {
- uint8_t port;
- port = (uint8_t) fetch_byte_imm(emu);
- emu->x86.R_AL = (*emu->emu_inb) (emu, port);
- }
- /*
- * REMARKS:
- * Handles opcode 0xe5
- */
- static void
- x86emuOp_in_word_AX_IMM(struct x86emu *emu)
- {
- uint8_t port;
- port = (uint8_t) fetch_byte_imm(emu);
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- emu->x86.R_EAX = (*emu->emu_inl) (emu, port);
- } else {
- emu->x86.R_AX = (*emu->emu_inw) (emu, port);
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0xe6
- */
- static void
- x86emuOp_out_byte_IMM_AL(struct x86emu *emu)
- {
- uint8_t port;
- port = (uint8_t) fetch_byte_imm(emu);
- (*emu->emu_outb) (emu, port, emu->x86.R_AL);
- }
- /*
- * REMARKS:
- * Handles opcode 0xe7
- */
- static void
- x86emuOp_out_word_IMM_AX(struct x86emu *emu)
- {
- uint8_t port;
- port = (uint8_t) fetch_byte_imm(emu);
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- (*emu->emu_outl) (emu, port, emu->x86.R_EAX);
- } else {
- (*emu->emu_outw) (emu, port, emu->x86.R_AX);
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0xe8
- */
- static void
- x86emuOp_call_near_IMM(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- int32_t ip;
- ip = (int32_t) fetch_long_imm(emu);
- ip += (int32_t) emu->x86.R_EIP;
- push_long(emu, emu->x86.R_EIP);
- emu->x86.R_EIP = ip;
- } else {
- int16_t ip;
- ip = (int16_t) fetch_word_imm(emu);
- ip += (int16_t) emu->x86.R_IP; /* CHECK SIGN */
- push_word(emu, emu->x86.R_IP);
- emu->x86.R_IP = ip;
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0xe9
- */
- static void
- x86emuOp_jump_near_IMM(struct x86emu *emu)
- {
- int ip;
- ip = (int16_t) fetch_word_imm(emu);
- ip += (int16_t) emu->x86.R_IP;
- emu->x86.R_IP = (uint16_t) ip;
- }
- /*
- * REMARKS:
- * Handles opcode 0xea
- */
- static void
- x86emuOp_jump_far_IMM(struct x86emu *emu)
- {
- uint16_t cs, ip;
- ip = fetch_word_imm(emu);
- cs = fetch_word_imm(emu);
- emu->x86.R_IP = ip;
- emu->x86.R_CS = cs;
- }
- /*
- * REMARKS:
- * Handles opcode 0xeb
- */
- static void
- x86emuOp_jump_byte_IMM(struct x86emu *emu)
- {
- uint16_t target;
- int8_t offset;
- offset = (int8_t) fetch_byte_imm(emu);
- target = (uint16_t) (emu->x86.R_IP + offset);
- emu->x86.R_IP = target;
- }
- /*
- * REMARKS:
- * Handles opcode 0xec
- */
- static void
- x86emuOp_in_byte_AL_DX(struct x86emu *emu)
- {
- emu->x86.R_AL = (*emu->emu_inb) (emu, emu->x86.R_DX);
- }
- /*
- * REMARKS:
- * Handles opcode 0xed
- */
- static void
- x86emuOp_in_word_AX_DX(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- emu->x86.R_EAX = (*emu->emu_inl) (emu, emu->x86.R_DX);
- } else {
- emu->x86.R_AX = (*emu->emu_inw) (emu, emu->x86.R_DX);
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0xee
- */
- static void
- x86emuOp_out_byte_DX_AL(struct x86emu *emu)
- {
- (*emu->emu_outb) (emu, emu->x86.R_DX, emu->x86.R_AL);
- }
- /*
- * REMARKS:
- * Handles opcode 0xef
- */
- static void
- x86emuOp_out_word_DX_AX(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- (*emu->emu_outl) (emu, emu->x86.R_DX, emu->x86.R_EAX);
- } else {
- (*emu->emu_outw) (emu, emu->x86.R_DX, emu->x86.R_AX);
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0xf0
- */
- static void
- x86emuOp_lock(struct x86emu *emu)
- {
- }
- /*opcode 0xf1 ILLEGAL OPERATION */
- /*
- * REMARKS:
- * Handles opcode 0xf5
- */
- static void
- x86emuOp_cmc(struct x86emu *emu)
- {
- if (ACCESS_FLAG(F_CF))
- CLEAR_FLAG(F_CF);
- else
- SET_FLAG(F_CF);
- }
- /*
- * REMARKS:
- * Handles opcode 0xf6
- */
- static void
- x86emuOp_opcF6_byte_RM(struct x86emu *emu)
- {
- uint8_t destval, srcval;
- /* long, drawn out code follows. Double switch for a total of 32
- * cases. */
- fetch_decode_modrm(emu);
- if (emu->cur_rh == 1)
- x86emu_halt_sys(emu);
- if (emu->cur_rh == 0) {
- destval = decode_and_fetch_byte_imm8(emu, &srcval);
- test_byte(emu, destval, srcval);
- return;
- }
- destval = decode_and_fetch_byte(emu);
- switch (emu->cur_rh) {
- case 2:
- destval = ~destval;
- write_back_byte(emu, destval);
- break;
- case 3:
- destval = neg_byte(emu, destval);
- write_back_byte(emu, destval);
- break;
- case 4:
- mul_byte(emu, destval);
- break;
- case 5:
- imul_byte(emu, destval);
- break;
- case 6:
- div_byte(emu, destval);
- break;
- case 7:
- idiv_byte(emu, destval);
- break;
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0xf7
- */
- static void
- x86emuOp32_opcF7_word_RM(struct x86emu *emu)
- {
- uint32_t destval, srcval;
- /* long, drawn out code follows. Double switch for a total of 32
- * cases. */
- fetch_decode_modrm(emu);
- if (emu->cur_rh == 1)
- x86emu_halt_sys(emu);
- if (emu->cur_rh == 0) {
- if (emu->cur_mod != 3) {
- uint32_t destoffset;
- destoffset = decode_rl_address(emu);
- srcval = fetch_long_imm(emu);
- destval = fetch_data_long(emu, destoffset);
- } else {
- srcval = fetch_long_imm(emu);
- destval = *decode_rl_long_register(emu);
- }
- test_long(emu, destval, srcval);
- return;
- }
- destval = decode_and_fetch_long(emu);
- switch (emu->cur_rh) {
- case 2:
- destval = ~destval;
- write_back_long(emu, destval);
- break;
- case 3:
- destval = neg_long(emu, destval);
- write_back_long(emu, destval);
- break;
- case 4:
- mul_long(emu, destval);
- break;
- case 5:
- imul_long(emu, destval);
- break;
- case 6:
- div_long(emu, destval);
- break;
- case 7:
- idiv_long(emu, destval);
- break;
- }
- }
- static void
- x86emuOp16_opcF7_word_RM(struct x86emu *emu)
- {
- uint16_t destval, srcval;
- /* long, drawn out code follows. Double switch for a total of 32
- * cases. */
- fetch_decode_modrm(emu);
- if (emu->cur_rh == 1)
- x86emu_halt_sys(emu);
- if (emu->cur_rh == 0) {
- if (emu->cur_mod != 3) {
- uint32_t destoffset;
- destoffset = decode_rl_address(emu);
- srcval = fetch_word_imm(emu);
- destval = fetch_data_word(emu, destoffset);
- } else {
- srcval = fetch_word_imm(emu);
- destval = *decode_rl_word_register(emu);
- }
- test_word(emu, destval, srcval);
- return;
- }
- destval = decode_and_fetch_word(emu);
- switch (emu->cur_rh) {
- case 2:
- destval = ~destval;
- write_back_word(emu, destval);
- break;
- case 3:
- destval = neg_word(emu, destval);
- write_back_word(emu, destval);
- break;
- case 4:
- mul_word(emu, destval);
- break;
- case 5:
- imul_word(emu, destval);
- break;
- case 6:
- div_word(emu, destval);
- break;
- case 7:
- idiv_word(emu, destval);
- break;
- }
- }
- static void
- x86emuOp_opcF7_word_RM(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- x86emuOp32_opcF7_word_RM(emu);
- else
- x86emuOp16_opcF7_word_RM(emu);
- }
- /*
- * REMARKS:
- * Handles opcode 0xfe
- */
- static void
- x86emuOp_opcFE_byte_RM(struct x86emu *emu)
- {
- uint8_t destval;
- uint32_t destoffset;
- uint8_t *destreg;
- /* Yet another special case instruction. */
- fetch_decode_modrm(emu);
- if (emu->cur_mod != 3) {
- destoffset = decode_rl_address(emu);
- switch (emu->cur_rh) {
- case 0: /* inc word ptr ... */
- destval = fetch_data_byte(emu, destoffset);
- destval = inc_byte(emu, destval);
- store_data_byte(emu, destoffset, destval);
- break;
- case 1: /* dec word ptr ... */
- destval = fetch_data_byte(emu, destoffset);
- destval = dec_byte(emu, destval);
- store_data_byte(emu, destoffset, destval);
- break;
- }
- } else {
- destreg = decode_rl_byte_register(emu);
- switch (emu->cur_rh) {
- case 0:
- *destreg = inc_byte(emu, *destreg);
- break;
- case 1:
- *destreg = dec_byte(emu, *destreg);
- break;
- }
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0xff
- */
- static void
- x86emuOp32_opcFF_word_RM(struct x86emu *emu)
- {
- uint32_t destoffset = 0;
- uint32_t destval, *destreg;
- if (emu->cur_mod != 3) {
- destoffset = decode_rl_address(emu);
- destval = fetch_data_long(emu, destoffset);
- switch (emu->cur_rh) {
- case 0: /* inc word ptr ... */
- destval = inc_long(emu, destval);
- store_data_long(emu, destoffset, destval);
- break;
- case 1: /* dec word ptr ... */
- destval = dec_long(emu, destval);
- store_data_long(emu, destoffset, destval);
- break;
- case 6: /* push word ptr ... */
- push_long(emu, destval);
- break;
- }
- } else {
- destreg = decode_rl_long_register(emu);
- switch (emu->cur_rh) {
- case 0:
- *destreg = inc_long(emu, *destreg);
- break;
- case 1:
- *destreg = dec_long(emu, *destreg);
- break;
- case 6:
- push_long(emu, *destreg);
- break;
- }
- }
- }
- static void
- x86emuOp16_opcFF_word_RM(struct x86emu *emu)
- {
- uint32_t destoffset = 0;
- uint16_t *destreg;
- uint16_t destval;
- if (emu->cur_mod != 3) {
- destoffset = decode_rl_address(emu);
- destval = fetch_data_word(emu, destoffset);
- switch (emu->cur_rh) {
- case 0:
- destval = inc_word(emu, destval);
- store_data_word(emu, destoffset, destval);
- break;
- case 1: /* dec word ptr ... */
- destval = dec_word(emu, destval);
- store_data_word(emu, destoffset, destval);
- break;
- case 6: /* push word ptr ... */
- push_word(emu, destval);
- break;
- }
- } else {
- destreg = decode_rl_word_register(emu);
- switch (emu->cur_rh) {
- case 0:
- *destreg = inc_word(emu, *destreg);
- break;
- case 1:
- *destreg = dec_word(emu, *destreg);
- break;
- case 6:
- push_word(emu, *destreg);
- break;
- }
- }
- }
- static void
- x86emuOp_opcFF_word_RM(struct x86emu *emu)
- {
- uint32_t destoffset = 0;
- uint16_t destval, destval2;
- /* Yet another special case instruction. */
- fetch_decode_modrm(emu);
- if ((emu->cur_mod == 3 && (emu->cur_rh == 3 || emu->cur_rh == 5)) ||
- emu->cur_rh == 7)
- x86emu_halt_sys(emu);
- if (emu->cur_rh == 0 || emu->cur_rh == 1 || emu->cur_rh == 6) {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- x86emuOp32_opcFF_word_RM(emu);
- else
- x86emuOp16_opcFF_word_RM(emu);
- return;
- }
- if (emu->cur_mod != 3) {
- destoffset = decode_rl_address(emu);
- destval = fetch_data_word(emu, destoffset);
- switch (emu->cur_rh) {
- case 3: /* call far ptr ... */
- destval2 = fetch_data_word(emu, destoffset + 2);
- push_word(emu, emu->x86.R_CS);
- emu->x86.R_CS = destval2;
- push_word(emu, emu->x86.R_IP);
- emu->x86.R_IP = destval;
- break;
- case 5: /* jmp far ptr ... */
- destval2 = fetch_data_word(emu, destoffset + 2);
- emu->x86.R_IP = destval;
- emu->x86.R_CS = destval2;
- break;
- }
- } else {
- destval = *decode_rl_word_register(emu);
- }
- switch (emu->cur_rh) {
- case 2: /* call word ptr */
- push_word(emu, emu->x86.R_IP);
- emu->x86.R_IP = destval;
- break;
- case 4: /* jmp */
- emu->x86.R_IP = destval;
- break;
- }
- }
- /*
- * * Single byte operation code table:
- */
- static void
- x86emu_exec_one_byte(struct x86emu * emu)
- {
- uint8_t op1;
- op1 = fetch_byte_imm(emu);
- switch (op1) {
- case 0x00:
- common_binop_byte_rm_r(emu, add_byte);
- break;
- case 0x01:
- common_binop_word_long_rm_r(emu, add_word, add_long);
- break;
- case 0x02:
- common_binop_byte_r_rm(emu, add_byte);
- break;
- case 0x03:
- common_binop_word_long_r_rm(emu, add_word, add_long);
- break;
- case 0x04:
- common_binop_byte_imm(emu, add_byte);
- break;
- case 0x05:
- common_binop_word_long_imm(emu, add_word, add_long);
- break;
- case 0x06:
- push_word(emu, emu->x86.R_ES);
- break;
- case 0x07:
- emu->x86.R_ES = pop_word(emu);
- break;
- case 0x08:
- common_binop_byte_rm_r(emu, or_byte);
- break;
- case 0x09:
- common_binop_word_long_rm_r(emu, or_word, or_long);
- break;
- case 0x0a:
- common_binop_byte_r_rm(emu, or_byte);
- break;
- case 0x0b:
- common_binop_word_long_r_rm(emu, or_word, or_long);
- break;
- case 0x0c:
- common_binop_byte_imm(emu, or_byte);
- break;
- case 0x0d:
- common_binop_word_long_imm(emu, or_word, or_long);
- break;
- case 0x0e:
- push_word(emu, emu->x86.R_CS);
- break;
- case 0x0f:
- x86emu_exec_two_byte(emu);
- break;
- case 0x10:
- common_binop_byte_rm_r(emu, adc_byte);
- break;
- case 0x11:
- common_binop_word_long_rm_r(emu, adc_word, adc_long);
- break;
- case 0x12:
- common_binop_byte_r_rm(emu, adc_byte);
- break;
- case 0x13:
- common_binop_word_long_r_rm(emu, adc_word, adc_long);
- break;
- case 0x14:
- common_binop_byte_imm(emu, adc_byte);
- break;
- case 0x15:
- common_binop_word_long_imm(emu, adc_word, adc_long);
- break;
- case 0x16:
- push_word(emu, emu->x86.R_SS);
- break;
- case 0x17:
- emu->x86.R_SS = pop_word(emu);
- break;
- case 0x18:
- common_binop_byte_rm_r(emu, sbb_byte);
- break;
- case 0x19:
- common_binop_word_long_rm_r(emu, sbb_word, sbb_long);
- break;
- case 0x1a:
- common_binop_byte_r_rm(emu, sbb_byte);
- break;
- case 0x1b:
- common_binop_word_long_r_rm(emu, sbb_word, sbb_long);
- break;
- case 0x1c:
- common_binop_byte_imm(emu, sbb_byte);
- break;
- case 0x1d:
- common_binop_word_long_imm(emu, sbb_word, sbb_long);
- break;
- case 0x1e:
- push_word(emu, emu->x86.R_DS);
- break;
- case 0x1f:
- emu->x86.R_DS = pop_word(emu);
- break;
- case 0x20:
- common_binop_byte_rm_r(emu, and_byte);
- break;
- case 0x21:
- common_binop_word_long_rm_r(emu, and_word, and_long);
- break;
- case 0x22:
- common_binop_byte_r_rm(emu, and_byte);
- break;
- case 0x23:
- common_binop_word_long_r_rm(emu, and_word, and_long);
- break;
- case 0x24:
- common_binop_byte_imm(emu, and_byte);
- break;
- case 0x25:
- common_binop_word_long_imm(emu, and_word, and_long);
- break;
- case 0x26:
- emu->x86.mode |= SYSMODE_SEGOVR_ES;
- break;
- case 0x27:
- emu->x86.R_AL = daa_byte(emu, emu->x86.R_AL);
- break;
- case 0x28:
- common_binop_byte_rm_r(emu, sub_byte);
- break;
- case 0x29:
- common_binop_word_long_rm_r(emu, sub_word, sub_long);
- break;
- case 0x2a:
- common_binop_byte_r_rm(emu, sub_byte);
- break;
- case 0x2b:
- common_binop_word_long_r_rm(emu, sub_word, sub_long);
- break;
- case 0x2c:
- common_binop_byte_imm(emu, sub_byte);
- break;
- case 0x2d:
- common_binop_word_long_imm(emu, sub_word, sub_long);
- break;
- case 0x2e:
- emu->x86.mode |= SYSMODE_SEGOVR_CS;
- break;
- case 0x2f:
- emu->x86.R_AL = das_byte(emu, emu->x86.R_AL);
- break;
- case 0x30:
- common_binop_byte_rm_r(emu, xor_byte);
- break;
- case 0x31:
- common_binop_word_long_rm_r(emu, xor_word, xor_long);
- break;
- case 0x32:
- common_binop_byte_r_rm(emu, xor_byte);
- break;
- case 0x33:
- common_binop_word_long_r_rm(emu, xor_word, xor_long);
- break;
- case 0x34:
- common_binop_byte_imm(emu, xor_byte);
- break;
- case 0x35:
- common_binop_word_long_imm(emu, xor_word, xor_long);
- break;
- case 0x36:
- emu->x86.mode |= SYSMODE_SEGOVR_SS;
- break;
- case 0x37:
- emu->x86.R_AX = aaa_word(emu, emu->x86.R_AX);
- break;
- case 0x38:
- common_binop_ns_byte_rm_r(emu, cmp_byte_no_return);
- break;
- case 0x39:
- common_binop_ns_word_long_rm_r(emu, cmp_word_no_return,
- cmp_long_no_return);
- break;
- case 0x3a:
- x86emuOp_cmp_byte_R_RM(emu);
- break;
- case 0x3b:
- x86emuOp_cmp_word_R_RM(emu);
- break;
- case 0x3c:
- x86emuOp_cmp_byte_AL_IMM(emu);
- break;
- case 0x3d:
- x86emuOp_cmp_word_AX_IMM(emu);
- break;
- case 0x3e:
- emu->x86.mode |= SYSMODE_SEGOVR_DS;
- break;
- case 0x3f:
- emu->x86.R_AX = aas_word(emu, emu->x86.R_AX);
- break;
- case 0x40:
- common_inc_word_long(emu, &emu->x86.register_a);
- break;
- case 0x41:
- common_inc_word_long(emu, &emu->x86.register_c);
- break;
- case 0x42:
- common_inc_word_long(emu, &emu->x86.register_d);
- break;
- case 0x43:
- common_inc_word_long(emu, &emu->x86.register_b);
- break;
- case 0x44:
- common_inc_word_long(emu, &emu->x86.register_sp);
- break;
- case 0x45:
- common_inc_word_long(emu, &emu->x86.register_bp);
- break;
- case 0x46:
- common_inc_word_long(emu, &emu->x86.register_si);
- break;
- case 0x47:
- common_inc_word_long(emu, &emu->x86.register_di);
- break;
- case 0x48:
- common_dec_word_long(emu, &emu->x86.register_a);
- break;
- case 0x49:
- common_dec_word_long(emu, &emu->x86.register_c);
- break;
- case 0x4a:
- common_dec_word_long(emu, &emu->x86.register_d);
- break;
- case 0x4b:
- common_dec_word_long(emu, &emu->x86.register_b);
- break;
- case 0x4c:
- common_dec_word_long(emu, &emu->x86.register_sp);
- break;
- case 0x4d:
- common_dec_word_long(emu, &emu->x86.register_bp);
- break;
- case 0x4e:
- common_dec_word_long(emu, &emu->x86.register_si);
- break;
- case 0x4f:
- common_dec_word_long(emu, &emu->x86.register_di);
- break;
- case 0x50:
- common_push_word_long(emu, &emu->x86.register_a);
- break;
- case 0x51:
- common_push_word_long(emu, &emu->x86.register_c);
- break;
- case 0x52:
- common_push_word_long(emu, &emu->x86.register_d);
- break;
- case 0x53:
- common_push_word_long(emu, &emu->x86.register_b);
- break;
- case 0x54:
- common_push_word_long(emu, &emu->x86.register_sp);
- break;
- case 0x55:
- common_push_word_long(emu, &emu->x86.register_bp);
- break;
- case 0x56:
- common_push_word_long(emu, &emu->x86.register_si);
- break;
- case 0x57:
- common_push_word_long(emu, &emu->x86.register_di);
- break;
- case 0x58:
- common_pop_word_long(emu, &emu->x86.register_a);
- break;
- case 0x59:
- common_pop_word_long(emu, &emu->x86.register_c);
- break;
- case 0x5a:
- common_pop_word_long(emu, &emu->x86.register_d);
- break;
- case 0x5b:
- common_pop_word_long(emu, &emu->x86.register_b);
- break;
- case 0x5c:
- common_pop_word_long(emu, &emu->x86.register_sp);
- break;
- case 0x5d:
- common_pop_word_long(emu, &emu->x86.register_bp);
- break;
- case 0x5e:
- common_pop_word_long(emu, &emu->x86.register_si);
- break;
- case 0x5f:
- common_pop_word_long(emu, &emu->x86.register_di);
- break;
- case 0x60:
- x86emuOp_push_all(emu);
- break;
- case 0x61:
- x86emuOp_pop_all(emu);
- break;
- /* 0x62 bound */
- /* 0x63 arpl */
- case 0x64:
- emu->x86.mode |= SYSMODE_SEGOVR_FS;
- break;
- case 0x65:
- emu->x86.mode |= SYSMODE_SEGOVR_GS;
- break;
- case 0x66:
- emu->x86.mode |= SYSMODE_PREFIX_DATA;
- break;
- case 0x67:
- emu->x86.mode |= SYSMODE_PREFIX_ADDR;
- break;
- case 0x68:
- x86emuOp_push_word_IMM(emu);
- break;
- case 0x69:
- common_imul_imm(emu, 0);
- break;
- case 0x6a:
- x86emuOp_push_byte_IMM(emu);
- break;
- case 0x6b:
- common_imul_imm(emu, 1);
- break;
- case 0x6c:
- ins(emu, 1);
- break;
- case 0x6d:
- x86emuOp_ins_word(emu);
- break;
- case 0x6e:
- outs(emu, 1);
- break;
- case 0x6f:
- x86emuOp_outs_word(emu);
- break;
- case 0x70:
- common_jmp_near(emu, ACCESS_FLAG(F_OF));
- break;
- case 0x71:
- common_jmp_near(emu, !ACCESS_FLAG(F_OF));
- break;
- case 0x72:
- common_jmp_near(emu, ACCESS_FLAG(F_CF));
- break;
- case 0x73:
- common_jmp_near(emu, !ACCESS_FLAG(F_CF));
- break;
- case 0x74:
- common_jmp_near(emu, ACCESS_FLAG(F_ZF));
- break;
- case 0x75:
- common_jmp_near(emu, !ACCESS_FLAG(F_ZF));
- break;
- case 0x76:
- common_jmp_near(emu, ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF));
- break;
- case 0x77:
- common_jmp_near(emu, !ACCESS_FLAG(F_CF) && !ACCESS_FLAG(F_ZF));
- break;
- case 0x78:
- common_jmp_near(emu, ACCESS_FLAG(F_SF));
- break;
- case 0x79:
- common_jmp_near(emu, !ACCESS_FLAG(F_SF));
- break;
- case 0x7a:
- common_jmp_near(emu, ACCESS_FLAG(F_PF));
- break;
- case 0x7b:
- common_jmp_near(emu, !ACCESS_FLAG(F_PF));
- break;
- case 0x7c:
- x86emuOp_jump_near_L(emu);
- break;
- case 0x7d:
- x86emuOp_jump_near_NL(emu);
- break;
- case 0x7e:
- x86emuOp_jump_near_LE(emu);
- break;
- case 0x7f:
- x86emuOp_jump_near_NLE(emu);
- break;
- case 0x80:
- x86emuOp_opc80_byte_RM_IMM(emu);
- break;
- case 0x81:
- x86emuOp_opc81_word_RM_IMM(emu);
- break;
- case 0x82:
- x86emuOp_opc82_byte_RM_IMM(emu);
- break;
- case 0x83:
- x86emuOp_opc83_word_RM_IMM(emu);
- break;
- case 0x84:
- common_binop_ns_byte_rm_r(emu, test_byte);
- break;
- case 0x85:
- common_binop_ns_word_long_rm_r(emu, test_word, test_long);
- break;
- case 0x86:
- x86emuOp_xchg_byte_RM_R(emu);
- break;
- case 0x87:
- x86emuOp_xchg_word_RM_R(emu);
- break;
- case 0x88:
- x86emuOp_mov_byte_RM_R(emu);
- break;
- case 0x89:
- x86emuOp_mov_word_RM_R(emu);
- break;
- case 0x8a:
- x86emuOp_mov_byte_R_RM(emu);
- break;
- case 0x8b:
- x86emuOp_mov_word_R_RM(emu);
- break;
- case 0x8c:
- x86emuOp_mov_word_RM_SR(emu);
- break;
- case 0x8d:
- x86emuOp_lea_word_R_M(emu);
- break;
- case 0x8e:
- x86emuOp_mov_word_SR_RM(emu);
- break;
- case 0x8f:
- x86emuOp_pop_RM(emu);
- break;
- case 0x90:
- /* nop */
- break;
- case 0x91:
- x86emuOp_xchg_word_AX_CX(emu);
- break;
- case 0x92:
- x86emuOp_xchg_word_AX_DX(emu);
- break;
- case 0x93:
- x86emuOp_xchg_word_AX_BX(emu);
- break;
- case 0x94:
- x86emuOp_xchg_word_AX_SP(emu);
- break;
- case 0x95:
- x86emuOp_xchg_word_AX_BP(emu);
- break;
- case 0x96:
- x86emuOp_xchg_word_AX_SI(emu);
- break;
- case 0x97:
- x86emuOp_xchg_word_AX_DI(emu);
- break;
- case 0x98:
- x86emuOp_cbw(emu);
- break;
- case 0x99:
- x86emuOp_cwd(emu);
- break;
- case 0x9a:
- x86emuOp_call_far_IMM(emu);
- break;
- case 0x9b:
- /* wait */
- break;
- case 0x9c:
- x86emuOp_pushf_word(emu);
- break;
- case 0x9d:
- x86emuOp_popf_word(emu);
- break;
- case 0x9e:
- x86emuOp_sahf(emu);
- break;
- case 0x9f:
- x86emuOp_lahf(emu);
- break;
- case 0xa0:
- x86emuOp_mov_AL_M_IMM(emu);
- break;
- case 0xa1:
- x86emuOp_mov_AX_M_IMM(emu);
- break;
- case 0xa2:
- x86emuOp_mov_M_AL_IMM(emu);
- break;
- case 0xa3:
- x86emuOp_mov_M_AX_IMM(emu);
- break;
- case 0xa4:
- x86emuOp_movs_byte(emu);
- break;
- case 0xa5:
- x86emuOp_movs_word(emu);
- break;
- case 0xa6:
- x86emuOp_cmps_byte(emu);
- break;
- case 0xa7:
- x86emuOp_cmps_word(emu);
- break;
- case 0xa8:
- test_byte(emu, emu->x86.R_AL, fetch_byte_imm(emu));
- break;
- case 0xa9:
- x86emuOp_test_AX_IMM(emu);
- break;
- case 0xaa:
- x86emuOp_stos_byte(emu);
- break;
- case 0xab:
- x86emuOp_stos_word(emu);
- break;
- case 0xac:
- x86emuOp_lods_byte(emu);
- break;
- case 0xad:
- x86emuOp_lods_word(emu);
- break;
- case 0xae:
- x86emuOp_scas_byte(emu);
- break;
- case 0xaf:
- x86emuOp_scas_word(emu);
- break;
- case 0xb0:
- emu->x86.R_AL = fetch_byte_imm(emu);
- break;
- case 0xb1:
- emu->x86.R_CL = fetch_byte_imm(emu);
- break;
- case 0xb2:
- emu->x86.R_DL = fetch_byte_imm(emu);
- break;
- case 0xb3:
- emu->x86.R_BL = fetch_byte_imm(emu);
- break;
- case 0xb4:
- emu->x86.R_AH = fetch_byte_imm(emu);
- break;
- case 0xb5:
- emu->x86.R_CH = fetch_byte_imm(emu);
- break;
- case 0xb6:
- emu->x86.R_DH = fetch_byte_imm(emu);
- break;
- case 0xb7:
- emu->x86.R_BH = fetch_byte_imm(emu);
- break;
- case 0xb8:
- x86emuOp_mov_word_AX_IMM(emu);
- break;
- case 0xb9:
- x86emuOp_mov_word_CX_IMM(emu);
- break;
- case 0xba:
- x86emuOp_mov_word_DX_IMM(emu);
- break;
- case 0xbb:
- x86emuOp_mov_word_BX_IMM(emu);
- break;
- case 0xbc:
- x86emuOp_mov_word_SP_IMM(emu);
- break;
- case 0xbd:
- x86emuOp_mov_word_BP_IMM(emu);
- break;
- case 0xbe:
- x86emuOp_mov_word_SI_IMM(emu);
- break;
- case 0xbf:
- x86emuOp_mov_word_DI_IMM(emu);
- break;
- case 0xc0:
- x86emuOp_opcC0_byte_RM_MEM(emu);
- break;
- case 0xc1:
- x86emuOp_opcC1_word_RM_MEM(emu);
- break;
- case 0xc2:
- x86emuOp_ret_near_IMM(emu);
- break;
- case 0xc3:
- emu->x86.R_IP = pop_word(emu);
- break;
- case 0xc4:
- common_load_far_pointer(emu, &emu->x86.R_ES);
- break;
- case 0xc5:
- common_load_far_pointer(emu, &emu->x86.R_DS);
- break;
- case 0xc6:
- x86emuOp_mov_byte_RM_IMM(emu);
- break;
- case 0xc7:
- x86emuOp_mov_word_RM_IMM(emu);
- break;
- case 0xc8:
- x86emuOp_enter(emu);
- break;
- case 0xc9:
- x86emuOp_leave(emu);
- break;
- case 0xca:
- x86emuOp_ret_far_IMM(emu);
- break;
- case 0xcb:
- x86emuOp_ret_far(emu);
- break;
- case 0xcc:
- x86emuOp_int3(emu);
- break;
- case 0xcd:
- x86emuOp_int_IMM(emu);
- break;
- case 0xce:
- x86emuOp_into(emu);
- break;
- case 0xcf:
- x86emuOp_iret(emu);
- break;
- case 0xd0:
- x86emuOp_opcD0_byte_RM_1(emu);
- break;
- case 0xd1:
- x86emuOp_opcD1_word_RM_1(emu);
- break;
- case 0xd2:
- x86emuOp_opcD2_byte_RM_CL(emu);
- break;
- case 0xd3:
- x86emuOp_opcD3_word_RM_CL(emu);
- break;
- case 0xd4:
- x86emuOp_aam(emu);
- break;
- case 0xd5:
- x86emuOp_aad(emu);
- break;
- /* 0xd6 Undocumented SETALC instruction */
- case 0xd7:
- x86emuOp_xlat(emu);
- break;
- case 0xd8:
- x86emuOp_esc_coprocess_d8(emu);
- break;
- case 0xd9:
- x86emuOp_esc_coprocess_d9(emu);
- break;
- case 0xda:
- x86emuOp_esc_coprocess_da(emu);
- break;
- case 0xdb:
- x86emuOp_esc_coprocess_db(emu);
- break;
- case 0xdc:
- x86emuOp_esc_coprocess_dc(emu);
- break;
- case 0xdd:
- x86emuOp_esc_coprocess_dd(emu);
- break;
- case 0xde:
- x86emuOp_esc_coprocess_de(emu);
- break;
- case 0xdf:
- x86emuOp_esc_coprocess_df(emu);
- break;
- case 0xe0:
- x86emuOp_loopne(emu);
- break;
- case 0xe1:
- x86emuOp_loope(emu);
- break;
- case 0xe2:
- x86emuOp_loop(emu);
- break;
- case 0xe3:
- x86emuOp_jcxz(emu);
- break;
- case 0xe4:
- x86emuOp_in_byte_AL_IMM(emu);
- break;
- case 0xe5:
- x86emuOp_in_word_AX_IMM(emu);
- break;
- case 0xe6:
- x86emuOp_out_byte_IMM_AL(emu);
- break;
- case 0xe7:
- x86emuOp_out_word_IMM_AX(emu);
- break;
- case 0xe8:
- x86emuOp_call_near_IMM(emu);
- break;
- case 0xe9:
- x86emuOp_jump_near_IMM(emu);
- break;
- case 0xea:
- x86emuOp_jump_far_IMM(emu);
- break;
- case 0xeb:
- x86emuOp_jump_byte_IMM(emu);
- break;
- case 0xec:
- x86emuOp_in_byte_AL_DX(emu);
- break;
- case 0xed:
- x86emuOp_in_word_AX_DX(emu);
- break;
- case 0xee:
- x86emuOp_out_byte_DX_AL(emu);
- break;
- case 0xef:
- x86emuOp_out_word_DX_AX(emu);
- break;
- case 0xf0:
- x86emuOp_lock(emu);
- break;
- case 0xf2:
- emu->x86.mode |= SYSMODE_PREFIX_REPNE;
- break;
- case 0xf3:
- emu->x86.mode |= SYSMODE_PREFIX_REPE;
- break;
- case 0xf4:
- x86emu_halt_sys(emu);
- break;
- case 0xf5:
- x86emuOp_cmc(emu);
- break;
- case 0xf6:
- x86emuOp_opcF6_byte_RM(emu);
- break;
- case 0xf7:
- x86emuOp_opcF7_word_RM(emu);
- break;
- case 0xf8:
- CLEAR_FLAG(F_CF);
- break;
- case 0xf9:
- SET_FLAG(F_CF);
- break;
- case 0xfa:
- CLEAR_FLAG(F_IF);
- break;
- case 0xfb:
- SET_FLAG(F_IF);
- break;
- case 0xfc:
- CLEAR_FLAG(F_DF);
- break;
- case 0xfd:
- SET_FLAG(F_DF);
- break;
- case 0xfe:
- x86emuOp_opcFE_byte_RM(emu);
- break;
- case 0xff:
- x86emuOp_opcFF_word_RM(emu);
- break;
- default:
- x86emu_halt_sys(emu);
- break;
- }
- if (op1 != 0x26 && op1 != 0x2e && op1 != 0x36 && op1 != 0x3e &&
- (op1 | 3) != 0x67)
- emu->x86.mode &= ~SYSMODE_CLRMASK;
- }
- static void
- common_jmp_long(struct x86emu *emu, int cond)
- {
- int16_t target;
- target = (int16_t) fetch_word_imm(emu);
- target += (int16_t) emu->x86.R_IP;
- if (cond)
- emu->x86.R_IP = (uint16_t) target;
- }
- static void
- common_set_byte(struct x86emu *emu, int cond)
- {
- uint32_t destoffset;
- uint8_t *destreg, destval;
- fetch_decode_modrm(emu);
- destval = cond ? 0x01 : 0x00;
- if (emu->cur_mod != 3) {
- destoffset = decode_rl_address(emu);
- store_data_byte(emu, destoffset, destval);
- } else {
- destreg = decode_rl_byte_register(emu);
- *destreg = destval;
- }
- }
- static void
- common_bitstring32(struct x86emu *emu, int op)
- {
- int bit;
- uint32_t srcval, *shiftreg, mask;
- fetch_decode_modrm(emu);
- shiftreg = decode_rh_long_register(emu);
- srcval = decode_and_fetch_long_disp(emu, (int16_t) *shiftreg >> 5);
- bit = *shiftreg & 0x1F;
- mask = 0x1 << bit;
- CONDITIONAL_SET_FLAG(srcval & mask, F_CF);
- switch (op) {
- case 0:
- break;
- case 1:
- write_back_long(emu, srcval | mask);
- break;
- case 2:
- write_back_long(emu, srcval & ~mask);
- break;
- case 3:
- write_back_long(emu, srcval ^ mask);
- break;
- }
- }
- static void
- common_bitstring16(struct x86emu *emu, int op)
- {
- int bit;
- uint16_t srcval, *shiftreg, mask;
- fetch_decode_modrm(emu);
- shiftreg = decode_rh_word_register(emu);
- srcval = decode_and_fetch_word_disp(emu, (int16_t) *shiftreg >> 4);
- bit = *shiftreg & 0xF;
- mask = 0x1 << bit;
- CONDITIONAL_SET_FLAG(srcval & mask, F_CF);
- switch (op) {
- case 0:
- break;
- case 1:
- write_back_word(emu, srcval | mask);
- break;
- case 2:
- write_back_word(emu, srcval & ~mask);
- break;
- case 3:
- write_back_word(emu, srcval ^ mask);
- break;
- }
- }
- static void
- common_bitstring(struct x86emu *emu, int op)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- common_bitstring32(emu, op);
- else
- common_bitstring16(emu, op);
- }
- static void
- common_bitsearch32(struct x86emu *emu, int diff)
- {
- uint32_t srcval, *dstreg;
- fetch_decode_modrm(emu);
- dstreg = decode_rh_long_register(emu);
- srcval = decode_and_fetch_long(emu);
- CONDITIONAL_SET_FLAG(srcval == 0, F_ZF);
- for (*dstreg = 0; *dstreg < 32; *dstreg += diff) {
- if ((srcval >> *dstreg) & 1)
- break;
- }
- }
- static void
- common_bitsearch16(struct x86emu *emu, int diff)
- {
- uint16_t srcval, *dstreg;
- fetch_decode_modrm(emu);
- dstreg = decode_rh_word_register(emu);
- srcval = decode_and_fetch_word(emu);
- CONDITIONAL_SET_FLAG(srcval == 0, F_ZF);
- for (*dstreg = 0; *dstreg < 16; *dstreg += diff) {
- if ((srcval >> *dstreg) & 1)
- break;
- }
- }
- static void
- common_bitsearch(struct x86emu *emu, int diff)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- common_bitsearch32(emu, diff);
- else
- common_bitsearch16(emu, diff);
- }
- static void
- common_shift32(struct x86emu *emu, int shift_left, int use_cl)
- {
- uint8_t shift;
- uint32_t destval, *shiftreg;
- fetch_decode_modrm(emu);
- shiftreg = decode_rh_long_register(emu);
- if (use_cl) {
- destval = decode_and_fetch_long(emu);
- shift = emu->x86.R_CL;
- } else {
- destval = decode_and_fetch_long_imm8(emu, &shift);
- }
- if (shift_left)
- destval = shld_long(emu, destval, *shiftreg, shift);
- else
- destval = shrd_long(emu, destval, *shiftreg, shift);
- write_back_long(emu, destval);
- }
- static void
- common_shift16(struct x86emu *emu, int shift_left, int use_cl)
- {
- uint8_t shift;
- uint16_t destval, *shiftreg;
- fetch_decode_modrm(emu);
- shiftreg = decode_rh_word_register(emu);
- if (use_cl) {
- destval = decode_and_fetch_word(emu);
- shift = emu->x86.R_CL;
- } else {
- destval = decode_and_fetch_word_imm8(emu, &shift);
- }
- if (shift_left)
- destval = shld_word(emu, destval, *shiftreg, shift);
- else
- destval = shrd_word(emu, destval, *shiftreg, shift);
- write_back_word(emu, destval);
- }
- static void
- common_shift(struct x86emu *emu, int shift_left, int use_cl)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- common_shift32(emu, shift_left, use_cl);
- else
- common_shift16(emu, shift_left, use_cl);
- }
- /*
- * Implementation
- */
- #define xorl(a,b) ((a) && !(b)) || (!(a) && (b))
- /*
- * REMARKS:
- * Handles opcode 0x0f,0x31
- */
- static void
- x86emuOp2_rdtsc(struct x86emu *emu)
- {
- emu->x86.R_EAX = emu->cur_cycles & 0xffffffff;
- emu->x86.R_EDX = emu->cur_cycles >> 32;
- }
- /*
- * REMARKS:
- * Handles opcode 0x0f,0xa0
- */
- static void
- x86emuOp2_push_FS(struct x86emu *emu)
- {
- push_word(emu, emu->x86.R_FS);
- }
- /*
- * REMARKS:
- * Handles opcode 0x0f,0xa1
- */
- static void
- x86emuOp2_pop_FS(struct x86emu *emu)
- {
- emu->x86.R_FS = pop_word(emu);
- }
- /*
- * REMARKS:
- * Handles opcode 0x0f,0xa1
- */
- #if defined(__i386__) || defined(__amd64__)
- static void
- hw_cpuid(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d)
- {
- __asm__ volatile("cpuid"
- : "=a" (*a), "=b" (*b),
- "=c" (*c), "=d" (*d)
- : "a" (*a), "c" (*c)
- : "cc");
- }
- #endif
- static void
- x86emuOp2_cpuid(struct x86emu *emu)
- {
- #if defined(__i386__) || defined(__amd64__)
- hw_cpuid(&emu->x86.R_EAX, &emu->x86.R_EBX, &emu->x86.R_ECX,
- &emu->x86.R_EDX);
- #endif
- switch (emu->x86.R_EAX) {
- case 0:
- emu->x86.R_EAX = 1;
- #if !defined(__i386__) && !defined(__amd64__)
- /* "GenuineIntel" */
- emu->x86.R_EBX = 0x756e6547;
- emu->x86.R_EDX = 0x49656e69;
- emu->x86.R_ECX = 0x6c65746e;
- #endif
- break;
- case 1:
- #if !defined(__i386__) && !defined(__amd64__)
- emu->x86.R_EAX = 0x00000480;
- emu->x86.R_EBX = emu->x86.R_ECX = 0;
- emu->x86.R_EDX = 0x00000002;
- #else
- emu->x86.R_EDX &= 0x00000012;
- #endif
- break;
- default:
- emu->x86.R_EAX = emu->x86.R_EBX = emu->x86.R_ECX =
- emu->x86.R_EDX = 0;
- break;
- }
- }
- /*
- * REMARKS:
- * Handles opcode 0x0f,0xa3
- */
- static void
- x86emuOp2_bt_R(struct x86emu *emu)
- {
- common_bitstring(emu, 0);
- }
- /*
- * REMARKS:
- * Handles opcode 0x0f,0xa4
- */
- static void
- x86emuOp2_shld_IMM(struct x86emu *emu)
- {
- common_shift(emu, 1, 0);
- }
- /*
- * REMARKS:
- * Handles opcode 0x0f,0xa5
- */
- static void
- x86emuOp2_shld_CL(struct x86emu *emu)
- {
- common_shift(emu, 1, 1);
- }
- /*
- * REMARKS:
- * Handles opcode 0x0f,0xa8
- */
- static void
- x86emuOp2_push_GS(struct x86emu *emu)
- {
- push_word(emu, emu->x86.R_GS);
- }
- /*
- * REMARKS:
- * Handles opcode 0x0f,0xa9
- */
- static void
- x86emuOp2_pop_GS(struct x86emu *emu)
- {
- emu->x86.R_GS = pop_word(emu);
- }
- /*
- * REMARKS:
- * Handles opcode 0x0f,0xab
- */
- static void
- x86emuOp2_bts_R(struct x86emu *emu)
- {
- common_bitstring(emu, 1);
- }
- /*
- * REMARKS:
- * Handles opcode 0x0f,0xac
- */
- static void
- x86emuOp2_shrd_IMM(struct x86emu *emu)
- {
- common_shift(emu, 0, 0);
- }
- /*
- * REMARKS:
- * Handles opcode 0x0f,0xad
- */
- static void
- x86emuOp2_shrd_CL(struct x86emu *emu)
- {
- common_shift(emu, 0, 1);
- }
- /*
- * REMARKS:
- * Handles opcode 0x0f,0xaf
- */
- static void
- x86emuOp2_32_imul_R_RM(struct x86emu *emu)
- {
- uint32_t *destreg, srcval;
- uint64_t res;
- fetch_decode_modrm(emu);
- destreg = decode_rh_long_register(emu);
- srcval = decode_and_fetch_long(emu);
- res = (int32_t) *destreg * (int32_t)srcval;
- if (res > 0xffffffff) {
- SET_FLAG(F_CF);
- SET_FLAG(F_OF);
- } else {
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_OF);
- }
- *destreg = (uint32_t) res;
- }
- static void
- x86emuOp2_16_imul_R_RM(struct x86emu *emu)
- {
- uint16_t *destreg, srcval;
- uint32_t res;
- fetch_decode_modrm(emu);
- destreg = decode_rh_word_register(emu);
- srcval = decode_and_fetch_word(emu);
- res = (int16_t) * destreg * (int16_t)srcval;
- if (res > 0xFFFF) {
- SET_FLAG(F_CF);
- SET_FLAG(F_OF);
- } else {
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_OF);
- }
- *destreg = (uint16_t) res;
- }
- static void
- x86emuOp2_imul_R_RM(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- x86emuOp2_32_imul_R_RM(emu);
- else
- x86emuOp2_16_imul_R_RM(emu);
- }
- /*
- * REMARKS:
- * Handles opcode 0x0f,0xb2
- */
- static void
- x86emuOp2_lss_R_IMM(struct x86emu *emu)
- {
- common_load_far_pointer(emu, &emu->x86.R_SS);
- }
- /*
- * REMARKS:
- * Handles opcode 0x0f,0xb3
- */
- static void
- x86emuOp2_btr_R(struct x86emu *emu)
- {
- common_bitstring(emu, 2);
- }
- /*
- * REMARKS:
- * Handles opcode 0x0f,0xb4
- */
- static void
- x86emuOp2_lfs_R_IMM(struct x86emu *emu)
- {
- common_load_far_pointer(emu, &emu->x86.R_FS);
- }
- /*
- * REMARKS:
- * Handles opcode 0x0f,0xb5
- */
- static void
- x86emuOp2_lgs_R_IMM(struct x86emu *emu)
- {
- common_load_far_pointer(emu, &emu->x86.R_GS);
- }
- /*
- * REMARKS:
- * Handles opcode 0x0f,0xb6
- */
- static void
- x86emuOp2_32_movzx_byte_R_RM(struct x86emu *emu)
- {
- uint32_t *destreg;
- fetch_decode_modrm(emu);
- destreg = decode_rh_long_register(emu);
- *destreg = decode_and_fetch_byte(emu);
- }
- static void
- x86emuOp2_16_movzx_byte_R_RM(struct x86emu *emu)
- {
- uint16_t *destreg;
- fetch_decode_modrm(emu);
- destreg = decode_rh_word_register(emu);
- *destreg = decode_and_fetch_byte(emu);
- }
- static void
- x86emuOp2_movzx_byte_R_RM(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- x86emuOp2_32_movzx_byte_R_RM(emu);
- else
- x86emuOp2_16_movzx_byte_R_RM(emu);
- }
- /*
- * REMARKS:
- * Handles opcode 0x0f,0xb7
- */
- static void
- x86emuOp2_movzx_word_R_RM(struct x86emu *emu)
- {
- uint32_t *destreg;
- fetch_decode_modrm(emu);
- destreg = decode_rh_long_register(emu);
- *destreg = decode_and_fetch_word(emu);
- }
- /*
- * REMARKS:
- * Handles opcode 0x0f,0xba
- */
- static void
- x86emuOp2_32_btX_I(struct x86emu *emu)
- {
- int bit;
- uint32_t srcval, mask;
- uint8_t shift;
- fetch_decode_modrm(emu);
- if (emu->cur_rh < 4)
- x86emu_halt_sys(emu);
- srcval = decode_and_fetch_long_imm8(emu, &shift);
- bit = shift & 0x1F;
- mask = (0x1 << bit);
- switch (emu->cur_rh) {
- case 5:
- write_back_long(emu, srcval | mask);
- break;
- case 6:
- write_back_long(emu, srcval & ~mask);
- break;
- case 7:
- write_back_long(emu, srcval ^ mask);
- break;
- }
- CONDITIONAL_SET_FLAG(srcval & mask, F_CF);
- }
- static void
- x86emuOp2_16_btX_I(struct x86emu *emu)
- {
- int bit;
- uint16_t srcval, mask;
- uint8_t shift;
- fetch_decode_modrm(emu);
- if (emu->cur_rh < 4)
- x86emu_halt_sys(emu);
- srcval = decode_and_fetch_word_imm8(emu, &shift);
- bit = shift & 0xF;
- mask = (0x1 << bit);
- switch (emu->cur_rh) {
- case 5:
- write_back_word(emu, srcval | mask);
- break;
- case 6:
- write_back_word(emu, srcval & ~mask);
- break;
- case 7:
- write_back_word(emu, srcval ^ mask);
- break;
- }
- CONDITIONAL_SET_FLAG(srcval & mask, F_CF);
- }
- static void
- x86emuOp2_btX_I(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- x86emuOp2_32_btX_I(emu);
- else
- x86emuOp2_16_btX_I(emu);
- }
- /*
- * REMARKS:
- * Handles opcode 0x0f,0xbb
- */
- static void
- x86emuOp2_btc_R(struct x86emu *emu)
- {
- common_bitstring(emu, 3);
- }
- /*
- * REMARKS:
- * Handles opcode 0x0f,0xbc
- */
- static void
- x86emuOp2_bsf(struct x86emu *emu)
- {
- common_bitsearch(emu, +1);
- }
- /*
- * REMARKS:
- * Handles opcode 0x0f,0xbd
- */
- static void
- x86emuOp2_bsr(struct x86emu *emu)
- {
- common_bitsearch(emu, -1);
- }
- /*
- * REMARKS:
- * Handles opcode 0x0f,0xbe
- */
- static void
- x86emuOp2_32_movsx_byte_R_RM(struct x86emu *emu)
- {
- uint32_t *destreg;
- fetch_decode_modrm(emu);
- destreg = decode_rh_long_register(emu);
- *destreg = (int32_t)(int8_t)decode_and_fetch_byte(emu);
- }
- static void
- x86emuOp2_16_movsx_byte_R_RM(struct x86emu *emu)
- {
- uint16_t *destreg;
- fetch_decode_modrm(emu);
- destreg = decode_rh_word_register(emu);
- *destreg = (int16_t)(int8_t)decode_and_fetch_byte(emu);
- }
- static void
- x86emuOp2_movsx_byte_R_RM(struct x86emu *emu)
- {
- if (emu->x86.mode & SYSMODE_PREFIX_DATA)
- x86emuOp2_32_movsx_byte_R_RM(emu);
- else
- x86emuOp2_16_movsx_byte_R_RM(emu);
- }
- /*
- * REMARKS:
- * Handles opcode 0x0f,0xbf
- */
- static void
- x86emuOp2_movsx_word_R_RM(struct x86emu *emu)
- {
- uint32_t *destreg;
- fetch_decode_modrm(emu);
- destreg = decode_rh_long_register(emu);
- *destreg = (int32_t)(int16_t)decode_and_fetch_word(emu);
- }
- static void
- x86emu_exec_two_byte(struct x86emu * emu)
- {
- uint8_t op2;
- op2 = fetch_byte_imm(emu);
- switch (op2) {
- /* 0x00 Group F (ring 0 PM) */
- /* 0x01 Group G (ring 0 PM) */
- /* 0x02 lar (ring 0 PM) */
- /* 0x03 lsl (ring 0 PM) */
- /* 0x05 loadall (undocumented) */
- /* 0x06 clts (ring 0 PM) */
- /* 0x07 loadall (undocumented) */
- /* 0x08 invd (ring 0 PM) */
- /* 0x09 wbinvd (ring 0 PM) */
- /* 0x20 mov reg32(op2); break;creg (ring 0 PM) */
- /* 0x21 mov reg32(op2); break;dreg (ring 0 PM) */
- /* 0x22 mov creg(op2); break;reg32 (ring 0 PM) */
- /* 0x23 mov dreg(op2); break;reg32 (ring 0 PM) */
- /* 0x24 mov reg32(op2); break;treg (ring 0 PM) */
- /* 0x26 mov treg(op2); break;reg32 (ring 0 PM) */
- case 0x31:
- x86emuOp2_rdtsc(emu);
- break;
- case 0x80:
- common_jmp_long(emu, ACCESS_FLAG(F_OF));
- break;
- case 0x81:
- common_jmp_long(emu, !ACCESS_FLAG(F_OF));
- break;
- case 0x82:
- common_jmp_long(emu, ACCESS_FLAG(F_CF));
- break;
- case 0x83:
- common_jmp_long(emu, !ACCESS_FLAG(F_CF));
- break;
- case 0x84:
- common_jmp_long(emu, ACCESS_FLAG(F_ZF));
- break;
- case 0x85:
- common_jmp_long(emu, !ACCESS_FLAG(F_ZF));
- break;
- case 0x86:
- common_jmp_long(emu, ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF));
- break;
- case 0x87:
- common_jmp_long(emu, !(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF)));
- break;
- case 0x88:
- common_jmp_long(emu, ACCESS_FLAG(F_SF));
- break;
- case 0x89:
- common_jmp_long(emu, !ACCESS_FLAG(F_SF));
- break;
- case 0x8a:
- common_jmp_long(emu, ACCESS_FLAG(F_PF));
- break;
- case 0x8b:
- common_jmp_long(emu, !ACCESS_FLAG(F_PF));
- break;
- case 0x8c:
- common_jmp_long(emu, xorl(ACCESS_FLAG(F_SF),
- ACCESS_FLAG(F_OF)));
- break;
- case 0x8d:
- common_jmp_long(emu, !(xorl(ACCESS_FLAG(F_SF),
- ACCESS_FLAG(F_OF))));
- break;
- case 0x8e:
- common_jmp_long(emu, (xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF))
- || ACCESS_FLAG(F_ZF)));
- break;
- case 0x8f:
- common_jmp_long(emu,
- !(xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) ||
- ACCESS_FLAG(F_ZF)));
- break;
- case 0x90:
- common_set_byte(emu, ACCESS_FLAG(F_OF));
- break;
- case 0x91:
- common_set_byte(emu, !ACCESS_FLAG(F_OF));
- break;
- case 0x92:
- common_set_byte(emu, ACCESS_FLAG(F_CF));
- break;
- case 0x93:
- common_set_byte(emu, !ACCESS_FLAG(F_CF));
- break;
- case 0x94:
- common_set_byte(emu, ACCESS_FLAG(F_ZF));
- break;
- case 0x95:
- common_set_byte(emu, !ACCESS_FLAG(F_ZF));
- break;
- case 0x96:
- common_set_byte(emu, ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF));
- break;
- case 0x97:
- common_set_byte(emu, !(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF)));
- break;
- case 0x98:
- common_set_byte(emu, ACCESS_FLAG(F_SF));
- break;
- case 0x99:
- common_set_byte(emu, !ACCESS_FLAG(F_SF));
- break;
- case 0x9a:
- common_set_byte(emu, ACCESS_FLAG(F_PF));
- break;
- case 0x9b:
- common_set_byte(emu, !ACCESS_FLAG(F_PF));
- break;
- case 0x9c:
- common_set_byte(emu, xorl(ACCESS_FLAG(F_SF),
- ACCESS_FLAG(F_OF)));
- break;
- case 0x9d:
- common_set_byte(emu, xorl(ACCESS_FLAG(F_SF),
- ACCESS_FLAG(F_OF)));
- break;
- case 0x9e:
- common_set_byte(emu,
- (xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) ||
- ACCESS_FLAG(F_ZF)));
- break;
- case 0x9f:
- common_set_byte(emu,
- !(xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) ||
- ACCESS_FLAG(F_ZF)));
- break;
- case 0xa0:
- x86emuOp2_push_FS(emu);
- break;
- case 0xa1:
- x86emuOp2_pop_FS(emu);
- break;
- case 0xa2:
- x86emuOp2_cpuid(emu);
- break;
- case 0xa3:
- x86emuOp2_bt_R(emu);
- break;
- case 0xa4:
- x86emuOp2_shld_IMM(emu);
- break;
- case 0xa5:
- x86emuOp2_shld_CL(emu);
- break;
- case 0xa8:
- x86emuOp2_push_GS(emu);
- break;
- case 0xa9:
- x86emuOp2_pop_GS(emu);
- break;
- case 0xab:
- x86emuOp2_bts_R(emu);
- break;
- case 0xac:
- x86emuOp2_shrd_IMM(emu);
- break;
- case 0xad:
- x86emuOp2_shrd_CL(emu);
- break;
- case 0xaf:
- x86emuOp2_imul_R_RM(emu);
- break;
- /* 0xb0 TODO: cmpxchg */
- /* 0xb1 TODO: cmpxchg */
- case 0xb2:
- x86emuOp2_lss_R_IMM(emu);
- break;
- case 0xb3:
- x86emuOp2_btr_R(emu);
- break;
- case 0xb4:
- x86emuOp2_lfs_R_IMM(emu);
- break;
- case 0xb5:
- x86emuOp2_lgs_R_IMM(emu);
- break;
- case 0xb6:
- x86emuOp2_movzx_byte_R_RM(emu);
- break;
- case 0xb7:
- x86emuOp2_movzx_word_R_RM(emu);
- break;
- case 0xba:
- x86emuOp2_btX_I(emu);
- break;
- case 0xbb:
- x86emuOp2_btc_R(emu);
- break;
- case 0xbc:
- x86emuOp2_bsf(emu);
- break;
- case 0xbd:
- x86emuOp2_bsr(emu);
- break;
- case 0xbe:
- x86emuOp2_movsx_byte_R_RM(emu);
- break;
- case 0xbf:
- x86emuOp2_movsx_word_R_RM(emu);
- break;
- /* 0xc0 TODO: xadd */
- /* 0xc1 TODO: xadd */
- /* 0xc8 TODO: bswap */
- /* 0xc9 TODO: bswap */
- /* 0xca TODO: bswap */
- /* 0xcb TODO: bswap */
- /* 0xcc TODO: bswap */
- /* 0xcd TODO: bswap */
- /* 0xce TODO: bswap */
- /* 0xcf TODO: bswap */
- default:
- x86emu_halt_sys(emu);
- break;
- }
- }
- /*
- * Carry Chain Calculation
- *
- * This represents a somewhat expensive calculation which is
- * apparently required to emulate the setting of the OF and AF flag.
- * The latter is not so important, but the former is. The overflow
- * flag is the XOR of the top two bits of the carry chain for an
- * addition (similar for subtraction). Since we do not want to
- * simulate the addition in a bitwise manner, we try to calculate the
- * carry chain given the two operands and the result.
- *
- * So, given the following table, which represents the addition of two
- * bits, we can derive a formula for the carry chain.
- *
- * a b cin r cout
- * 0 0 0 0 0
- * 0 0 1 1 0
- * 0 1 0 1 0
- * 0 1 1 0 1
- * 1 0 0 1 0
- * 1 0 1 0 1
- * 1 1 0 0 1
- * 1 1 1 1 1
- *
- * Construction of table for cout:
- *
- * ab
- * r \ 00 01 11 10
- * |------------------
- * 0 | 0 1 1 1
- * 1 | 0 0 1 0
- *
- * By inspection, one gets: cc = ab + r'(a + b)
- *
- * That represents alot of operations, but NO CHOICE....
- *
- * Borrow Chain Calculation.
- *
- * The following table represents the subtraction of two bits, from
- * which we can derive a formula for the borrow chain.
- *
- * a b bin r bout
- * 0 0 0 0 0
- * 0 0 1 1 1
- * 0 1 0 1 1
- * 0 1 1 0 1
- * 1 0 0 1 0
- * 1 0 1 0 0
- * 1 1 0 0 0
- * 1 1 1 1 1
- *
- * Construction of table for cout:
- *
- * ab
- * r \ 00 01 11 10
- * |------------------
- * 0 | 0 1 0 0
- * 1 | 1 1 1 0
- *
- * By inspection, one gets: bc = a'b + r(a' + b)
- *
- */
- /*
- * Global Variables
- */
- static uint32_t x86emu_parity_tab[8] =
- {
- 0x96696996,
- 0x69969669,
- 0x69969669,
- 0x96696996,
- 0x69969669,
- 0x96696996,
- 0x96696996,
- 0x69969669,
- };
- #define PARITY(x) (((x86emu_parity_tab[(x) / 32] >> ((x) % 32)) & 1) == 0)
- #define XOR2(x) (((x) ^ ((x)>>1)) & 0x1)
- /*
- * REMARKS:
- * Implements the AAA instruction and side effects.
- */
- static uint16_t
- aaa_word(struct x86emu *emu, uint16_t d)
- {
- uint16_t res;
- if ((d & 0xf) > 0x9 || ACCESS_FLAG(F_AF)) {
- d += 0x6;
- d += 0x100;
- SET_FLAG(F_AF);
- SET_FLAG(F_CF);
- } else {
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_AF);
- }
- res = (uint16_t) (d & 0xFF0F);
- CLEAR_FLAG(F_SF);
- CONDITIONAL_SET_FLAG(res == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- return res;
- }
- /*
- * REMARKS:
- * Implements the AAA instruction and side effects.
- */
- static uint16_t
- aas_word(struct x86emu *emu, uint16_t d)
- {
- uint16_t res;
- if ((d & 0xf) > 0x9 || ACCESS_FLAG(F_AF)) {
- d -= 0x6;
- d -= 0x100;
- SET_FLAG(F_AF);
- SET_FLAG(F_CF);
- } else {
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_AF);
- }
- res = (uint16_t) (d & 0xFF0F);
- CLEAR_FLAG(F_SF);
- CONDITIONAL_SET_FLAG(res == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- return res;
- }
- /*
- * REMARKS:
- * Implements the AAD instruction and side effects.
- */
- static uint16_t
- aad_word(struct x86emu *emu, uint16_t d)
- {
- uint16_t l;
- uint8_t hb, lb;
- hb = (uint8_t) ((d >> 8) & 0xff);
- lb = (uint8_t) ((d & 0xff));
- l = (uint16_t) ((lb + 10 * hb) & 0xFF);
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_AF);
- CLEAR_FLAG(F_OF);
- CONDITIONAL_SET_FLAG(l & 0x80, F_SF);
- CONDITIONAL_SET_FLAG(l == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(l & 0xff), F_PF);
- return l;
- }
- /*
- * REMARKS:
- * Implements the AAM instruction and side effects.
- */
- static uint16_t
- aam_word(struct x86emu *emu, uint8_t d)
- {
- uint16_t h, l;
- h = (uint16_t) (d / 10);
- l = (uint16_t) (d % 10);
- l |= (uint16_t) (h << 8);
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_AF);
- CLEAR_FLAG(F_OF);
- CONDITIONAL_SET_FLAG(l & 0x80, F_SF);
- CONDITIONAL_SET_FLAG(l == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(l & 0xff), F_PF);
- return l;
- }
- /*
- * REMARKS:
- * Implements the ADC instruction and side effects.
- */
- static uint8_t
- adc_byte(struct x86emu *emu, uint8_t d, uint8_t s)
- {
- uint32_t res; /* all operands in native machine order */
- uint32_t cc;
- if (ACCESS_FLAG(F_CF))
- res = 1 + d + s;
- else
- res = d + s;
- CONDITIONAL_SET_FLAG(res & 0x100, F_CF);
- CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- /* calculate the carry chain SEE NOTE AT TOP. */
- cc = (s & d) | ((~res) & (s | d));
- CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF);
- CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
- return (uint8_t) res;
- }
- /*
- * REMARKS:
- * Implements the ADC instruction and side effects.
- */
- static uint16_t
- adc_word(struct x86emu *emu, uint16_t d, uint16_t s)
- {
- uint32_t res; /* all operands in native machine order */
- uint32_t cc;
- if (ACCESS_FLAG(F_CF))
- res = 1 + d + s;
- else
- res = d + s;
- CONDITIONAL_SET_FLAG(res & 0x10000, F_CF);
- CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- /* calculate the carry chain SEE NOTE AT TOP. */
- cc = (s & d) | ((~res) & (s | d));
- CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF);
- CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
- return (uint16_t) res;
- }
- /*
- * REMARKS:
- * Implements the ADC instruction and side effects.
- */
- static uint32_t
- adc_long(struct x86emu *emu, uint32_t d, uint32_t s)
- {
- uint32_t lo; /* all operands in native machine order */
- uint32_t hi;
- uint32_t res;
- uint32_t cc;
- if (ACCESS_FLAG(F_CF)) {
- lo = 1 + (d & 0xFFFF) + (s & 0xFFFF);
- res = 1 + d + s;
- } else {
- lo = (d & 0xFFFF) + (s & 0xFFFF);
- res = d + s;
- }
- hi = (lo >> 16) + (d >> 16) + (s >> 16);
- CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF);
- CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- /* calculate the carry chain SEE NOTE AT TOP. */
- cc = (s & d) | ((~res) & (s | d));
- CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF);
- CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
- return res;
- }
- /*
- * REMARKS:
- * Implements the ADD instruction and side effects.
- */
- static uint8_t
- add_byte(struct x86emu *emu, uint8_t d, uint8_t s)
- {
- uint32_t res; /* all operands in native machine order */
- uint32_t cc;
- res = d + s;
- CONDITIONAL_SET_FLAG(res & 0x100, F_CF);
- CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- /* calculate the carry chain SEE NOTE AT TOP. */
- cc = (s & d) | ((~res) & (s | d));
- CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF);
- CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
- return (uint8_t) res;
- }
- /*
- * REMARKS:
- * Implements the ADD instruction and side effects.
- */
- static uint16_t
- add_word(struct x86emu *emu, uint16_t d, uint16_t s)
- {
- uint32_t res; /* all operands in native machine order */
- uint32_t cc;
- res = d + s;
- CONDITIONAL_SET_FLAG(res & 0x10000, F_CF);
- CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- /* calculate the carry chain SEE NOTE AT TOP. */
- cc = (s & d) | ((~res) & (s | d));
- CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF);
- CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
- return (uint16_t) res;
- }
- /*
- * REMARKS:
- * Implements the ADD instruction and side effects.
- */
- static uint32_t
- add_long(struct x86emu *emu, uint32_t d, uint32_t s)
- {
- uint32_t lo; /* all operands in native machine order */
- uint32_t hi;
- uint32_t res;
- uint32_t cc;
- lo = (d & 0xFFFF) + (s & 0xFFFF);
- res = d + s;
- hi = (lo >> 16) + (d >> 16) + (s >> 16);
- CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF);
- CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- /* calculate the carry chain SEE NOTE AT TOP. */
- cc = (s & d) | ((~res) & (s | d));
- CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF);
- CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
- return res;
- }
- /*
- * REMARKS:
- * Implements the AND instruction and side effects.
- */
- static uint8_t
- and_byte(struct x86emu *emu, uint8_t d, uint8_t s)
- {
- uint8_t res; /* all operands in native machine order */
- res = d & s;
- /* set the flags */
- CLEAR_FLAG(F_OF);
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_AF);
- CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
- CONDITIONAL_SET_FLAG(res == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(res), F_PF);
- return res;
- }
- /*
- * REMARKS:
- * Implements the AND instruction and side effects.
- */
- static uint16_t
- and_word(struct x86emu *emu, uint16_t d, uint16_t s)
- {
- uint16_t res; /* all operands in native machine order */
- res = d & s;
- /* set the flags */
- CLEAR_FLAG(F_OF);
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_AF);
- CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
- CONDITIONAL_SET_FLAG(res == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- return res;
- }
- /*
- * REMARKS:
- * Implements the AND instruction and side effects.
- */
- static uint32_t
- and_long(struct x86emu *emu, uint32_t d, uint32_t s)
- {
- uint32_t res; /* all operands in native machine order */
- res = d & s;
- /* set the flags */
- CLEAR_FLAG(F_OF);
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_AF);
- CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
- CONDITIONAL_SET_FLAG(res == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- return res;
- }
- /*
- * REMARKS:
- * Implements the CMP instruction and side effects.
- */
- static uint8_t
- cmp_byte(struct x86emu *emu, uint8_t d, uint8_t s)
- {
- uint32_t res; /* all operands in native machine order */
- uint32_t bc;
- res = d - s;
- CLEAR_FLAG(F_CF);
- CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
- CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- /* calculate the borrow chain. See note at top */
- bc = (res & (~d | s)) | (~d & s);
- CONDITIONAL_SET_FLAG(bc & 0x80, F_CF);
- CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
- CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
- return d;
- }
- static void
- cmp_byte_no_return(struct x86emu *emu, uint8_t d, uint8_t s)
- {
- cmp_byte(emu, d, s);
- }
- /*
- * REMARKS:
- * Implements the CMP instruction and side effects.
- */
- static uint16_t
- cmp_word(struct x86emu *emu, uint16_t d, uint16_t s)
- {
- uint32_t res; /* all operands in native machine order */
- uint32_t bc;
- res = d - s;
- CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
- CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- /* calculate the borrow chain. See note at top */
- bc = (res & (~d | s)) | (~d & s);
- CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF);
- CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
- CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
- return d;
- }
- static void
- cmp_word_no_return(struct x86emu *emu, uint16_t d, uint16_t s)
- {
- cmp_word(emu, d, s);
- }
- /*
- * REMARKS:
- * Implements the CMP instruction and side effects.
- */
- static uint32_t
- cmp_long(struct x86emu *emu, uint32_t d, uint32_t s)
- {
- uint32_t res; /* all operands in native machine order */
- uint32_t bc;
- res = d - s;
- CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
- CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- /* calculate the borrow chain. See note at top */
- bc = (res & (~d | s)) | (~d & s);
- CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF);
- CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
- CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
- return d;
- }
- static void
- cmp_long_no_return(struct x86emu *emu, uint32_t d, uint32_t s)
- {
- cmp_long(emu, d, s);
- }
- /*
- * REMARKS:
- * Implements the DAA instruction and side effects.
- */
- static uint8_t
- daa_byte(struct x86emu *emu, uint8_t d)
- {
- uint32_t res = d;
- if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) {
- res += 6;
- SET_FLAG(F_AF);
- }
- if (res > 0x9F || ACCESS_FLAG(F_CF)) {
- res += 0x60;
- SET_FLAG(F_CF);
- }
- CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
- CONDITIONAL_SET_FLAG((res & 0xFF) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- return (uint8_t) res;
- }
- /*
- * REMARKS:
- * Implements the DAS instruction and side effects.
- */
- static uint8_t
- das_byte(struct x86emu *emu, uint8_t d)
- {
- if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) {
- d -= 6;
- SET_FLAG(F_AF);
- }
- if (d > 0x9F || ACCESS_FLAG(F_CF)) {
- d -= 0x60;
- SET_FLAG(F_CF);
- }
- CONDITIONAL_SET_FLAG(d & 0x80, F_SF);
- CONDITIONAL_SET_FLAG(d == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(d & 0xff), F_PF);
- return d;
- }
- /*
- * REMARKS:
- * Implements the DEC instruction and side effects.
- */
- static uint8_t
- dec_byte(struct x86emu *emu, uint8_t d)
- {
- uint32_t res; /* all operands in native machine order */
- uint32_t bc;
- res = d - 1;
- CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
- CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- /* calculate the borrow chain. See note at top */
- /* based on sub_byte, uses s==1. */
- bc = (res & (~d | 1)) | (~d & 1);
- /* carry flag unchanged */
- CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
- CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
- return (uint8_t) res;
- }
- /*
- * REMARKS:
- * Implements the DEC instruction and side effects.
- */
- static uint16_t
- dec_word(struct x86emu *emu, uint16_t d)
- {
- uint32_t res; /* all operands in native machine order */
- uint32_t bc;
- res = d - 1;
- CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
- CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- /* calculate the borrow chain. See note at top */
- /* based on the sub_byte routine, with s==1 */
- bc = (res & (~d | 1)) | (~d & 1);
- /* carry flag unchanged */
- CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
- CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
- return (uint16_t) res;
- }
- /*
- * REMARKS:
- * Implements the DEC instruction and side effects.
- */
- static uint32_t
- dec_long(struct x86emu *emu, uint32_t d)
- {
- uint32_t res; /* all operands in native machine order */
- uint32_t bc;
- res = d - 1;
- CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
- CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- /* calculate the borrow chain. See note at top */
- bc = (res & (~d | 1)) | (~d & 1);
- /* carry flag unchanged */
- CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
- CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
- return res;
- }
- /*
- * REMARKS:
- * Implements the INC instruction and side effects.
- */
- static uint8_t
- inc_byte(struct x86emu *emu, uint8_t d)
- {
- uint32_t res; /* all operands in native machine order */
- uint32_t cc;
- res = d + 1;
- CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- /* calculate the carry chain SEE NOTE AT TOP. */
- cc = ((1 & d) | (~res)) & (1 | d);
- CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF);
- CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
- return (uint8_t) res;
- }
- /*
- * REMARKS:
- * Implements the INC instruction and side effects.
- */
- static uint16_t
- inc_word(struct x86emu *emu, uint16_t d)
- {
- uint32_t res; /* all operands in native machine order */
- uint32_t cc;
- res = d + 1;
- CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- /* calculate the carry chain SEE NOTE AT TOP. */
- cc = (1 & d) | ((~res) & (1 | d));
- CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF);
- CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
- return (uint16_t) res;
- }
- /*
- * REMARKS:
- * Implements the INC instruction and side effects.
- */
- static uint32_t
- inc_long(struct x86emu *emu, uint32_t d)
- {
- uint32_t res; /* all operands in native machine order */
- uint32_t cc;
- res = d + 1;
- CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- /* calculate the carry chain SEE NOTE AT TOP. */
- cc = (1 & d) | ((~res) & (1 | d));
- CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF);
- CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
- return res;
- }
- /*
- * REMARKS:
- * Implements the OR instruction and side effects.
- */
- static uint8_t
- or_byte(struct x86emu *emu, uint8_t d, uint8_t s)
- {
- uint8_t res; /* all operands in native machine order */
- res = d | s;
- CLEAR_FLAG(F_OF);
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_AF);
- CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
- CONDITIONAL_SET_FLAG(res == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(res), F_PF);
- return res;
- }
- /*
- * REMARKS:
- * Implements the OR instruction and side effects.
- */
- static uint16_t
- or_word(struct x86emu *emu, uint16_t d, uint16_t s)
- {
- uint16_t res; /* all operands in native machine order */
- res = d | s;
- /* set the carry flag to be bit 8 */
- CLEAR_FLAG(F_OF);
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_AF);
- CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
- CONDITIONAL_SET_FLAG(res == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- return res;
- }
- /*
- * REMARKS:
- * Implements the OR instruction and side effects.
- */
- static uint32_t
- or_long(struct x86emu *emu, uint32_t d, uint32_t s)
- {
- uint32_t res; /* all operands in native machine order */
- res = d | s;
- /* set the carry flag to be bit 8 */
- CLEAR_FLAG(F_OF);
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_AF);
- CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
- CONDITIONAL_SET_FLAG(res == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- return res;
- }
- /*
- * REMARKS:
- * Implements the OR instruction and side effects.
- */
- static uint8_t
- neg_byte(struct x86emu *emu, uint8_t s)
- {
- uint8_t res;
- uint8_t bc;
- CONDITIONAL_SET_FLAG(s != 0, F_CF);
- res = (uint8_t) - s;
- CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
- CONDITIONAL_SET_FLAG(PARITY(res), F_PF);
- /* calculate the borrow chain --- modified such that d=0.
- * substitutiing d=0 into bc= res&(~d|s)|(~d&s); (the one used for
- * sub) and simplifying, since ~d=0xff..., ~d|s == 0xffff..., and
- * res&0xfff... == res. Similarly ~d&s == s. So the simplified
- * result is: */
- bc = res | s;
- CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
- CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
- return res;
- }
- /*
- * REMARKS:
- * Implements the OR instruction and side effects.
- */
- static uint16_t
- neg_word(struct x86emu *emu, uint16_t s)
- {
- uint16_t res;
- uint16_t bc;
- CONDITIONAL_SET_FLAG(s != 0, F_CF);
- res = (uint16_t) - s;
- CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- /* calculate the borrow chain --- modified such that d=0.
- * substitutiing d=0 into bc= res&(~d|s)|(~d&s); (the one used for
- * sub) and simplifying, since ~d=0xff..., ~d|s == 0xffff..., and
- * res&0xfff... == res. Similarly ~d&s == s. So the simplified
- * result is: */
- bc = res | s;
- CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
- CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
- return res;
- }
- /*
- * REMARKS:
- * Implements the OR instruction and side effects.
- */
- static uint32_t
- neg_long(struct x86emu *emu, uint32_t s)
- {
- uint32_t res;
- uint32_t bc;
- CONDITIONAL_SET_FLAG(s != 0, F_CF);
- res = (uint32_t) - s;
- CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- /* calculate the borrow chain --- modified such that d=0.
- * substitutiing d=0 into bc= res&(~d|s)|(~d&s); (the one used for
- * sub) and simplifying, since ~d=0xff..., ~d|s == 0xffff..., and
- * res&0xfff... == res. Similarly ~d&s == s. So the simplified
- * result is: */
- bc = res | s;
- CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
- CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
- return res;
- }
- /*
- * REMARKS:
- * Implements the RCL instruction and side effects.
- */
- static uint8_t
- rcl_byte(struct x86emu *emu, uint8_t d, uint8_t s)
- {
- unsigned int res, cnt, mask, cf;
- /* s is the rotate distance. It varies from 0 - 8. */
- /* have
- *
- * CF B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0
- *
- * want to rotate through the carry by "s" bits. We could loop, but
- * that's inefficient. So the width is 9, and we split into three
- * parts:
- *
- * The new carry flag (was B_n) the stuff in B_n-1 .. B_0 the stuff
- * in B_7 .. B_n+1
- *
- * The new rotate is done mod 9, and given this, for a rotation of n
- * bits (mod 9) the new carry flag is then located n bits from the MSB.
- * The low part is then shifted up cnt bits, and the high part is or'd
- * in. Using CAPS for new values, and lowercase for the original
- * values, this can be expressed as:
- *
- * IF n > 0 1) CF <- b_(8-n) 2) B_(7) .. B_(n) <- b_(8-(n+1)) .. b_0
- * 3) B_(n-1) <- cf 4) B_(n-2) .. B_0 <- b_7 .. b_(8-(n-1))
- */
- res = d;
- if ((cnt = s % 9) != 0) {
- /* extract the new CARRY FLAG. */
- /* CF <- b_(8-n) */
- cf = (d >> (8 - cnt)) & 0x1;
- /*
- * Get the low stuff which rotated into the range B_7 .. B_cnt
- * B_(7) .. B_(n) <- b_(8-(n+1)) .. b_0
- * note that the right hand side done by the mask.
- */
- res = (d << cnt) & 0xff;
- /*
- * now the high stuff which rotated around into the positions
- * B_cnt-2 .. B_0
- * B_(n-2) .. B_0 <- b_7 .. b_(8-(n-1))
- * shift it downward, 7-(n-2) = 9-n positions. and mask off
- * the result before or'ing in.
- */
- mask = (1 << (cnt - 1)) - 1;
- res |= (d >> (9 - cnt)) & mask;
- /* if the carry flag was set, or it in. */
- if (ACCESS_FLAG(F_CF)) { /* carry flag is set */
- /* B_(n-1) <- cf */
- res |= 1 << (cnt - 1);
- }
- /* set the new carry flag, based on the variable "cf" */
- CONDITIONAL_SET_FLAG(cf, F_CF);
- /* OVERFLOW is set *IFF* cnt==1, then it is the xor of CF and
- * the most significant bit. Blecck. */
- /* parenthesized this expression since it appears to be
- * causing OF to be misset */
- CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 6) & 0x2)),
- F_OF);
- }
- return (uint8_t) res;
- }
- /*
- * REMARKS:
- * Implements the RCL instruction and side effects.
- */
- static uint16_t
- rcl_word(struct x86emu *emu, uint16_t d, uint8_t s)
- {
- unsigned int res, cnt, mask, cf;
- res = d;
- if ((cnt = s % 17) != 0) {
- cf = (d >> (16 - cnt)) & 0x1;
- res = (d << cnt) & 0xffff;
- mask = (1 << (cnt - 1)) - 1;
- res |= (d >> (17 - cnt)) & mask;
- if (ACCESS_FLAG(F_CF)) {
- res |= 1 << (cnt - 1);
- }
- CONDITIONAL_SET_FLAG(cf, F_CF);
- CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 14) & 0x2)),
- F_OF);
- }
- return (uint16_t) res;
- }
- /*
- * REMARKS:
- * Implements the RCL instruction and side effects.
- */
- static uint32_t
- rcl_long(struct x86emu *emu, uint32_t d, uint8_t s)
- {
- uint32_t res, cnt, mask, cf;
- res = d;
- if ((cnt = s % 33) != 0) {
- cf = (d >> (32 - cnt)) & 0x1;
- res = (d << cnt) & 0xffffffff;
- mask = (1 << (cnt - 1)) - 1;
- res |= (d >> (33 - cnt)) & mask;
- if (ACCESS_FLAG(F_CF)) { /* carry flag is set */
- res |= 1 << (cnt - 1);
- }
- CONDITIONAL_SET_FLAG(cf, F_CF);
- CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 30) & 0x2)),
- F_OF);
- }
- return res;
- }
- /*
- * REMARKS:
- * Implements the RCR instruction and side effects.
- */
- static uint8_t
- rcr_byte(struct x86emu *emu, uint8_t d, uint8_t s)
- {
- uint32_t res, cnt;
- uint32_t mask, cf, ocf = 0;
- /* rotate right through carry */
- /* s is the rotate distance. It varies from 0 - 8. d is the byte
- * object rotated.
- *
- * have
- *
- * CF B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0
- *
- * The new rotate is done mod 9, and given this, for a rotation of n
- * bits (mod 9) the new carry flag is then located n bits from the LSB.
- * The low part is then shifted up cnt bits, and the high part is or'd
- * in. Using CAPS for new values, and lowercase for the original
- * values, this can be expressed as:
- *
- * IF n > 0
- * 1) CF <- b_(n-1)
- * 2) B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n)
- * 3) B_(8-n) <- cf 4) B_(7) .. B_(8-(n-1)) <- b_(n-2) .. b_(0)
- */
- res = d;
- if ((cnt = s % 9) != 0) {
- /* extract the new CARRY FLAG. */
- /* CF <- b_(n-1) */
- if (cnt == 1) {
- cf = d & 0x1;
- /* note hackery here. Access_flag(..) evaluates to
- * either 0 if flag not set non-zero if flag is set.
- * doing access_flag(..) != 0 casts that into either
- * 0..1 in any representation of the flags register
- * (i.e. packed bit array or unpacked.) */
- ocf = ACCESS_FLAG(F_CF) != 0;
- } else
- cf = (d >> (cnt - 1)) & 0x1;
- /* B_(8-(n+1)) .. B_(0) <- b_(7) .. b_n */
- /* note that the right hand side done by the mask This is
- * effectively done by shifting the object to the right. The
- * result must be masked, in case the object came in and was
- * treated as a negative number. Needed??? */
- mask = (1 << (8 - cnt)) - 1;
- res = (d >> cnt) & mask;
- /* now the high stuff which rotated around into the positions
- * B_cnt-2 .. B_0 */
- /* B_(7) .. B_(8-(n-1)) <- b_(n-2) .. b_(0) */
- /* shift it downward, 7-(n-2) = 9-n positions. and mask off
- * the result before or'ing in. */
- res |= (d << (9 - cnt));
- /* if the carry flag was set, or it in. */
- if (ACCESS_FLAG(F_CF)) { /* carry flag is set */
- /* B_(8-n) <- cf */
- res |= 1 << (8 - cnt);
- }
- /* set the new carry flag, based on the variable "cf" */
- CONDITIONAL_SET_FLAG(cf, F_CF);
- /* OVERFLOW is set *IFF* cnt==1, then it is the xor of CF and
- * the most significant bit. Blecck. */
- /* parenthesized... */
- if (cnt == 1) {
- CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 6) & 0x2)),
- F_OF);
- }
- }
- return (uint8_t) res;
- }
- /*
- * REMARKS:
- * Implements the RCR instruction and side effects.
- */
- static uint16_t
- rcr_word(struct x86emu *emu, uint16_t d, uint8_t s)
- {
- uint32_t res, cnt;
- uint32_t mask, cf, ocf = 0;
- /* rotate right through carry */
- res = d;
- if ((cnt = s % 17) != 0) {
- if (cnt == 1) {
- cf = d & 0x1;
- ocf = ACCESS_FLAG(F_CF) != 0;
- } else
- cf = (d >> (cnt - 1)) & 0x1;
- mask = (1 << (16 - cnt)) - 1;
- res = (d >> cnt) & mask;
- res |= (d << (17 - cnt));
- if (ACCESS_FLAG(F_CF)) {
- res |= 1 << (16 - cnt);
- }
- CONDITIONAL_SET_FLAG(cf, F_CF);
- if (cnt == 1) {
- CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 14) & 0x2)),
- F_OF);
- }
- }
- return (uint16_t) res;
- }
- /*
- * REMARKS:
- * Implements the RCR instruction and side effects.
- */
- static uint32_t
- rcr_long(struct x86emu *emu, uint32_t d, uint8_t s)
- {
- uint32_t res, cnt;
- uint32_t mask, cf, ocf = 0;
- /* rotate right through carry */
- res = d;
- if ((cnt = s % 33) != 0) {
- if (cnt == 1) {
- cf = d & 0x1;
- ocf = ACCESS_FLAG(F_CF) != 0;
- } else
- cf = (d >> (cnt - 1)) & 0x1;
- mask = (1 << (32 - cnt)) - 1;
- res = (d >> cnt) & mask;
- if (cnt != 1)
- res |= (d << (33 - cnt));
- if (ACCESS_FLAG(F_CF)) { /* carry flag is set */
- res |= 1 << (32 - cnt);
- }
- CONDITIONAL_SET_FLAG(cf, F_CF);
- if (cnt == 1) {
- CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 30) & 0x2)),
- F_OF);
- }
- }
- return res;
- }
- /*
- * REMARKS:
- * Implements the ROL instruction and side effects.
- */
- static uint8_t
- rol_byte(struct x86emu *emu, uint8_t d, uint8_t s)
- {
- unsigned int res, cnt, mask;
- /* rotate left */
- /* s is the rotate distance. It varies from 0 - 8. d is the byte
- * object rotated.
- *
- * have
- *
- * CF B_7 ... B_0
- *
- * The new rotate is done mod 8. Much simpler than the "rcl" or "rcr"
- * operations.
- *
- * IF n > 0 1) B_(7) .. B_(n) <- b_(8-(n+1)) .. b_(0) 2) B_(n-1) ..
- * B_(0) <- b_(7) .. b_(8-n) */
- res = d;
- if ((cnt = s % 8) != 0) {
- /* B_(7) .. B_(n) <- b_(8-(n+1)) .. b_(0) */
- res = (d << cnt);
- /* B_(n-1) .. B_(0) <- b_(7) .. b_(8-n) */
- mask = (1 << cnt) - 1;
- res |= (d >> (8 - cnt)) & mask;
- /* set the new carry flag, Note that it is the low order bit
- * of the result!!! */
- CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
- /* OVERFLOW is set *IFF* s==1, then it is the xor of CF and
- * the most significant bit. Blecck. */
- CONDITIONAL_SET_FLAG(s == 1 &&
- XOR2((res & 0x1) + ((res >> 6) & 0x2)),
- F_OF);
- } if (s != 0) {
- /* set the new carry flag, Note that it is the low order bit
- * of the result!!! */
- CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
- }
- return (uint8_t) res;
- }
- /*
- * REMARKS:
- * Implements the ROL instruction and side effects.
- */
- static uint16_t
- rol_word(struct x86emu *emu, uint16_t d, uint8_t s)
- {
- unsigned int res, cnt, mask;
- res = d;
- if ((cnt = s % 16) != 0) {
- res = (d << cnt);
- mask = (1 << cnt) - 1;
- res |= (d >> (16 - cnt)) & mask;
- CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
- CONDITIONAL_SET_FLAG(s == 1 &&
- XOR2((res & 0x1) + ((res >> 14) & 0x2)),
- F_OF);
- } if (s != 0) {
- /* set the new carry flag, Note that it is the low order bit
- * of the result!!! */
- CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
- }
- return (uint16_t) res;
- }
- /*
- * REMARKS:
- * Implements the ROL instruction and side effects.
- */
- static uint32_t
- rol_long(struct x86emu *emu, uint32_t d, uint8_t s)
- {
- uint32_t res, cnt, mask;
- res = d;
- if ((cnt = s % 32) != 0) {
- res = (d << cnt);
- mask = (1 << cnt) - 1;
- res |= (d >> (32 - cnt)) & mask;
- CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
- CONDITIONAL_SET_FLAG(s == 1 &&
- XOR2((res & 0x1) + ((res >> 30) & 0x2)),
- F_OF);
- } if (s != 0) {
- /* set the new carry flag, Note that it is the low order bit
- * of the result!!! */
- CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
- }
- return res;
- }
- /*
- * REMARKS:
- * Implements the ROR instruction and side effects.
- */
- static uint8_t
- ror_byte(struct x86emu *emu, uint8_t d, uint8_t s)
- {
- unsigned int res, cnt, mask;
- /* rotate right */
- /* s is the rotate distance. It varies from 0 - 8. d is the byte
- * object rotated.
- *
- * have
- *
- * B_7 ... B_0
- *
- * The rotate is done mod 8.
- *
- * IF n > 0 1) B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n) 2) B_(7) ..
- * B_(8-n) <- b_(n-1) .. b_(0) */
- res = d;
- if ((cnt = s % 8) != 0) { /* not a typo, do nada if cnt==0 */
- /* B_(7) .. B_(8-n) <- b_(n-1) .. b_(0) */
- res = (d << (8 - cnt));
- /* B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n) */
- mask = (1 << (8 - cnt)) - 1;
- res |= (d >> (cnt)) & mask;
- /* set the new carry flag, Note that it is the low order bit
- * of the result!!! */
- CONDITIONAL_SET_FLAG(res & 0x80, F_CF);
- /* OVERFLOW is set *IFF* s==1, then it is the xor of the two
- * most significant bits. Blecck. */
- CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 6), F_OF);
- } else if (s != 0) {
- /* set the new carry flag, Note that it is the low order bit
- * of the result!!! */
- CONDITIONAL_SET_FLAG(res & 0x80, F_CF);
- }
- return (uint8_t) res;
- }
- /*
- * REMARKS:
- * Implements the ROR instruction and side effects.
- */
- static uint16_t
- ror_word(struct x86emu *emu, uint16_t d, uint8_t s)
- {
- unsigned int res, cnt, mask;
- res = d;
- if ((cnt = s % 16) != 0) {
- res = (d << (16 - cnt));
- mask = (1 << (16 - cnt)) - 1;
- res |= (d >> (cnt)) & mask;
- CONDITIONAL_SET_FLAG(res & 0x8000, F_CF);
- CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 14), F_OF);
- } else if (s != 0) {
- /* set the new carry flag, Note that it is the low order bit
- * of the result!!! */
- CONDITIONAL_SET_FLAG(res & 0x8000, F_CF);
- }
- return (uint16_t) res;
- }
- /*
- * REMARKS:
- * Implements the ROR instruction and side effects.
- */
- static uint32_t
- ror_long(struct x86emu *emu, uint32_t d, uint8_t s)
- {
- uint32_t res, cnt, mask;
- res = d;
- if ((cnt = s % 32) != 0) {
- res = (d << (32 - cnt));
- mask = (1 << (32 - cnt)) - 1;
- res |= (d >> (cnt)) & mask;
- CONDITIONAL_SET_FLAG(res & 0x80000000, F_CF);
- CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 30), F_OF);
- } else if (s != 0) {
- /* set the new carry flag, Note that it is the low order bit
- * of the result!!! */
- CONDITIONAL_SET_FLAG(res & 0x80000000, F_CF);
- }
- return res;
- }
- /*
- * REMARKS:
- * Implements the SHL instruction and side effects.
- */
- static uint8_t
- shl_byte(struct x86emu *emu, uint8_t d, uint8_t s)
- {
- unsigned int cnt, res, cf;
- if (s < 8) {
- cnt = s % 8;
- /* last bit shifted out goes into carry flag */
- if (cnt > 0) {
- res = d << cnt;
- cf = d & (1 << (8 - cnt));
- CONDITIONAL_SET_FLAG(cf, F_CF);
- CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- } else {
- res = (uint8_t) d;
- }
- if (cnt == 1) {
- /* Needs simplification. */
- CONDITIONAL_SET_FLAG(
- (((res & 0x80) == 0x80) ^
- (ACCESS_FLAG(F_CF) != 0)),
- /* was (emu->x86.R_FLG&F_CF)==F_CF)), */
- F_OF);
- } else {
- CLEAR_FLAG(F_OF);
- }
- } else {
- res = 0;
- CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x80, F_CF);
- CLEAR_FLAG(F_OF);
- CLEAR_FLAG(F_SF);
- SET_FLAG(F_PF);
- SET_FLAG(F_ZF);
- }
- return (uint8_t) res;
- }
- /*
- * REMARKS:
- * Implements the SHL instruction and side effects.
- */
- static uint16_t
- shl_word(struct x86emu *emu, uint16_t d, uint8_t s)
- {
- unsigned int cnt, res, cf;
- if (s < 16) {
- cnt = s % 16;
- if (cnt > 0) {
- res = d << cnt;
- cf = d & (1 << (16 - cnt));
- CONDITIONAL_SET_FLAG(cf, F_CF);
- CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- } else {
- res = (uint16_t) d;
- }
- if (cnt == 1) {
- CONDITIONAL_SET_FLAG(
- (((res & 0x8000) == 0x8000) ^
- (ACCESS_FLAG(F_CF) != 0)),
- F_OF);
- } else {
- CLEAR_FLAG(F_OF);
- }
- } else {
- res = 0;
- CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x8000, F_CF);
- CLEAR_FLAG(F_OF);
- CLEAR_FLAG(F_SF);
- SET_FLAG(F_PF);
- SET_FLAG(F_ZF);
- }
- return (uint16_t) res;
- }
- /*
- * REMARKS:
- * Implements the SHL instruction and side effects.
- */
- static uint32_t
- shl_long(struct x86emu *emu, uint32_t d, uint8_t s)
- {
- unsigned int cnt, res, cf;
- if (s < 32) {
- cnt = s % 32;
- if (cnt > 0) {
- res = d << cnt;
- cf = d & (1 << (32 - cnt));
- CONDITIONAL_SET_FLAG(cf, F_CF);
- CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- } else {
- res = d;
- }
- if (cnt == 1) {
- CONDITIONAL_SET_FLAG((((res & 0x80000000) == 0x80000000)
- ^ (ACCESS_FLAG(F_CF) != 0)), F_OF);
- } else {
- CLEAR_FLAG(F_OF);
- }
- } else {
- res = 0;
- CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x80000000, F_CF);
- CLEAR_FLAG(F_OF);
- CLEAR_FLAG(F_SF);
- SET_FLAG(F_PF);
- SET_FLAG(F_ZF);
- }
- return res;
- }
- /*
- * REMARKS:
- * Implements the SHR instruction and side effects.
- */
- static uint8_t
- shr_byte(struct x86emu *emu, uint8_t d, uint8_t s)
- {
- unsigned int cnt, res, cf;
- if (s < 8) {
- cnt = s % 8;
- if (cnt > 0) {
- cf = d & (1 << (cnt - 1));
- res = d >> cnt;
- CONDITIONAL_SET_FLAG(cf, F_CF);
- CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- } else {
- res = (uint8_t) d;
- }
- if (cnt == 1) {
- CONDITIONAL_SET_FLAG(XOR2(res >> 6), F_OF);
- } else {
- CLEAR_FLAG(F_OF);
- }
- } else {
- res = 0;
- CONDITIONAL_SET_FLAG((d >> (s - 1)) & 0x1, F_CF);
- CLEAR_FLAG(F_OF);
- CLEAR_FLAG(F_SF);
- SET_FLAG(F_PF);
- SET_FLAG(F_ZF);
- }
- return (uint8_t) res;
- }
- /*
- * REMARKS:
- * Implements the SHR instruction and side effects.
- */
- static uint16_t
- shr_word(struct x86emu *emu, uint16_t d, uint8_t s)
- {
- unsigned int cnt, res, cf;
- if (s < 16) {
- cnt = s % 16;
- if (cnt > 0) {
- cf = d & (1 << (cnt - 1));
- res = d >> cnt;
- CONDITIONAL_SET_FLAG(cf, F_CF);
- CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- } else {
- res = d;
- }
- if (cnt == 1) {
- CONDITIONAL_SET_FLAG(XOR2(res >> 14), F_OF);
- } else {
- CLEAR_FLAG(F_OF);
- }
- } else {
- res = 0;
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_OF);
- SET_FLAG(F_ZF);
- CLEAR_FLAG(F_SF);
- CLEAR_FLAG(F_PF);
- }
- return (uint16_t) res;
- }
- /*
- * REMARKS:
- * Implements the SHR instruction and side effects.
- */
- static uint32_t
- shr_long(struct x86emu *emu, uint32_t d, uint8_t s)
- {
- unsigned int cnt, res, cf;
- if (s < 32) {
- cnt = s % 32;
- if (cnt > 0) {
- cf = d & (1 << (cnt - 1));
- res = d >> cnt;
- CONDITIONAL_SET_FLAG(cf, F_CF);
- CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- } else {
- res = d;
- }
- if (cnt == 1) {
- CONDITIONAL_SET_FLAG(XOR2(res >> 30), F_OF);
- } else {
- CLEAR_FLAG(F_OF);
- }
- } else {
- res = 0;
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_OF);
- SET_FLAG(F_ZF);
- CLEAR_FLAG(F_SF);
- CLEAR_FLAG(F_PF);
- }
- return res;
- }
- /*
- * REMARKS:
- * Implements the SAR instruction and side effects.
- */
- static uint8_t
- sar_byte(struct x86emu *emu, uint8_t d, uint8_t s)
- {
- unsigned int cnt, res, cf, mask, sf;
- res = d;
- sf = d & 0x80;
- cnt = s % 8;
- if (cnt > 0 && cnt < 8) {
- mask = (1 << (8 - cnt)) - 1;
- cf = d & (1 << (cnt - 1));
- res = (d >> cnt) & mask;
- CONDITIONAL_SET_FLAG(cf, F_CF);
- if (sf) {
- res |= ~mask;
- }
- CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
- } else if (cnt >= 8) {
- if (sf) {
- res = 0xff;
- SET_FLAG(F_CF);
- CLEAR_FLAG(F_ZF);
- SET_FLAG(F_SF);
- SET_FLAG(F_PF);
- } else {
- res = 0;
- CLEAR_FLAG(F_CF);
- SET_FLAG(F_ZF);
- CLEAR_FLAG(F_SF);
- CLEAR_FLAG(F_PF);
- }
- }
- return (uint8_t) res;
- }
- /*
- * REMARKS:
- * Implements the SAR instruction and side effects.
- */
- static uint16_t
- sar_word(struct x86emu *emu, uint16_t d, uint8_t s)
- {
- unsigned int cnt, res, cf, mask, sf;
- sf = d & 0x8000;
- cnt = s % 16;
- res = d;
- if (cnt > 0 && cnt < 16) {
- mask = (1 << (16 - cnt)) - 1;
- cf = d & (1 << (cnt - 1));
- res = (d >> cnt) & mask;
- CONDITIONAL_SET_FLAG(cf, F_CF);
- if (sf) {
- res |= ~mask;
- }
- CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- } else if (cnt >= 16) {
- if (sf) {
- res = 0xffff;
- SET_FLAG(F_CF);
- CLEAR_FLAG(F_ZF);
- SET_FLAG(F_SF);
- SET_FLAG(F_PF);
- } else {
- res = 0;
- CLEAR_FLAG(F_CF);
- SET_FLAG(F_ZF);
- CLEAR_FLAG(F_SF);
- CLEAR_FLAG(F_PF);
- }
- }
- return (uint16_t) res;
- }
- /*
- * REMARKS:
- * Implements the SAR instruction and side effects.
- */
- static uint32_t
- sar_long(struct x86emu *emu, uint32_t d, uint8_t s)
- {
- uint32_t cnt, res, cf, mask, sf;
- sf = d & 0x80000000;
- cnt = s % 32;
- res = d;
- if (cnt > 0 && cnt < 32) {
- mask = (1 << (32 - cnt)) - 1;
- cf = d & (1 << (cnt - 1));
- res = (d >> cnt) & mask;
- CONDITIONAL_SET_FLAG(cf, F_CF);
- if (sf) {
- res |= ~mask;
- }
- CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- } else if (cnt >= 32) {
- if (sf) {
- res = 0xffffffff;
- SET_FLAG(F_CF);
- CLEAR_FLAG(F_ZF);
- SET_FLAG(F_SF);
- SET_FLAG(F_PF);
- } else {
- res = 0;
- CLEAR_FLAG(F_CF);
- SET_FLAG(F_ZF);
- CLEAR_FLAG(F_SF);
- CLEAR_FLAG(F_PF);
- }
- }
- return res;
- }
- /*
- * REMARKS:
- * Implements the SHLD instruction and side effects.
- */
- static uint16_t
- shld_word(struct x86emu *emu, uint16_t d, uint16_t fill, uint8_t s)
- {
- unsigned int cnt, res, cf;
- if (s < 16) {
- cnt = s % 16;
- if (cnt > 0) {
- res = (d << cnt) | (fill >> (16 - cnt));
- cf = d & (1 << (16 - cnt));
- CONDITIONAL_SET_FLAG(cf, F_CF);
- CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- } else {
- res = d;
- }
- if (cnt == 1) {
- CONDITIONAL_SET_FLAG((((res & 0x8000) == 0x8000) ^
- (ACCESS_FLAG(F_CF) != 0)), F_OF);
- } else {
- CLEAR_FLAG(F_OF);
- }
- } else {
- res = 0;
- CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x8000, F_CF);
- CLEAR_FLAG(F_OF);
- CLEAR_FLAG(F_SF);
- SET_FLAG(F_PF);
- SET_FLAG(F_ZF);
- }
- return (uint16_t) res;
- }
- /*
- * REMARKS:
- * Implements the SHLD instruction and side effects.
- */
- static uint32_t
- shld_long(struct x86emu *emu, uint32_t d, uint32_t fill, uint8_t s)
- {
- unsigned int cnt, res, cf;
- if (s < 32) {
- cnt = s % 32;
- if (cnt > 0) {
- res = (d << cnt) | (fill >> (32 - cnt));
- cf = d & (1 << (32 - cnt));
- CONDITIONAL_SET_FLAG(cf, F_CF);
- CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- } else {
- res = d;
- }
- if (cnt == 1) {
- CONDITIONAL_SET_FLAG((((res & 0x80000000) == 0x80000000)
- ^ (ACCESS_FLAG(F_CF) != 0)), F_OF);
- } else {
- CLEAR_FLAG(F_OF);
- }
- } else {
- res = 0;
- CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x80000000, F_CF);
- CLEAR_FLAG(F_OF);
- CLEAR_FLAG(F_SF);
- SET_FLAG(F_PF);
- SET_FLAG(F_ZF);
- }
- return res;
- }
- /*
- * REMARKS:
- * Implements the SHRD instruction and side effects.
- */
- static uint16_t
- shrd_word(struct x86emu *emu, uint16_t d, uint16_t fill, uint8_t s)
- {
- unsigned int cnt, res, cf;
- if (s < 16) {
- cnt = s % 16;
- if (cnt > 0) {
- cf = d & (1 << (cnt - 1));
- res = (d >> cnt) | (fill << (16 - cnt));
- CONDITIONAL_SET_FLAG(cf, F_CF);
- CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- } else {
- res = d;
- }
- if (cnt == 1) {
- CONDITIONAL_SET_FLAG(XOR2(res >> 14), F_OF);
- } else {
- CLEAR_FLAG(F_OF);
- }
- } else {
- res = 0;
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_OF);
- SET_FLAG(F_ZF);
- CLEAR_FLAG(F_SF);
- CLEAR_FLAG(F_PF);
- }
- return (uint16_t) res;
- }
- /*
- * REMARKS:
- * Implements the SHRD instruction and side effects.
- */
- static uint32_t
- shrd_long(struct x86emu *emu, uint32_t d, uint32_t fill, uint8_t s)
- {
- unsigned int cnt, res, cf;
- if (s < 32) {
- cnt = s % 32;
- if (cnt > 0) {
- cf = d & (1 << (cnt - 1));
- res = (d >> cnt) | (fill << (32 - cnt));
- CONDITIONAL_SET_FLAG(cf, F_CF);
- CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- } else {
- res = d;
- }
- if (cnt == 1) {
- CONDITIONAL_SET_FLAG(XOR2(res >> 30), F_OF);
- } else {
- CLEAR_FLAG(F_OF);
- }
- } else {
- res = 0;
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_OF);
- SET_FLAG(F_ZF);
- CLEAR_FLAG(F_SF);
- CLEAR_FLAG(F_PF);
- }
- return res;
- }
- /*
- * REMARKS:
- * Implements the SBB instruction and side effects.
- */
- static uint8_t
- sbb_byte(struct x86emu *emu, uint8_t d, uint8_t s)
- {
- uint32_t res; /* all operands in native machine order */
- uint32_t bc;
- if (ACCESS_FLAG(F_CF))
- res = d - s - 1;
- else
- res = d - s;
- CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
- CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- /* calculate the borrow chain. See note at top */
- bc = (res & (~d | s)) | (~d & s);
- CONDITIONAL_SET_FLAG(bc & 0x80, F_CF);
- CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
- CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
- return (uint8_t) res;
- }
- /*
- * REMARKS:
- * Implements the SBB instruction and side effects.
- */
- static uint16_t
- sbb_word(struct x86emu *emu, uint16_t d, uint16_t s)
- {
- uint32_t res; /* all operands in native machine order */
- uint32_t bc;
- if (ACCESS_FLAG(F_CF))
- res = d - s - 1;
- else
- res = d - s;
- CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
- CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- /* calculate the borrow chain. See note at top */
- bc = (res & (~d | s)) | (~d & s);
- CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF);
- CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
- CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
- return (uint16_t) res;
- }
- /*
- * REMARKS:
- * Implements the SBB instruction and side effects.
- */
- static uint32_t
- sbb_long(struct x86emu *emu, uint32_t d, uint32_t s)
- {
- uint32_t res; /* all operands in native machine order */
- uint32_t bc;
- if (ACCESS_FLAG(F_CF))
- res = d - s - 1;
- else
- res = d - s;
- CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
- CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- /* calculate the borrow chain. See note at top */
- bc = (res & (~d | s)) | (~d & s);
- CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF);
- CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
- CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
- return res;
- }
- /*
- * REMARKS:
- * Implements the SUB instruction and side effects.
- */
- static uint8_t
- sub_byte(struct x86emu *emu, uint8_t d, uint8_t s)
- {
- uint32_t res; /* all operands in native machine order */
- uint32_t bc;
- res = d - s;
- CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
- CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- /* calculate the borrow chain. See note at top */
- bc = (res & (~d | s)) | (~d & s);
- CONDITIONAL_SET_FLAG(bc & 0x80, F_CF);
- CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
- CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
- return (uint8_t) res;
- }
- /*
- * REMARKS:
- * Implements the SUB instruction and side effects.
- */
- static uint16_t
- sub_word(struct x86emu *emu, uint16_t d, uint16_t s)
- {
- uint32_t res; /* all operands in native machine order */
- uint32_t bc;
- res = d - s;
- CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
- CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- /* calculate the borrow chain. See note at top */
- bc = (res & (~d | s)) | (~d & s);
- CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF);
- CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
- CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
- return (uint16_t) res;
- }
- /*
- * REMARKS:
- * Implements the SUB instruction and side effects.
- */
- static uint32_t
- sub_long(struct x86emu *emu, uint32_t d, uint32_t s)
- {
- uint32_t res; /* all operands in native machine order */
- uint32_t bc;
- res = d - s;
- CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
- CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- /* calculate the borrow chain. See note at top */
- bc = (res & (~d | s)) | (~d & s);
- CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF);
- CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
- CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
- return res;
- }
- /*
- * REMARKS:
- * Implements the TEST instruction and side effects.
- */
- static void
- test_byte(struct x86emu *emu, uint8_t d, uint8_t s)
- {
- uint32_t res; /* all operands in native machine order */
- res = d & s;
- CLEAR_FLAG(F_OF);
- CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
- CONDITIONAL_SET_FLAG(res == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- /* AF == dont care */
- CLEAR_FLAG(F_CF);
- }
- /*
- * REMARKS:
- * Implements the TEST instruction and side effects.
- */
- static void
- test_word(struct x86emu *emu, uint16_t d, uint16_t s)
- {
- uint32_t res; /* all operands in native machine order */
- res = d & s;
- CLEAR_FLAG(F_OF);
- CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
- CONDITIONAL_SET_FLAG(res == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- /* AF == dont care */
- CLEAR_FLAG(F_CF);
- }
- /*
- * REMARKS:
- * Implements the TEST instruction and side effects.
- */
- static void
- test_long(struct x86emu *emu, uint32_t d, uint32_t s)
- {
- uint32_t res; /* all operands in native machine order */
- res = d & s;
- CLEAR_FLAG(F_OF);
- CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
- CONDITIONAL_SET_FLAG(res == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- /* AF == dont care */
- CLEAR_FLAG(F_CF);
- }
- /*
- * REMARKS:
- * Implements the XOR instruction and side effects.
- */
- static uint8_t
- xor_byte(struct x86emu *emu, uint8_t d, uint8_t s)
- {
- uint8_t res; /* all operands in native machine order */
- res = d ^ s;
- CLEAR_FLAG(F_OF);
- CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
- CONDITIONAL_SET_FLAG(res == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(res), F_PF);
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_AF);
- return res;
- }
- /*
- * REMARKS:
- * Implements the XOR instruction and side effects.
- */
- static uint16_t
- xor_word(struct x86emu *emu, uint16_t d, uint16_t s)
- {
- uint16_t res; /* all operands in native machine order */
- res = d ^ s;
- CLEAR_FLAG(F_OF);
- CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
- CONDITIONAL_SET_FLAG(res == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_AF);
- return res;
- }
- /*
- * REMARKS:
- * Implements the XOR instruction and side effects.
- */
- static uint32_t
- xor_long(struct x86emu *emu, uint32_t d, uint32_t s)
- {
- uint32_t res; /* all operands in native machine order */
- res = d ^ s;
- CLEAR_FLAG(F_OF);
- CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
- CONDITIONAL_SET_FLAG(res == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_AF);
- return res;
- }
- /*
- * REMARKS:
- * Implements the IMUL instruction and side effects.
- */
- static void
- imul_byte(struct x86emu *emu, uint8_t s)
- {
- int16_t res = (int16_t) ((int8_t) emu->x86.R_AL * (int8_t) s);
- emu->x86.R_AX = res;
- if (((emu->x86.R_AL & 0x80) == 0 && emu->x86.R_AH == 0x00) ||
- ((emu->x86.R_AL & 0x80) != 0 && emu->x86.R_AH == 0xFF)) {
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_OF);
- } else {
- SET_FLAG(F_CF);
- SET_FLAG(F_OF);
- }
- }
- /*
- * REMARKS:
- * Implements the IMUL instruction and side effects.
- */
- static void
- imul_word(struct x86emu *emu, uint16_t s)
- {
- int32_t res = (int16_t) emu->x86.R_AX * (int16_t) s;
- emu->x86.R_AX = (uint16_t) res;
- emu->x86.R_DX = (uint16_t) (res >> 16);
- if (((emu->x86.R_AX & 0x8000) == 0 && emu->x86.R_DX == 0x00) ||
- ((emu->x86.R_AX & 0x8000) != 0 && emu->x86.R_DX == 0xFF)) {
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_OF);
- } else {
- SET_FLAG(F_CF);
- SET_FLAG(F_OF);
- }
- }
- /*
- * REMARKS:
- * Implements the IMUL instruction and side effects.
- */
- static void
- imul_long(struct x86emu *emu, uint32_t s)
- {
- int64_t res;
-
- res = (int64_t)(int32_t)emu->x86.R_EAX * (int32_t)s;
- emu->x86.R_EAX = (uint32_t)res;
- emu->x86.R_EDX = ((uint64_t)res) >> 32;
- if (((emu->x86.R_EAX & 0x80000000) == 0 && emu->x86.R_EDX == 0x00) ||
- ((emu->x86.R_EAX & 0x80000000) != 0 && emu->x86.R_EDX == 0xFF)) {
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_OF);
- } else {
- SET_FLAG(F_CF);
- SET_FLAG(F_OF);
- }
- }
- /*
- * REMARKS:
- * Implements the MUL instruction and side effects.
- */
- static void
- mul_byte(struct x86emu *emu, uint8_t s)
- {
- uint16_t res = (uint16_t) (emu->x86.R_AL * s);
- emu->x86.R_AX = res;
- if (emu->x86.R_AH == 0) {
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_OF);
- } else {
- SET_FLAG(F_CF);
- SET_FLAG(F_OF);
- }
- }
- /*
- * REMARKS:
- * Implements the MUL instruction and side effects.
- */
- static void
- mul_word(struct x86emu *emu, uint16_t s)
- {
- uint32_t res = emu->x86.R_AX * s;
- emu->x86.R_AX = (uint16_t) res;
- emu->x86.R_DX = (uint16_t) (res >> 16);
- if (emu->x86.R_DX == 0) {
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_OF);
- } else {
- SET_FLAG(F_CF);
- SET_FLAG(F_OF);
- }
- }
- /*
- * REMARKS:
- * Implements the MUL instruction and side effects.
- */
- static void
- mul_long(struct x86emu *emu, uint32_t s)
- {
- uint64_t res = (uint64_t) emu->x86.R_EAX * s;
- emu->x86.R_EAX = (uint32_t) res;
- emu->x86.R_EDX = (uint32_t) (res >> 32);
- if (emu->x86.R_EDX == 0) {
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_OF);
- } else {
- SET_FLAG(F_CF);
- SET_FLAG(F_OF);
- }
- }
- /*
- * REMARKS:
- * Implements the IDIV instruction and side effects.
- */
- static void
- idiv_byte(struct x86emu *emu, uint8_t s)
- {
- int32_t dvd, div, mod;
- dvd = (int16_t) emu->x86.R_AX;
- if (s == 0) {
- x86emu_intr_raise(emu, 8);
- return;
- }
- div = dvd / (int8_t) s;
- mod = dvd % (int8_t) s;
- if (div > 0x7f || div < -0x7f) {
- x86emu_intr_raise(emu, 8);
- return;
- }
- emu->x86.R_AL = (int8_t) div;
- emu->x86.R_AH = (int8_t) mod;
- }
- /*
- * REMARKS:
- * Implements the IDIV instruction and side effects.
- */
- static void
- idiv_word(struct x86emu *emu, uint16_t s)
- {
- int32_t dvd, div, mod;
- dvd = (((int32_t) emu->x86.R_DX) << 16) | emu->x86.R_AX;
- if (s == 0) {
- x86emu_intr_raise(emu, 8);
- return;
- }
- div = dvd / (int16_t) s;
- mod = dvd % (int16_t) s;
- if (div > 0x7fff || div < -0x7fff) {
- x86emu_intr_raise(emu, 8);
- return;
- }
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_SF);
- CONDITIONAL_SET_FLAG(div == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
- emu->x86.R_AX = (uint16_t) div;
- emu->x86.R_DX = (uint16_t) mod;
- }
- /*
- * REMARKS:
- * Implements the IDIV instruction and side effects.
- */
- static void
- idiv_long(struct x86emu *emu, uint32_t s)
- {
- int64_t dvd, div, mod;
- dvd = (((int64_t) emu->x86.R_EDX) << 32) | emu->x86.R_EAX;
- if (s == 0) {
- x86emu_intr_raise(emu, 8);
- return;
- }
- div = dvd / (int32_t) s;
- mod = dvd % (int32_t) s;
- if (div > 0x7fffffff || div < -0x7fffffff) {
- x86emu_intr_raise(emu, 8);
- return;
- }
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_AF);
- CLEAR_FLAG(F_SF);
- SET_FLAG(F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
- emu->x86.R_EAX = (uint32_t) div;
- emu->x86.R_EDX = (uint32_t) mod;
- }
- /*
- * REMARKS:
- * Implements the DIV instruction and side effects.
- */
- static void
- div_byte(struct x86emu *emu, uint8_t s)
- {
- uint32_t dvd, div, mod;
- dvd = emu->x86.R_AX;
- if (s == 0) {
- x86emu_intr_raise(emu, 8);
- return;
- }
- div = dvd / (uint8_t) s;
- mod = dvd % (uint8_t) s;
- if (div > 0xff) {
- x86emu_intr_raise(emu, 8);
- return;
- }
- emu->x86.R_AL = (uint8_t) div;
- emu->x86.R_AH = (uint8_t) mod;
- }
- /*
- * REMARKS:
- * Implements the DIV instruction and side effects.
- */
- static void
- div_word(struct x86emu *emu, uint16_t s)
- {
- uint32_t dvd, div, mod;
- dvd = (((uint32_t) emu->x86.R_DX) << 16) | emu->x86.R_AX;
- if (s == 0) {
- x86emu_intr_raise(emu, 8);
- return;
- }
- div = dvd / (uint16_t) s;
- mod = dvd % (uint16_t) s;
- if (div > 0xffff) {
- x86emu_intr_raise(emu, 8);
- return;
- }
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_SF);
- CONDITIONAL_SET_FLAG(div == 0, F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
- emu->x86.R_AX = (uint16_t) div;
- emu->x86.R_DX = (uint16_t) mod;
- }
- /*
- * REMARKS:
- * Implements the DIV instruction and side effects.
- */
- static void
- div_long(struct x86emu *emu, uint32_t s)
- {
- uint64_t dvd, div, mod;
- dvd = (((uint64_t) emu->x86.R_EDX) << 32) | emu->x86.R_EAX;
- if (s == 0) {
- x86emu_intr_raise(emu, 8);
- return;
- }
- div = dvd / (uint32_t) s;
- mod = dvd % (uint32_t) s;
- if (div > 0xffffffff) {
- x86emu_intr_raise(emu, 8);
- return;
- }
- CLEAR_FLAG(F_CF);
- CLEAR_FLAG(F_AF);
- CLEAR_FLAG(F_SF);
- SET_FLAG(F_ZF);
- CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
- emu->x86.R_EAX = (uint32_t) div;
- emu->x86.R_EDX = (uint32_t) mod;
- }
- /*
- * REMARKS:
- * Implements the IN string instruction and side effects.
- */
- static void
- ins(struct x86emu *emu, int size)
- {
- int inc = size;
- if (ACCESS_FLAG(F_DF)) {
- inc = -size;
- }
- if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
- /* dont care whether REPE or REPNE */
- /* in until CX is ZERO. */
- uint32_t count = ((emu->x86.mode & SYSMODE_PREFIX_DATA) ?
- emu->x86.R_ECX : emu->x86.R_CX);
- switch (size) {
- case 1:
- while (count--) {
- store_byte(emu, emu->x86.R_ES, emu->x86.R_DI,
- (*emu->emu_inb) (emu, emu->x86.R_DX));
- emu->x86.R_DI += inc;
- }
- break;
- case 2:
- while (count--) {
- store_word(emu, emu->x86.R_ES, emu->x86.R_DI,
- (*emu->emu_inw) (emu, emu->x86.R_DX));
- emu->x86.R_DI += inc;
- }
- break;
- case 4:
- while (count--) {
- store_long(emu, emu->x86.R_ES, emu->x86.R_DI,
- (*emu->emu_inl) (emu, emu->x86.R_DX));
- emu->x86.R_DI += inc;
- break;
- }
- }
- emu->x86.R_CX = 0;
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- emu->x86.R_ECX = 0;
- }
- emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
- } else {
- switch (size) {
- case 1:
- store_byte(emu, emu->x86.R_ES, emu->x86.R_DI,
- (*emu->emu_inb) (emu, emu->x86.R_DX));
- break;
- case 2:
- store_word(emu, emu->x86.R_ES, emu->x86.R_DI,
- (*emu->emu_inw) (emu, emu->x86.R_DX));
- break;
- case 4:
- store_long(emu, emu->x86.R_ES, emu->x86.R_DI,
- (*emu->emu_inl) (emu, emu->x86.R_DX));
- break;
- }
- emu->x86.R_DI += inc;
- }
- }
- /*
- * REMARKS:
- * Implements the OUT string instruction and side effects.
- */
- static void
- outs(struct x86emu *emu, int size)
- {
- int inc = size;
- if (ACCESS_FLAG(F_DF)) {
- inc = -size;
- }
- if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
- /* dont care whether REPE or REPNE */
- /* out until CX is ZERO. */
- uint32_t count = ((emu->x86.mode & SYSMODE_PREFIX_DATA) ?
- emu->x86.R_ECX : emu->x86.R_CX);
- switch (size) {
- case 1:
- while (count--) {
- (*emu->emu_outb) (emu, emu->x86.R_DX,
- fetch_byte(emu, emu->x86.R_ES,
- emu->x86.R_SI));
- emu->x86.R_SI += inc;
- }
- break;
- case 2:
- while (count--) {
- (*emu->emu_outw) (emu, emu->x86.R_DX,
- fetch_word(emu, emu->x86.R_ES,
- emu->x86.R_SI));
- emu->x86.R_SI += inc;
- }
- break;
- case 4:
- while (count--) {
- (*emu->emu_outl) (emu, emu->x86.R_DX,
- fetch_long(emu, emu->x86.R_ES,
- emu->x86.R_SI));
- emu->x86.R_SI += inc;
- break;
- }
- }
- emu->x86.R_CX = 0;
- if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
- emu->x86.R_ECX = 0;
- }
- emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
- } else {
- switch (size) {
- case 1:
- (*emu->emu_outb) (emu, emu->x86.R_DX,
- fetch_byte(emu, emu->x86.R_ES, emu->x86.R_SI));
- break;
- case 2:
- (*emu->emu_outw) (emu, emu->x86.R_DX,
- fetch_word(emu, emu->x86.R_ES, emu->x86.R_SI));
- break;
- case 4:
- (*emu->emu_outl) (emu, emu->x86.R_DX,
- fetch_long(emu, emu->x86.R_ES, emu->x86.R_SI));
- break;
- }
- emu->x86.R_SI += inc;
- }
- }
- /*
- * REMARKS:
- * Pushes a word onto the stack.
- *
- * NOTE: Do not inline this, as (*emu->emu_wrX) is already inline!
- */
- static void
- push_word(struct x86emu *emu, uint16_t w)
- {
- emu->x86.R_SP -= 2;
- store_word(emu, emu->x86.R_SS, emu->x86.R_SP, w);
- }
- /*
- * REMARKS:
- * Pushes a long onto the stack.
- *
- * NOTE: Do not inline this, as (*emu->emu_wrX) is already inline!
- */
- static void
- push_long(struct x86emu *emu, uint32_t w)
- {
- emu->x86.R_SP -= 4;
- store_long(emu, emu->x86.R_SS, emu->x86.R_SP, w);
- }
- /*
- * REMARKS:
- * Pops a word from the stack.
- *
- * NOTE: Do not inline this, as (*emu->emu_rdX) is already inline!
- */
- static uint16_t
- pop_word(struct x86emu *emu)
- {
- uint16_t res;
- res = fetch_word(emu, emu->x86.R_SS, emu->x86.R_SP);
- emu->x86.R_SP += 2;
- return res;
- }
- /*
- * REMARKS:
- * Pops a long from the stack.
- *
- * NOTE: Do not inline this, as (*emu->emu_rdX) is already inline!
- */
- static uint32_t
- pop_long(struct x86emu *emu)
- {
- uint32_t res;
- res = fetch_long(emu, emu->x86.R_SS, emu->x86.R_SP);
- emu->x86.R_SP += 4;
- return res;
- }
|