See what's going on with flipcode!




This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

 

  Pure Run-Time Assembler
  Submitted by



When you strive for the maximum performance of the software running on your CPU, you often need to use assembly. At some occasions, however, even that can be too slow... Since I am a true software 3D rendering freak, every clock cycle counts. This is not a big problem when using optimized assembly, but it does pose another problem. Graphics cards can do hundreds of combinations of filtering, shading, sampling, blending and lots more. The newest generation of cards can even do per-pixel operation with a small shader program. To have the same possibilities in a software engine, I could use a few jump instructions, but this drastically decreases performance when they're used in the inner loops. A mispredicted jump on a Pentium 4 takes dozens of clock cycles. I could also write every possible scanline function as a separate, optimized function. But that takes ages and when you change one thing they all have to change. I recently started using SSE and now I need to write every function again just to change a few instructions. There are really thousands of possibilities that would all need a new function. So generally, speed and versatility don't go together. The solution is conditional compilation at run-time. For every situation, you can generate the exact code you need. So this is why I wrote this run-time assembler. It perfectly suits my needs. Now I can collect all information about the render state and 'compose' a function from a few snippets of assembly code. It won't be as fast as optimizing every function separately, but it opens many doors to an impressive software engine with a rich set of features. Things like loop unrolling would be trivial. Pixel and vertex shaders are also easy now, and the powerful x86 instruction set allows an even greater freedom than any hardware accelerated shader. That's why I called the project "SoftWire", because it's almost like rewiring your CPU. Of course, this is not only usable for software rendering freaks, but for any application where you need lots of flexibility and performance in a tight inner loop. One example is video compression. You often have lots of parameters for tweaking the quality, so it has to happen in separate passes. Since they all need to read the data from system RAM, memory throughput could be a serious bottleneck, and per-pixel jumps are a bottleneck for the CPU. With a run-time assembler, the right algorithms can be put into one function, and the video processing can be done in less passes. This has reduced the memory throughput, improves cache coherency and there can be less jumps in the inner loops. Things like software vertex shaders could be handy so the game developer or maybe even the artists can simply plug-in new shaders every minute without starting Visual Studio. Of course it could be used to make a real assembler or even a compiler with it. Before you start messing with my code, please read the 'Readme.txt' file. There are very little comments in the code itself, so I wrote some external documentation. It briefly explains the syntax, the design, the things you could do with it and... the license. The code is released under the LGPL, but the most important thing is that you just give me credit if you use my work. I called this a "pure" assembler because it does nothing more than assembling instructions. You'll have to implement the directives for conditional compilation yourself. If you're serious about using this for run-time conditional compilation, it won't be that hard, and I think I have left all options open to choose your own favorite method for your specific project. For the video processing example, you could create 'Filter' classes which can combine into one function, but this method is not usable for a rasterizer. So it all depends on your application and I left this open for you. The code also has four little assembly test programs to show you the syntax. Actually they are just functions, but they could be test programs on their own. The first one, 'SetBits.asm', was originally written in C++ (see Test.cpp), and I used the listing files to compile it with my assembler. It was the first function I compiled which had jump labels too. It sets a number of bits in a buffer starting from a certain bit. The second one, 'CrossProduct.asm', demonstrates FPU instructions for use with vectors. The third file, 'AlphaBlend.asm', shows the use of MMX instructions to blend two 32-bit colors. The assembler also supports SSE, but I didn't write a demo for that. The last file, 'HelloWorld.asm', shows that it is possible to call external functions like printf by passing their function pointer as an argument. Regards,


Nicolas "Nick" Capens


Currently browsing [SoftWire.zip] (112,805 bytes) - [Assembler.cpp] - (1,754 bytes)

#include "Assembler.hpp"
#include "Instruction.hpp"

#include "InstructionSet.hpp" #include "Token.hpp" #include "Error.hpp"

#include <stdio.h> #include <string.h> #include <io.h>

namespace SoftWire { Assembler::Assembler(const char *sourceFile) { assembleFile(sourceFile); }

Assembler::~Assembler() { }

void Assembler::assembleFile(const char *sourceFile) { FILE *file = fopen(sourceFile, "rb");

if(!file) { printf("Could not open source file: '%s'\n", sourceFile); return; } else { printf("Assembling '%s'...\n\n", sourceFile); }

int length = _filelength(_fileno(file));

char *buffer = new char[length + 1]; fread(buffer, sizeof(char), length, file); fclose(file); buffer[length] = 0;

char *sourceLine = buffer;

lineNumber = 1; error = false;

while(*sourceLine) { assembleLine(sourceLine);

while(*sourceLine != '\0' && *sourceLine != '\n' && *sourceLine != '\r') sourceLine++; while(*sourceLine == '\n' || *sourceLine == '\r') sourceLine++; }

delete[] buffer; }

const void *Assembler::callable() { if(error) { return 0; } else { return loader.callable(); } }

void Assembler::assembleLine(const char *sourceLine) { try { const Encoding &encoding = parser.parseLine(sourceLine);

loader.addEncoding(encoding); } catch(Error &errorMessage) { error = true;

errorMessage.print(); printLine(sourceLine); } catch(...) { printf("error: Unhandled exception\n"); } }

void Assembler::printLine(const char *string) { while(*string != '\0' && *string != '\n') { putchar(*string++); } putchar('\n'); } };

Currently browsing [SoftWire.zip] (112,805 bytes) - [Encoding.cpp] - (5,180 bytes)

#include "Encoding.hpp"

#include "Error.hpp"

#include <stdio.h> #include <string.h>

namespace SoftWire { Encoding::Encoding() { reset();

O1 = 0xCC; // Breakpoint format.O1 = true; }

Encoding::~Encoding() { delete[] label; delete[] reference; }

void Encoding::reset() { label = 0; reference = 0;

format.P1 = false; format.P2 = false; format.P3 = false; format.P4 = false; format.O2 = false; format.O1 = false; format.modRM = false; format.SIB = false; format.D1 = false; format.D2 = false; format.D3 = false; format.D4 = false; format.I1 = false; format.I2 = false; format.I3 = false; format.I4 = false;

P1 = 0; P2 = 0; P3 = 0; P4 = 0; O2 = 0; O1 = 0; modRM.b = 0; SIB.b = 0; D1 = 0; D2 = 0; D3 = 0; D4 = 0; I1 = 0; I2 = 0; I3 = 0; I4 = 0;

immediate = 0; displacement = 0; }

const char *Encoding::getLabel() const { return label; }

const char *Encoding::getReference() const { return reference; }

int Encoding::length() const { int length = 0;

if(format.P1) length++; if(format.P2) length++; if(format.P3) length++; if(format.P4) length++; if(format.O2) length++; if(format.O1) length++; if(format.modRM) length++; if(format.SIB) length++; if(format.D1) length++; if(format.D2) length++; if(format.D3) length++; if(format.D4) length++; if(format.I1) length++; if(format.I2) length++; if(format.I3) length++; if(format.I4) length++;

return length; }

void Encoding::addPrefix(byte p) { if(!format.P1) { P1 = p; format.P1 = true;; } else if(!format.P2) { P2 = p; format.P2 = true; } else if(!format.P3) { P3 = p; format.P3 = true; } else if(!format.P4) { P4 = p; format.P4 = true; } else { throw Error("Too many prefixes in opcode"); } }

void Encoding::setImmediate(int immediate) { this->immediate = immediate; }

void Encoding::setJumpOffset(int offset) { if((char)offset != offset && format.I2) { throw Error("Jump offset range too big"); }

this->immediate = offset; }

void Encoding::setLabel(const char *label) { this->label = strdup(label); }

void Encoding::setReference(const char *label) { reference = strdup(label); }

void Encoding::checkFormat() const { // Bytes cannot be changed without updating format, except immediate and displacement if((P1 && !format.P1) || (P2 && !format.P2) || (P3 && !format.P3) || (P4 && !format.P4) || (O2 && !format.O2) || (O1 && !format.O1) || (modRM.b && !format.modRM) || (SIB.b && !format.SIB)) { throw Error::INTERNAL; }

if((format.P4 && !format.P3) || (format.P3 && !format.P2) || (format.P2 && !format.P1)) { throw Error::INTERNAL; }

if(format.O2 && (O2 != 0x0F && O2 != 0xD8 && O2 != 0xD9 && O2 != 0xDA && O2 != 0xDB && O2 != 0xDC && O2 != 0xDD && O2 != 0xDE && O2 != 0xDF)) { throw Error::INTERNAL; }

if(format.SIB) { if(!format.modRM) { throw Error::INTERNAL; }

if(modRM.r_m != ESP) { throw Error::INTERNAL; } }

// Byte, word or doubleword if((format.D4 && !format.D3) || (format.D3 && !format.D4) || (format.D3 && !format.D2) || (format.D2 && !format.D1)) { throw Error::INTERNAL; }

// Byte, word or doubleword if((format.I4 && !format.I3) || (format.I3 && !format.I4) || (format.I3 && !format.I2) || (format.I2 && !format.I1)) { throw Error::INTERNAL; } }

int Encoding::writeCode(byte *output) const { #ifndef NDEBUG checkFormat();

if(format.P1) printf("%.2X ", P1); if(format.P2) printf("%.2X ", P2); if(format.P3) printf("%.2X ", P3); if(format.P4) printf("%.2X ", P4); if(format.O2) printf("%.2X ", O2); if(format.O1) printf("%.2X ", O1); if(format.modRM) printf("%.2X ", modRM.b); if(format.SIB) printf("%.2X ", SIB.b); if(format.D1) printf("%.2X ", D1); if(format.D2) printf("%.2X ", D2); if(format.D3) printf("%.2X ", D3); if(format.D4) printf("%.2X ", D4); if(format.I1) printf("%.2X ", I1); if(format.I2) printf("%.2X ", I2); if(format.I3) printf("%.2X ", I3); if(format.I4) printf("%.2X ", I4);

printf("\n"); #endif

byte *start = output;

if(format.P1) *output++ = P1; if(format.P2) *output++ = P2; if(format.P3) *output++ = P3; if(format.P4) *output++ = P4; if(format.O2) *output++ = O2; if(format.O1) *output++ = O1; if(format.modRM) *output++ = modRM.b; if(format.SIB) *output++ = SIB.b; if(format.D1) *output++ = D1; if(format.D2) *output++ = D2; if(format.D3) *output++ = D3; if(format.D4) *output++ = D4; if(format.I1) *output++ = I1; if(format.I2) *output++ = I2; if(format.I3) *output++ = I3; if(format.I4) *output++ = I4;

return output - start; } }

Currently browsing [SoftWire.zip] (112,805 bytes) - [Error.cpp] - (490 bytes)

#include "Error.hpp"

#include <stdio.h> #include <stdarg.h>

namespace SoftWire { const Error Error::INTERNAL("Internal error");

Error::Error(const char *format, ...) { buffer[0] = 0;

va_list argList;

va_start(argList, format); _vsnprintf(buffer, stringMax, format, argList); va_end(argList); }

void Error::print() const { if(buffer[0] == 0) { printf("error: <Unknown>\n"); } else { printf("error: %s\n", buffer); } } }

Currently browsing [SoftWire.zip] (112,805 bytes) - [Instruction.cpp] - (6,131 bytes)

#include "Instruction.hpp"

#include "InstructionSet.hpp" #include "Keywords.hpp" #include "Error.hpp"

#include <string.h> #include <stdio.h> #include <stdlib.h> #include <assert.h> #include <ctype.h>

namespace SoftWire { Instruction::Instruction(const Syntax &instruction) : syntax(instruction) { extractOperands(instruction.operands);

syntaxMnemonic = false; syntaxSpecifier = false; syntaxFirstOperand = false; syntaxSecondOperand = false; syntaxThirdOperand = false;

flags = instruction.flags; next = 0; }

Instruction::~Instruction() { delete next; }

void Instruction::extractOperands(const char *syntax) { assert(syntax);

specifier = Specifier::UNKNOWN; firstOperand = Operand::VOID; secondOperand = Operand::VOID; thirdOperand = Operand::VOID;

char *string = strdup(syntax); const char *token = strtok(string, " ,");

if(!token) { return; }

specifier = Specifier::scan(token);

if(specifier != Specifier::UNKNOWN) { token = strtok(0, " ,");

if(!token) { delete[] string; return; } }

firstOperand = Operand::scanSyntax(token);

if(firstOperand != Operand::UNKNOWN) { token = strtok(0, " ,");

if(token == 0) { delete[] string; return; } }

secondOperand = Operand::scanSyntax(token);

if(secondOperand != Operand::UNKNOWN) { token = strtok(0, " ,");

if(token == 0) { delete[] string; return; } }

thirdOperand = Operand::scanSyntax(token);

if(thirdOperand != Operand::UNKNOWN) { token = strtok(0, " ,");

if(token == 0) { delete[] string; return; } }

if(token == 0) { delete[] string; return; } else { throw Error("Invalid operand encoding '%s %s'", syntax); } }

void Instruction::attachNew(const Syntax &instruction) { if(!next) { next = new Instruction(instruction); } else { next->attachNew(instruction); } }

Instruction *Instruction::getNext() const { return next; }

bool Instruction::matchSyntax() const { return syntaxMnemonic == true && syntaxSpecifier == true && syntaxFirstOperand == true && syntaxSecondOperand == true && syntaxThirdOperand == true; }

void Instruction::resetMatch() { syntaxMnemonic = false; syntaxSpecifier = false; syntaxFirstOperand = false; syntaxSecondOperand = false; syntaxThirdOperand = false;

if(next) { next->resetMatch(); } }

void Instruction::matchMnemonic(const char *mnemonic) { if(stricmp(syntax.mnemonic, mnemonic) == 0) { syntaxMnemonic = true; }

if(next) { next->matchMnemonic(mnemonic); } }

void Instruction::matchSpecifier(Specifier::Type specifier) { if(this->specifier == Specifier::UNKNOWN) { if(specifier != Specifier::UNKNOWN) { if(firstOperand == Operand::R_M8 || secondOperand == Operand::R_M8) { syntaxSpecifier = specifier == Specifier::BYTE; } else if(firstOperand == Operand::R_M16 || secondOperand == Operand::R_M16) { syntaxSpecifier = specifier == Specifier::WORD; } else if(firstOperand == Operand::R_M32 || secondOperand == Operand::R_M32) { syntaxSpecifier = specifier == Specifier::DWORD; } else if(firstOperand == Operand::R_M64 || secondOperand == Operand::R_M64) { syntaxSpecifier = (specifier == Specifier::QWORD || specifier == Specifier::MMWORD); } else if(firstOperand == Operand::R_M128 || secondOperand == Operand::R_M128) { syntaxSpecifier = specifier == Specifier::XMMWORD; } else { syntaxSpecifier = true; } } else { syntaxSpecifier = true; } } else if(this->specifier != Specifier::UNKNOWN) // Explicit specifier { if(this->specifier == specifier) { syntaxSpecifier = true; } else if(specifier == Specifier::UNKNOWN) // Specifiers are optional { syntaxSpecifier = true; } else { syntaxSpecifier = false; } }

if(next) { next->matchSpecifier(specifier); } }

void Instruction::matchFirstOperand(const Operand &operand) { if(operand.isSubtypeOf(firstOperand)) { syntaxFirstOperand = true; } else if(operand.type == Operand::MEM && firstOperand & Operand::MEM) { if(syntaxSpecifier) // Explicit size specfier { syntaxFirstOperand = true; } else if(secondOperand != Operand::UNKNOWN) // Implicit size specifier { syntaxFirstOperand = true; } }

if(next) { next->matchFirstOperand(operand); } }

void Instruction::matchSecondOperand(const Operand &operand) { if(operand.isSubtypeOf(secondOperand)) { syntaxSecondOperand = true; } else if(operand.type == Operand::MEM && secondOperand & Operand::MEM) { if(syntaxSpecifier) // Explicit size specfier { syntaxSecondOperand = true; } else if(firstOperand != Operand::UNKNOWN) // Implicit size specifier { syntaxSecondOperand = true; } }

if(next) { next->matchSecondOperand(operand); } }

void Instruction::matchThirdOperand(const Operand &operand) { if(operand.isSubtypeOf(thirdOperand)) { syntaxThirdOperand = true; }

if(next) { next->matchThirdOperand(operand); } }

const char *Instruction::getMnemonic() const { return syntax.mnemonic; }

Operand::Type Instruction::getFirstOperand() const { return firstOperand; }

Operand::Type Instruction::getSecondOperand() const { return secondOperand; }

Operand::Type Instruction::getThirdOperand() const { return thirdOperand; }

const char *Instruction::getOperandSyntax() const { return syntax.operands; }

const char *Instruction::getEncoding() const { return syntax.encoding; }

bool Instruction::is32Bit() const { return (flags & CPU_386) == CPU_386; } }

Currently browsing [SoftWire.zip] (112,805 bytes) - [InstructionSet.cpp] - (81,530 bytes)

#include "InstructionSet.hpp"

#include "Error.hpp"

#include <assert.h> #include <string.h> #include <stdlib.h> #include <search.h> #include <stdio.h>

namespace SoftWire { InstructionSet::InstructionSet() { qsort(instructionSet, numInstructions(), sizeof(Instruction::Syntax), compareSyntax);

instructionMap = new Entry[numMnemonics()];

int j = 0; int i = 0;

while(i < numInstructions()) { instructionMap[j].mnemonic = instructionSet[i].mnemonic; instructionMap[j].instruction = new Instruction(instructionSet[i++]);

while(i < numInstructions() && stricmp(instructionSet[i - 1].mnemonic, instructionSet[i].mnemonic) == 0) { instructionMap[j].instruction->attachNew(instructionSet[i++]); }

j++; }

assert(j == numMnemonics()); }

InstructionSet::~InstructionSet() { delete[] instructionMap; }

Instruction *InstructionSet::query(const char *mnemonic) const { assert(instructionMap); if(!mnemonic) { throw Error::INTERNAL; }

Entry *query = (Entry*)bsearch(mnemonic, instructionMap, numMnemonics(), sizeof(Entry), compareEntry);

if(!query) { throw Error("Unrecognised mnemonic '%s'", mnemonic); }

query->instruction->resetMatch();

return query->instruction; }

int InstructionSet::compareSyntax(const void *element1, const void *element2) { return stricmp(((Instruction::Syntax*)element1)->mnemonic, ((Instruction::Syntax*)element2)->mnemonic); }

int InstructionSet::compareEntry(const void *mnemonic, const void *entry) { return stricmp((char*)mnemonic, ((Entry*)entry)->mnemonic); }

Instruction::Syntax InstructionSet::instructionSet[] = { /* Encoding syntax: ---------------- +r Add register value to opcode /# Value for Mod R/M register field encoding /r Effective address encoding ib Byte immediate iw Word immediate id Dword immediate -b Byte relative address -i Word or dword relative address p0 LOCK instruction prefix (F0h) p2 REPNE/REPNZ instruction prefix (F2h) p3 REP/REPE/REPZ instruction prefix (F3h) (also SSE prefix) po Offset override prefix (66h) pa Address override prefix (67h) */

{"AAA", "", "37", Instruction::CPU_8086}, {"AAS", "", "3F", Instruction::CPU_8086}, {"AAD", "", "D5 0A", Instruction::CPU_8086}, {"AAD", "imm", "D5 ib", Instruction::CPU_8086}, {"AAM", "", "D4 0A", Instruction::CPU_8086}, {"AAM", "imm", "D4 ib", Instruction::CPU_8086}, {"ADC", "r/m8,reg8", "10 /r", Instruction::CPU_8086}, {"ADC", "r/m16,reg16", "po 11 /r", Instruction::CPU_8086}, {"ADC", "r/m32,reg32", "po 11 /r", Instruction::CPU_386}, {"ADC", "reg8,r/m8", "12 /r", Instruction::CPU_8086}, {"ADC", "reg16,r/m16", "po 13 /r", Instruction::CPU_8086}, {"ADC", "reg32,r/m32", "po 13 /r", Instruction::CPU_386}, {"ADC", "r/m8,imm8", "80 /2 ib", Instruction::CPU_8086}, {"ADC", "r/m16,imm16", "po 81 /2 iw", Instruction::CPU_8086}, {"ADC", "r/m32,imm32", "po 81 /2 id", Instruction::CPU_386}, {"ADC", "r/m16,imm8", "po 83 /2 ib", Instruction::CPU_8086}, {"ADC", "r/m32,imm8", "po 83 /2 ib", Instruction::CPU_386}, {"ADC", "AL,imm8", "14 ib", Instruction::CPU_8086}, {"ADC", "AX,imm16", "po 15 iw", Instruction::CPU_8086}, {"ADC", "EAX,imm32", "po 15 id", Instruction::CPU_386}, {"ADD", "r/m8,reg8", "00 /r", Instruction::CPU_8086}, {"ADD", "r/m16,reg16", "po 01 /r", Instruction::CPU_8086}, {"ADD", "r/m32,reg32", "po 01 /r", Instruction::CPU_386}, {"ADD", "reg8,r/m8", "02 /r", Instruction::CPU_8086}, {"ADD", "reg16,r/m16", "po 03 /r", Instruction::CPU_8086}, {"ADD", "reg32,r/m32", "po 03 /r", Instruction::CPU_386}, {"ADD", "r/m8,imm8", "80 /0 ib", Instruction::CPU_8086}, {"ADD", "r/m16,imm16", "po 81 /0 iw", Instruction::CPU_8086}, {"ADD", "r/m32,imm32", "po 81 /0 id", Instruction::CPU_386}, {"ADD", "r/m16,imm8", "po 83 /0 ib", Instruction::CPU_8086}, {"ADD", "r/m32,imm8", "po 83 /0 ib", Instruction::CPU_386}, {"ADD", "AL,imm8", "04 ib", Instruction::CPU_8086}, {"ADD", "AX,imm16", "po 05 iw", Instruction::CPU_8086}, {"ADD", "EAX,imm32", "po 05 id", Instruction::CPU_386}, {"ADDPS", "xmmreg,r/m128", "0F 58 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"ADDSS", "xmmreg,xmmreg/mem32", "p3 0F 58 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"AND", "r/m8,reg8", "20 /r", Instruction::CPU_8086}, {"AND", "r/m16,reg16", "po 21 /r", Instruction::CPU_8086}, {"AND", "r/m32,reg32", "po 21 /r", Instruction::CPU_386}, {"AND", "reg8,r/m8", "22 /r", Instruction::CPU_8086}, {"AND", "reg16,r/m16", "po 23 /r", Instruction::CPU_8086}, {"AND", "reg32,r/m32", "po 23 /r", Instruction::CPU_386}, {"AND", "r/m8,imm8", "80 /4 ib", Instruction::CPU_8086}, {"AND", "r/m16,imm16", "po 81 /4 iw", Instruction::CPU_8086}, {"AND", "r/m32,imm32", "po 81 /4 id", Instruction::CPU_386}, {"AND", "r/m16,imm8", "po 83 /4 ib", Instruction::CPU_8086}, {"AND", "r/m32,imm8", "po 83 /4 ib", Instruction::CPU_386}, {"AND", "AL,imm8", "24 ib", Instruction::CPU_8086}, {"AND", "AX,imm16", "po 25 iw", Instruction::CPU_8086}, {"AND", "EAX,imm32", "po 25 id", Instruction::CPU_386}, {"ANDNPS", "xmmreg,r/m128", "0F 55 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"ANDPS", "xmmreg,r/m128", "0F 54 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, // {"ARPL", "r/m16,reg16", "63 /r", Instruction::CPU_286 | Instruction::CPU_PRIV}, {"BOUND", "reg16,mem", "po 62 /r", Instruction::CPU_186}, {"BOUND", "reg32,mem", "po 62 /r", Instruction::CPU_386}, {"BSF", "reg16,r/m16", "po 0F BC /r", Instruction::CPU_386}, {"BSF", "reg32,r/m32", "po 0F BC /r", Instruction::CPU_386}, {"BSR", "reg16,r/m16", "po 0F BD /r", Instruction::CPU_386}, {"BSR", "reg32,r/m32", "po 0F BD /r", Instruction::CPU_386}, {"BSWAP", "reg32", "po 0F C8 +r", Instruction::CPU_486}, {"BT", "r/m16,reg16", "po 0F A3 /r", Instruction::CPU_386}, {"BT", "r/m32,reg32", "po 0F A3 /r", Instruction::CPU_386}, {"BT", "r/m16,imm8", "po 0F BA /4 ib", Instruction::CPU_386}, {"BT", "r/m32,imm8", "po 0F BA /4 ib", Instruction::CPU_386}, {"BTC", "r/m16,reg16", "po 0F BB /r", Instruction::CPU_386}, {"BTC", "r/m32,reg32", "po 0F BB /r", Instruction::CPU_386}, {"BTC", "r/m16,imm8", "po 0F BA /7 ib", Instruction::CPU_386}, {"BTC", "r/m32,imm8", "po 0F BA /7 ib", Instruction::CPU_386}, {"BTR", "r/m16,reg16", "po 0F B3 /r", Instruction::CPU_386}, {"BTR", "r/m32,reg32", "po 0F B3 /r", Instruction::CPU_386}, {"BTR", "r/m16,imm8", "po 0F BA /6 ib", Instruction::CPU_386}, {"BTR", "r/m32,imm8", "po 0F BA /6 ib", Instruction::CPU_386}, {"BTS", "r/m16,reg16", "po 0F AB /r", Instruction::CPU_386}, {"BTS", "r/m32,reg32", "po 0F AB /r", Instruction::CPU_386}, {"BTS", "r/m16,imm", "po 0F BA /5 ib", Instruction::CPU_386}, {"BTS", "r/m32,imm", "po 0F BA /5 ib", Instruction::CPU_386}, {"CALL", "imm", "E8 -i", Instruction::CPU_8086}, // {"CALL", "imm:imm16", "po 9A iw iw", Instruction::CPU_8086}, // {"CALL", "imm:imm32", "po 9A id iw", Instruction::CPU_386}, // {"CALL", "FAR mem16", "po FF /3", Instruction::CPU_8086}, // {"CALL", "FAR mem32", "po FF /3", Instruction::CPU_386}, {"CALL", "WORD r/m16", "po FF /2", Instruction::CPU_8086}, {"CALL", "DWORD r/m32", "po FF /2", Instruction::CPU_386}, {"CBW", "", "po 98", Instruction::CPU_8086}, {"CWD", "", "po 99", Instruction::CPU_8086}, {"CDQ", "", "po 99", Instruction::CPU_386}, {"CWDE", "", "po 98", Instruction::CPU_386}, {"CLC", "", "F8", Instruction::CPU_8086}, {"CLD", "", "FC", Instruction::CPU_8086}, {"CLI", "", "FA", Instruction::CPU_8086}, // {"CLTS", "", "0F 06", Instruction::CPU_286 | Instruction::CPU_PRIV}, {"CMC", "", "F5", Instruction::CPU_8086}, {"CMOVO", "reg16,r/m16", "po 0F 40 /r", Instruction::CPU_P6}, {"CMOVNO", "reg16,r/m16", "po 0F 41 /r", Instruction::CPU_P6}, {"CMOVB", "reg16,r/m16", "po 0F 42 /r", Instruction::CPU_P6}, {"CMOVC", "reg16,r/m16", "po 0F 42 /r", Instruction::CPU_P6}, {"CMOVNEA", "reg16,r/m16", "po 0F 42 /r", Instruction::CPU_P6}, {"CMOVAE", "reg16,r/m16", "po 0F 43 /r", Instruction::CPU_P6}, {"CMOVNB", "reg16,r/m16", "po 0F 43 /r", Instruction::CPU_P6}, {"CMOVNC", "reg16,r/m16", "po 0F 43 /r", Instruction::CPU_P6}, {"CMOVE", "reg16,r/m16", "po 0F 44 /r", Instruction::CPU_P6}, {"CMOVZ", "reg16,r/m16", "po 0F 44 /r", Instruction::CPU_P6}, {"CMOVNE", "reg16,r/m16", "po 0F 45 /r", Instruction::CPU_P6}, {"CMOVNZ", "reg16,r/m16", "po 0F 45 /r", Instruction::CPU_P6}, {"CMOVBE", "reg16,r/m16", "po 0F 46 /r", Instruction::CPU_P6}, {"CMOVNA", "reg16,r/m16", "po 0F 46 /r", Instruction::CPU_P6}, {"CMOVA", "reg16,r/m16", "po 0F 47 /r", Instruction::CPU_P6}, {"CMOVNBE", "reg16,r/m16", "po 0F 47 /r", Instruction::CPU_P6}, {"CMOVS", "reg16,r/m16", "po 0F 48 /r", Instruction::CPU_P6}, {"CMOVNS", "reg16,r/m16", "po 0F 49 /r", Instruction::CPU_P6}, {"CMOVP", "reg16,r/m16", "po 0F 4A /r", Instruction::CPU_P6}, {"CMOVPE", "reg16,r/m16", "po 0F 4A /r", Instruction::CPU_P6}, {"CMOVNP", "reg16,r/m16", "po 0F 4B /r", Instruction::CPU_P6}, {"CMOVPO", "reg16,r/m16", "po 0F 4B /r", Instruction::CPU_P6}, {"CMOVL", "reg16,r/m16", "po 0F 4C /r", Instruction::CPU_P6}, {"CMOVNGE", "reg16,r/m16", "po 0F 4C /r", Instruction::CPU_P6}, {"CMOVGE", "reg16,r/m16", "po 0F 4D /r", Instruction::CPU_P6}, {"CMOVNL", "reg16,r/m16", "po 0F 4D /r", Instruction::CPU_P6}, {"CMOVLE", "reg16,r/m16", "po 0F 4E /r", Instruction::CPU_P6}, {"CMOVNG", "reg16,r/m16", "po 0F 4E /r", Instruction::CPU_P6}, {"CMOVG", "reg16,r/m16", "po 0F 4F /r", Instruction::CPU_P6}, {"CMOVNLE", "reg16,r/m16", "po 0F 4F /r", Instruction::CPU_P6}, {"CMOVO", "reg32,r/m32", "po 0F 40 /r", Instruction::CPU_P6}, {"CMOVNO", "reg32,r/m32", "po 0F 41 /r", Instruction::CPU_P6}, {"CMOVB", "reg32,r/m32", "po 0F 42 /r", Instruction::CPU_P6}, {"CMOVC", "reg32,r/m32", "po 0F 42 /r", Instruction::CPU_P6}, {"CMOVNEA", "reg32,r/m32", "po 0F 42 /r", Instruction::CPU_P6}, {"CMOVAE", "reg32,r/m32", "po 0F 43 /r", Instruction::CPU_P6}, {"CMOVNB", "reg32,r/m32", "po 0F 43 /r", Instruction::CPU_P6}, {"CMOVNC", "reg32,r/m32", "po 0F 43 /r", Instruction::CPU_P6}, {"CMOVE", "reg32,r/m32", "po 0F 44 /r", Instruction::CPU_P6}, {"CMOVZ", "reg32,r/m32", "po 0F 44 /r", Instruction::CPU_P6}, {"CMOVNE", "reg32,r/m32", "po 0F 45 /r", Instruction::CPU_P6}, {"CMOVNZ", "reg32,r/m32", "po 0F 45 /r", Instruction::CPU_P6}, {"CMOVBE", "reg32,r/m32", "po 0F 46 /r", Instruction::CPU_P6}, {"CMOVNA", "reg32,r/m32", "po 0F 46 /r", Instruction::CPU_P6}, {"CMOVA", "reg32,r/m32", "po 0F 47 /r", Instruction::CPU_P6}, {"CMOVNBE", "reg32,r/m32", "po 0F 47 /r", Instruction::CPU_P6}, {"CMOVS", "reg32,r/m32", "po 0F 48 /r", Instruction::CPU_P6}, {"CMOVNS", "reg32,r/m32", "po 0F 49 /r", Instruction::CPU_P6}, {"CMOVP", "reg32,r/m32", "po 0F 4A /r", Instruction::CPU_P6}, {"CMOVPE", "reg32,r/m32", "po 0F 4A /r", Instruction::CPU_P6}, {"CMOVNP", "reg32,r/m32", "po 0F 4B /r", Instruction::CPU_P6}, {"CMOVPO", "reg32,r/m32", "po 0F 4B /r", Instruction::CPU_P6}, {"CMOVL", "reg32,r/m32", "po 0F 4C /r", Instruction::CPU_P6}, {"CMOVNGE", "reg32,r/m32", "po 0F 4C /r", Instruction::CPU_P6}, {"CMOVGE", "reg32,r/m32", "po 0F 4D /r", Instruction::CPU_P6}, {"CMOVNL", "reg32,r/m32", "po 0F 4D /r", Instruction::CPU_P6}, {"CMOVLE", "reg32,r/m32", "po 0F 4E /r", Instruction::CPU_P6}, {"CMOVNG", "reg32,r/m32", "po 0F 4E /r", Instruction::CPU_P6}, {"CMOVG", "reg32,r/m32", "po 0F 4F /r", Instruction::CPU_P6}, {"CMOVNLE", "reg32,r/m32", "po 0F 4F /r", Instruction::CPU_P6}, {"CMP", "r/m8,reg8", "38 /r", Instruction::CPU_8086}, {"CMP", "r/m16,reg16", "po 39 /r", Instruction::CPU_8086}, {"CMP", "r/m32,reg32", "po 39 /r", Instruction::CPU_386}, {"CMP", "reg8,r/m8", "3A /r", Instruction::CPU_8086}, {"CMP", "reg16,r/m16", "po 3B /r", Instruction::CPU_8086}, {"CMP", "reg32,r/m32", "po 3B /r", Instruction::CPU_386}, {"CMP", "r/m8,imm8", "80 /7 ib", Instruction::CPU_8086}, {"CMP", "r/m16,imm16", "po 81 /7 iw", Instruction::CPU_8086}, {"CMP", "r/m32,imm32", "po 81 /7 id", Instruction::CPU_386}, {"CMP", "r/m16,imm8", "po 83 /7 ib", Instruction::CPU_8086}, {"CMP", "r/m32,imm8", "po 83 /7 ib", Instruction::CPU_386}, {"CMP", "AL,imm8", "3C ib", Instruction::CPU_8086}, {"CMP", "AX,imm16", "po 3D iw", Instruction::CPU_8086}, {"CMP", "EAX,imm32", "po 3D id", Instruction::CPU_386}, {"CMPPS", "xmmreg,r/m128,imm8", "0F C2 /r ib", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"CMPEQPS", "xmmreg,r/m128", "0F C2 /r 00", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"CMPLEPS", "xmmreg,r/m128", "0F C2 /r 02", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"CMPLTPS", "xmmreg,r/m128", "0F C2 /r 01", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"CMPNEQPS", "xmmreg,r/m128", "0F C2 /r 04", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"CMPNLEPS", "xmmreg,r/m128", "0F C2 /r 06", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"CMPNLTPS", "xmmreg,r/m128", "0F C2 /r 05", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"CMPORDPS", "xmmreg,r/m128", "0F C2 /r 07", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"CMPUNORDPS", "xmmreg,r/m128", "0F C2 /r 03", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"CMPSB", "", "A6", Instruction::CPU_8086}, {"CMPSW", "", "po A7", Instruction::CPU_8086}, {"CMPSD", "", "po A7", Instruction::CPU_386}, {"CMPSS", "xmmreg,xmmreg/mem32,imm8", "p3 0F C2 /r ib", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"CMPEQSS", "xmmreg,xmmreg/mem32", "p3 0F C2 /r 00", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"CMPLESS", "xmmreg,xmmreg/mem32", "p3 0F C2 /r 02", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"CMPLTSS", "xmmreg,xmmreg/mem32", "p3 0F C2 /r 01", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"CMPNEQSS", "xmmreg,xmmreg/mem32", "p3 0F C2 /r 04", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"CMPNLESS", "xmmreg,xmmreg/mem32", "p3 0F C2 /r 06", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"CMPNLTSS", "xmmreg,xmmreg/mem32", "p3 0F C2 /r 05", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"CMPORDSS", "xmmreg,xmmreg/mem32", "p3 0F C2 /r 07", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"CMPUNORDSS", "xmmreg,xmmreg/mem32", "p3 0F C2 /r 03", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"CMPXCHG", "r/m8,reg8", "0F B0 /r", Instruction::CPU_PENT}, {"CMPXCHG", "r/m16,reg16", "po 0F B1 /r", Instruction::CPU_PENT}, {"CMPXCHG", "r/m32,reg32", "po 0F B1 /r", Instruction::CPU_PENT}, // {"CMPXCHG486", "r/m8,reg8", "0F A6 /r", Instruction::CPU_486 | Instruction::CPU_UNDOC}, // {"CMPXCHG486", "r/m16,reg16", "po 0F A7 /r", Instruction::CPU_486 | Instruction::CPU_UNDOC}, // {"CMPXCHG486", "r/m32,reg32", "po 0F A7 /r", Instruction::CPU_486 | Instruction::CPU_UNDOC}, {"CMPXCHG8B", "mem", "0F C7 /1", Instruction::CPU_PENT}, {"COMISS", "xmmreg,xmmreg/mem32", "0F 2F /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"CPUID", "", "0F A2", Instruction::CPU_PENT}, {"CVTPI2PS", "xmmreg,r/m64", "0F 2A /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"CVTPS2PI", "mmreg,xmmreg/mem64", "0F 2D /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"CVTTPS2PI", "mmreg,xmmreg/mem64", "0F 2C /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"CVTSI2SS", "xmmreg,r/m32", "p3 0F 2A /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"CVTSS2SI", "reg32,xmmreg/mem32", "p3 0F 2D /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"CVTTSS2SI", "reg32,xmmreg/mem32", "p3 0F 2C /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"DAA", "", "27", Instruction::CPU_8086}, {"DAS", "", "2F", Instruction::CPU_8086}, {"DEC", "reg16", "po 48 +r", Instruction::CPU_8086}, {"DEC", "reg32", "po 48 +r", Instruction::CPU_386}, {"DEC", "BYTE r/m8", "FE /1", Instruction::CPU_8086}, {"DEC", "WORD r/m16", "po FF /1", Instruction::CPU_8086}, {"DEC", "DWORD r/m32", "po FF /1", Instruction::CPU_386}, {"DIV", "BYTE r/m8", "F6 /6", Instruction::CPU_8086}, {"DIV", "WORD r/m16", "po F7 /6", Instruction::CPU_8086}, {"DIV", "DWORD r/m32", "po F7 /6", Instruction::CPU_386}, {"DIVPS", "xmmreg,r/m128", "0F 5E /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"DIVSS", "xmmreg,xmmreg/mem32", "p3 0F 5E /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"EMMS", "", "0F 77", Instruction::CPU_PENT | Instruction::CPU_MMX}, // {"ENTER", "imm,imm", "C8 iw ib", Instruction::CPU_186}, {"F2XM1", "", "D9 F0", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FABS", "", "D9 E1", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FADD", "DWORD mem32", "D8 /0", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FADD", "QWORD mem64", "DC /0", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FADD", "fpureg", "D8 C0 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FADD", "ST0,fpureg", "D8 C0 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, // {"FADD", "TO fpureg", "DC C0 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FADD", "fpureg,ST0", "DC C0 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FADDP", "fpureg", "DE C0 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FADDP", "fpureg,ST0", "DE C0 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, // {"FBLD", "mem80", "DF /4", Instruction::CPU_8086 | Instruction::CPU_FPU}, // {"FBSTP", "mem80", "DF /6", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FCHS", "", "D9 E0", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FCLEX", "", "9B DB E2", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FNCLEX", "", "DB E2", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FCMOVB", "fpureg", "DA C0 +r", Instruction::CPU_P6 | Instruction::CPU_FPU}, {"FCMOVB", "ST0,fpureg", "DA C0 +r", Instruction::CPU_P6 | Instruction::CPU_FPU}, {"FCMOVBE", "fpureg", "DA D0 +r", Instruction::CPU_P6 | Instruction::CPU_FPU}, {"FCMOVBE", "ST0,fpureg", "DA D0 +r", Instruction::CPU_P6 | Instruction::CPU_FPU}, {"FCMOVE", "fpureg", "DA C8 +r", Instruction::CPU_P6 | Instruction::CPU_FPU}, {"FCMOVE", "ST0,fpureg", "DA C8 +r", Instruction::CPU_P6 | Instruction::CPU_FPU}, {"FCMOVNB", "fpureg", "DB C0 +r", Instruction::CPU_P6 | Instruction::CPU_FPU}, {"FCMOVNB", "ST0,fpureg", "DB C0 +r", Instruction::CPU_P6 | Instruction::CPU_FPU}, {"FCMOVNBE", "fpureg", "DB D0 +r", Instruction::CPU_P6 | Instruction::CPU_FPU}, {"FCMOVNBE", "ST0,fpureg", "DB D0 +r", Instruction::CPU_P6 | Instruction::CPU_FPU}, {"FCMOVNE", "fpureg", "DB C8 +r", Instruction::CPU_P6 | Instruction::CPU_FPU}, {"FCMOVNE", "ST0,fpureg", "DB C8 +r", Instruction::CPU_P6 | Instruction::CPU_FPU}, {"FCMOVNU", "fpureg", "DB D8 +r", Instruction::CPU_P6 | Instruction::CPU_FPU}, {"FCMOVNU", "ST0,fpureg", "DB D8 +r", Instruction::CPU_P6 | Instruction::CPU_FPU}, {"FCMOVU", "fpureg", "DA D8 +r", Instruction::CPU_P6 | Instruction::CPU_FPU}, {"FCMOVU", "ST0,fpureg", "DA D8 +r", Instruction::CPU_P6 | Instruction::CPU_FPU}, {"FCOM", "DWORD mem32", "D8 /2", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FCOM", "QWORD mem64", "DC /2", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FCOM", "fpureg", "D8 D0 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FCOM", "ST0,fpureg", "D8 D0 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FCOMP", "DWORD mem32", "D8 /3", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FCOMP", "QWORD mem64", "DC /3", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FCOMP", "fpureg", "D8 D8 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FCOMP", "ST0,fpureg", "D8 D8 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FCOMPP", "", "DE D9", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FCOMI", "fpureg", "DB F0 +r", Instruction::CPU_P6 | Instruction::CPU_FPU}, {"FCOMI", "ST0,fpureg", "DB F0 +r", Instruction::CPU_P6 | Instruction::CPU_FPU}, {"FCOMIP", "fpureg", "DF F0 +r", Instruction::CPU_P6 | Instruction::CPU_FPU}, {"FCOMIP", "ST0,fpureg", "DF F0 +r", Instruction::CPU_P6 | Instruction::CPU_FPU}, {"FCOS", "", "D9 FF", Instruction::CPU_386 | Instruction::CPU_FPU}, {"FDECSTP", "", "D9 F6", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FDISI", "", "9B DB E1", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FNDISI", "", "DB E1", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FENI", "", "9B DB E0", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FNENI", "", "DB E0", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FDIV", "DWORD mem32", "D8 /6", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FDIV", "QWORD mem64", "DC /6", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FDIV", "fpureg", "D8 F0 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FDIV", "ST0,fpureg", "D8 F0 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, // {"FDIV", "TO fpureg", "DC F8 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FDIV", "fpureg,ST0", "DC F8 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FDIVR", "DWORD mem32", "D8 /7", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FDIVR", "QWORD mem64", "DC /7", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FDIVR", "fpureg", "D8 F8 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FDIVR", "ST0,fpureg", "D8 F8 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, // {"FDIVR", "TO fpureg", "DC F0 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FDIVR", "fpureg,ST0", "DC F0 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FDIVP", "fpureg", "DE F8 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FDIVP", "fpureg,ST0", "DE F8 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FDIVRP", "fpureg", "DE F0 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FDIVRP", "fpureg,ST0", "DE F0 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FEMMS", "", "0F 0E", Instruction::CPU_3DNOW}, {"FFREE", "fpureg", "DD C0 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, // {"FFREEP", "fpureg", "DF C0 +r", Instruction::CPU_P6 | Instruction::CPU_FPU | Instruction::CPU_UNDOC}, {"FIADD", "WORD mem16", "DE /0", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FIADD", "DWORD mem32", "DA /0", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FICOM", "WORD mem16", "DE /2", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FICOM", "DWORD mem32", "DA /2", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FICOMP", "WORD mem16", "DE /3", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FICOMP", "DWORD mem32", "DA /3", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FIDIV", "WORD mem16", "DE /6", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FIDIV", "DWORD mem32", "DA /6", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FIDIVR", "WORD mem16", "DE /7", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FIDIVR", "DWORD mem32", "DA /7", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FILD", "WORD mem16", "DF /0", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FILD", "DWORD mem32", "DB /0", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FILD", "QWORD mem64", "DF /5", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FIST", "WORD mem16", "DF /2", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FIST", "DWORD mem32", "DB /2", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FISTP", "WORD mem16", "DF /3", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FISTP", "DWORD mem32", "DB /3", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FISTP", "QWORD mem64", "DF /0", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FIMUL", "WORD mem16", "DE /1", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FIMUL", "DWORD mem32", "DA /1", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FINCSTP", "", "D9 F7", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FINIT", "", "9B DB E3", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FNINIT", "", "DB E3", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FISUB", "WORD mem16", "DE /4", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FISUB", "DWORD mem32", "DA /4", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FISUBR", "WORD mem16", "DE /5", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FISUBR", "DWORD mem32", "DA /5", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FLD", "DWORD mem32", "D9 /0", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FLD", "QWORD mem64", "DD /0", Instruction::CPU_8086 | Instruction::CPU_FPU}, // {"FLD", "mem80", "DB /5", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FLD", "fpureg", "D9 C0 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FLD1", "", "D9 E8", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FLDL2E", "", "D9 EA", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FLDL2T", "", "D9 E9", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FLDLG2", "", "D9 EC", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FLDLN2", "", "D9 ED", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FLDPI", "", "D9 EB", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FLDZ", "", "D9 EE", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FLDCW", "mem16", "D9 /5", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FLDENV", "mem", "D9 /4", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FMUL", "DWORD mem32", "D8 /1", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FMUL", "QWORD mem64", "DC /1", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FMUL", "fpureg", "D8 C8 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FMUL", "ST0,fpureg", "D8 C8 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, // {"FMUL", "TO fpureg", "DC C8 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FMUL", "fpureg,ST0", "DC C8 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FMULP", "fpureg", "DE C8 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FMULP", "fpureg,ST0", "DE C8 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FNOP", "", "D9 D0", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FPATAN", "", "D9 F3", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FPTAN", "", "D9 F2", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FPREM", "", "D9 F8", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FPREM1", "", "D9 F5", Instruction::CPU_386 | Instruction::CPU_FPU}, {"FRNDINT", "", "D9 FC", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FSAVE", "mem", "9B DD /6", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FNSAVE", "mem", "DD /6", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FRSTOR", "mem", "DD /4", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FSCALE", "", "D9 FD", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FSETPM", "", "DB E4", Instruction::CPU_286 | Instruction::CPU_FPU}, {"FSIN", "", "D9 FE", Instruction::CPU_386 | Instruction::CPU_FPU}, {"FSINCOS", "", "D9 FB", Instruction::CPU_386 | Instruction::CPU_FPU}, {"FSQRT", "", "D9 FA", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FST", "DWORD mem32", "D9 /2", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FST", "QWORD mem64", "DD /2", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FST", "fpureg", "DD D0 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FSTP", "DWORD mem32", "D9 /3", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FSTP", "QWORD mem64", "DD /3", Instruction::CPU_8086 | Instruction::CPU_FPU}, // {"FSTP", "mem80", "DB /0", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FSTP", "fpureg", "DD D8 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FSTCW", "mem16", "9B D9 /0", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FNSTCW", "mem16", "D9 /0", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FSTENV", "mem", "9B D9 /6", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FNSTENV", "mem", "D9 /6", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FSTSW", "mem16", "9B DD /0", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FSTSW", "AX", "9B DF E0", Instruction::CPU_286 | Instruction::CPU_FPU}, {"FNSTSW", "mem16", "DD /0", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FNSTSW", "AX", "DF E0", Instruction::CPU_286 | Instruction::CPU_FPU}, {"FSUB", "DWORD mem32", "D8 /4", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FSUB", "QWORD mem64", "DC /4", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FSUB", "fpureg", "D8 E0 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FSUB", "ST0,fpureg", "D8 E0 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, // {"FSUB", "TO fpureg", "DC E8 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FSUB", "fpureg,ST0", "DC E8 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FSUBR", "DWORD mem32", "D8 /5", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FSUBR", "QWORD mem64", "DC /5", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FSUBR", "fpureg", "D8 E8 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FSUBR", "ST0,fpureg", "D8 E8 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, // {"FSUBR", "TO fpureg", "DC E0 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FSUBR", "fpureg,ST0", "DC E0 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FSUBP", "fpureg", "DE E8 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FSUBP", "fpureg,ST0", "DE E8 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FSUBRP", "fpureg", "DE E0 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FSUBRP", "fpureg,ST0", "DE E0 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FTST", "", "D9 E4", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FUCOM", "fpureg", "DD E0 +r", Instruction::CPU_386 | Instruction::CPU_FPU}, {"FUCOM", "ST0,fpureg", "DD E0 +r", Instruction::CPU_386 | Instruction::CPU_FPU}, {"FUCOMP", "fpureg", "DD E8 +r", Instruction::CPU_386 | Instruction::CPU_FPU}, {"FUCOMP", "ST0,fpureg", "DD E8 +r", Instruction::CPU_386 | Instruction::CPU_FPU}, {"FUCOMPP", "", "DA E9", Instruction::CPU_386 | Instruction::CPU_FPU}, {"FUCOMI", "fpureg", "DB E8 +r", Instruction::CPU_P6 | Instruction::CPU_FPU}, {"FUCOMI", "ST0,fpureg", "DB E8 +r", Instruction::CPU_P6 | Instruction::CPU_FPU}, {"FUCOMIP", "fpureg", "DF E8 +r", Instruction::CPU_P6 | Instruction::CPU_FPU}, {"FUCOMIP", "ST0,fpureg", "DF E8 +r", Instruction::CPU_P6 | Instruction::CPU_FPU}, {"FWAIT", "", "9B", Instruction::CPU_8086}, {"FXAM", "", "D9 E5", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FXCH", "", "D9 C9", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FXCH", "fpureg", "D9 C8 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FXCH", "fpureg,ST0", "D9 C8 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FXCH", "ST0,fpureg", "D9 C8 +r", Instruction::CPU_8086 | Instruction::CPU_FPU}, // {"FXRSTOR", "m512byte", "0F AE /1", Instruction::CPU_P6 | Instruction::CPU_SSE | Instruction::CPU_FPU}, // {"FXSAVE", "m512byte", "0F AE /0", Instruction::CPU_P6 | Instruction::CPU_SSE | Instruction::CPU_FPU}, {"FXTRACT", "", "D9 F4", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FYL2X", "", "D9 F1", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"FYL2XP1", "", "D9 F9", Instruction::CPU_8086 | Instruction::CPU_FPU}, {"HLT", "", "F4", Instruction::CPU_8086}, // {"IBTS", "r/m16,reg16", "po 0F A7 /r", Instruction::CPU_386 | Instruction::CPU_UNDOC}, // {"IBTS", "r/m32,reg32", "po 0F A7 /r", Instruction::CPU_386 | Instruction::CPU_UNDOC}, {"IDIV", "BYTE r/m8", "F6 /7", Instruction::CPU_8086}, {"IDIV", "WORD r/m16", "po F7 /7", Instruction::CPU_8086}, {"IDIV", "DWORD r/m32", "po F7 /7", Instruction::CPU_386}, {"IMUL", "BYTE r/m8", "F6 /5", Instruction::CPU_8086}, {"IMUL", "WORD r/m16", "po F7 /5", Instruction::CPU_8086}, {"IMUL", "DWORD r/m32", "po F7 /5", Instruction::CPU_386}, {"IMUL", "reg16,r/m16", "po 0F AF /r", Instruction::CPU_386}, {"IMUL", "reg32,r/m32", "po 0F AF /r", Instruction::CPU_386}, {"IMUL", "reg16,imm8", "po 6B /r ib", Instruction::CPU_286}, {"IMUL", "reg16,imm16", "po 69 /r iw", Instruction::CPU_286}, {"IMUL", "reg32,imm8", "po 6B /r ib", Instruction::CPU_386}, {"IMUL", "reg32,imm32", "po 69 /r id", Instruction::CPU_386}, {"IMUL", "reg16,r/m16,imm8", "po 6B /r ib", Instruction::CPU_286}, {"IMUL", "reg16,r/m16,imm16", "po 69 /r iw", Instruction::CPU_286}, {"IMUL", "reg32,r/m32,imm8", "po 6B /r ib", Instruction::CPU_386}, {"IMUL", "reg32,r/m32,imm32", "po 69 /r id", Instruction::CPU_386}, {"IN", "AL,imm8", "E4 ib", Instruction::CPU_8086}, {"IN", "AX,imm8", "po E5 ib", Instruction::CPU_8086}, {"IN", "EAX,imm8", "po E5 ib", Instruction::CPU_386}, {"IN", "AL,DX", "EC", Instruction::CPU_8086}, {"IN", "AX,DX", "po ED", Instruction::CPU_8086}, {"IN", "EAX,DX", "po ED", Instruction::CPU_386}, {"INC", "reg16", "po 40 +r", Instruction::CPU_8086}, {"INC", "reg32", "po 40 +r", Instruction::CPU_386}, {"INC", "BYTE r/m8", "FE /0", Instruction::CPU_8086}, {"INC", "WORD r/m16", "po FF /0", Instruction::CPU_8086}, {"INC", "DWORD r/m32", "po FF /0", Instruction::CPU_386}, {"INSB", "", "6C", Instruction::CPU_186}, {"INSW", "", "po 6D", Instruction::CPU_186}, {"INSD", "", "po 6D", Instruction::CPU_386}, {"INT", "imm8", "CD ib", Instruction::CPU_8086}, {"INT1", "", "F1", Instruction::CPU_P6}, {"ICEBP", "", "F1", Instruction::CPU_P6}, {"INT01", "", "F1", Instruction::CPU_P6}, {"INT3", "", "CC", Instruction::CPU_8086}, {"INT03", "", "CC", Instruction::CPU_8086}, {"INTO", "", "CE", Instruction::CPU_8086}, {"INVD", "", "0F 08", Instruction::CPU_486}, {"INVLPG", "mem", "0F 01 /0", Instruction::CPU_486}, {"IRET", "", "CF", Instruction::CPU_8086}, {"IRETW", "", "po CF", Instruction::CPU_8086}, {"IRETD", "", "po CF", Instruction::CPU_386}, {"JCXZ", "imm", "po E3 -b", Instruction::CPU_8086}, {"JECXZ", "imm", "po E3 -b", Instruction::CPU_386}, {"JMP", "imm", "E9 -i", Instruction::CPU_8086}, {"JMP", "SHORT imm", "EB -b", Instruction::CPU_8086}, // {"JMP", "imm:imm16", "po EA iw iw", Instruction::CPU_8086}, // {"JMP", "imm:imm32", "po EA id iw", Instruction::CPU_386}, {"JMP", "mem", "po FF /5", Instruction::CPU_8086}, // {"JMP", "FAR mem", "po FF /5", Instruction::CPU_386}, {"JMP", "WORD r/m16", "po FF /4", Instruction::CPU_8086}, {"JMP", "DWORD r/m32", "po FF /4", Instruction::CPU_386}, {"JO", "imm", "70 -b", Instruction::CPU_8086}, {"JNO", "imm", "71 -b", Instruction::CPU_8086}, {"JB", "imm", "72 -b", Instruction::CPU_8086}, {"JC", "imm", "72 -b", Instruction::CPU_8086}, {"JNEA", "imm", "72 -b", Instruction::CPU_8086}, {"JAE", "imm", "73 -b", Instruction::CPU_8086}, {"JNB", "imm", "73 -b", Instruction::CPU_8086}, {"JNC", "imm", "73 -b", Instruction::CPU_8086}, {"JE", "imm", "74 -b", Instruction::CPU_8086}, {"JZ", "imm", "74 -b", Instruction::CPU_8086}, {"JNE", "imm", "75 -b", Instruction::CPU_8086}, {"JNZ", "imm", "75 -b", Instruction::CPU_8086}, {"JBE", "imm", "76 -b", Instruction::CPU_8086}, {"JNA", "imm", "76 -b", Instruction::CPU_8086}, {"JA", "imm", "77 -b", Instruction::CPU_8086}, {"JNBE", "imm", "77 -b", Instruction::CPU_8086}, {"JS", "imm", "78 -b", Instruction::CPU_8086}, // {"JNS", "imm", "79 -b", Instruction::CPU_8086}, {"JP", "imm", "7A -b", Instruction::CPU_8086}, {"JPE", "imm", "7A -b", Instruction::CPU_8086}, {"JNP", "imm", "7B -b", Instruction::CPU_8086}, {"JPO", "imm", "7B -b", Instruction::CPU_8086}, {"JL", "imm", "7C -b", Instruction::CPU_8086}, {"JNGE", "imm", "7C -b", Instruction::CPU_8086}, {"JGE", "imm", "7D -b", Instruction::CPU_8086}, {"JNL", "imm", "7D -b", Instruction::CPU_8086}, {"JLE", "imm", "7E -b", Instruction::CPU_8086}, {"JNG", "imm", "7E -b", Instruction::CPU_8086}, {"JG", "imm", "7F -b", Instruction::CPU_8086}, {"JNLE", "imm", "7F -b", Instruction::CPU_8086}, {"JO", "NEAR imm", "0F 80 -i", Instruction::CPU_386}, {"JNO", "NEAR imm", "0F 81 -i", Instruction::CPU_386}, {"JB", "NEAR imm", "0F 82 -i", Instruction::CPU_386}, {"JC", "NEAR imm", "0F 82 -i", Instruction::CPU_386}, {"JNEA", "NEAR imm", "0F 82 -i", Instruction::CPU_386}, {"JAE", "NEAR imm", "0F 83 -i", Instruction::CPU_386}, {"JNB", "NEAR imm", "0F 83 -i", Instruction::CPU_386}, {"JNC", "NEAR imm", "0F 83 -i", Instruction::CPU_386}, {"JE", "NEAR imm", "0F 84 -i", Instruction::CPU_386}, {"JZ", "NEAR imm", "0F 84 -i", Instruction::CPU_386}, {"JNE", "NEAR imm", "0F 85 -i", Instruction::CPU_386}, {"JNZ", "NEAR imm", "0F 85 -i", Instruction::CPU_386}, {"JBE", "NEAR imm", "0F 86 -i", Instruction::CPU_386}, {"JNA", "NEAR imm", "0F 86 -i", Instruction::CPU_386}, {"JA", "NEAR imm", "0F 87 -i", Instruction::CPU_386}, {"JNBE", "NEAR imm", "0F 87 -i", Instruction::CPU_386}, {"JS", "NEAR imm", "0F 88 -i", Instruction::CPU_386}, {"JNS", "NEAR imm", "0F 89 -i", Instruction::CPU_386}, {"JP", "NEAR imm", "0F 8A -i", Instruction::CPU_386}, {"JPE", "NEAR imm", "0F 8A -i", Instruction::CPU_386}, {"JNP", "NEAR imm", "0F 8B -i", Instruction::CPU_386}, {"JPO", "NEAR imm", "0F 8B -i", Instruction::CPU_386}, {"JL", "NEAR imm", "0F 8C -i", Instruction::CPU_386}, {"JNGE", "NEAR imm", "0F 8C -i", Instruction::CPU_386}, {"JGE", "NEAR imm", "0F 8D -i", Instruction::CPU_386}, {"JNL", "NEAR imm", "0F 8D -i", Instruction::CPU_386}, {"JLE", "NEAR imm", "0F 8E -i", Instruction::CPU_386}, {"JNG", "NEAR imm", "0F 8E -i", Instruction::CPU_386}, {"JG", "NEAR imm", "0F 8F -i", Instruction::CPU_386}, {"JNLE", "NEAR imm", "0F 8F -i", Instruction::CPU_386}, {"LAHF", "", "9F", Instruction::CPU_8086}, // {"LAR", "reg16,r/m16", "po 0F 02 /r", Instruction::CPU_286 | Instruction::CPU_PRIV}, // {"LAR", "reg32,r/m32", "po 0F 02 /r", Instruction::CPU_286 | Instruction::CPU_PRIV}, {"LDS", "reg16,mem", "po C5 /r", Instruction::CPU_8086}, {"LDS", "reg32,mem", "po C5 /r", Instruction::CPU_8086}, {"LES", "reg16,mem", "po C4 /r", Instruction::CPU_8086}, {"LES", "reg32,mem", "po C4 /r", Instruction::CPU_8086}, {"LFS", "reg16,mem", "po 0F B4 /r", Instruction::CPU_386}, {"LFS", "reg32,mem", "po 0F B4 /r", Instruction::CPU_386}, {"LGS", "reg16,mem", "po 0F B5 /r", Instruction::CPU_386}, {"LGS", "reg32,mem", "po 0F B5 /r", Instruction::CPU_386}, {"LSS", "reg16,mem", "po 0F B2 /r", Instruction::CPU_386}, {"LSS", "reg32,mem", "po 0F B2 /r", Instruction::CPU_386}, {"LDMXCSR", "mem32", "0F AE /2", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"LEA", "reg16,mem", "po 8D /r", Instruction::CPU_8086}, {"LEA", "reg32,mem", "po 8D /r", Instruction::CPU_386}, {"LEAVE", "", "C9", Instruction::CPU_186}, // {"LGDT", "mem", "0F 01 /2", Instruction::CPU_286 | Instruction::CPU_PRIV}, // {"LIDT", "mem", "0F 01 /3", Instruction::CPU_286 | Instruction::CPU_PRIV}, // {"LLDT", "r/m16", "0F 00 /2", Instruction::CPU_286 | Instruction::CPU_PRIV}, // {"LMSW", "r/m16", "0F 01 /6", Instruction::CPU_286 | Instruction::CPU_PRIV}, // {"LOADALL", "", "0F 07", Instruction::CPU_386 | Instruction::CPU_UNDOC}, // {"LOADALL286", "", "0F 05", Instruction::CPU_286 | Instruction::CPU_UNDOC}, {"LODSB", "", "AC", Instruction::CPU_8086}, {"LODSW", "", "po AD", Instruction::CPU_8086}, {"LODSD", "", "po AD", Instruction::CPU_386}, {"LOOP", "imm", "E2 -b", Instruction::CPU_8086}, {"LOOP", "imm,CX", "pa E2 -b", Instruction::CPU_8086}, {"LOOP", "imm,ECX", "pa E2 -b", Instruction::CPU_386}, {"LOOPE", "imm", "E1 -b", Instruction::CPU_8086}, {"LOOPE", "imm,CX", "pa E1 -b", Instruction::CPU_8086}, {"LOOPE", "imm,ECX", "pa E1 -b", Instruction::CPU_386}, {"LOOPZ", "imm", "E1 -b", Instruction::CPU_8086}, {"LOOPZ", "imm,CX", "pa E1 -b", Instruction::CPU_8086}, {"LOOPZ", "imm,ECX", "pa E1 -b", Instruction::CPU_386}, {"LOOPNE", "imm", "E0 -b", Instruction::CPU_8086}, {"LOOPNE", "imm,CX", "pa E0 -b", Instruction::CPU_8086}, {"LOOPNE", "imm,ECX", "pa E0 -b", Instruction::CPU_386}, {"LOOPNZ", "imm", "E0 -b", Instruction::CPU_8086}, {"LOOPNZ", "imm,CX", "pa E0 -b", Instruction::CPU_8086}, {"LOOPNZ", "imm,ECX", "pa E0 -b", Instruction::CPU_386}, // {"LSL", "reg16,r/m16", "po 0F 03 /r", Instruction::CPU_286 | Instruction::CPU_PRIV}, // {"LSL", "reg32,r/m32", "po 0F 03 /r", Instruction::CPU_286 | Instruction::CPU_PRIV}, // {"LTR", "r/m16", "0F 00 /3", Instruction::CPU_286 | Instruction::CPU_PRIV}, {"MASKMOVQ", "mmreg,mmreg", "0F F7 /r", Instruction::CPU_KATMAI}, // {"MAXPS", "xmmreg,r/m128", "0F 5F /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, // {"MAXSS", "xmmreg,r/m128", "p3 0F 5F /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, // {"MINPS", "xmmreg,r/m128", "0F 5D /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, // {"MINSS", "xmmreg,r/m128", "p3 0F 5D /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"MOV", "r/m8,reg8", "88 /r", Instruction::CPU_8086}, {"MOV", "r/m16,reg16", "po 89 /r", Instruction::CPU_8086}, {"MOV", "r/m32,reg32", "po 89 /r", Instruction::CPU_386}, {"MOV", "reg8,r/m8", "8A /r", Instruction::CPU_8086}, {"MOV", "reg16,r/m16", "po 8B /r", Instruction::CPU_8086}, {"MOV", "reg32,r/m32", "po 8B /r", Instruction::CPU_386}, {"MOV", "reg8,imm8", "B0 +r ib", Instruction::CPU_8086}, {"MOV", "reg16,imm16", "po B8 +r iw", Instruction::CPU_8086}, {"MOV", "reg32,imm32", "po B8 +r id", Instruction::CPU_386}, {"MOV", "r/m8,imm8", "C6 /0 ib", Instruction::CPU_8086}, {"MOV", "r/m16,imm16", "po C7 /0 iw", Instruction::CPU_8086}, {"MOV", "r/m32,imm32", "po C7 /0 id", Instruction::CPU_386}, // {"MOV", "AL,memoffs8", "A0 id", Instruction::CPU_8086}, // {"MOV", "AX,memoffs16", "po A1 id", Instruction::CPU_8086}, // {"MOV", "EAX,memoffs32", "po A1 id", Instruction::CPU_386}, // {"MOV", "memoffs8,AL", "A2 id", Instruction::CPU_8086}, // {"MOV", "memoffs16,AX", "po A3 id", Instruction::CPU_8086}, // {"MOV", "memoffs32,EAX", "po A3 id", Instruction::CPU_386}, // {"MOV", "r/m16,segreg", "po 8C /r", Instruction::CPU_8086}, // {"MOV", "r/m32,segreg", "po 8C /r", Instruction::CPU_386}, // {"MOV", "segreg,r/m16", "po 8E /r", Instruction::CPU_8086}, // {"MOV", "segreg,r/m32", "po 8E /r", Instruction::CPU_386}, // {"MOV", "reg32,CR0/2/3/4", "0F 20 /r", Instruction::CPU_386}, // {"MOV", "reg32,DR0/1/2/3/6/7", "0F 21 /r", Instruction::CPU_386}, // {"MOV", "reg32,TR3/4/5/6/7", "0F 24 /r", Instruction::CPU_386}, // {"MOV", "CR0/2/3/4,reg32", "0F 22 /r", Instruction::CPU_386}, // {"MOV", "DR0/1/2/3/6/7,reg32", "0F 23 /r", Instruction::CPU_386}, // {"MOV", "TR3/4/5/6/7,reg32", "0F 26 /r", Instruction::CPU_386}, {"MOVAPS", "xmmreg,r/m128", "0F 28 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"MOVAPS", "r/m128,xmmreg", "0F 29 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"MOVD", "mmreg,r/m32", "0F 6E /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"MOVD", "r/m32,mmreg", "0F 7E /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"MOVHLPS", "xmmreg,xmmreg", "0F 12 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"MOVHPS", "xmmreg,mem64", "0F 16 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"MOVHPS", "mem64,xmmreg", "0F 17 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"MOVHPS", "xmmreg,xmmreg", "0F 16 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"MOVLHPS", "xmmreg,xmmreg", "0F 16 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"MOVLPS", "xmmreg,mem64", "0F 12 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"MOVLPS", "mem64,xmmreg", "0F 13 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"MOVLPS", "xmmreg,xmmreg", "0F 12 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"MOVMSKPS", "reg32,xmmreg", "0F 50 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"MOVNTPS", "mem128,xmmreg", "0F 2B /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"MOVNTQ", "mem64,mmreg", "0F E7 /r", Instruction::CPU_KATMAI}, {"MOVQ", "mmreg,r/m64", "0F 6F /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"MOVQ", "r/m64,mmreg", "0F 7F /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"MOVSB", "", "A4", Instruction::CPU_8086}, {"MOVSW", "", "po A5", Instruction::CPU_8086}, {"MOVSD", "", "po A5", Instruction::CPU_386}, {"MOVSS", "xmmreg,xmmreg/mem32", "p3 0F 10 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"MOVSS", "xmmreg/mem32,xmmreg", "p3 0F 11 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"MOVSX", "reg16,r/m8", "po 0F BE /r", Instruction::CPU_386}, {"MOVSX", "reg32,r/m8", "po 0F BE /r", Instruction::CPU_386}, {"MOVSX", "reg32,r/m16", "po 0F BF /r", Instruction::CPU_386}, {"MOVZX", "reg16,r/m8", "po 0F B6 /r", Instruction::CPU_386}, {"MOVZX", "reg32,r/m8", "po 0F B6 /r", Instruction::CPU_386}, {"MOVZX", "reg32,r/m16", "po 0F B7 /r", Instruction::CPU_386}, {"MOVUPS", "xmmreg,r/m128", "0F 10 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"MOVUPS", "r/m128,xmmreg", "0F 11 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"MUL", "BYTE r/m8", "F6 /4", Instruction::CPU_8086}, {"MUL", "WORD r/m16", "po F7 /4", Instruction::CPU_8086}, {"MUL", "DWORD r/m32", "po F7 /4", Instruction::CPU_386}, {"MULPS", "xmmreg,r/m128", "0F 59 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"MULSS", "xmmreg,xmmreg/mem32", "p3 0F 59 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"NEG", "BYTE r/m8", "F6 /3", Instruction::CPU_8086}, {"NEG", "WORD r/m16", "po F7 /3", Instruction::CPU_8086}, {"NEG", "DWORD r/m32", "po F7 /3", Instruction::CPU_386}, {"NOT", "BYTE r/m8", "F6 /2", Instruction::CPU_8086}, {"NOT", "WORD r/m16", "po F7 /2", Instruction::CPU_8086}, {"NOT", "DWORD r/m32", "po F7 /2", Instruction::CPU_386}, {"NOP", "", "90", Instruction::CPU_8086}, {"OR", "r/m8,reg8", "08 /r", Instruction::CPU_8086}, {"OR", "r/m16,reg16", "po 09 /r", Instruction::CPU_8086}, {"OR", "r/m32,reg32", "po 09 /r", Instruction::CPU_386}, {"OR", "reg8,r/m8", "0A /r", Instruction::CPU_8086}, {"OR", "reg16,r/m16", "po 0B /r", Instruction::CPU_8086}, {"OR", "reg32,r/m32", "po 0B /r", Instruction::CPU_386}, {"OR", "r/m8,imm8", "80 /1 ib", Instruction::CPU_8086}, {"OR", "r/m16,imm16", "po 81 /1 iw", Instruction::CPU_8086}, {"OR", "r/m32,imm32", "po 81 /1 id", Instruction::CPU_386}, {"OR", "r/m16,imm8", "po 83 /1 ib", Instruction::CPU_8086}, {"OR", "r/m32,imm8", "po 83 /1 ib", Instruction::CPU_386}, {"OR", "AL,imm8", "0C ib", Instruction::CPU_8086}, {"OR", "AX,imm16", "po 0D iw", Instruction::CPU_8086}, {"OR", "EAX,imm32", "po 0D id", Instruction::CPU_386}, {"ORPS", "xmmreg,r/m128", "0F 56 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"OUT", "imm8,AL", "E6 ib", Instruction::CPU_8086}, {"OUT", "imm8,AX", "po E7 ib", Instruction::CPU_8086}, {"OUT", "imm8,EAX", "po E7 ib", Instruction::CPU_386}, {"OUT", "DX,AL", "EE", Instruction::CPU_8086}, {"OUT", "DX,AX", "po EF", Instruction::CPU_8086}, {"OUT", "DX,EAX", "po EF", Instruction::CPU_386}, {"OUTSB", "", "6E", Instruction::CPU_186}, {"OUTSW", "", "po 6F", Instruction::CPU_186}, {"OUTSD", "", "po 6F", Instruction::CPU_386}, {"PACKSSDW", "mmreg,r/m64", "0F 6B /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PACKSSWB", "mmreg,r/m64", "0F 63 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PACKUSWB", "mmreg,r/m64", "0F 67 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PADDB", "mmreg,r/m64", "0F FC /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PADDW", "mmreg,r/m64", "0F FD /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PADDD", "mmreg,r/m64", "0F FE /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PADDSB", "mmreg,r/m64", "0F EC /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PADDSW", "mmreg,r/m64", "0F ED /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PADDUSB", "mmreg,r/m64", "0F DC /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PADDUSW", "mmreg,r/m64", "0F DD /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PADDSIW", "mmreg,r/m64", "0F 51 /r", Instruction::CPU_CYRIX | Instruction::CPU_MMX}, {"PAND", "mmreg,r/m64", "0F DB /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PANDN", "mmreg,r/m64", "0F DF /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PAVEB", "mmreg,r/m64", "0F 50 /r", Instruction::CPU_CYRIX | Instruction::CPU_MMX}, {"PAVGB", "mmreg,r/m64", "0F E0 /r", Instruction::CPU_KATMAI}, {"PAVGW", "mmreg,r/m64", "0F E3 /r", Instruction::CPU_KATMAI}, {"PAVGUSB", "mmreg,r/m64", "0F 0F /r BF", Instruction::CPU_3DNOW}, {"PCMPEQB", "mmreg,r/m64", "0F 74 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PCMPEQW", "mmreg,r/m64", "0F 75 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PCMPEQD", "mmreg,r/m64", "0F 76 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PCMPGTB", "mmreg,r/m64", "0F 64 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PCMPGTW", "mmreg,r/m64", "0F 65 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PCMPGTD", "mmreg,r/m64", "0F 66 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PDISTIB", "mmreg,mem64", "0F 54 /r", Instruction::CPU_CYRIX | Instruction::CPU_MMX}, {"PEXTRW", "reg32,mmreg,imm8", "0F C5 /r ib", Instruction::CPU_KATMAI}, {"PF2ID", "mmreg,r/m64", "0F 0F /r 1D", Instruction::CPU_3DNOW}, {"PF2IW", "mmreg,r/m64", "0F 0F /r 1C", Instruction::CPU_ATHLON}, {"PFACC", "mmreg,r/m64", "0F 0F /r AE", Instruction::CPU_3DNOW}, {"PFADD", "mmreg,r/m64", "0F 0F /r 9E", Instruction::CPU_3DNOW}, {"PFCMPEQ", "mmreg,r/m64", "0F 0F /r B0", Instruction::CPU_3DNOW}, {"PFCMPGE", "mmreg,r/m64", "0F 0F /r 90", Instruction::CPU_3DNOW}, {"PFCMPGT", "mmreg,r/m64", "0F 0F /r A0", Instruction::CPU_3DNOW}, {"PFMAX", "mmreg,r/m64", "0F 0F /r A4", Instruction::CPU_3DNOW}, {"PFMIN", "mmreg,r/m64", "0F 0F /r 94", Instruction::CPU_3DNOW}, {"PFMUL", "mmreg,r/m64", "0F 0F /r B4", Instruction::CPU_3DNOW}, {"PFNACC", "mmreg,r/m64", "0F 0F /r 8A", Instruction::CPU_ATHLON}, {"PFPNACC", "mmreg,r/m64", "0F 0F /r 8E", Instruction::CPU_ATHLON}, {"PFRCP", "mmreg,r/m64", "0F 0F /r 96", Instruction::CPU_3DNOW}, {"PFRCPIT1", "mmreg,r/m64", "0F 0F /r A6", Instruction::CPU_3DNOW}, {"PFRCPIT2", "mmreg,r/m64", "0F 0F /r B6", Instruction::CPU_3DNOW}, {"PFRSQIT1", "mmreg,r/m64", "0F 0F /r A7", Instruction::CPU_3DNOW}, {"PFRSQRT", "mmreg,r/m64", "0F 0F /r 97", Instruction::CPU_3DNOW}, {"PFSUB", "mmreg,r/m64", "0F 0F /r 9A", Instruction::CPU_3DNOW}, {"PFSUBR", "mmreg,r/m64", "0F 0F /r AA", Instruction::CPU_3DNOW}, {"PI2FD", "mmreg,r/m64", "0F 0F /r 0D", Instruction::CPU_3DNOW}, {"PI2FW", "mmreg,r/m64", "0F 0F /r 0C", Instruction::CPU_ATHLON}, {"PINSRW", "mmreg,r/m16,imm8", "0F C4 /r ib", Instruction::CPU_KATMAI}, {"PMACHRIW", "mmreg,mem64", "0F 5E /r", Instruction::CPU_CYRIX | Instruction::CPU_MMX}, {"PMADDWD", "mmreg,r/m64", "0F F5 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PMAGW", "mmreg,r/m64", "0F 52 /r", Instruction::CPU_CYRIX | Instruction::CPU_MMX}, {"PMAXSW", "mmreg,r/m64", "0F EE /r", Instruction::CPU_KATMAI}, {"PMAXUB", "mmreg,r/m64", "0F DE /r", Instruction::CPU_KATMAI}, {"PMINSW", "mmreg,r/m64", "0F EA /r", Instruction::CPU_KATMAI}, {"PMINUB", "mmreg,r/m64", "0F DA /r", Instruction::CPU_KATMAI}, {"PMOVMSKB", "reg32,mmreg", "0F D7 /r", Instruction::CPU_KATMAI}, {"PMULHRWA", "mmreg,r/m64", "0F 0F /r B7", Instruction::CPU_3DNOW}, {"PMULHRWC", "mmreg,r/m64", "0F 59 /r", Instruction::CPU_CYRIX | Instruction::CPU_MMX}, {"PMULHRIW", "mmreg,r/m64", "0F 5D /r", Instruction::CPU_CYRIX | Instruction::CPU_MMX}, {"PMULHUW", "mmreg,r/m64", "0F E4 /r", Instruction::CPU_KATMAI}, {"PMULHW", "mmreg,r/m64", "0F E5 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PMULLW", "mmreg,r/m64", "0F D5 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PMVZB", "mmreg,mem64", "0F 58 /r", Instruction::CPU_CYRIX | Instruction::CPU_MMX}, {"PMVNZB", "mmreg,mem64", "0F 5A /r", Instruction::CPU_CYRIX | Instruction::CPU_MMX}, {"PMVLZB", "mmreg,mem64", "0F 5B /r", Instruction::CPU_CYRIX | Instruction::CPU_MMX}, {"PMVGEZB", "mmreg,mem64", "0F 5C /r", Instruction::CPU_CYRIX | Instruction::CPU_MMX}, {"POP", "reg16", "po 58 +r", Instruction::CPU_8086}, {"POP", "reg32", "po 58 +r", Instruction::CPU_386}, {"POP", "WORD r/m16", "po 8F /0", Instruction::CPU_8086}, {"POP", "DWORD r/m32", "po 8F /0", Instruction::CPU_386}, // {"POP", "CS", "0F", Instruction::CPU_8086 | Instruction::CPU_UNDOC}, // {"POP", "DS", "1F", Instruction::CPU_8086}, // {"POP", "ES", "07", Instruction::CPU_8086}, // {"POP", "SS", "17", Instruction::CPU_8086}, // {"POP", "FS", "0F A1", Instruction::CPU_386}, // {"POP", "GS", "0F A9", Instruction::CPU_386}, {"POPA", "", "61", Instruction::CPU_186}, {"POPAW", "", "po 61", Instruction::CPU_186}, {"POPAD", "", "po 61", Instruction::CPU_386}, {"POPF", "", "9D", Instruction::CPU_186}, {"POPFW", "", "po 9D", Instruction::CPU_186}, {"POPFD", "", "po 9D", Instruction::CPU_386}, {"POR", "mmreg,r/m64", "0F EB /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PREFETCH", "mem", "0F 0D /0", Instruction::CPU_3DNOW}, {"PREFETCHW", "mem", "0F 0D /1", Instruction::CPU_3DNOW}, {"PREFETCHNTA", "mem", "0F 18 /0", Instruction::CPU_KATMAI}, {"PREFETCHT0", "mem", "0F 18 /1", Instruction::CPU_KATMAI}, {"PREFETCHT1", "mem", "0F 18 /2", Instruction::CPU_KATMAI}, {"PREFETCHT2", "mem", "0F 18 /3", Instruction::CPU_KATMAI}, {"PSADBW", "mmreg,r/m64", "0F F6 /r", Instruction::CPU_KATMAI}, {"PSHUFW", "mmreg,r/m64,imm8", "0F 70 /r ib", Instruction::CPU_KATMAI}, {"PSLLW", "mmreg,r/m64", "0F F1 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PSLLW", "mmreg,imm8", "0F 71 /6 ib", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PSLLD", "mmreg,r/m64", "0F F2 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PSLLD", "mmreg,imm8", "0F 72 /6 ib", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PSLLQ", "mmreg,r/m64", "0F F3 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PSLLQ", "mmreg,imm8", "0F 73 /6 ib", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PSRAW", "mmreg,r/m64", "0F E1 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PSRAW", "mmreg,imm8", "0F 71 /4 ib", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PSRAD", "mmreg,r/m64", "0F E2 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PSRAD", "mmreg,imm8", "0F 72 /4 ib", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PSRLW", "mmreg,r/m64", "0F D1 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PSRLW", "mmreg,imm8", "0F 71 /2 ib", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PSRLD", "mmreg,r/m64", "0F D2 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PSRLD", "mmreg,imm8", "0F 72 /2 ib", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PSRLQ", "mmreg,r/m64", "0F D3 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PSRLQ", "mmreg,imm8", "0F 73 /2 ib", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PSUBB", "mmreg,r/m64", "0F F8 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PSUBW", "mmreg,r/m64", "0F F9 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PSUBD", "mmreg,r/m64", "0F FA /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PSUBSB", "mmreg,r/m64", "0F E8 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PSUBSW", "mmreg,r/m64", "0F E9 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PSUBUSB", "mmreg,r/m64", "0F D8 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PSUBUSW", "mmreg,r/m64", "0F D9 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PSUBSIW", "mmreg,r/m64", "0F 55 /r", Instruction::CPU_CYRIX | Instruction::CPU_MMX}, {"PSWAPD", "mmreg,r/m64", "0F 0F /r BB", Instruction::CPU_ATHLON}, {"PUNPCKHBW", "mmreg,r/m64", "0F 68 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PUNPCKHWD", "mmreg,r/m64", "0F 69 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PUNPCKHDQ", "mmreg,r/m64", "0F 6A /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PUNPCKLBW", "mmreg,r/m64", "0F 60 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PUNPCKLWD", "mmreg,r/m64", "0F 61 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PUNPCKLDQ", "mmreg,r/m64", "0F 62 /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"PUSH", "reg16", "po 50 +r", Instruction::CPU_8086}, {"PUSH", "reg32", "po 50 +r", Instruction::CPU_386}, {"PUSH", "WORD r/m16", "po FF /6", Instruction::CPU_8086}, {"PUSH", "DWORD r/m32", "po FF /6", Instruction::CPU_386}, // {"PUSH", "CS", "0E", Instruction::CPU_8086}, // {"PUSH", "DS", "1E", Instruction::CPU_8086}, // {"PUSH", "ES", "06", Instruction::CPU_8086}, // {"PUSH", "SS", "16", Instruction::CPU_8086}, // {"PUSH", "FS", "0F A0", Instruction::CPU_386}, // {"PUSH", "GS", "0F A8", Instruction::CPU_386}, {"PUSH", "imm8", "6A ib", Instruction::CPU_286}, {"PUSH", "imm16", "po 68 iw", Instruction::CPU_286}, {"PUSH", "imm32", "po 68 id", Instruction::CPU_386}, {"PUSHA", "", "60", Instruction::CPU_186}, {"PUSHAD", "", "po 60", Instruction::CPU_386}, {"PUSHAW", "", "po 60", Instruction::CPU_186}, {"PUSHF", "", "9C", Instruction::CPU_186}, {"PUSHFD", "", "po 9C", Instruction::CPU_386}, {"PUSHFW", "", "po 9C", Instruction::CPU_186}, {"PXOR", "mmreg,r/m64", "0F EF /r", Instruction::CPU_PENT | Instruction::CPU_MMX}, {"RCL", "r/m8,1", "D0 /2", Instruction::CPU_8086}, {"RCL", "r/m8,CL", "D2 /2", Instruction::CPU_8086}, {"RCL", "r/m8,imm8", "C0 /2 ib", Instruction::CPU_286}, {"RCL", "r/m16,1", "po D1 /2", Instruction::CPU_8086}, {"RCL", "r/m16,CL", "po D3 /2", Instruction::CPU_8086}, {"RCL", "r/m16,imm8", "po C1 /2 ib", Instruction::CPU_286}, {"RCL", "r/m32,1", "po D1 /2", Instruction::CPU_386}, {"RCL", "r/m32,CL", "po D3 /2", Instruction::CPU_386}, {"RCL", "r/m32,imm8", "po C1 /2 ib", Instruction::CPU_386}, {"RCR", "r/m8,1", "D0 /3", Instruction::CPU_8086}, {"RCR", "r/m8,CL", "D2 /3", Instruction::CPU_8086}, {"RCR", "r/m8,imm8", "C0 /3 ib", Instruction::CPU_286}, {"RCR", "r/m16,1", "po D1 /3", Instruction::CPU_8086}, {"RCR", "r/m16,CL", "po D3 /3", Instruction::CPU_8086}, {"RCR", "r/m16,imm8", "po C1 /3 ib", Instruction::CPU_286}, {"RCR", "r/m32,1", "po D1 /3", Instruction::CPU_386}, {"RCR", "r/m32,CL", "po D3 /3", Instruction::CPU_386}, {"RCR", "r/m32,imm8", "po C1 /3 ib", Instruction::CPU_386}, {"RCPPS", "xmmreg,r/m128", "0F 53 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"RCPSS", "xmmreg,xmmreg/mem32", "p3 0F 53 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"RDMSR", "", "0F 32", Instruction::CPU_PENT}, {"RDPMC", "", "0F 33", Instruction::CPU_P6}, // {"RDSHR", "", "0F 36", Instruction::CPU_P6 | Instruction::CPU_CYRIX | Instruction::CPU_SMM}, {"RDTSC", "", "0F 31", Instruction::CPU_PENT}, {"RET", "", "C3", Instruction::CPU_8086}, {"RET", "imm16", "C2 iw", Instruction::CPU_8086}, {"RETF", "", "CB", Instruction::CPU_8086}, {"RETF", "imm16", "CA iw", Instruction::CPU_8086}, {"RETN", "", "C3", Instruction::CPU_8086}, {"RETN", "imm16", "C2 iw", Instruction::CPU_8086}, {"ROL", "r/m8,1", "D0 /0", Instruction::CPU_8086}, {"ROL", "r/m8,CL", "D2 /0", Instruction::CPU_8086}, {"ROL", "r/m8,imm8", "C0 /0 ib", Instruction::CPU_286}, {"ROL", "r/m16,1", "po D1 /0", Instruction::CPU_8086}, {"ROL", "r/m16,CL", "po D3 /0", Instruction::CPU_8086}, {"ROL", "r/m16,imm8", "po C1 /0 ib", Instruction::CPU_286}, {"ROL", "r/m32,1", "po D1 /0", Instruction::CPU_386}, {"ROL", "r/m32,CL", "po D3 /0", Instruction::CPU_386}, {"ROL", "r/m32,imm8", "po C1 /0 ib", Instruction::CPU_386}, {"ROR", "r/m8,1", "D0 /1", Instruction::CPU_8086}, {"ROR", "r/m8,CL", "D2 /1", Instruction::CPU_8086}, {"ROR", "r/m8,imm8", "C0 /1 ib", Instruction::CPU_286}, {"ROR", "r/m16,1", "po D1 /1", Instruction::CPU_8086}, {"ROR", "r/m16,CL", "po D3 /1", Instruction::CPU_8086}, {"ROR", "r/m16,imm8", "po C1 /1 ib", Instruction::CPU_286}, {"ROR", "r/m32,1", "po D1 /1", Instruction::CPU_386}, {"ROR", "r/m32,CL", "po D3 /1", Instruction::CPU_386}, {"ROR", "r/m32,imm8", "po C1 /1 ib", Instruction::CPU_386}, // {"RSDC", "segreg,mem80", "0F 79 /r", Instruction::CPU_486 | Instruction::CPU_CYRIX | Instruction::CPU_SMM}, // {"RSLDT", "mem80", "0F 7B /0", Instruction::CPU_486 | Instruction::CPU_CYRIX | Instruction::CPU_SMM}, {"RSM", "", "0F AA", Instruction::CPU_PENT}, {"RSQRTPS", "xmmreg,r/m128", "0F 52 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"RSQRTSS", "xmmreg,r/m128", "p3 0F 52 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, // {"RSTS", "mem80", "0F 7D /0", Instruction::CPU_486 | Instruction::CPU_CYRIX | Instruction::CPU_SMM}, {"SAHF", "", "9E", Instruction::CPU_8086}, {"SAL", "r/m8,1", "D0 /4", Instruction::CPU_8086}, {"SAL", "r/m8,CL", "D2 /4", Instruction::CPU_8086}, {"SAL", "r/m8,imm8", "C0 /4 ib", Instruction::CPU_286}, {"SAL", "r/m16,1", "po D1 /4", Instruction::CPU_8086}, {"SAL", "r/m16,CL", "po D3 /4", Instruction::CPU_8086}, {"SAL", "r/m16,imm8", "po C1 /4 ib", Instruction::CPU_286}, {"SAL", "r/m32,1", "po D1 /4", Instruction::CPU_386}, {"SAL", "r/m32,CL", "po D3 /4", Instruction::CPU_386}, {"SAL", "r/m32,imm8", "po C1 /4 ib", Instruction::CPU_386}, {"SAR", "r/m8,1", "D0 /7", Instruction::CPU_8086}, {"SAR", "r/m8,CL", "D2 /7", Instruction::CPU_8086}, {"SAR", "r/m8,imm8", "C0 /7 ib", Instruction::CPU_286}, {"SAR", "r/m16,1", "po D1 /7", Instruction::CPU_8086}, {"SAR", "r/m16,CL", "po D3 /7", Instruction::CPU_8086}, {"SAR", "r/m16,imm8", "po C1 /7 ib", Instruction::CPU_286}, {"SAR", "r/m32,1", "po D1 /7", Instruction::CPU_386}, {"SAR", "r/m32,CL", "po D3 /7", Instruction::CPU_386}, {"SAR", "r/m32,imm8", "po C1 /7 ib", Instruction::CPU_386}, // {"SALC", "", "D6", Instruction::CPU_8086 | Instruction::CPU_UNDOC}, {"SBB", "r/m8,reg8", "18 /r", Instruction::CPU_8086}, {"SBB", "r/m16,reg16", "po 19 /r", Instruction::CPU_8086}, {"SBB", "r/m32,reg32", "po 19 /r", Instruction::CPU_386}, {"SBB", "reg8,r/m8", "1A /r", Instruction::CPU_8086}, {"SBB", "reg16,r/m16", "po 1B /r", Instruction::CPU_8086}, {"SBB", "reg32,r/m32", "po 1B /r", Instruction::CPU_386}, {"SBB", "r/m8,imm8", "80 /3 ib", Instruction::CPU_8086}, {"SBB", "r/m16,imm16", "po 81 /3 iw", Instruction::CPU_8086}, {"SBB", "r/m32,imm32", "po 81 /3 id", Instruction::CPU_386}, {"SBB", "r/m16,imm8", "po 83 /3 ib", Instruction::CPU_8086}, {"SBB", "r/m32,imm8", "po 83 /3 ib", Instruction::CPU_8086}, {"SBB", "AL,imm8", "1C ib", Instruction::CPU_8086}, {"SBB", "AX,imm16", "po 1D iw", Instruction::CPU_8086}, {"SBB", "EAX,imm32", "po 1D id", Instruction::CPU_386}, {"SCASB", "", "AE", Instruction::CPU_8086}, {"SCASW", "", "po AF", Instruction::CPU_8086}, {"SCASD", "", "po AF", Instruction::CPU_386}, {"SETO", "BYTE r/m8", "0F 90 /2", Instruction::CPU_386}, {"SETNO", "BYTE r/m8", "0F 91 /2", Instruction::CPU_386}, {"SETB", "BYTE r/m8", "0F 92 /2", Instruction::CPU_386}, {"SETC", "BYTE r/m8", "0F 92 /2", Instruction::CPU_386}, {"SETNEA", "BYTE r/m8", "0F 92 /2", Instruction::CPU_386}, {"SETAE", "BYTE r/m8", "0F 93 /2", Instruction::CPU_386}, {"SETNB", "BYTE r/m8", "0F 93 /2", Instruction::CPU_386}, {"SETNC", "BYTE r/m8", "0F 93 /2", Instruction::CPU_386}, {"SETE", "BYTE r/m8", "0F 94 /2", Instruction::CPU_386}, {"SETZ", "BYTE r/m8", "0F 94 /2", Instruction::CPU_386}, {"SETNE", "BYTE r/m8", "0F 95 /2", Instruction::CPU_386}, {"SETNZ", "BYTE r/m8", "0F 95 /2", Instruction::CPU_386}, {"SETBE", "BYTE r/m8", "0F 96 /2", Instruction::CPU_386}, {"SETNA", "BYTE r/m8", "0F 96 /2", Instruction::CPU_386}, {"SETA", "BYTE r/m8", "0F 97 /2", Instruction::CPU_386}, {"SETNBE", "BYTE r/m8", "0F 97 /2", Instruction::CPU_386}, {"SETS", "BYTE r/m8", "0F 98 /2", Instruction::CPU_386}, {"SETNS", "BYTE r/m8", "0F 99 /2", Instruction::CPU_386}, {"SETP", "BYTE r/m8", "0F 9A /2", Instruction::CPU_386}, {"SETPE", "BYTE r/m8", "0F 9A /2", Instruction::CPU_386}, {"SETNP", "BYTE r/m8", "0F 9B /2", Instruction::CPU_386}, {"SETPO", "BYTE r/m8", "0F 9B /2", Instruction::CPU_386}, {"SETL", "BYTE r/m8", "0F 9C /2", Instruction::CPU_386}, {"SETNGE", "BYTE r/m8", "0F 9C /2", Instruction::CPU_386}, {"SETGE", "BYTE r/m8", "0F 9D /2", Instruction::CPU_386}, {"SETNL", "BYTE r/m8", "0F 9D /2", Instruction::CPU_386}, {"SETLE", "BYTE r/m8", "0F 9E /2", Instruction::CPU_386}, {"SETNG", "BYTE r/m8", "0F 9E /2", Instruction::CPU_386}, {"SETG", "BYTE r/m8", "0F 9F /2", Instruction::CPU_386}, {"SETNLE", "BYTE r/m8", "0F 9F /2", Instruction::CPU_386}, {"SFENCE", "", "0F AE /7", Instruction::CPU_KATMAI}, // {"SGDT", "mem", "0F 01 /0", Instruction::CPU_286 | Instruction::CPU_PRIV}, // {"SIDT", "mem", "0F 01 /1", Instruction::CPU_286 | Instruction::CPU_PRIV}, // {"SLDT", "r/m16", "0F 00 /0", Instruction::CPU_286 | Instruction::CPU_PRIV}, {"SHL", "BYTE r/m8,1", "D0 /4", Instruction::CPU_8086}, {"SHL", "BYTE r/m8,CL", "D2 /4", Instruction::CPU_8086}, {"SHL", "BYTE r/m8,imm8", "C0 /4 ib", Instruction::CPU_286}, {"SHL", "WORD r/m16,1", "po D1 /4", Instruction::CPU_8086}, {"SHL", "WORD r/m16,CL", "po D3 /4", Instruction::CPU_8086}, {"SHL", "WORD r/m16,imm8", "po C1 /4 ib", Instruction::CPU_286}, {"SHL", "DWORD r/m32,1", "po D1 /4", Instruction::CPU_386}, {"SHL", "DWORD r/m32,CL", "po D3 /4", Instruction::CPU_386}, {"SHL", "DWORD r/m32,imm8", "po C1 /4 ib", Instruction::CPU_386}, {"SHR", "BYTE r/m8,1", "D0 /5", Instruction::CPU_8086}, {"SHR", "BYTE r/m8,CL", "D2 /5", Instruction::CPU_8086}, {"SHR", "BYTE r/m8,imm8", "C0 /5 ib", Instruction::CPU_286}, {"SHR", "WORD r/m16,1", "po D1 /5", Instruction::CPU_8086}, {"SHR", "WORD r/m16,CL", "po D3 /5", Instruction::CPU_8086}, {"SHR", "WORD r/m16,imm8", "po C1 /5 ib", Instruction::CPU_286}, {"SHR", "DWORD r/m32,1", "po D1 /5", Instruction::CPU_386}, {"SHR", "DWORD r/m32,CL", "po D3 /5", Instruction::CPU_386}, {"SHR", "DWORD r/m32,imm8", "po C1 /5 ib", Instruction::CPU_386}, {"SHLD", "WORD r/m16,reg16,imm8", "po 0F A4 /r ib", Instruction::CPU_386}, {"SHLD", "DWORD r/m32,reg32,imm8", "po 0F A4 /r ib", Instruction::CPU_386}, {"SHLD", "WORD r/m16,reg16,CL", "po 0F A5 /r", Instruction::CPU_386}, {"SHLD", "DWORD r/m32,reg32,CL", "po 0F A5 /r", Instruction::CPU_386}, {"SHRD", "WORD r/m16,reg16,imm8", "po 0F AC /r ib", Instruction::CPU_386}, {"SHRD", "DWORD r/m32,reg32,imm8", "po 0F AC /r ib", Instruction::CPU_386}, {"SHRD", "WORD r/m16,reg16,CL", "po 0F AD /r", Instruction::CPU_386}, {"SHRD", "DWORD r/m32,reg32,CL", "po 0F AD /r", Instruction::CPU_386}, {"SHUFPS", "xmmreg,r/m128,imm8", "0F C6 /r ib", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, // {"SMI", "", "F1", Instruction::CPU_386 | Instruction::CPU_UNDOC}, {"SMINT", "", "0F 38", Instruction::CPU_P6 | Instruction::CPU_CYRIX}, {"SMINTOLD", "", "0F 7E", Instruction::CPU_486 | Instruction::CPU_CYRIX}, // {"SMSW", "r/m16", "0F 01 /4", Instruction::CPU_286 | Instruction::CPU_PRIV}, {"SQRTPS", "xmmreg,r/m128", "0F 51 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"SQRTSS", "xmmreg,xmmreg/mem32", "p3 0F 51 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"STC", "", "F9", Instruction::CPU_8086}, {"STD", "", "FD", Instruction::CPU_8086}, {"STI", "", "FB", Instruction::CPU_8086}, {"STMXCSR", "mem32", "0F AE /3", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"STOSB", "", "AA", Instruction::CPU_8086}, {"STOSW", "", "po AB", Instruction::CPU_8086}, {"STOSD", "", "po AB", Instruction::CPU_386}, // {"STR", "r/m16", "0F 00 /1", Instruction::CPU_286 | Instruction::CPU_PRIV}, {"SUB", "r/m8,reg8", "28 /r", Instruction::CPU_8086}, {"SUB", "r/m16,reg16", "po 29 /r", Instruction::CPU_8086}, {"SUB", "r/m32,reg32", "po 29 /r", Instruction::CPU_386}, {"SUB", "reg8,r/m8", "2A /r", Instruction::CPU_8086}, {"SUB", "reg16,r/m16", "po 2B /r", Instruction::CPU_8086}, {"SUB", "reg32,r/m32", "po 2B /r", Instruction::CPU_386}, {"SUB", "r/m8,imm8", "80 /5 ib", Instruction::CPU_8086}, {"SUB", "r/m16,imm16", "po 81 /5 iw", Instruction::CPU_8086}, {"SUB", "r/m32,imm32", "po 81 /5 id", Instruction::CPU_386}, {"SUB", "r/m16,imm8", "po 83 /5 ib", Instruction::CPU_8086}, {"SUB", "r/m32,imm8", "po 83 /5 ib", Instruction::CPU_386}, {"SUB", "AL,imm8", "2C ib", Instruction::CPU_8086}, {"SUB", "AX,imm16", "po 2D iw", Instruction::CPU_8086}, {"SUB", "EAX,imm32", "po 2D id", Instruction::CPU_386}, {"SUBPS", "xmmreg,r/m128", "0F 5C /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"SUBSS", "xmmreg,xmmreg/mem32", "p3 0F 5C /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, // {"SVDC", "mem80,segreg", "0F 78 /r", Instruction::CPU_486 | Instruction::CPU_CYRIX | Instruction::CPU_SMM}, // {"SVLDT", "mem80", "0F 7A /0", Instruction::CPU_486 | Instruction::CPU_CYRIX | Instruction::CPU_SMM}, // {"SVTS", "mem80", "0F 7C /0", Instruction::CPU_486 | Instruction::CPU_CYRIX | Instruction::CPU_SMM}, // {"SYSCALL", "", "0F 05", Instruction::CPU_P6 | Instruction::CPU_AMD}, {"SYSENTER", "", "0F 34", Instruction::CPU_P6}, // {"SYSEXIT", "", "0F 36", Instruction::CPU_P6 | Instruction::CPU_PRIV}, // {"SYSRET", "", "0F 07", Instruction::CPU_P6 | Instruction::CPU_AMD | Instruction::CPU_PRIV}, {"TEST", "r/m8,reg8", "84 /r", Instruction::CPU_8086}, {"TEST", "r/m16,reg16", "po 85 /r", Instruction::CPU_8086}, {"TEST", "r/m32,reg32", "po 85 /r", Instruction::CPU_386}, {"TEST", "r/m8,imm8", "F6 /7 ib", Instruction::CPU_8086}, {"TEST", "r/m16,imm16", "po F7 /7 iw", Instruction::CPU_8086}, {"TEST", "r/m32,imm32", "po F7 /7 id", Instruction::CPU_386}, {"TEST", "AL,imm8", "A8 ib", Instruction::CPU_8086}, {"TEST", "AX,imm16", "po A9 iw", Instruction::CPU_8086}, {"TEST", "EAX,imm32", "po A9 id", Instruction::CPU_386}, {"UCOMISS", "xmmreg,xmmreg/mem32", "0F 2E /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"UD2", "", "0F 0B", Instruction::CPU_286}, // {"UMOV", "r/m8,reg8", "0F 10 /r", Instruction::CPU_386 | Instruction::CPU_UNDOC}, // {"UMOV", "r/m16,reg16", "po 0F 11 /r", Instruction::CPU_386 | Instruction::CPU_UNDOC}, // {"UMOV", "r/m32,reg32", "po 0F 11 /r", Instruction::CPU_386 | Instruction::CPU_UNDOC}, // {"UMOV", "reg8,r/m8", "0F 12 /r", Instruction::CPU_386 | Instruction::CPU_UNDOC}, // {"UMOV", "reg16,r/m16", "po 0F 13 /r", Instruction::CPU_386 | Instruction::CPU_UNDOC}, // {"UMOV", "reg32,r/m32", "po 0F 13 /r", Instruction::CPU_386 | Instruction::CPU_UNDOC}, {"UNPCKHPS", "xmmreg,r/m128", "0F 15 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, {"UNPCKLPS", "xmmreg,r/m128", "0F 14 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE}, // {"VERR", "r/m16", "0F 00 /4", Instruction::CPU_286 | Instruction::CPU_PRIV}, // {"VERW", "r/m16", "0F 00 /5", Instruction::CPU_286 | Instruction::CPU_PRIV}, {"WAIT", "", "9B", Instruction::CPU_8086}, {"WBINVD", "", "0F 09", Instruction::CPU_486}, {"WRMSR", "", "0F 30", Instruction::CPU_PENT}, // {"WRSHR", "", "0F 37", Instruction::CPU_P6 | Instruction::CPU_CYRIX | Instruction::CPU_SMM}, {"XADD", "r/m8,reg8", "0F C0 /r", Instruction::CPU_486}, {"XADD", "r/m16,reg16", "po 0F C1 /r", Instruction::CPU_486}, {"XADD", "r/m32,reg32", "po 0F C1 /r", Instruction::CPU_486}, // {"XBTS", "reg16,r/m16", "po 0F A6 /r", Instruction::CPU_386 | Instruction::CPU_UNDOC}, // {"XBTS", "reg32,r/m32", "po 0F A6 /r", Instruction::CPU_386 | Instruction::CPU_UNDOC}, {"XCHG", "reg8,r/m8", "86 /r", Instruction::CPU_8086}, {"XCHG", "reg16,r/m8", "po 87 /r", Instruction::CPU_8086}, {"XCHG", "reg32,r/m32", "po 87 /r", Instruction::CPU_386}, {"XCHG", "r/m8,reg8", "86 /r", Instruction::CPU_8086}, {"XCHG", "r/m16,reg16", "po 87 /r", Instruction::CPU_8086}, {"XCHG", "r/m32,reg32", "po 87 /r", Instruction::CPU_386}, {"XCHG", "AX,reg16", "po 90 +r", Instruction::CPU_8086}, {"XCHG", "EAX,reg32", "po 90 +r", Instruction::CPU_386}, {"XCHG", "reg16,AX", "po 90 +r", Instruction::CPU_8086}, {"XCHG", "reg32,EAX", "po 90 +r", Instruction::CPU_386}, {"XLATB", "", "D7", Instruction::CPU_8086}, {"XOR", "r/m8,reg8", "30 /r", Instruction::CPU_8086}, {"XOR", "r/m16,reg16", "po 31 /r", Instruction::CPU_8086}, {"XOR", "r/m32,reg32", "po 31 /r", Instruction::CPU_386}, {"XOR", "reg8,r/m8", "32 /r", Instruction::CPU_8086}, {"XOR", "reg16,r/m16", "po 33 /r", Instruction::CPU_8086}, {"XOR", "reg32,r/m32", "po 33 /r", Instruction::CPU_386}, {"XOR", "r/m8,imm8", "80 /6 ib", Instruction::CPU_8086}, {"XOR", "r/m16,imm16", "po 81 /6 iw", Instruction::CPU_8086}, {"XOR", "r/m32,imm32", "po 81 /6 id", Instruction::CPU_386}, {"XOR", "r/m16,imm8", "po 83 /6 ib", Instruction::CPU_8086}, {"XOR", "r/m32,imm8", "po 83 /6 ib", Instruction::CPU_386}, {"XOR", "AL,imm8", "34 ib", Instruction::CPU_8086}, {"XOR", "AX,imm16", "po 35 iw", Instruction::CPU_8086}, {"XOR", "EAX,imm32", "po 35 id", Instruction::CPU_386}, {"XORPS", "xmmreg,r/m128", "0F 57 /r", Instruction::CPU_KATMAI | Instruction::CPU_SSE} };

int InstructionSet::numInstructions() { return sizeof(instructionSet) / sizeof(Instruction::Syntax); }

int InstructionSet::numMnemonics() { static int num = 0;

if(!num) { if(numInstructions != 0) { num = 1; }

for(int i = 0; i + 1 < numInstructions(); i++) { if(stricmp(instructionSet[i].mnemonic, instructionSet[i + 1].mnemonic) != 0) { num++; } } }

return num; } }

Currently browsing [SoftWire.zip] (112,805 bytes) - [Keywords.cpp] - (4,540 bytes)

#include "Keywords.hpp"

#include <string.h>

namespace SoftWire { const Specifier Specifier::specifierSet[] = { {UNKNOWN, ""},

{NEAR, "NEAR"}, {SHORT, "SHORT"}, // {FAR, "FAR"}, {BYTE, "BYTE"}, {WORD, "WORD"}, {DWORD, "DWORD"}, {QWORD, "QWORD"}, {MMWORD, "MMWORD"}, {XMMWORD, "XMMWORD"} };

Specifier::Type Specifier::scan(const char *string) { if(string) { for(int i = 0; i < sizeof(specifierSet) / sizeof(Specifier); i++) { if(stricmp(string, specifierSet[i].notation) == 0) { return specifierSet[i].type; } } }

return UNKNOWN; }

bool Operand::isSubtypeOf(Type baseType) const { return (type & baseType) == type; }

bool Operand::isVoid(Type type) { return type == VOID; }

bool Operand::isImm(Type type) { return (type & IMM) == type; }

bool Operand::isReg(Type type) { return (type & REG) == type; }

bool Operand::isMem(Type type) { return (type & MEM) == type; }

bool Operand::isR_M(Type type) { return (type & R_M) == type; }

bool Operand::isVoid(const Operand &operand) { return isVoid(operand.type); }

bool Operand::isImm(const Operand &operand) { return isImm(operand.type); }

bool Operand::isReg(const Operand &operand) { return isReg(operand.type); }

bool Operand::isMem(const Operand &operand) { return isMem(operand.type); }

bool Operand::isR_M(const Operand &operand) { return isR_M(operand.type); }

const Operand Operand::registerSet[] = { {VOID, ""},

{AL, "AL", 0}, {CL, "CL", 1}, {REG8, "DL", 2}, {REG8, "BL", 3}, {REG8, "AH", 4}, {REG8, "CH", 5}, {REG8, "DH", 6}, {REG8, "BH", 7},

{AX, "AX", 0}, {CX, "CX", 1}, {DX, "DX", 2}, {REG16, "BX", 3}, {REG16, "SP", 4}, {REG16, "BP", 5}, {REG16, "SI", 6}, {REG16, "DI", 7},

{EAX, "EAX", 0}, {ECX, "ECX", 1}, {REG32, "EDX", 2}, {REG32, "EBX", 3}, {REG32, "ESP", 4}, {REG32, "EBP", 5}, {REG32, "ESI", 6}, {REG32, "EDI", 7},

{ES, "ES", 0}, {CS, "CS", 1}, {SS, "SS", 2}, {DS, "DS", 3}, {FS, "FS", 4}, {GS, "GS", 5},

{ST0, "ST0", 0}, {FPUREG, "ST1", 1}, {FPUREG, "ST2", 2}, {FPUREG, "ST3", 3}, {FPUREG, "ST4", 4}, {FPUREG, "ST5", 5}, {FPUREG, "ST6", 6}, {FPUREG, "ST7", 7},

{MMREG, "MM0", 0}, {MMREG, "MM1", 1}, {MMREG, "MM2", 2}, {MMREG, "MM3", 3}, {MMREG, "MM4", 4}, {MMREG, "MM5", 5}, {MMREG, "MM6", 6}, {MMREG, "MM7", 7},

{XMMREG, "XMM0", 0}, {XMMREG, "XMM1", 1}, {XMMREG, "XMM2", 2}, {XMMREG, "XMM3", 3}, {XMMREG, "XMM4", 4}, {XMMREG, "XMM5", 5}, {XMMREG, "XMM6", 6}, {XMMREG, "XMM7", 7} };

Operand Operand::scanReg(const char *string) { if(string) { for(int i = 0; i < sizeof(registerSet) / sizeof(Operand); i++) { if(stricmp(string, registerSet[i].notation) == 0) { return registerSet[i]; } } }

return NOT_FOUND; }

const Operand Operand::syntaxSet[] = { {VOID, ""},

{ONE, "1"}, {IMM, "imm"}, {IMM8, "imm8"}, {IMM16, "imm16"}, {IMM32, "imm32"},

{AL, "AL"}, {AX, "AX"}, {EAX, "EAX"}, {DX, "DX"}, {CL, "CL"}, {CX, "CX"}, {ECX, "ECX"}, {CS, "CS"}, {DS, "DS"}, {ES, "ES"}, {SS, "SS"}, {FS, "FS"}, {GS, "GS"}, {ST0, "ST0"},

{REG8, "reg8"}, {REG16, "reg16"}, {REG32, "reg32"}, {SEGREG, "segreg"}, {FPUREG, "fpureg"}, {CR, "CR0/2/3/4"}, {DR, "DR0/1/2/3/6/7"}, {TR, "TR3/4/5/6/7"}, {MMREG, "mmreg"}, {XMMREG, "xmmreg"},

{MEM, "mem"}, {MEM8, "mem8"}, {MEM16, "mem16"}, {MEM32, "mem32"}, {MEM64, "mem64"}, {MEM80, "mem80"}, {MEM128, "mem128"},

{R_M8, "r/m8"}, {R_M16, "r/m16"}, {R_M32, "r/m32"}, {R_M64, "r/m64"}, {R_M128, "r/m128"},

{XMM32, "xmmreg/mem32"}, {XMM32, "xmmreg/mem64"}, {M512B, "m512byte"},

{MOFF8, "memoffs8"}, {MOFF16, "memoffs16"}, {MOFF32, "memoffs32"} };

Operand::Type Operand::scanSyntax(const char *string) { if(string) { for(int i = 0; i < sizeof(registerSet) / sizeof(Operand); i++) { if(stricmp(string, syntaxSet[i].notation) == 0) { return syntaxSet[i].type; } } }

return UNKNOWN; }

const Operand Operand::INIT = {Operand::VOID}; const Operand Operand::NOT_FOUND = {Operand::UNKNOWN}; }

Currently browsing [SoftWire.zip] (112,805 bytes) - [Loader.cpp] - (1,988 bytes)

#include "Loader.hpp"

#include "Encoding.hpp" #include "Error.hpp"

#include <string.h> #include <stdio.h>

namespace SoftWire { Loader::Link::Link() { next = 0; }

Loader::Link::~Link() { delete next; }

void Loader::Link::attachNew(const Encoding &encoding) { if(next) { next->attachNew(encoding); } else { this->encoding = encoding;

next = new Link(); } }

Loader::Loader() { objectCode = 0; entry = 0; }

Loader::~Loader() { delete[] objectCode; delete entry; }

const void *Loader::callable() { if(!objectCode) { loadCode(); }

if(!objectCode) { throw Error::INTERNAL; }

return objectCode; }

void Loader::addEncoding(const Encoding &encoding) { if(!entry) { entry = new Link(); }

entry->attachNew(encoding); }

void Loader::loadCode() { int length = codeLength();

objectCode = new byte[length]; byte *code = objectCode;

Link *link = entry;

while(link) { if(link->encoding.getReference()) { int offset = resolveLabel(link->encoding.getReference()) - code - link->encoding.length(); link->encoding.setJumpOffset(offset); }

code += link->encoding.writeCode(code);

link = link->next; }

#ifndef NDEBUG printf("\n"); #endif }

byte *Loader::resolveLabel(const char *label) const { int offset = 0; const Link *link = entry;

while(link) { if(link->encoding.getLabel() && strcmp(link->encoding.getLabel(), label) == 0) { return objectCode + offset; } else { offset += link->encoding.length(); }

link = link->next; }

throw Error("Undefined label '%s'", label);

return 0; }

int Loader::codeLength() const { const Link *link = entry; int length = 0;

while(link) { length += link->encoding.length();

link = link->next; } return length; } }

Currently browsing [SoftWire.zip] (112,805 bytes) - [Parser.cpp] - (8,750 bytes)

#include "Parser.hpp"

#include "Token.hpp" #include "InstructionSet.hpp" #include "Instruction.hpp" #include "Keywords.hpp" #include "Error.hpp"

#include <assert.h> #include <stdio.h> #include <string.h>

namespace SoftWire { const InstructionSet Parser::instructionSet;

Parser::Parser() { }

Parser::~Parser() { }

const Encoding &Parser::parseLine(const char *sourceLine) { if(!sourceLine) { throw Error::INTERNAL; }

token.setSource(sourceLine);

instruction = 0; synthesizer.reset();

if(!token.isEndOfLine()) { parseLabel(); } if(!token.isEndOfLine()) { parseMnemonic();

if(!instruction) { throw Error("Unrecognised mnemonic"); }

parseFirstOperand(); parseSecondOperand(); parseThirdOperand(); }

if(instruction) { do { if(instruction->matchSyntax()) { break; }

instruction = instruction->getNext(); } while(instruction);

if(!instruction) { throw Error("Operands mismatch"); } }

return synthesizer.encodeInstruction(instruction); }

void Parser::parseLabel() { if(token.isIdentifier() && token.lookAhead().getChar() == ':') { synthesizer.defineLabel(token.getString());

token.advance(2); } }

void Parser::parseMnemonic() { instruction = instructionSet.query(token.getString());

if(instruction) { instruction->matchMnemonic(token.getString());

token.advance(); } else { throw Error("Mnemonic not recognised"); } }

void Parser::parseSpecifier() { Specifier::Type type = Specifier::UNKNOWN;

if(token.isIdentifier()) { type = Specifier::scan(token.getString()); } instruction->matchSpecifier(type);

if(type != Specifier::UNKNOWN) { token.advance(); } }

void Parser::parseFirstOperand() { assert(instruction);

parseSpecifier();

Operand firstOperand = Operand::INIT;

if(token.isEndOfLine()) { } else if(token.isPunctuator()) { switch(token.getChar()) { case '[': firstOperand = parseMemoryReference(); break; case '+': case '-': case '~': firstOperand = parseImmediate(); break; default: throw Error("Unexpected punctuator after mnemonic '%c'", token.getChar()); } } else if(token.isConstant()) { firstOperand = parseImmediate(); } else if(token.isIdentifier()) { firstOperand = parseRegister(); } else { throw Error("Invalid destination operand"); }

instruction->matchFirstOperand(firstOperand); synthesizer.encodeFirstOperand(firstOperand); }

void Parser::parseSecondOperand() { assert(instruction);

if(token.getChar() == ',') { token.advance(); } else if(!token.isEndOfLine()) { throw Error("Operands must be separated by comma"); } else { instruction->matchSecondOperand(Operand::INIT); return; }

parseSpecifier();

Operand secondOperand = Operand::INIT;

if(token.isEndOfLine()) { } else if(token.isPunctuator()) { switch(token.getChar()) { case '[': secondOperand = parseMemoryReference(); break; case '+': case '-': case '~': secondOperand = parseImmediate(); break; default: throw Error("Unexpected punctuator after mnemonic '%c'", token.getChar()); } } else if(token.isConstant()) { secondOperand = parseImmediate(); } else if(token.isIdentifier()) { secondOperand = parseRegister(); } else { throw Error("Invalid source operand"); }

instruction->matchSecondOperand(secondOperand); synthesizer.encodeSecondOperand(secondOperand); }

void Parser::parseThirdOperand() { assert(instruction);

if(token.getChar() == ',') { token.advance(); } else if(!token.isEndOfLine()) { throw Error("Operands must be separated by comma"); } else { instruction->matchThirdOperand(Operand::INIT); return; }

Operand thirdOperand = Operand::INIT;

if(token.isEndOfLine()) { } else if(token.isPunctuator()) { switch(token.getChar()) { case '+': case '-': case '~': thirdOperand = parseImmediate(); break; default: throw Error("Unexpected punctuator after mnemonic '%c'", token.getChar()); } } else if(token.isConstant()) { thirdOperand = parseImmediate(); } else { throw Error("Too many operands"); }

instruction->matchThirdOperand(thirdOperand); synthesizer.encodeThirdOperand(thirdOperand); }

Operand Parser::parseImmediate() { Operand imm = Operand::INIT;

if(token.isPunctuator()) { if(token.getChar() == '+') { token.advance(); imm.value = +token.getValue(); } else if(token.getChar() == '-') { token.advance(); imm.value = -token.getValue(); } else if(token.getChar() == '~') { token.advance(); imm.value = ~token.getValue(); } else { throw Error::INTERNAL; // Method shouldn't have been called } } else if(token.isConstant()) { imm.value = token.getValue(); } else { throw Error::INTERNAL; // Method shouldn't have been called }

if((unsigned char)imm.value == imm.value) { imm.type = Operand::IMM8; } else if((unsigned short)imm.value == imm.value) { imm.type = Operand::IMM16; } else { imm.type = Operand::IMM32; }

token.advance();

return imm; }

Operand Parser::parseRegister() { Operand reg = Operand::scanReg(token.getString());

// It's not a register, so it must be a reference if(reg.type == Operand::UNKNOWN) { synthesizer.referenceLabel(token.getString());

// First operand should be immediate reg.type = Operand::IMM8; // Also matches IMM32 instruction->matchFirstOperand(reg); }

token.advance();

return reg; }

Operand Parser::parseMemoryReference() { Operand mem = Operand::INIT;

while(!token.lookAhead().isEndOfLine()) { const Token &prev = token.currentToken(); token.advance(); const Token &next = token.lookAhead();

if(token.isIdentifier()) { Operand reg = Operand::scanReg(token.getString());

if(reg.type == Operand::UNKNOWN) { throw Error("Unrecognised identifier '%s'", token.getString()); }

// Check if this is a scaled index register if(prev.getChar() == '*' || next.getChar() == '*') { synthesizer.encodeIndex(reg); } else { synthesizer.encodeBase(reg); } } else if(token.isPunctuator()) { switch(token.getChar()) { case ']': mem.type = Operand::MEM; token.advance(); return mem; case '+': // Check if previous and next tokens are identifier or number if((!prev.isConstant() && !prev.isIdentifier()) || (!next.isIdentifier() && !next.isConstant())) { throw Error("Syntax error '+' in memory reference"); } break; case '-': // Check if previous and next tokens are correct type if((!prev.isConstant() && !prev.isIdentifier() && !(prev.getChar() == '[')) || !next.isConstant()) { throw Error("Syntax error '-' in memory reference"); } break; case '*': // Check if previous and next tokens are index and scale if(!(prev.isConstant() && next.isIdentifier()) && !(next.isConstant() && prev.isIdentifier())) { throw Error("Syntax error '*' in memory reference"); } break; default: throw Error("Unexpected punctuator in memory reference '%c'", token.getChar()); } } else if(token.isConstant()) { if(prev.getChar() == '*' || next.getChar() == '*') { if(token.getValue() == 1 || token.getValue() == 2 || token.getValue() == 4 || token.getValue() == 8) { synthesizer.encodeScale(token.getValue()); } else { throw Error("Invalid scale in memory reference"); } } else if(prev.getChar() == '-') { synthesizer.encodeDisplacement(-token.getValue()); } else if(prev.getChar() == '+' || next.getChar() == '+') { synthesizer.encodeDisplacement(token.getValue()); } else { throw Error("Invalid number in memory reference"); } } else { throw Error("Unexpected token in memory reference '%s'", token.getString()); } }

throw Error("Unexpected end of line in memory reference"); } }

Currently browsing [SoftWire.zip] (112,805 bytes) - [Scanner.cpp] - (3,762 bytes)

#include "Scanner.hpp"

#include "Token.hpp" #include "Error.hpp"

#include <ctype.h> #include <string.h> #include <stdio.h> #include <stdlib.h>

namespace SoftWire { Scanner::Link::Link() { token = 0; next = 0; }

Scanner::Link::~Link() { delete token; delete next; }

Scanner::Scanner() { root = 0; pointer = 0; }

Scanner::~Scanner() { delete root; }

void Scanner::setSource(const char *source) { if(!source) { throw Error::INTERNAL; }

delete root; root = new Link();

Link *link = root;

int i = 0;

while(link) { char buffer[tokenMax]; int c = 0;

switch(source[i]) { case '\0': case '\n': case '\r': case ';': link->token = new Token(); pointer = root; return; case ' ': case ' ': i++; continue; case '\'': throw Error("Character constants not supported yet"); case '\"': throw Error("String literals not supported yet"); case '*': case '+': case '-': case '~': case ',': case '[': case ']': case ':': link->token = new Punctuator(source[i++]); break; default: if(__iscsymf(source[i])) { do { if(c >= tokenMax) { throw Error("Token too long"); }

buffer[c++] = source[i++]; } while(__iscsym(source[i]) && c < tokenMax);

buffer[c] = 0;

link->token = new Identifier(buffer); } else if(isdigit(source[i])) { do { buffer[c++] = source[i++]; } while((isxdigit(source[i]) || source[i] == 'x') && c < tokenMax - 1);

buffer[c] = 0; char *endptr;

if(source[i] == 'h') // Hexadecimal { link->token = new Constant(strtoul(buffer, &endptr, 16));

buffer[c++] = source[i++]; } else if(source[i] == 'q') // Octal { link->token = new Constant(strtoul(buffer, &endptr, 8));

buffer[c++] = source[i++]; } else if(source[i] == 'b') // Binary { link->token = new Constant(strtoul(buffer, &endptr, 2));

buffer[c++] = source[i++]; } else // Decimal { link->token = new Constant(strtol(buffer, &endptr, 10)); } } else { throw Error("Invalid token '%c'", source[i]); } }

link->next = new Link(); link = link->next; }

throw Error::INTERNAL;

pointer = root;

return; }

bool Scanner::isEndOfLine() const { assertPointer();

return pointer->token->isEndOfLine(); }

bool Scanner::isIdentifier() const { assertPointer();

return pointer->token->isIdentifier(); }

bool Scanner::isConstant() const { assertPointer();

return pointer->token->isConstant(); }

bool Scanner::isPunctuator() const { assertPointer();

return pointer->token->isPunctuator(); }

const Token &Scanner::advance(int n) { while(n--) { assertPointer();

pointer = pointer->next; }

return *pointer->token; }

const char *Scanner::getString() const { assertPointer();

return pointer->token->getString(); }

const Token &Scanner::lookAhead() const { assertPointer();

return *pointer->next->token; }

char Scanner::getChar() const { assertPointer();

return pointer->token->getChar(); }

int Scanner::getValue() const { assertPointer();

return pointer->token->getValue(); }

const Token &Scanner::currentToken() const { assertPointer();

return *pointer->token; }

void Scanner::assertPointer() const { if(!pointer || !pointer->token) { throw Error::INTERNAL; } } }

Currently browsing [SoftWire.zip] (112,805 bytes) - [Synthesizer.cpp] - (10,267 bytes)

#include "Synthesizer.hpp"

#include "Keywords.hpp" #include "Instruction.hpp" #include "Error.hpp"

#include <stdio.h> #include <string.h> #include <stdlib.h>

namespace SoftWire { Synthesizer::Synthesizer() { reset(); }

Synthesizer::~Synthesizer() { }

void Synthesizer::reset() { encoding.reset();

firstType = Operand::UNKNOWN; secondType = Operand::UNKNOWN;

firstReg = Encoding::REG_UNKNOWN; secondReg = Encoding::REG_UNKNOWN; baseReg = Encoding::REG_UNKNOWN; indexReg = Encoding::REG_UNKNOWN; scale = 0; }

void Synthesizer::defineLabel(const char *label) { if(encoding.label != 0) { throw Error::INTERNAL; // Parser error }

encoding.setLabel(label); }

void Synthesizer::referenceLabel(const char *label) { if(encoding.reference != 0) { throw Error("Instruction can't have multiple references"); }

encoding.setReference(label); }

void Synthesizer::encodeFirstOperand(const Operand &firstOperand) { if(firstType != Operand::UNKNOWN) { throw Error::INTERNAL; // Instrucition destination already set } firstType = firstOperand.type;

if(Operand::isReg(firstType) || Operand::isMem(firstType)) { firstReg = firstOperand.reg; } else if(Operand::isImm(firstType)) { encodeImmediate(firstOperand.value); } else if(!Operand::isVoid(firstType)) { throw Error::INTERNAL; } }

void Synthesizer::encodeSecondOperand(const Operand &secondOperand) { if(secondType != Operand::UNKNOWN) { throw Error::INTERNAL; // Instruction source already set }

secondType = secondOperand.type;

if(Operand::isReg(secondType) || Operand::isMem(secondType)) { secondReg = secondOperand.reg; } else if(Operand::isImm(secondType)) { encodeImmediate(secondOperand.value); } else if(!Operand::isVoid(secondType)) { throw Error::INTERNAL; } }

void Synthesizer::encodeThirdOperand(const Operand &thirdOperand) { if(Operand::isImm(thirdOperand)) { encodeImmediate(thirdOperand.value); } else if(!Operand::isVoid(thirdOperand)) { throw Error::INTERNAL; } }

void Synthesizer::encodeBase(const Operand &base) { if(baseReg != Encoding::REG_UNKNOWN) { // Base already set, use as index with scale = 1 encodeIndex(base); encodeScale(1); return; }

baseReg = base.reg; }

void Synthesizer::encodeIndex(const Operand &index) { if(indexReg != Encoding::REG_UNKNOWN) { throw Error("Memory reference can't have multiple index registers"); }

indexReg = index.reg; } void Synthesizer::encodeScale(int scale) { if(this->scale != 0) { throw Error("Memory reference can't have multiple scale factors"); }

if(scale != 1 && scale != 2 && scale != 4 && scale != 8) { throw Error("Invalid scale value '%d'", scale); }

this->scale = scale; }

void Synthesizer::encodeImmediate(int immediate) { if(encoding.immediate != 0) { throw Error("Instruction can't have multiple immediate operands"); }

encoding.immediate = immediate; }

void Synthesizer::encodeDisplacement(int displacement) { encoding.displacement += displacement; }

const Encoding &Synthesizer::encodeInstruction(const Instruction *instruction) { if(!instruction) { return encoding; }

const char *format = instruction->getEncoding();

if(!format) { throw Error::INTERNAL; }

while(*format) { switch((short)format[1] | format[0] << 8) // Swap byte order so we can use character constants { case 'p0': encoding.addPrefix(0xF0); break; case 'p2': encoding.addPrefix(0xF2); break; case 'p3': encoding.addPrefix(0xF3); break; case 'po': if(!instruction->is32Bit()) { encoding.addPrefix(0x66); } break; case 'pa': if(!instruction->is32Bit()) { encoding.addPrefix(0x67); } break; case '+r': if(encoding.format.O1) { if(Operand::isReg(firstType)) { encoding.O1 += firstReg; } else if(Operand::isReg(secondType)) { encoding.O1 += secondReg; } else { throw Error::INTERNAL; // '+r' not compatible with operands } } else { throw Error::INTERNAL; // '+r' needs first opcode byte } break; case '/r': encodeModField();

if(Operand::isReg(instruction->getFirstOperand()) && Operand::isR_M(instruction->getSecondOperand())) { if(Operand::isMem(secondType)) { encoding.modRM.r_m = baseReg; } else if(Operand::isReg(secondType)) { encoding.modRM.r_m = secondReg; } else { throw Error::INTERNAL; // Syntax error should be detected by parser }

encoding.modRM.reg = firstReg; } else if(Operand::isR_M(instruction->getFirstOperand()) && Operand::isReg(instruction->getSecondOperand())) { if(Operand::isMem(firstType)) { encoding.modRM.r_m = baseReg; } else if(Operand::isReg(firstType)) { encoding.modRM.r_m = firstReg; } else { throw Error::INTERNAL; // Syntax error should be detected by parser }

encoding.modRM.reg = secondReg; } else { throw Error::INTERNAL; }

encodeSibByte();

break; case '/0': case '/1': case '/2': case '/3': case '/4': case '/5': case '/6': case '/7': encodeModField();

encoding.modRM.reg = (Encoding::Reg)(format[1] - '0');

if(Operand::isMem(firstType)) { encoding.modRM.r_m = baseReg; } else if(Operand::isReg(firstType)) { encoding.modRM.r_m = firstReg; } else { throw Error::INTERNAL; // Syntax error should be caught by parser }

encodeSibByte();

break; case 'id': encoding.format.I1 = true; encoding.format.I2 = true; encoding.format.I3 = true; encoding.format.I4 = true; break; case 'iw': encoding.format.I1 = true; encoding.format.I2 = true; break; case 'ib': encoding.format.I1 = true; break; case '-b': encoding.format.I1 = true; break; case '-i': // Assume 32-bit code encoding.format.I1 = true; encoding.format.I2 = true; encoding.format.I3 = true; encoding.format.I4 = true; break; default: unsigned int O = strtoul(format, 0, 16);

if(O > 0xFF) { throw Error::INTERNAL; }

if(!encoding.format.O1) { encoding.O1 = (byte)O;

encoding.format.O1 = true; } else if(!encoding.format.O2 && (encoding.O1 == 0x0F || encoding.O1 == 0xD8 || encoding.O1 == 0xD9 || encoding.O1 == 0xDA || encoding.O1 == 0xDB || encoding.O1 == 0xDC || encoding.O1 == 0xDD || encoding.O1 == 0xDE || encoding.O1 == 0xDF)) { encoding.O2 = encoding.O1; encoding.O1 = O;

encoding.format.O2 = true; } else { throw Error::INTERNAL; } }

format += 2;

if(*format == ' ') { format++; } else if(*format == '\0') { break; } else { throw Error::INTERNAL; } }

return encoding; }

void Synthesizer::encodeModField() { encoding.format.modRM = true; if(Operand::isReg(firstType) && (Operand::isReg(secondType) || Operand::isImm(secondType) || Operand::isVoid(secondType))) { encoding.modRM.mod = Encoding::MOD_REG; } else if((Operand::isMem(firstType) || Operand::isMem(secondType)) && (Operand::isReg(firstType) || Operand::isReg(secondType))) { if(!encoding.displacement) { encoding.modRM.mod = Encoding::MOD_NO_DISP; } else if((char)encoding.displacement == encoding.displacement) { encoding.modRM.mod = Encoding::MOD_BYTE_DISP; encoding.format.D1 = true; } else { encoding.modRM.mod = Encoding::MOD_DWORD_DISP; encoding.format.D1 = true; encoding.format.D2 = true; encoding.format.D3 = true; encoding.format.D4 = true; } } else { throw Error::INTERNAL; } }

void Synthesizer::encodeSibByte() { if(scale == 0 && indexReg == Encoding::REG_UNKNOWN) { if((baseReg == Encoding::REG_UNKNOWN) || (encoding.modRM.r_m != Encoding::ESP && encoding.modRM.r_m != Encoding::EBP)) { if(encoding.format.SIB) { throw Error::INTERNAL; }

return; // No SIB byte needed } }

encoding.format.SIB = true;

encoding.modRM.r_m = Encoding::ESP; // Indicates use of SIB in mod R/M if(baseReg == Encoding::EBP && encoding.modRM.mod == Encoding::MOD_NO_DISP) { encoding.modRM.mod = Encoding::MOD_BYTE_DISP;

encoding.format.D1 = true; }

if(indexReg == Encoding::ESP) { if(scale != 1) { throw Error("ESP can't be scaled index in memory reference"); } else // Switch base and index { Encoding::Reg tempReg;

tempReg = indexReg; indexReg = baseReg; baseReg = tempReg; } }

if(baseReg == Encoding::REG_UNKNOWN) { encoding.SIB.base = Encoding::EBP; // No Base encoding.modRM.mod = Encoding::MOD_NO_DISP; encoding.format.D1 = true; encoding.format.D2 = true; encoding.format.D3 = true; encoding.format.D4 = true; } else { encoding.SIB.base = baseReg; }

if(indexReg != Encoding::REG_UNKNOWN) { encoding.SIB.index = indexReg; } else { encoding.SIB.index = Encoding::ESP; }

switch(scale) { case 0: case 1: encoding.SIB.scale = Encoding::SCALE_1; break; case 2: encoding.SIB.scale = Encoding::SCALE_2; break; case 4: encoding.SIB.scale = Encoding::SCALE_4; break; case 8: encoding.SIB.scale = Encoding::SCALE_8; break; default: throw Error::INTERNAL; } } }

Currently browsing [SoftWire.zip] (112,805 bytes) - [Test.cpp] - (3,210 bytes)

#include "Assembler.hpp"
#include "Scanner.hpp"
#include "Instruction.hpp"
#include "Error.hpp"

#include <stdio.h> #include <conio.h> #include <stdlib.h> #include <string.h> /* void setBits(unsigned int *bitBuffer, int i, int n) { int j = i / 32; int k = i % 32;

while(n > 0) { unsigned int x = -1;

int y = x >> (32 - n); x = n < 32 ? y : x;

x <<= k; n += k; k = 0;

bitBuffer[j++] |= x;

n -= 32; } } */
void testSetBits() { SoftWire::Assembler x86("SetBits.asm");

void (__cdecl *setBits)(unsigned int*, int, int) = (void(__cdecl*)(unsigned int*, int, int))x86.callable();

if(setBits) { printf("Execute code (y/n)?\n\n");

int c; do { c = getch(); } while(c != 'y' && c != 'n');

if(c == 'y') { unsigned int bitBuffer[] = {0x00000000, 0x00000000};

setBits(bitBuffer, 5, 44);

printf("output: %.8X %.8X\n\n", bitBuffer[1], bitBuffer[0]); } } } /* void crossProduct(float *V0, float *V1, float *V2) { V2[0] = V0[1] * V1[2] - V0[2] * V1[1]; V2[1] = V0[2] * V1[0] - V0[0] * V1[2]; V2[2] = V0[0] * V1[1] - V0[1] * V1[0]; } */ void testCrossProduct() { SoftWire::Assembler x86("CrossProduct.asm");

void (__cdecl *crossProduct)(float*, float*, float*) = (void(__cdecl*)(float*, float*, float*))x86.callable();

if(crossProduct) { printf("Execute code (y/n)?\n\n");

int c; do { c = getch(); } while(c != 'y' && c != 'n');

if(c == 'y') { float V0[3] = {1, 0, 0}; float V1[3] = {0, 1, 0}; float V2[3];

crossProduct(V0, V1, V2);

printf("output: (%.3f, %.3f, %.3f)\n\n", V2[0], V2[1], V2[2]); } } } /* int alphaBlend(int c1, int c2, int a) { __asm { movd mm0, a punpcklwd mm0, mm0 punpckldq mm0, mm0 pcmpeqb mm7, mm7 psubw mm7, mm0 punpcklbw mm1, c1 psrlw mm1, 8 punpcklbw mm2, c2 psrlw mm2, 8

pmullw mm1, mm7 pmullw mm2, mm0 paddw mm1, mm2

psrlw mm1, 8 packuswb mm1, mm1 movd eax, mm1 } } */
void testAlphaBlend() { SoftWire::Assembler x86("AlphaBlend.asm");

int (__cdecl *alphaBlend)(int, int, int) = (int(__cdecl*)(int, int, int))x86.callable();

if(alphaBlend) { printf("Execute code (y/n)?\n\n");

int c; do { c = getch(); } while(c != 'y' && c != 'n');

if(c == 'y') { int x = alphaBlend(0x00FF00FF, 0xFF00FF00, 128);

printf("output: %.8X\n\n", x); } } } /* void helloWorld(int (*print)(const char *format, ...), const char *string) { print(string); } */ void testHelloWorld() { SoftWire::Assembler x86("HelloWorld.asm");

void (__cdecl *helloWorld)(int(*)(const char*, ...), const char*) = (void(__cdecl*)(int(*)(const char*, ...), const char*))x86.callable();

if(helloWorld) { printf("Execute code (y/n)?\n\n");

int c; do { c = getch(); } while(c != 'y' && c != 'n');

if(c == 'y') { printf("output: "); helloWorld(printf, "Hello world!\n\n"); } } }

void main() { testSetBits(); testCrossProduct(); testAlphaBlend(); testHelloWorld();

printf("Press any key to continue"); getch();

return; }


Currently browsing [SoftWire.zip] (112,805 bytes) - [Token.cpp] - (1,389 bytes)

#include "Token.hpp"

#include "Error.hpp"

#include <ctype.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <conio.h> #include <assert.h>

namespace SoftWire { Token::Token() { }

Token::~Token() { }

bool Token::isEndOfLine() const { return !isIdentifier() && !isConstant() && !isPunctuator(); }

bool Token::isIdentifier() const { return false; }

bool Token::isConstant() const { return false; }

bool Token::isPunctuator() const { return false; }

const char *Token::getString() const { return ""; }

char Token::getChar() const { return '\0'; }

int Token::getValue() const { return 0; }

Identifier::Identifier(const char *string) { this->string = strdup(string); }

Identifier::~Identifier() { delete[] string; }

bool Identifier::isIdentifier() const { return true; }

const char *Identifier::getString() const { return string; }

Constant::Constant(int value) { this->value = value; }

bool Constant::isConstant() const { return true; }

int Constant::getValue() const { return value; }

Punctuator::Punctuator(char c) { this->c = c; }

bool Punctuator::isPunctuator() const { return true; }

char Punctuator::getChar() const { return c; } }

Currently browsing [SoftWire.zip] (112,805 bytes) - [Assembler.hpp] - (497 bytes)

#ifndef Assembler_hpp
#define Assembler_hpp

#include "Parser.hpp" #include "Loader.hpp"

namespace SoftWire { class Assembler { public: Assembler(const char *fileName);

~Assembler();

const void *callable();

private: Parser parser; Loader loader;

int lineNumber; bool error;

void assembleFile(const char *sourceFile); void assembleLine(const char *sourceLine);

static void printLine(const char *string); }; }

#endif // Assembler_hpp

Currently browsing [SoftWire.zip] (112,805 bytes) - [Encoding.hpp] - (2,399 bytes)

#ifndef Encoding_hpp
#define Encoding_hpp

namespace SoftWire { typedef unsigned char byte;

class Synthesizer;

class Encoding { friend Synthesizer;

public: enum Reg { REG_UNKNOWN = -1,

AL = 0, AX = 0, EAX = 0, ST0 = 0, MM0 = 0, XMM0 = 0, CL = 1, CX = 1, ECX = 1, ST1 = 1, MM1 = 1, XMM1 = 1, DL = 2, DX = 2, EDX = 2, ST2 = 2, MM2 = 2, XMM2 = 2, BL = 3, BX = 3, EBX = 3, ST3 = 3, MM3 = 3, XMM3 = 3, AH = 4, SP = 4, ESP = 4, ST4 = 4, MM4 = 4, XMM4 = 4, CH = 5, BP = 5, EBP = 5, ST5 = 5, MM5 = 5, XMM5 = 5, DH = 6, SI = 6, ESI = 6, ST6 = 6, MM6 = 6, XMM6 = 6, BH = 7, DI = 7, EDI = 7, ST7 = 7, MM7 = 7, XMM7 = 7 }; Encoding();

~Encoding();

void reset();

const char *getLabel() const; const char *getReference() const;

void addPrefix(byte p); void checkFormat() const;

int length() const; // Length of encoded instruction in bytes int writeCode(byte *output) const;

void setImmediate(int immediate); void setJumpOffset(int offset); void setLabel(const char *label); void setReference(const char *label);

private: char *label; char *reference;

enum Mod { MOD_NO_DISP = 0, MOD_BYTE_DISP = 1, MOD_DWORD_DISP = 2, MOD_REG = 3 };

enum Scale { SCALE_UNKNOWN = 0, SCALE_1 = 0, SCALE_2 = 1, SCALE_4 = 2, SCALE_8 = 3 };

struct { bool P1 : 1; bool P2 : 1; bool P3 : 1; bool P4 : 1; bool O2 : 1; bool O1 : 1; bool modRM : 1; bool SIB : 1; bool D1 : 1; bool D2 : 1; bool D3 : 1; bool D4 : 1; bool I1 : 1; bool I2 : 1; bool I3 : 1; bool I4 : 1; } format;

byte P1; // Prefixes byte P2; byte P3; byte P4; byte O1; // Opcode byte O2; struct { union { struct { byte r_m : 3; byte reg : 3; byte mod : 2; };

byte b; }; } modRM; struct { union { struct { byte base : 3; byte index : 3; byte scale : 2; };

byte b; }; } SIB; union { int displacement;

struct { byte D1; byte D2; byte D3; byte D4; }; }; union { int immediate;

struct { byte I1; byte I2; byte I3; byte I4; }; }; }; }

#endif // Encoding_hpp

Currently browsing [SoftWire.zip] (112,805 bytes) - [Error.hpp] - (280 bytes)

#ifndef Error_hpp
#define Error_hpp

namespace SoftWire { class Error { public: Error(const char *format, ...);

void print() const;

const static Error INTERNAL;

private: enum {stringMax = 256};

char buffer[stringMax]; }; }

#endif Error_hpp

Currently browsing [SoftWire.zip] (112,805 bytes) - [Instruction.hpp] - (2,184 bytes)

#ifndef Instruction_hpp
#define Instruction_hpp

#include "Keywords.hpp"

namespace SoftWire { class Instruction { public: enum { CPU_UNKNOWN = 0x00000000,

CPU_8086 = 0x00000001, CPU_186 = 0x00000002, CPU_286 = 0x00000004, CPU_386 = 0x00000008, CPU_486 = 0x00000010, CPU_PENT = 0x00000020, // Pentium CPU_P6 = 0x00000040, // Pentium Pro CPU_FPU = 0x00000080, CPU_MMX = 0x00000100, CPU_KATMAI = 0x00000200, CPU_SSE = 0x00000400,

// CPU_AMD = 0x00000800, // AMD specific system calls CPU_CYRIX = 0x00001000, CPU_3DNOW = 0x00002000, CPU_ATHLON = 0x00004000, // CPU_SMM = 0x00008000, // System Management Mode, standby mode // CPU_UNDOC = 0x00010000, // Undocumented, also not supported by inline assembler // CPU_PRIV = 0x00020000 // Priviledged, run-time compiled OS kernel anyone? };

struct Syntax { char *mnemonic; char *operands; char *encoding; int flags; };

Instruction(const Syntax &instruction);

~Instruction();

Instruction *getNext() const;

void attachNew(const Syntax &instruction); void resetMatch(); bool matchSyntax() const; void matchMnemonic(const char *mnemonic); void matchSpecifier(Specifier::Type sizeSpecifier); void matchFirstOperand(const Operand &operand); void matchSecondOperand(const Operand &operand); void matchThirdOperand(const Operand &operand);

Operand::Type getFirstOperand() const; Operand::Type getSecondOperand() const; Operand::Type getThirdOperand() const;

const char *getMnemonic() const; const char *getOperandSyntax() const; const char *getEncoding() const; bool is32Bit() const;

private: bool syntaxMnemonic : 1; bool syntaxSpecifier : 1; bool syntaxFirstOperand : 1; bool syntaxSecondOperand : 1; bool syntaxThirdOperand : 1;

const Syntax &syntax; Specifier::Type specifier; Operand::Type firstOperand; Operand::Type secondOperand; Operand::Type thirdOperand; int flags;

Instruction *next;

void extractOperands(const char *syntax); }; }

#endif // Instruction_hpp

Currently browsing [SoftWire.zip] (112,805 bytes) - [InstructionSet.hpp] - (669 bytes)

#ifndef InstructionSet_hpp
#define InstructionSet_hpp

#include "Instruction.hpp"

namespace SoftWire { class InstructionSet { public: InstructionSet();

~InstructionSet();

Instruction *query(const char *mnemonic) const;

private: struct Entry { const char *mnemonic;

Instruction *instruction; };

Entry *instructionMap;

static int compareSyntax(const void *syntax1, const void *syntax2); static int compareEntry(const void *mnemonic, const void *entry);

static Instruction::Syntax instructionSet[];

static int numInstructions(); static int numMnemonics(); }; }

#endif // InstructionSet_hpp

Currently browsing [SoftWire.zip] (112,805 bytes) - [Keywords.hpp] - (2,955 bytes)

#ifndef Keywords_hpp
#define Keywords_hpp

#include "Encoding.hpp"

namespace SoftWire { struct Specifier { enum Type { UNKNOWN = 0,

NEAR, SHORT = NEAR, // FAR, BYTE, WORD, DWORD, QWORD, MMWORD = QWORD, XMMWORD };

Type type; const char *notation;

static Specifier::Type scan(const char *string);

static const Specifier specifierSet[]; };

struct Operand { enum Type { UNKNOWN = 0,

VOID = 0x00000001,

ONE = 0x00000002, IMM8 = 0x00000004 | ONE, IMM16 = 0x00000008 | IMM8 | ONE, IMM32 = 0x00000010 | IMM16 | IMM8 | ONE, IMM = IMM32 | IMM16 | IMM8 | ONE,

AL = 0x00000020, CL = 0x00000040, REG8 = CL | AL,

AX = 0x00000080, DX = 0x00000100, CX = 0x00000200, REG16 = CX | DX | AX,

EAX = 0x00000400, ECX = 0x00000800, REG32 = ECX | EAX,

CS = UNKNOWN, // No need to touch these in 32-bit protected mode DS = UNKNOWN, ES = UNKNOWN, SS = UNKNOWN, FS = UNKNOWN, GS = UNKNOWN, SEGREG = GS | FS | SS | ES | DS | CS,

ST0 = 0x00001000, FPUREG = 0x00002000 | ST0, CR = UNKNOWN, // You won't need these in a JIT assembler DR = UNKNOWN, TR = UNKNOWN,

MMREG = 0x00004000, XMMREG = 0x00008000,

REG = XMMREG | MMREG | TR | DR | CR | FPUREG | SEGREG | REG32 | REG16 | REG8,

MEM8 = 0x00010000, MEM16 = 0x00020000, MEM32 = 0x00040000, MEM64 = 0x00080000, MEM80 = UNKNOWN, // Extended double not supported by NT MEM128 = 0x00100000, M512B = UNKNOWN, // Only for state save/restore instructions MEM = M512B | MEM128 | MEM80 | MEM64 | MEM32 | MEM16 | MEM8, XMM32 = MEM32 | XMMREG, XMM64 = MEM64 | XMMREG,

R_M8 = MEM8 | REG8, R_M16 = MEM16 | REG16, R_M32 = MEM32 | REG32, R_M64 = MEM64 | MMREG, R_M128 = MEM128 | XMMREG, R_M = MEM | REG,

MOFF8 = UNKNOWN, // Not supported MOFF16 = UNKNOWN, // Not supported MOFF32 = UNKNOWN // Not supported };

Type type; const char *notation; union { int value; // For immediates Encoding::Reg reg; // For registers };

bool isSubtypeOf(Type baseType) const;

static bool isVoid(Type type); static bool isImm(Type type); static bool isReg(Type type); static bool isMem(Type type); static bool isR_M(Type type);

static bool isVoid(const Operand &operand); static bool isImm(const Operand &operand); static bool isReg(const Operand &operand); static bool isMem(const Operand &operand); static bool isR_M(const Operand &operand);

static Operand scanReg(const char *string); static Operand::Type scanSyntax(const char *string);

static const Operand registerSet[]; static const Operand syntaxSet[];

static const Operand INIT; static const Operand NOT_FOUND; }; }

#endif // Keywords_hpp

Currently browsing [SoftWire.zip] (112,805 bytes) - [Loader.hpp] - (585 bytes)

#ifndef Loader_hpp
#define Loader_hpp

#include "Encoding.hpp"

namespace SoftWire { typedef unsigned char byte;

class Loader { public: Loader();

~Loader();

const void *callable();

void addEncoding(const Encoding &encoding);

private: struct Link { Link();

~Link();

void attachNew(const Encoding &encoding);

Encoding encoding; Link *next; };

Link *entry;

byte *objectCode;

void loadCode(); byte *resolveLabel(const char *label) const; int codeLength() const; }; }

#endif // Loader_hpp

Currently browsing [SoftWire.zip] (112,805 bytes) - [Parser.hpp] - (730 bytes)

#ifndef Parser_hpp
#define Parser_hpp

#include "Synthesizer.hpp" #include "InstructionSet.hpp" #include "Scanner.hpp"

namespace SoftWire { class Instruction; class Token;

class Parser { public: Parser();

~Parser();

const Encoding &parseLine(const char *sourceLine);

private: static const InstructionSet instructionSet;

Scanner token; Instruction *instruction; Synthesizer synthesizer;

void parseLabel(); void parseMnemonic(); void parseSpecifier();

void parseFirstOperand(); void parseSecondOperand(); void parseThirdOperand();

Operand parseImmediate(); Operand parseRegister(); Operand parseMemoryReference(); }; }

#endif // Parser_hpp

Currently browsing [SoftWire.zip] (112,805 bytes) - [Scanner.hpp] - (828 bytes)

#ifndef Scanner_hpp
#define Scanner_hpp

#include "Token.hpp"

namespace SoftWire { class Scanner : public Token { public: Scanner();

~Scanner();

void setSource(const char *source);

bool isEndOfLine() const; bool isIdentifier() const; bool isConstant() const; bool isPunctuator() const;

const char *getString() const; char getChar() const; int getValue() const;

int stringLength() const;

const Token ¤tToken() const; const Token &lookAhead() const; const Token &advance(int n = 1);

private: class Link { public: Link();

~Link();

Token *token; Link *next; };

void assertPointer() const;

Link *root; const Link *pointer;

enum {tokenMax = 256}; // Maximum token length }; }

#endif // Scanner_hpp

Currently browsing [SoftWire.zip] (112,805 bytes) - [Synthesizer.hpp] - (1,116 bytes)

#ifndef Synthesizer_hpp
#define Synthesizer_hpp

#include "Encoding.hpp" #include "Keywords.hpp"

namespace SoftWire { typedef unsigned char byte;

class Instruction;

class Synthesizer { public: Synthesizer();

~Synthesizer();

void reset();

void defineLabel(const char *label); void referenceLabel(const char *label);

void encodeFirstOperand(const Operand &firstOperand); void encodeSecondOperand(const Operand &secondOperand); void encodeThirdOperand(const Operand &thirdOperand); void encodeBase(const Operand &base); void encodeIndex(const Operand &index); void encodeScale(int scale);

void encodeDisplacement(int displacement); void encodeImmediate(int i);

const Encoding &encodeInstruction(const Instruction *instruction);

private: Encoding encoding;

Operand::Type firstType; Operand::Type secondType;

Encoding::Reg firstReg; Encoding::Reg secondReg; Encoding::Reg baseReg; Encoding::Reg indexReg;

int scale;

void encodeModField(); void encodeSibByte(); }; }

#endif // Synthesizer_hpp

Currently browsing [SoftWire.zip] (112,805 bytes) - [Token.hpp] - (980 bytes)

#ifndef Token_hpp
#define Token_hpp

namespace SoftWire { class Scanner;

class Token { friend Scanner;

public: Token();

virtual ~Token();

bool isEndOfLine() const; virtual bool isIdentifier() const; virtual bool isConstant() const; virtual bool isPunctuator() const;

virtual const char *getString() const; virtual char getChar() const; virtual int getValue() const; };

class Identifier : public Token { public: Identifier(const char *string);

~Identifier();

bool isIdentifier() const;

const char *getString() const;

private: char *string; };

class Constant : public Token { public: Constant(int value);

bool isConstant() const;

int getValue() const;

private: int value; };

class Punctuator : public Token { public: Punctuator(char c);

bool isPunctuator() const;

char getChar() const;

private: char c; }; }

#endif // Token_hpp

The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

 

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.