Merge zizzer.eecs.umich.edu:/bk/newmem

into  ahchoo.blinky.homelinux.org:/home/gblack/m5/newmem-x86

--HG--
extra : convert_revision : 8e624bb95cb9f478ca7ac1dbbd64e20674e3e224
This commit is contained in:
Gabe Black 2007-04-06 16:39:47 +00:00
commit a3ed19f82a
11 changed files with 167 additions and 148 deletions

View file

@ -79,6 +79,13 @@ output header {{
void printReg(std::ostream &os, int reg) const; void printReg(std::ostream &os, int reg) const;
void printSrcReg(std::ostream &os, int reg) const; void printSrcReg(std::ostream &os, int reg) const;
void printDestReg(std::ostream &os, int reg) const; void printDestReg(std::ostream &os, int reg) const;
inline uint64_t merge(uint64_t into, uint64_t val, int size) const
{
//FIXME This needs to be significantly more sophisticated
return val;
}
}; };
}}; }};

View file

@ -95,9 +95,6 @@
//malfunction of the decode mechanism. //malfunction of the decode mechanism.
##include "error.isa" ##include "error.isa"
//Include code to build up macro op instructions
##include "macroop.isa"
//Include a format which implements a batch of instructions which do the same //Include a format which implements a batch of instructions which do the same
//thing on a variety of inputs //thing on a variety of inputs
##include "multi.isa" ##include "multi.isa"

View file

@ -55,16 +55,20 @@
// //
// Authors: Gabe Black // Authors: Gabe Black
//////////////////////////////////////////////////////////////////// // Execute method for macroops.
// def template MacroExecPanic {{
// Instructions that do the same thing to multiple sets of arguments. Fault execute(%(CPU_exec_context)s *, Trace::InstRecord *) const
// {
panic("Tried to execute macroop directly!");
M5_DUMMY_RETURN
}
}};
output header {{ output header {{
// Base class for most macroops, except ones that need to commit as // Base class for most macroops, except ones that need to commit as
// they go. // they go.
class X86MacroInst : public X86StaticInst class X86MacroInst : public StaticInst
{ {
protected: protected:
const uint32_t numMicroOps; const uint32_t numMicroOps;
@ -72,7 +76,7 @@ output header {{
//Constructor. //Constructor.
X86MacroInst(const char *mnem, ExtMachInst _machInst, X86MacroInst(const char *mnem, ExtMachInst _machInst,
uint32_t _numMicroOps) uint32_t _numMicroOps)
: X86StaticInst(mnem, _machInst, No_OpClass), : StaticInst(mnem, _machInst, No_OpClass),
numMicroOps(_numMicroOps) numMicroOps(_numMicroOps)
{ {
assert(numMicroOps); assert(numMicroOps);
@ -85,9 +89,6 @@ output header {{
delete [] microOps; delete [] microOps;
} }
std::string generateDisassembly(Addr pc,
const SymbolTable *symtab) const;
StaticInstPtr * microOps; StaticInstPtr * microOps;
StaticInstPtr fetchMicroOp(MicroPC microPC) StaticInstPtr fetchMicroOp(MicroPC microPC)
@ -96,21 +97,7 @@ output header {{
return microOps[microPC]; return microOps[microPC];
} }
%(BasicExecPanic)s %(MacroExecPanic)s
};
// Base class for macroops which commit as they go. This is for
// instructions which can be partially completed like those with the
// rep prefix. This prevents those instructions from overflowing
// buffers with uncommitted microops.
class X86RollingMacroInst : public X86MacroInst
{
protected:
//Constructor.
X86RollingMacroInst(const char *mnem, ExtMachInst _machInst,
uint32_t _numMicroOps)
: X86MacroInst(mnem, _machInst, numMicroOps)
{}
}; };
}}; }};
@ -121,34 +108,24 @@ def template MacroConstructor {{
{ {
%(constructor)s; %(constructor)s;
//alloc_micro_ops is the code that sets up the microOps //alloc_micro_ops is the code that sets up the microOps
//array in the parent class. This hook will hopefully //array in the parent class.
//allow all that to be automated.
%(alloc_micro_ops)s; %(alloc_micro_ops)s;
setMicroFlags();
} }
}}; }};
let {{ let {{
def genMacroOp(name, Name, ops, rolling = False): def genMacroOp(name, Name, opSeq):
baseClass = 'X86MacroInst' baseClass = 'X86MacroInst'
if rolling: numMicroOps = len(opSeq.ops)
baseClass = 'X86RollingMacroInst'
numMicroOps = len(ops)
allocMicroOps = '' allocMicroOps = ''
micropc = 0 micropc = 0
allocMicroOps += \ for op in opSeq.ops:
"microOps[0] = %s;\n" % \ allocMicroOps += \
op.getAllocator(True, not rolling, True, False) "microOps[%d] = %s;\n" % \
micropc += 1 (micropc, op.getAllocator(True, op.delayed,
if numMicroOps > 2: micropc == 0,
for op in ops[1:-1]: micropc == numMicroOps - 1))
allocMicroOps += \ micropc += 1
"microOps[%d] = %s;\n" % \
(micropc, op.getAllocator(True, not rolling, False, False))
micropc += 1
allocMicroOps += \
"microOps[%d] = %s;\n" % \
op.getAllocator(True, not rolling, False, True)
iop = InstObjParams(name, Name, baseClass, iop = InstObjParams(name, Name, baseClass,
{'code' : '', 'num_micro_ops' : numMicroOps, {'code' : '', 'num_micro_ops' : numMicroOps,
'alloc_micro_ops' : allocMicroOps}) 'alloc_micro_ops' : allocMicroOps})

View file

@ -72,26 +72,34 @@
namespace X86ISA; namespace X86ISA;
//Include the simple microcode assembler //Include the simple microcode assembler. This will hopefully stay
//unspecialized for x86 and can later be made available to other ISAs.
##include "microasm.isa" ##include "microasm.isa"
//Include the bitfield definitions //Include code to build macroops.
##include "bitfields.isa" ##include "macroop.isa"
//Include the operand_types and operand definitions
##include "operands.isa"
//Include the base class for x86 instructions, and some support code //Include the base class for x86 instructions, and some support code
//Code in this file should be general and useful everywhere
##include "base.isa" ##include "base.isa"
//Include the instruction definitions
##include "insts/insts.isa"
//Include the definitions for the instruction formats //Include the definitions for the instruction formats
##include "formats/formats.isa" ##include "formats/formats.isa"
//Include the definitions of the micro ops //Include the operand_types and operand definitions. These are needed by
//the microop definitions.
##include "operands.isa"
//Include the definitions of the micro ops.
//These are StaticInst classes which stand on their own and make up an
//internal instruction set.
##include "microops/microops.isa" ##include "microops/microops.isa"
//Include the instruction definitions which are microop assembler programs.
##include "insts/insts.isa"
//Include the bitfield definitions
##include "bitfields.isa"
//Include the decoder definition //Include the decoder definition
##include "decoder/decoder.isa" ##include "decoder/decoder.isa"

View file

@ -61,23 +61,6 @@
// variety of operands // variety of operands
// //
let {{
# This builds either a regular or macro op to implement the sequence of
# ops we give it.
def genInst(name, Name, ops):
# If we can implement this instruction with exactly one microop, just
# use that directly.
newStmnt = ''
if len(ops) == 1:
decode_block = "return (X86StaticInst *)(%s);" % \
ops[0].getAllocator()
return ('', '', decode_block, '')
else:
# Build a macroop to contain the sequence of microops we've
# been given.
return genMacroOp(name, Name, ops)
}};
let {{ let {{
# This code builds up a decode block which decodes based on switchval. # This code builds up a decode block which decodes based on switchval.
# vals is a dict which matches case values with what should be decoded to. # vals is a dict which matches case values with what should be decoded to.
@ -187,14 +170,8 @@ let {{
# At this point, we've built up "code" to have all the necessary extra # At this point, we've built up "code" to have all the necessary extra
# instructions needed to implement whatever types of operands were # instructions needed to implement whatever types of operands were
# specified. Now we'll assemble it it into a microOp sequence. # specified. Now we'll assemble it it into a StaticInst.
ops = assembleMicro(code) return assembleMicro(name, Name, code)
# Build a macroop to contain the sequence of microops we've
# constructed. The decode block will be used to fill in our
# inner decode structure, and the rest will be concatenated and
# passed back.
return genInst(name, Name, ops)
}}; }};
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -202,6 +179,13 @@ let {{
// The microcode assembler // The microcode assembler
// //
let {{
# These are used when setting up microops so that they can specialize their
# base class template properly.
RegOpType = "RegisterOperand"
ImmOpType = "ImmediateOperand"
}};
let {{ let {{
class MicroOpStatement(object): class MicroOpStatement(object):
def __init__(self): def __init__(self):
@ -242,19 +226,9 @@ let {{
return 'new %s%s(machInst%s%s)' % (self.className, signature, self.microFlagsText(microFlags), args) return 'new %s%s(machInst%s%s)' % (self.className, signature, self.microFlagsText(microFlags), args)
}}; }};
let {{
def buildLabelDict(ops):
labels = {}
micropc = 0
for op in ops:
if op.label:
labels[op.label] = count
micropc += 1
return labels
}};
let{{ let{{
def assembleMicro(code): def assembleMicro(name, Name, code):
# This function takes in a block of microcode assembly and returns # This function takes in a block of microcode assembly and returns
# a python list of objects which describe it. # a python list of objects which describe it.
@ -341,7 +315,13 @@ let{{
lineMatch = lineRe.search(code) lineMatch = lineRe.search(code)
# Decode the labels into displacements # Decode the labels into displacements
labels = buildLabelDict(statements)
labels = {}
micropc = 0
for statement in statements:
if statement.label:
labels[statement.label] = count
micropc += 1
micropc = 0 micropc = 0
for statement in statements: for statement in statements:
for arg in statement.args: for arg in statement.args:
@ -353,5 +333,15 @@ let{{
# micropc + 1 + displacement. # micropc + 1 + displacement.
arg["operandImm"] = labels[arg["operandLabel"]] - micropc - 1 arg["operandImm"] = labels[arg["operandLabel"]] - micropc - 1
micropc += 1 micropc += 1
return statements
# If we can implement this instruction with exactly one microop, just
# use that directly.
if len(statements) == 1:
decode_block = "return %s;" % \
statements[0].getAllocator()
return ('', '', decode_block, '')
else:
# Build a macroop to contain the sequence of microops we've
# been given.
return genMacroOp(name, Name, statements)
}}; }};

View file

@ -63,12 +63,15 @@ output header {{
}; };
}}; }};
//A class which is the base of all x86 micro ops it provides a function to //A class which is the base of all x86 micro ops. It provides a function to
//set necessary flags appropriately. //set necessary flags appropriately.
output header {{ output header {{
class X86MicroOpBase : public X86StaticInst class X86MicroOpBase : public X86StaticInst
{ {
protected: protected:
uint8_t opSize;
uint8_t addrSize;
X86MicroOpBase(bool isMicro, bool isDelayed, X86MicroOpBase(bool isMicro, bool isDelayed,
bool isFirst, bool isLast, bool isFirst, bool isLast,
const char *mnem, ExtMachInst _machInst, const char *mnem, ExtMachInst _machInst,
@ -94,6 +97,7 @@ def template BaseMicroOpTemplateDeclare {{
let {{ let {{
def buildBaseMicroOpTemplate(Name, numParams): def buildBaseMicroOpTemplate(Name, numParams):
assert(numParams > 0)
signature = "<" signature = "<"
signature += "int SignatureOperandTypeSpecifier0" signature += "int SignatureOperandTypeSpecifier0"
for count in xrange(1,numParams): for count in xrange(1,numParams):
@ -102,10 +106,9 @@ let {{
signature += ">" signature += ">"
subs = {"signature" : signature, "class_name" : Name} subs = {"signature" : signature, "class_name" : Name}
return BaseMicroOpTemplateDeclare.subst(subs) return BaseMicroOpTemplateDeclare.subst(subs)
}};
RegOpType = "RegisterOperand" let {{
ImmOpType = "ImmediateOperand"
def buildMicroOpTemplateDict(*params): def buildMicroOpTemplateDict(*params):
signature = "<" signature = "<"
if len(params): if len(params):

View file

@ -117,37 +117,33 @@ namespace X86ISA
//Operand size override prefixes //Operand size override prefixes
case OperandSizeOverride: case OperandSizeOverride:
DPRINTF(Predecoder, "Found operand size override prefix.\n"); DPRINTF(Predecoder, "Found operand size override prefix.\n");
emi.legacy.op = true;
break; break;
case AddressSizeOverride: case AddressSizeOverride:
DPRINTF(Predecoder, "Found address size override prefix.\n"); DPRINTF(Predecoder, "Found address size override prefix.\n");
emi.legacy.addr = true;
break; break;
//Segment override prefixes //Segment override prefixes
case CSOverride: case CSOverride:
DPRINTF(Predecoder, "Found cs segment override.\n");
break;
case DSOverride: case DSOverride:
DPRINTF(Predecoder, "Found ds segment override.\n");
break;
case ESOverride: case ESOverride:
DPRINTF(Predecoder, "Found es segment override.\n");
break;
case FSOverride: case FSOverride:
DPRINTF(Predecoder, "Found fs segment override.\n");
break;
case GSOverride: case GSOverride:
DPRINTF(Predecoder, "Found gs segment override.\n");
break;
case SSOverride: case SSOverride:
DPRINTF(Predecoder, "Found ss segment override.\n"); DPRINTF(Predecoder, "Found segment override.\n");
emi.legacy.seg = prefix;
break; break;
case Lock: case Lock:
DPRINTF(Predecoder, "Found lock prefix.\n"); DPRINTF(Predecoder, "Found lock prefix.\n");
emi.legacy.lock = true;
break; break;
case Rep: case Rep:
DPRINTF(Predecoder, "Found rep prefix.\n"); DPRINTF(Predecoder, "Found rep prefix.\n");
emi.legacy.rep = true;
break; break;
case Repne: case Repne:
DPRINTF(Predecoder, "Found repne prefix.\n"); DPRINTF(Predecoder, "Found repne prefix.\n");
emi.legacy.repne = true;
break; break;
case RexPrefix: case RexPrefix:
DPRINTF(Predecoder, "Found Rex prefix %#x.\n", nextByte); DPRINTF(Predecoder, "Found Rex prefix %#x.\n", nextByte);
@ -198,16 +194,36 @@ namespace X86ISA
displacementCollected = 0; displacementCollected = 0;
emi.displacement = 0; emi.displacement = 0;
//Figure out the effective operand size. This can be overriden to
//a fixed value at the decoder level.
if(/*FIXME long mode*/1)
{
if(emi.rex && emi.rex.w)
emi.opSize = 3; // 64 bit operand size
else if(emi.legacy.op)
emi.opSize = 1; // 16 bit operand size
else
emi.opSize = 2; // 32 bit operand size
}
else if(/*FIXME default 32*/1)
{
if(emi.legacy.op)
emi.opSize = 1; // 16 bit operand size
else
emi.opSize = 2; // 32 bit operand size
}
else // 16 bit default operand size
{
if(emi.legacy.op)
emi.opSize = 2; // 32 bit operand size
else
emi.opSize = 1; // 16 bit operand size
}
//Figure out how big of an immediate we'll retreive based //Figure out how big of an immediate we'll retreive based
//on the opcode. //on the opcode.
int immType = ImmediateType[ int immType = ImmediateType[emi.opcode.num - 1][nextByte];
emi.opcode.num - 1][nextByte]; immediateSize = SizeTypeToSize[emi.opSize - 1][immType];
if(0) //16 bit mode
immediateSize = ImmediateTypeToSize[0][immType];
else if(!(emi.rex & 0x4)) //32 bit mode
immediateSize = ImmediateTypeToSize[1][immType];
else //64 bit mode
immediateSize = ImmediateTypeToSize[2][immType];
//Determine what to expect next //Determine what to expect next
if (UsesModRM[emi.opcode.num - 1][nextByte]) { if (UsesModRM[emi.opcode.num - 1][nextByte]) {
@ -351,6 +367,16 @@ namespace X86ISA
if(immediateSize == immediateCollected) if(immediateSize == immediateCollected)
{ {
//XXX Warning! The following is an observed pattern and might
//not always be true!
//Instructions which use 64 bit operands but 32 bit immediates
//need to have the immediate sign extended to 64 bits.
//Instructions which use true 64 bit immediates won't be
//affected, and instructions that use true 32 bit immediates
//won't notice.
if(immediateSize == 4)
emi.immediate = sext<32>(emi.immediate);
DPRINTF(Predecoder, "Collected immediate %#x.\n", DPRINTF(Predecoder, "Collected immediate %#x.\n",
emi.immediate); emi.immediate);
emiIsReady = true; emiIsReady = true;

View file

@ -73,7 +73,7 @@ namespace X86ISA
static const uint8_t Prefixes[256]; static const uint8_t Prefixes[256];
static const uint8_t UsesModRM[2][256]; static const uint8_t UsesModRM[2][256];
static const uint8_t ImmediateType[2][256]; static const uint8_t ImmediateType[2][256];
static const uint8_t ImmediateTypeToSize[3][10]; static const uint8_t SizeTypeToSize[3][10];
protected: protected:
ThreadContext * tc; ThreadContext * tc;

View file

@ -141,7 +141,7 @@ namespace X86ISA
} }
}; };
enum ImmediateTypes { enum SizeType {
NoImm, NoImm,
NI = NoImm, NI = NoImm,
ByteImm, ByteImm,
@ -158,19 +158,19 @@ namespace X86ISA
VW = VWordImm, VW = VWordImm,
ZWordImm, ZWordImm,
ZW = ZWordImm, ZW = ZWordImm,
Pointer,
PO = Pointer,
//The enter instruction takes -2- immediates for a total of 3 bytes //The enter instruction takes -2- immediates for a total of 3 bytes
Enter, Enter,
EN = Enter EN = Enter,
Pointer,
PO = Pointer
}; };
const uint8_t Predecoder::ImmediateTypeToSize[3][10] = const uint8_t Predecoder::SizeTypeToSize[3][10] =
{ {
// noimm byte word dword qword oword vword zword enter // noimm byte word dword qword oword vword zword enter pointer
{0, 1, 2, 4, 8, 16, 2, 2, 3, 4}, //16 bit {0, 1, 2, 4, 8, 16, 2, 2, 3, 4 }, //16 bit
{0, 1, 2, 4, 8, 16, 4, 4, 3, 6}, //32 bit {0, 1, 2, 4, 8, 16, 4, 4, 3, 6 }, //32 bit
{0, 1, 2, 4, 8, 16, 4, 8, 3, 0} //64 bit {0, 1, 2, 4, 8, 16, 4, 8, 3, 0 } //64 bit
}; };
//This table determines the immediate type. The first index is the //This table determines the immediate type. The first index is the

View file

@ -70,25 +70,31 @@ namespace X86ISA
typedef uint64_t MachInst; typedef uint64_t MachInst;
enum Prefixes { enum Prefixes {
NoOverride = 0, NoOverride,
CSOverride = 1, CSOverride,
DSOverride = 2, DSOverride,
ESOverride = 3, ESOverride,
FSOverride = 4, FSOverride,
GSOverride = 5, GSOverride,
SSOverride = 6, SSOverride,
//The Rex prefix obviously doesn't fit in with the above, but putting RexPrefix,
//it here lets us save double the space the enums take up. OperandSizeOverride,
RexPrefix = 7, AddressSizeOverride,
Lock,
Rep,
Repne
};
BitUnion8(LegacyPrefixVector)
Bitfield<7> repne;
Bitfield<6> rep;
Bitfield<5> lock;
Bitfield<4> addr;
Bitfield<3> op;
//There can be only one segment override, so they share the //There can be only one segment override, so they share the
//first 3 bits in the legacyPrefixes bitfield. //first 3 bits in the legacyPrefixes bitfield.
SegmentOverride = 0x7, Bitfield<2,0> seg;
OperandSizeOverride = 8, EndBitUnion(LegacyPrefixVector)
AddressSizeOverride = 16,
Lock = 32,
Rep = 64,
Repne = 128
};
BitUnion8(ModRM) BitUnion8(ModRM)
Bitfield<7,6> mod; Bitfield<7,6> mod;
@ -118,7 +124,7 @@ namespace X86ISA
struct ExtMachInst struct ExtMachInst
{ {
//Prefixes //Prefixes
uint8_t legacy; LegacyPrefixVector legacy;
Rex rex; Rex rex;
//This holds all of the bytes of the opcode //This holds all of the bytes of the opcode
struct struct
@ -140,6 +146,10 @@ namespace X86ISA
//Immediate fields //Immediate fields
uint64_t immediate; uint64_t immediate;
uint64_t displacement; uint64_t displacement;
//The effective operand size.
uint8_t opSize;
//The
}; };
inline static std::ostream & inline static std::ostream &

View file

@ -78,7 +78,8 @@ namespace __hash_namespace {
((uint64_t)emi.opcode.prefixA << 16) | ((uint64_t)emi.opcode.prefixA << 16) |
((uint64_t)emi.opcode.prefixB << 8) | ((uint64_t)emi.opcode.prefixB << 8) |
((uint64_t)emi.opcode.op)) ^ ((uint64_t)emi.opcode.op)) ^
emi.immediate ^ emi.displacement; emi.immediate ^ emi.displacement ^
emi.opSize;
}; };
}; };
} }