Something went wrong. Try again.
Reactos
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447/* * Fast486 386/486 CPU Emulation Library * opgroups.c * * Copyright (C) 2015 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
/* INCLUDES *******************************************************************/
#include <windef.h>
// #define NDEBUG#include <debug.h>
#include <fast486.h>#include "opcodes.h"#include "common.h"
/* PRIVATE FUNCTIONS **********************************************************/
staticinlineULONGFast486ArithmeticOperation(PFAST486_STATE State, INT Operation, ULONG FirstValue, ULONG SecondValue, UCHAR Bits){ ULONG Result; ULONG SignFlag = 1 << (Bits - 1); ULONG MaxValue = (SignFlag - 1) | SignFlag;
/* Make sure the values don't exceed the maximum for their size */ FirstValue &= MaxValue; SecondValue &= MaxValue;
/* Check which operation is this */ switch (Operation) { /* ADD */ case 0: { Result = (FirstValue + SecondValue) & MaxValue;
/* Update CF, OF and AF */ State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue); State->Flags.Of = ((FirstValue & SignFlag) == (SecondValue & SignFlag)) && ((FirstValue & SignFlag) != (Result & SignFlag)); State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
break; }
/* OR */ case 1: { Result = FirstValue | SecondValue; State->Flags.Cf = State->Flags.Of = FALSE; break; }
/* ADC */ case 2: { INT Carry = State->Flags.Cf ? 1 : 0;
Result = (FirstValue + SecondValue + Carry) & MaxValue;
/* Update CF, OF and AF */ State->Flags.Cf = ((SecondValue == MaxValue) && (Carry == 1)) || ((Result < FirstValue) && (Result < (SecondValue + Carry))); State->Flags.Of = ((FirstValue & SignFlag) == (SecondValue & SignFlag)) && ((FirstValue & SignFlag) != (Result & SignFlag)); State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
break; }
/* SBB */ case 3: { INT Carry = State->Flags.Cf ? 1 : 0;
Result = (FirstValue - SecondValue - Carry) & MaxValue;
/* Update CF, OF and AF */ State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue); State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag)) && ((FirstValue & SignFlag) != (Result & SignFlag)); State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
break; }
/* AND */ case 4: { Result = FirstValue & SecondValue; State->Flags.Cf = State->Flags.Of = FALSE; break; }
/* SUB or CMP */ case 5: case 7: { Result = (FirstValue - SecondValue) & MaxValue;
/* Update CF, OF and AF */ State->Flags.Cf = (FirstValue < SecondValue); State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag)) && ((FirstValue & SignFlag) != (Result & SignFlag)); State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
break; }
/* XOR */ case 6: { Result = FirstValue ^ SecondValue; State->Flags.Cf = State->Flags.Of = FALSE; break; }
default: { /* Shouldn't happen */ ASSERT(FALSE); } }
/* Update ZF, SF and PF */ State->Flags.Zf = (Result == 0); State->Flags.Sf = ((Result & SignFlag) != 0); State->Flags.Pf = Fast486CalculateParity(LOBYTE(Result));
/* Return the result */ return Result;}
staticinlineULONGFast486RotateOperation(PFAST486_STATE State, INT Operation, ULONG Value, UCHAR Bits, UCHAR Count){ ULONG HighestBit = 1 << (Bits - 1); ULONG MaxValue = HighestBit | (HighestBit - 1); ULONG Result;
/* Normalize the count */ Count &= 0x1F;
if ((Operation == 2) || (Operation == 3)) Count %= Bits + 1;
/* If the count is zero, do nothing */ if (Count == 0) return Value;
/* Check which operation is this */ switch (Operation) { /* ROL */ case 0: { Count %= Bits; Result = (Value << Count) | (Value >> (Bits - Count));
/* Update CF and OF */ State->Flags.Cf = Result & 1; if (Count == 1) State->Flags.Of = State->Flags.Cf ^ ((Result & HighestBit) != 0);
break; }
/* ROR */ case 1: { Count %= Bits; Result = (Value >> Count) | (Value << (Bits - Count));
/* Update CF and OF */ State->Flags.Cf = ((Result & HighestBit) != 0); if (Count == 1) State->Flags.Of = State->Flags.Cf ^ ((Result & (HighestBit >> 1)) != 0);
break; }
/* RCL */ case 2: { Result = (Value << Count) | (State->Flags.Cf << (Count - 1));
/* Complete the calculation, but make sure we don't shift by too much */ if ((Bits - Count) < 31) Result |= Value >> (Bits - Count + 1);
/* Update CF and OF */ State->Flags.Cf = ((Value & (1 << (Bits - Count))) != 0); if (Count == 1) State->Flags.Of = State->Flags.Cf ^ ((Result & HighestBit) != 0);
break; }
/* RCR */ case 3: { /* Update OF */ if (Count == 1) State->Flags.Of = State->Flags.Cf ^ ((Value & HighestBit) != 0);
Result = (Value >> Count) | (State->Flags.Cf << (Bits - Count));
/* Complete the calculation, but make sure we don't shift by too much */ if ((Bits - Count) < 31) Result |= Value << (Bits - Count + 1);
/* Update CF */ State->Flags.Cf = ((Value & (1 << (Count - 1))) != 0);
break; }
/* SHL/SAL */ case 4: case 6: { Result = Value << Count;
/* Update CF and OF */ State->Flags.Cf = ((Value & (1 << (Bits - Count))) != 0); if (Count == 1) State->Flags.Of = State->Flags.Cf ^ ((Result & HighestBit) != 0);
break; }
/* SHR */ case 5: { Result = Value >> Count;
/* Update CF and OF */ State->Flags.Cf = ((Value & (1 << (Count - 1))) != 0); if (Count == 1) State->Flags.Of = ((Value & HighestBit) != 0);
break; }
/* SAR */ case 7: { Result = Value >> Count;
/* Fill the top Count bits with the sign bit */ if (Value & HighestBit) Result |= ((1 << Count) - 1) << (Bits - Count);
/* Update CF and OF */ State->Flags.Cf = ((Value & (1 << (Count - 1))) != 0); if (Count == 1) State->Flags.Of = FALSE;
break; } }
if (Operation >= 4) { /* Update ZF, SF and PF */ State->Flags.Zf = ((Result & MaxValue) == 0); State->Flags.Sf = ((Result & HighestBit) != 0); State->Flags.Pf = Fast486CalculateParity(Result); }
/* Return the result */ return Result;}
/* PUBLIC FUNCTIONS ***********************************************************/
FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8082){ UCHAR Immediate, Value; FAST486_MOD_REG_RM ModRegRm; BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
TOGGLE_ADSIZE(AddressSize);
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
/* Fetch the immediate operand */ if (!Fast486FetchByte(State, &Immediate)) { /* Exception occurred */ return; }
/* Read the operands */ if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
/* Calculate the result */ Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 8);
/* Unless this is CMP, write back the result */ if (ModRegRm.Register != 7) { Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value); }}
FAST486_OPCODE_HANDLER(Fast486OpcodeGroup81){ FAST486_MOD_REG_RM ModRegRm; BOOLEAN OperandSize, AddressSize;
OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
TOGGLE_OPSIZE(OperandSize); TOGGLE_ADSIZE(AddressSize);
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
if (OperandSize) { ULONG Immediate, Value;
/* Fetch the immediate operand */ if (!Fast486FetchDword(State, &Immediate)) { /* Exception occurred */ return; }
/* Read the operands */ if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
/* Calculate the result */ Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 32);
/* Unless this is CMP, write back the result */ if (ModRegRm.Register != 7) { Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value); } } else { USHORT Immediate, Value;
/* Fetch the immediate operand */ if (!Fast486FetchWord(State, &Immediate)) { /* Exception occurred */ return; }
/* Read the operands */ if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
/* Calculate the result */ Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 16);
/* Unless this is CMP, write back the result */ if (ModRegRm.Register != 7) { Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value); } }}
FAST486_OPCODE_HANDLER(Fast486OpcodeGroup83){ CHAR ImmByte; FAST486_MOD_REG_RM ModRegRm; BOOLEAN OperandSize, AddressSize;
OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
TOGGLE_OPSIZE(OperandSize); TOGGLE_ADSIZE(AddressSize);
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
/* Fetch the immediate operand */ if (!Fast486FetchByte(State, (PUCHAR)&ImmByte)) { /* Exception occurred */ return; }
if (OperandSize) { ULONG Immediate = (ULONG)((LONG)ImmByte); // Sign extend ULONG Value;
/* Read the operands */ if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
/* Calculate the result */ Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 32);
/* Unless this is CMP, write back the result */ if (ModRegRm.Register != 7) { Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value); } } else { USHORT Immediate = (USHORT)((SHORT)ImmByte); // Sign extend USHORT Value;
/* Read the operands */ if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
/* Calculate the result */ Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 16);
/* Unless this is CMP, write back the result */ if (ModRegRm.Register != 7) { Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value); } }}
FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8F){ ULONG Value; FAST486_MOD_REG_RM ModRegRm; BOOLEAN OperandSize, AddressSize;
OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
TOGGLE_OPSIZE(OperandSize); TOGGLE_ADSIZE(AddressSize);
/* Pop a value from the stack - this must be done first */ if (!Fast486StackPop(State, &Value)) { /* Exception occurred */ return; }
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
if (ModRegRm.Register != 0) { /* Invalid */ Fast486Exception(State, FAST486_EXCEPTION_UD); return; }
if (OperandSize) Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value); else Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, LOWORD(Value));}
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC0){ UCHAR Value, Count; FAST486_MOD_REG_RM ModRegRm; BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
TOGGLE_ADSIZE(AddressSize);
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
/* Fetch the count */ if (!Fast486FetchByte(State, &Count)) { /* Exception occurred */ return; }
/* Read the operands */ if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
/* Calculate the result */ Value = LOBYTE(Fast486RotateOperation(State, ModRegRm.Register, Value, 8, Count));
/* Write back the result */ Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);}
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC1){ UCHAR Count; FAST486_MOD_REG_RM ModRegRm; BOOLEAN OperandSize, AddressSize;
OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
TOGGLE_OPSIZE(OperandSize); TOGGLE_ADSIZE(AddressSize);
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
/* Fetch the count */ if (!Fast486FetchByte(State, &Count)) { /* Exception occurred */ return; }
if (OperandSize) { ULONG Value;
/* Read the operands */ if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
/* Calculate the result */ Value = Fast486RotateOperation(State, ModRegRm.Register, Value, 32, Count);
/* Write back the result */ Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value); } else { USHORT Value;
/* Read the operands */ if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
/* Calculate the result */ Value = LOWORD(Fast486RotateOperation(State, ModRegRm.Register, Value, 16, Count));
/* Write back the result */ Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value); }}
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC6){ UCHAR Immediate; FAST486_MOD_REG_RM ModRegRm; BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
TOGGLE_ADSIZE(AddressSize);
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
if (ModRegRm.Register != 0) { /* Invalid */ Fast486Exception(State, FAST486_EXCEPTION_UD); return; }
/* Get the immediate operand */ if (!Fast486FetchByte(State, &Immediate)) { /* Exception occurred */ return; }
Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Immediate);}
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC7){ FAST486_MOD_REG_RM ModRegRm; BOOLEAN OperandSize, AddressSize;
OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
TOGGLE_OPSIZE(OperandSize); TOGGLE_ADSIZE(AddressSize);
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
if (ModRegRm.Register != 0) { /* Invalid */ Fast486Exception(State, FAST486_EXCEPTION_UD); return; }
if (OperandSize) { ULONG Immediate;
/* Get the immediate operand */ if (!Fast486FetchDword(State, &Immediate)) { /* Exception occurred */ return; }
Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Immediate); } else { USHORT Immediate;
/* Get the immediate operand */ if (!Fast486FetchWord(State, &Immediate)) { /* Exception occurred */ return; }
Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Immediate); }}
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD0){ UCHAR Value; FAST486_MOD_REG_RM ModRegRm; BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
TOGGLE_ADSIZE(AddressSize);
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
/* Read the operands */ if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
/* Calculate the result */ Value = LOBYTE(Fast486RotateOperation(State, ModRegRm.Register, Value, 8, 1));
/* Write back the result */ Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
}
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD1){ FAST486_MOD_REG_RM ModRegRm; BOOLEAN OperandSize, AddressSize;
OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
TOGGLE_OPSIZE(OperandSize); TOGGLE_ADSIZE(AddressSize);
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
if (OperandSize) { ULONG Value;
/* Read the operands */ if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
/* Calculate the result */ Value = Fast486RotateOperation(State, ModRegRm.Register, Value, 32, 1);
/* Write back the result */ Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value); } else { USHORT Value;
/* Read the operands */ if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
/* Calculate the result */ Value = LOWORD(Fast486RotateOperation(State, ModRegRm.Register, Value, 16, 1));
/* Write back the result */ Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value); }}
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD2){ UCHAR Value; FAST486_MOD_REG_RM ModRegRm; BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
TOGGLE_ADSIZE(AddressSize);
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
/* Read the operands */ if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
/* Calculate the result */ Value = LOBYTE(Fast486RotateOperation(State, ModRegRm.Register, Value, 8, State->GeneralRegs[FAST486_REG_ECX].LowByte));
/* Write back the result */ Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);}
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD3){ FAST486_MOD_REG_RM ModRegRm; BOOLEAN OperandSize, AddressSize;
OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
TOGGLE_OPSIZE(OperandSize); TOGGLE_ADSIZE(AddressSize);
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
if (OperandSize) { ULONG Value;
/* Read the operands */ if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
/* Calculate the result */ Value = Fast486RotateOperation(State, ModRegRm.Register, Value, 32, State->GeneralRegs[FAST486_REG_ECX].LowByte);
/* Write back the result */ Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value); } else { USHORT Value;
/* Read the operands */ if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
/* Calculate the result */ Value = LOWORD(Fast486RotateOperation(State, ModRegRm.Register, Value, 16, State->GeneralRegs[FAST486_REG_ECX].LowByte));
/* Write back the result */ Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value); }}
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF6){ UCHAR Value = 0; FAST486_MOD_REG_RM ModRegRm; BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
TOGGLE_ADSIZE(AddressSize);
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
/* Read the operands */ if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
switch (ModRegRm.Register) { /* TEST */ case 0: case 1: { UCHAR Immediate, Result;
/* Fetch the immediate byte */ if (!Fast486FetchByte(State, &Immediate)) { /* Exception occurred */ return; }
/* Calculate the result */ Result = Value & Immediate;
/* Update the flags */ State->Flags.Cf = FALSE; State->Flags.Of = FALSE; State->Flags.Zf = (Result == 0); State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0); State->Flags.Pf = Fast486CalculateParity(Result);
break; }
/* NOT */ case 2: { /* Write back the result */ Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, ~Value);
break; }
/* NEG */ case 3: { /* Calculate the result */ UCHAR Result = -Value;
/* Update the flags */ State->Flags.Cf = (Value != 0); State->Flags.Of = (Value & SIGN_FLAG_BYTE) && (Result & SIGN_FLAG_BYTE); State->Flags.Af = ((Value & 0x0F) != 0); State->Flags.Zf = (Result == 0); State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0); State->Flags.Pf = Fast486CalculateParity(Result);
/* Write back the result */ Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Result);
break; }
/* MUL */ case 4: { USHORT Result = (USHORT)Value * (USHORT)State->GeneralRegs[FAST486_REG_EAX].LowByte;
/* Update the flags */ State->Flags.Cf = State->Flags.Of = (HIBYTE(Result) != 0);
/* Write back the result */ State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
break; }
/* IMUL */ case 5: { SHORT Result = (SHORT)((CHAR)Value) * (SHORT)((CHAR)State->GeneralRegs[FAST486_REG_EAX].LowByte);
/* Update the flags */ State->Flags.Cf = State->Flags.Of = ((Result < FAST486_CHAR_MIN) || (Result > FAST486_CHAR_MAX));
/* Write back the result */ State->GeneralRegs[FAST486_REG_EAX].LowWord = (USHORT)Result;
break; }
/* DIV */ case 6: { USHORT Quotient; UCHAR Remainder;
if (Value == 0) { /* Divide error */ Fast486Exception(State, FAST486_EXCEPTION_DE); return; }
Quotient = State->GeneralRegs[FAST486_REG_EAX].LowWord / Value; Remainder = State->GeneralRegs[FAST486_REG_EAX].LowWord % Value;
if (Quotient > 0xFF) { /* Divide error */ Fast486Exception(State, FAST486_EXCEPTION_DE); return; }
/* Write back the results */ State->GeneralRegs[FAST486_REG_EAX].LowByte = (UCHAR)Quotient; State->GeneralRegs[FAST486_REG_EAX].HighByte = Remainder;
break; }
/* IDIV */ case 7: { SHORT Quotient; CHAR Remainder;
if (Value == 0) { /* Divide error */ Fast486Exception(State, FAST486_EXCEPTION_DE); return; }
Quotient = (SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord / (CHAR)Value; Remainder = (SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord % (CHAR)Value;
if (Quotient > FAST486_CHAR_MAX || Quotient < FAST486_CHAR_MIN) { /* Divide error */ Fast486Exception(State, FAST486_EXCEPTION_DE); return; }
/* Write back the results */ State->GeneralRegs[FAST486_REG_EAX].LowByte = (UCHAR)((CHAR)Quotient); State->GeneralRegs[FAST486_REG_EAX].HighByte = (UCHAR)Remainder;
break; } }}
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7){ ULONG Value = 0, SignFlag; FAST486_MOD_REG_RM ModRegRm; BOOLEAN OperandSize, AddressSize;
OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
TOGGLE_OPSIZE(OperandSize); TOGGLE_ADSIZE(AddressSize);
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
/* Set the sign flag */ if (OperandSize) SignFlag = SIGN_FLAG_LONG; else SignFlag = SIGN_FLAG_WORD;
/* Read the operand */ if (OperandSize) { /* 32-bit */ if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; } } else { /* 16-bit */ if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, (PUSHORT)&Value)) { /* Exception occurred */ return; } }
switch (ModRegRm.Register) { /* TEST */ case 0: case 1: { ULONG Immediate = 0, Result = 0;
if (OperandSize) { /* Fetch the immediate dword */ if (!Fast486FetchDword(State, &Immediate)) { /* Exception occurred */ return; } } else { /* Fetch the immediate word */ if (!Fast486FetchWord(State, (PUSHORT)&Immediate)) { /* Exception occurred */ return; } }
/* Calculate the result */ Result = Value & Immediate;
/* Update the flags */ State->Flags.Cf = FALSE; State->Flags.Of = FALSE; State->Flags.Zf = (Result == 0); State->Flags.Sf = ((Result & SignFlag) != 0); State->Flags.Pf = Fast486CalculateParity(Result);
break; }
/* NOT */ case 2: { /* Write back the result */ if (OperandSize) { /* 32-bit */ Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, ~Value); } else { /* 16-bit */ Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, LOWORD(~Value)); }
break; }
/* NEG */ case 3: { /* Calculate the result */ ULONG Result = -(LONG)Value; if (!OperandSize) Result &= 0xFFFF;
/* Update the flags */ State->Flags.Cf = (Value != 0); State->Flags.Of = (Value & SignFlag) && (Result & SignFlag); State->Flags.Af = ((Value & 0x0F) != 0); State->Flags.Zf = (Result == 0); State->Flags.Sf = ((Result & SignFlag) != 0); State->Flags.Pf = Fast486CalculateParity(Result);
/* Write back the result */ if (OperandSize) { /* 32-bit */ Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result); } else { /* 16-bit */ Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, LOWORD(Result)); }
break; }
/* MUL */ case 4: { if (OperandSize) { ULONGLONG Result = (ULONGLONG)Value * (ULONGLONG)State->GeneralRegs[FAST486_REG_EAX].Long;
/* Update the flags */ State->Flags.Cf = State->Flags.Of = ((Result & 0xFFFFFFFF00000000ULL) != 0);
/* Write back the result */ State->GeneralRegs[FAST486_REG_EAX].Long = Result & 0xFFFFFFFFULL; State->GeneralRegs[FAST486_REG_EDX].Long = Result >> 32; } else { ULONG Result = (ULONG)Value * (ULONG)State->GeneralRegs[FAST486_REG_EAX].LowWord;
/* Update the flags */ State->Flags.Cf = State->Flags.Of = (HIWORD(Result) != 0);
/* Write back the result */ State->GeneralRegs[FAST486_REG_EAX].LowWord = LOWORD(Result); State->GeneralRegs[FAST486_REG_EDX].LowWord = HIWORD(Result); }
break; }
/* IMUL */ case 5: { if (OperandSize) { LONGLONG Result = (LONGLONG)((LONG)Value) * (LONGLONG)((LONG)State->GeneralRegs[FAST486_REG_EAX].Long);
/* Update the flags */ State->Flags.Cf = State->Flags.Of = ((Result < FAST486_LONG_MIN) || (Result > FAST486_LONG_MAX));
/* Write back the result */ State->GeneralRegs[FAST486_REG_EAX].Long = Result & 0xFFFFFFFFULL; State->GeneralRegs[FAST486_REG_EDX].Long = Result >> 32; } else { LONG Result = (LONG)((SHORT)Value) * (LONG)((SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord);
/* Update the flags */ State->Flags.Cf = State->Flags.Of = ((Result < FAST486_SHORT_MIN) || (Result > FAST486_SHORT_MAX));
/* Write back the result */ State->GeneralRegs[FAST486_REG_EAX].LowWord = LOWORD(Result); State->GeneralRegs[FAST486_REG_EDX].LowWord = HIWORD(Result); }
break; }
/* DIV */ case 6: { if (Value == 0) { /* Divide error */ Fast486Exception(State, FAST486_EXCEPTION_DE); return; }
if (OperandSize) { ULONGLONG Dividend = (ULONGLONG)State->GeneralRegs[FAST486_REG_EAX].Long | ((ULONGLONG)State->GeneralRegs[FAST486_REG_EDX].Long << 32); ULONGLONG Quotient = Dividend / Value; ULONG Remainder = Dividend % Value;
if (Quotient > 0xFFFFFFFFULL) { /* Divide error */ Fast486Exception(State, FAST486_EXCEPTION_DE); return; }
/* Write back the results */ State->GeneralRegs[FAST486_REG_EAX].Long = (ULONG)Quotient; State->GeneralRegs[FAST486_REG_EDX].Long = Remainder; } else { ULONG Dividend = (ULONG)State->GeneralRegs[FAST486_REG_EAX].LowWord | ((ULONG)State->GeneralRegs[FAST486_REG_EDX].LowWord << 16); ULONG Quotient = Dividend / Value; USHORT Remainder = Dividend % Value;
if (Quotient > 0xFFFF) { /* Divide error */ Fast486Exception(State, FAST486_EXCEPTION_DE); return; }
/* Write back the results */ State->GeneralRegs[FAST486_REG_EAX].LowWord = (USHORT)Quotient; State->GeneralRegs[FAST486_REG_EDX].LowWord = Remainder; }
break; }
/* IDIV */ case 7: { if (Value == 0) { /* Divide error */ Fast486Exception(State, FAST486_EXCEPTION_DE); return; }
if (OperandSize) { LONGLONG Dividend = (LONGLONG)State->GeneralRegs[FAST486_REG_EAX].Long | ((LONGLONG)State->GeneralRegs[FAST486_REG_EDX].Long << 32); LONGLONG Quotient = Dividend / (LONG)Value; LONG Remainder = Dividend % (LONG)Value;
if (Quotient > FAST486_LONG_MAX || Quotient < FAST486_LONG_MIN) { /* Divide error */ Fast486Exception(State, FAST486_EXCEPTION_DE); return; }
/* Write back the results */ State->GeneralRegs[FAST486_REG_EAX].Long = (ULONG)((LONG)Quotient); State->GeneralRegs[FAST486_REG_EDX].Long = (ULONG)Remainder; } else { LONG Dividend = (LONG)State->GeneralRegs[FAST486_REG_EAX].LowWord | ((LONG)State->GeneralRegs[FAST486_REG_EDX].LowWord << 16); LONG Quotient = Dividend / (SHORT)LOWORD(Value); SHORT Remainder = Dividend % (SHORT)LOWORD(Value);
if (Quotient > FAST486_SHORT_MAX || Quotient < FAST486_SHORT_MIN) { /* Divide error */ Fast486Exception(State, FAST486_EXCEPTION_DE); return; }
/* Write back the results */ State->GeneralRegs[FAST486_REG_EAX].LowWord = (USHORT)((SHORT)Quotient); State->GeneralRegs[FAST486_REG_EDX].LowWord = (USHORT)Remainder; }
break; } }}
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFE){ UCHAR Value; FAST486_MOD_REG_RM ModRegRm; BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
TOGGLE_ADSIZE(AddressSize);
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
if (ModRegRm.Register > 1) { /* Invalid */ Fast486Exception(State, FAST486_EXCEPTION_UD); return; }
/* Read the operands */ if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
if (ModRegRm.Register == 0) { /* Increment and update OF and AF */ Value++; State->Flags.Of = (Value == SIGN_FLAG_BYTE); State->Flags.Af = ((Value & 0x0F) == 0); } else { /* Decrement and update OF and AF */ State->Flags.Of = (Value == SIGN_FLAG_BYTE); Value--; State->Flags.Af = ((Value & 0x0F) == 0x0F); }
/* Update flags */ State->Flags.Zf = (Value == 0); State->Flags.Sf = ((Value & SIGN_FLAG_BYTE) != 0); State->Flags.Pf = Fast486CalculateParity(Value);
/* Write back the result */ Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);}
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF){ FAST486_MOD_REG_RM ModRegRm; BOOLEAN OperandSize, AddressSize;
OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
TOGGLE_OPSIZE(OperandSize); TOGGLE_ADSIZE(AddressSize);
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
if (ModRegRm.Register == 7) { /* Invalid */ Fast486Exception(State, FAST486_EXCEPTION_UD); return; }
/* Read the operands */ if (OperandSize) { ULONG Value;
if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
if (ModRegRm.Register == 0) { /* Increment and update OF and AF */ Value++; State->Flags.Of = (Value == SIGN_FLAG_LONG); State->Flags.Af = ((Value & 0x0F) == 0); } else if (ModRegRm.Register == 1) { /* Decrement and update OF and AF */ State->Flags.Of = (Value == SIGN_FLAG_LONG); Value--; State->Flags.Af = ((Value & 0x0F) == 0x0F); } else if (ModRegRm.Register == 2) { /* Push the current value of EIP */ if (!Fast486StackPush(State, State->InstPtr.Long)) { /* Exception occurred */ return; }
/* Set the EIP to the address */ State->InstPtr.Long = Value; } else if (ModRegRm.Register == 3) { USHORT Selector; FAST486_SEG_REGS Segment = FAST486_REG_DS;
/* Check for the segment override */ if (State->PrefixFlags & FAST486_PREFIX_SEG) { /* Use the override segment instead */ Segment = State->SegmentOverride; }
/* Read the selector */ if (!Fast486ReadMemory(State, Segment, ModRegRm.MemoryAddress + sizeof(ULONG), FALSE, &Selector, sizeof(USHORT))) { /* Exception occurred */ return; }
if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm) { if (!Fast486ProcessGate(State, Selector, Value, TRUE)) { /* Gate processed or exception occurred */ return; } }
/* Push the current value of CS */ if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector)) { /* Exception occurred */ return; }
/* Push the current value of EIP */ if (!Fast486StackPush(State, State->InstPtr.Long)) { /* Exception occurred */ return; }
/* Load the new code segment */ if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector)) { /* Exception occurred */ return; }
/* Set the EIP to the address */ State->InstPtr.Long = Value; } else if (ModRegRm.Register == 4) { /* Set the EIP to the address */ State->InstPtr.Long = Value; } else if (ModRegRm.Register == 5) { USHORT Selector; FAST486_SEG_REGS Segment = FAST486_REG_DS;
/* Check for the segment override */ if (State->PrefixFlags & FAST486_PREFIX_SEG) { /* Use the override segment instead */ Segment = State->SegmentOverride; }
/* Read the selector */ if (!Fast486ReadMemory(State, Segment, ModRegRm.MemoryAddress + sizeof(ULONG), FALSE, &Selector, sizeof(USHORT))) { /* Exception occurred */ return; }
if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm) { if (!Fast486ProcessGate(State, Selector, Value, FALSE)) { /* Gate processed or exception occurred */ return; } }
/* Load the new code segment */ if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector)) { /* Exception occurred */ return; }
/* Set the EIP to the address */ State->InstPtr.Long = Value; } else if (ModRegRm.Register == 6) { /* Push the value on to the stack */ Fast486StackPush(State, Value); return; }
if (ModRegRm.Register <= 1) { /* Update flags */ State->Flags.Sf = ((Value & SIGN_FLAG_LONG) != 0); State->Flags.Zf = (Value == 0); State->Flags.Pf = Fast486CalculateParity(Value);
/* Write back the result */ Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value); } } else { USHORT Value;
if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
if (ModRegRm.Register == 0) { /* Increment and update OF */ Value++; State->Flags.Of = (Value == SIGN_FLAG_WORD); State->Flags.Af = ((Value & 0x0F) == 0); } else if (ModRegRm.Register == 1) { /* Decrement and update OF */ State->Flags.Of = (Value == SIGN_FLAG_WORD); Value--; State->Flags.Af = ((Value & 0x0F) == 0x0F); } else if (ModRegRm.Register == 2) { /* Push the current value of IP */ if (!Fast486StackPush(State, State->InstPtr.LowWord)) { /* Exception occurred */ return; }
/* Set the IP to the address */ State->InstPtr.LowWord = Value;
/* Clear the top half of EIP */ State->InstPtr.Long &= 0xFFFF; } else if (ModRegRm.Register == 3) { USHORT Selector; FAST486_SEG_REGS Segment = FAST486_REG_DS;
/* Check for the segment override */ if (State->PrefixFlags & FAST486_PREFIX_SEG) { /* Use the override segment instead */ Segment = State->SegmentOverride; }
/* Read the selector */ if (!Fast486ReadMemory(State, Segment, ModRegRm.MemoryAddress + sizeof(USHORT), FALSE, &Selector, sizeof(USHORT))) { /* Exception occurred */ return; }
if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm) { if (!Fast486ProcessGate(State, Selector, Value, TRUE)) { /* Gate processed or exception occurred */ return; } }
/* Push the current value of CS */ if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector)) { /* Exception occurred */ return; }
/* Push the current value of IP */ if (!Fast486StackPush(State, State->InstPtr.LowWord)) { /* Exception occurred */ return; }
/* Load the new code segment */ if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector)) { /* Exception occurred */ return; }
/* Set the IP to the address */ State->InstPtr.LowWord = Value;
/* Clear the top half of EIP */ State->InstPtr.Long &= 0xFFFF; } else if (ModRegRm.Register == 4) { /* Set the IP to the address */ State->InstPtr.LowWord = Value;
/* Clear the top half of EIP */ State->InstPtr.Long &= 0xFFFF; } else if (ModRegRm.Register == 5) { USHORT Selector; FAST486_SEG_REGS Segment = FAST486_REG_DS;
/* Check for the segment override */ if (State->PrefixFlags & FAST486_PREFIX_SEG) { /* Use the override segment instead */ Segment = State->SegmentOverride; }
/* Read the selector */ if (!Fast486ReadMemory(State, Segment, ModRegRm.MemoryAddress + sizeof(USHORT), FALSE, &Selector, sizeof(USHORT))) { /* Exception occurred */ return; }
if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm) { if (!Fast486ProcessGate(State, Selector, Value, FALSE)) { /* Gate processed or exception occurred */ return; } }
/* Load the new code segment */ if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector)) { /* Exception occurred */ return; }
/* Set the IP to the address */ State->InstPtr.LowWord = Value;
/* Clear the top half of EIP */ State->InstPtr.Long &= 0xFFFF; } else if (ModRegRm.Register == 6) { /* Push the value on to the stack */ Fast486StackPush(State, Value); return; } else { /* Invalid */ Fast486Exception(State, FAST486_EXCEPTION_UD); return; }
if (ModRegRm.Register <= 1) { /* Update flags */ State->Flags.Sf = ((Value & SIGN_FLAG_WORD) != 0); State->Flags.Zf = (Value == 0); State->Flags.Pf = Fast486CalculateParity(Value);
/* Write back the result */ Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value); } }}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00){ FAST486_MOD_REG_RM ModRegRm; BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
NO_LOCK_PREFIX(); TOGGLE_ADSIZE(AddressSize);
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
/* Check which operation this is */ switch (ModRegRm.Register) { /* SLDT */ case 0: { /* Not recognized in real mode or virtual 8086 mode */ if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) || State->Flags.Vm) { Fast486Exception(State, FAST486_EXCEPTION_UD); return; }
Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, State->Ldtr.Selector); break; }
/* STR */ case 1: { /* Not recognized in real mode or virtual 8086 mode */ if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) || State->Flags.Vm) { Fast486Exception(State, FAST486_EXCEPTION_UD); return; }
Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, State->TaskReg.Selector); break; }
/* LLDT */ case 2: { BOOLEAN Valid; USHORT Selector; FAST486_SYSTEM_DESCRIPTOR GdtEntry;
/* Not recognized in real mode or virtual 8086 mode */ if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) || State->Flags.Vm) { Fast486Exception(State, FAST486_EXCEPTION_UD); return; }
/* This is a privileged instruction */ if (Fast486GetCurrentPrivLevel(State) != 0) { Fast486Exception(State, FAST486_EXCEPTION_GP); return; }
if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Selector)) { /* Exception occurred */ return; }
if (Selector & SEGMENT_TABLE_INDICATOR) { /* This selector doesn't point to the GDT */ Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); return; }
if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, (PFAST486_GDT_ENTRY)&GdtEntry)) { /* Exception occurred */ return; }
if (!Valid) { /* Invalid selector */ Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); return; }
if (GET_SEGMENT_INDEX(Selector) == 0) { RtlZeroMemory(&State->Ldtr, sizeof(State->Ldtr)); return; }
if (!GdtEntry.Present) { Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector); return; }
if (GdtEntry.Signature != FAST486_LDT_SIGNATURE) { /* This is not a LDT descriptor */ Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); return; }
/* Update the LDTR */ State->Ldtr.Selector = Selector; State->Ldtr.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24); State->Ldtr.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
if (GdtEntry.Granularity) { State->Ldtr.Limit <<= 12; State->Ldtr.Limit |= 0x00000FFF; }
break; }
/* LTR */ case 3: { BOOLEAN Valid; USHORT Selector; FAST486_SYSTEM_DESCRIPTOR GdtEntry;
/* Not recognized in real mode or virtual 8086 mode */ if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) || State->Flags.Vm) { Fast486Exception(State, FAST486_EXCEPTION_UD); return; }
/* This is a privileged instruction */ if (Fast486GetCurrentPrivLevel(State) != 0) { Fast486Exception(State, FAST486_EXCEPTION_GP); return; }
if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Selector)) { /* Exception occurred */ return; }
if (Selector & SEGMENT_TABLE_INDICATOR) { /* This selector doesn't point to the GDT */ Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); return; }
if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, (PFAST486_GDT_ENTRY)&GdtEntry)) { /* Exception occurred */ return; }
if (!Valid) { /* Invalid selector */ Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); return; }
if (GET_SEGMENT_INDEX(Selector) == 0) { Fast486Exception(State, FAST486_EXCEPTION_GP); return; }
if (!GdtEntry.Present) { Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector); return; }
if (GdtEntry.Signature != FAST486_TSS_SIGNATURE && GdtEntry.Signature != FAST486_BUSY_TSS_SIGNATURE && GdtEntry.Signature != FAST486_TSS_16_SIGNATURE && GdtEntry.Signature != FAST486_BUSY_TSS_16_SIGNATURE) { /* This is not a TSS descriptor */ Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); return; }
/* Update the TR */ State->TaskReg.Selector = Selector; State->TaskReg.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24); State->TaskReg.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16); State->TaskReg.Modern = GdtEntry.Signature == FAST486_TSS_SIGNATURE || GdtEntry.Signature == FAST486_BUSY_TSS_SIGNATURE;
if (GdtEntry.Granularity) { State->TaskReg.Limit <<= 12; State->TaskReg.Limit |= 0x00000FFF; }
if (GdtEntry.Signature != FAST486_BUSY_TSS_SIGNATURE && GdtEntry.Signature != FAST486_BUSY_TSS_16_SIGNATURE) { /* Set the busy bit of this TSS descriptor and write it back */ GdtEntry.Signature |= 2;
Fast486WriteLinearMemory(State, State->Gdtr.Address + GET_SEGMENT_INDEX(Selector), &GdtEntry, sizeof(GdtEntry), FALSE /* We already made sure CPL is 0 */); }
break; }
/* VERR/VERW */ case 4: case 5: { USHORT Selector; BOOLEAN Valid; FAST486_GDT_ENTRY GdtEntry;
/* Not recognized in real mode or virtual 8086 mode */ if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) || State->Flags.Vm) { Fast486Exception(State, FAST486_EXCEPTION_UD); return; }
if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Selector)) { /* Exception occurred */ return; }
if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry)) { /* Exception occurred */ return; }
if (!Valid) { /* Clear ZF */ State->Flags.Zf = FALSE; return; }
/* Set ZF if it is valid and accessible */ State->Flags.Zf = GdtEntry.Present // must be present && GdtEntry.SystemType // must be a segment && (((ModRegRm.Register == 4) /* code segments are only readable if the RW bit is set */ && (!GdtEntry.Executable || GdtEntry.ReadWrite)) || ((ModRegRm.Register == 5) /* code segments are never writable, data segments are writable when RW is set */ && (!GdtEntry.Executable && GdtEntry.ReadWrite))) /* * for segments other than conforming code segments, * both RPL and CPL must be less than or equal to DPL */ && (((!GdtEntry.Executable || !GdtEntry.DirConf) && (GET_SEGMENT_RPL(Selector) <= GdtEntry.Dpl) && (Fast486GetCurrentPrivLevel(State) <= GdtEntry.Dpl)) /* for conforming code segments, DPL must be less than or equal to CPL */ || ((GdtEntry.Executable && GdtEntry.DirConf) && (GdtEntry.Dpl <= Fast486GetCurrentPrivLevel(State))));
break; }
/* Invalid */ default: { Fast486Exception(State, FAST486_EXCEPTION_UD); } }}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F01){ // FAST486_TABLE_REG TableReg; UCHAR TableReg[6]; FAST486_MOD_REG_RM ModRegRm; BOOLEAN OperandSize, AddressSize; FAST486_SEG_REGS Segment = FAST486_REG_DS;
OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
NO_LOCK_PREFIX(); TOGGLE_OPSIZE(OperandSize); TOGGLE_ADSIZE(AddressSize);
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
/* Check for the segment override */ if (State->PrefixFlags & FAST486_PREFIX_SEG) { /* Use the override segment instead */ Segment = State->SegmentOverride; }
/* Check which operation this is */ switch (ModRegRm.Register) { /* SGDT */ case 0: { if (!ModRegRm.Memory) { /* The second operand must be a memory location */ Fast486Exception(State, FAST486_EXCEPTION_UD); return; }
/* Fill the 6-byte table register */ // TableReg = State->Gdtr; *((PUSHORT)&TableReg) = State->Gdtr.Size; *((PULONG)&TableReg[sizeof(USHORT)]) = State->Gdtr.Address;
/* Store the GDTR */ Fast486WriteMemory(State, Segment, ModRegRm.MemoryAddress, TableReg, sizeof(TableReg));
break; }
/* SIDT */ case 1: { if (!ModRegRm.Memory) { /* The second operand must be a memory location */ Fast486Exception(State, FAST486_EXCEPTION_UD); return; }
/* Fill the 6-byte table register */ // TableReg = State->Idtr; *((PUSHORT)&TableReg) = State->Idtr.Size; *((PULONG)&TableReg[sizeof(USHORT)]) = State->Idtr.Address;
/* Store the IDTR */ Fast486WriteMemory(State, Segment, ModRegRm.MemoryAddress, TableReg, sizeof(TableReg));
break; }
/* LGDT */ case 2: { /* This is a privileged instruction */ if (Fast486GetCurrentPrivLevel(State) != 0) { Fast486Exception(State, FAST486_EXCEPTION_GP); return; }
if (!ModRegRm.Memory) { /* The second operand must be a memory location */ Fast486Exception(State, FAST486_EXCEPTION_UD); return; }
/* Read the new GDTR */ if (!Fast486ReadMemory(State, Segment, ModRegRm.MemoryAddress, FALSE, TableReg, sizeof(TableReg))) { /* Exception occurred */ return; }
/* Load the new GDT */ // State->Gdtr = TableReg; State->Gdtr.Size = *((PUSHORT)&TableReg); State->Gdtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
/* In 16-bit mode the highest byte is masked out */ if (!OperandSize) State->Gdtr.Address &= 0x00FFFFFF;
break; }
/* LIDT */ case 3: { /* This is a privileged instruction */ if (Fast486GetCurrentPrivLevel(State) != 0) { Fast486Exception(State, FAST486_EXCEPTION_GP); return; }
if (!ModRegRm.Memory) { /* The second operand must be a memory location */ Fast486Exception(State, FAST486_EXCEPTION_UD); return; }
/* Read the new IDTR */ if (!Fast486ReadMemory(State, Segment, ModRegRm.MemoryAddress, FALSE, TableReg, sizeof(TableReg))) { /* Exception occurred */ return; }
/* Load the new IDT */ // State->Idtr = TableReg; State->Idtr.Size = *((PUSHORT)&TableReg); State->Idtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
/* In 16-bit mode the highest byte is masked out */ if (!OperandSize) State->Idtr.Address &= 0x00FFFFFF;
break; }
/* SMSW */ case 4: { /* Store the lower 16 bits (Machine Status Word) of CR0 */ Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, LOWORD(State->ControlRegisters[FAST486_REG_CR0]));
break; }
/* LMSW */ case 6: { USHORT MachineStatusWord;
if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) { /* This is a privileged instruction */ if (Fast486GetCurrentPrivLevel(State) != 0) { Fast486Exception(State, FAST486_EXCEPTION_GP); return; } }
/* Read the new Machine Status Word */ if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &MachineStatusWord)) { /* Exception occurred */ return; }
/* Set the lowest 4 bits, but never clear bit 0 */ State->ControlRegisters[FAST486_REG_CR0] &= 0xFFFFFFF1; State->ControlRegisters[FAST486_REG_CR0] |= MachineStatusWord & 0x0F;
break; }
/* INVLPG */ case 7: {#ifndef FAST486_NO_PREFETCH /* Invalidate the prefetch */ State->PrefetchValid = FALSE;#endif
/* This is a privileged instruction */ if (Fast486GetCurrentPrivLevel(State) != 0) { Fast486Exception(State, FAST486_EXCEPTION_GP); return; }
if (!ModRegRm.Memory) { /* The second operand must be a memory location */ Fast486Exception(State, FAST486_EXCEPTION_UD); return; }
if (State->Tlb != NULL) { /* Clear the TLB entry */ State->Tlb[ModRegRm.MemoryAddress >> 12] = INVALID_TLB_FIELD; }
break; }
/* Invalid */ default: { Fast486Exception(State, FAST486_EXCEPTION_UD); } }}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0FB9){ FAST486_MOD_REG_RM ModRegRm; BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
TOGGLE_ADSIZE(AddressSize);
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
/* All of them are reserved (UD2) */ Fast486Exception(State, FAST486_EXCEPTION_UD); return;}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0FBA){ FAST486_MOD_REG_RM ModRegRm; BOOLEAN OperandSize, AddressSize; UINT DataSize; UCHAR BitNumber;
OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
TOGGLE_OPSIZE(OperandSize); TOGGLE_ADSIZE(AddressSize);
/* Get the number of bits */ if (OperandSize) DataSize = 32; else DataSize = 16;
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
if (ModRegRm.Register < 4) { /* Invalid */ Fast486Exception(State, FAST486_EXCEPTION_UD); return; }
/* Get the bit number */ if (!Fast486FetchByte(State, &BitNumber)) { /* Exception occurred */ return; }
if (ModRegRm.Memory) { /* * For memory operands, add the bit offset divided by * the data size to the address */ ModRegRm.MemoryAddress += BitNumber / DataSize; }
/* Normalize the bit number */ BitNumber %= DataSize;
if (OperandSize) { ULONG Value;
/* Read the value */ if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
/* Set CF to the bit value */ State->Flags.Cf = (Value >> BitNumber) & 1;
if (ModRegRm.Register == 5) { /* BTS */ Value |= 1 << BitNumber; } else if (ModRegRm.Register == 6) { /* BTR */ Value &= ~(1 << BitNumber); } else if (ModRegRm.Register == 7) { /* BTC */ Value ^= 1 << BitNumber; }
if (ModRegRm.Register >= 5) { /* Write back the result */ if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value)) { /* Exception occurred */ return; } } } else { USHORT Value;
/* Read the value */ if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
/* Set CF to the bit value */ State->Flags.Cf = (Value >> BitNumber) & 1;
if (ModRegRm.Register == 5) { /* BTS */ Value |= 1 << BitNumber; } else if (ModRegRm.Register == 6) { /* BTR */ Value &= ~(1 << BitNumber); } else if (ModRegRm.Register == 7) { /* BTC */ Value ^= 1 << BitNumber; }
if (ModRegRm.Register >= 5) { /* Write back the result */ if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value)) { /* Exception occurred */ return; } } }}
/* EOF */