X86: Autogenerate macroop generateDisassemble function.
This commit is contained in:
parent
8cab1805f9
commit
115b1a7ed3
11 changed files with 121 additions and 32 deletions
|
@ -65,17 +65,19 @@
|
|||
namespace X86ISA
|
||||
{
|
||||
// Base class for combinationally generated macroops
|
||||
class MacroopBase : public StaticInst
|
||||
class MacroopBase : public X86StaticInst
|
||||
{
|
||||
protected:
|
||||
const char *macrocodeBlock;
|
||||
|
||||
const uint32_t numMicroops;
|
||||
X86ISA::EmulEnv emulEnv;
|
||||
X86ISA::EmulEnv env;
|
||||
|
||||
//Constructor.
|
||||
MacroopBase(const char *mnem, ExtMachInst _machInst,
|
||||
uint32_t _numMicroops, X86ISA::EmulEnv _emulEnv)
|
||||
: StaticInst(mnem, _machInst, No_OpClass),
|
||||
numMicroops(_numMicroops), emulEnv(_emulEnv)
|
||||
uint32_t _numMicroops, X86ISA::EmulEnv _env) :
|
||||
X86StaticInst(mnem, _machInst, No_OpClass),
|
||||
numMicroops(_numMicroops), env(_env)
|
||||
{
|
||||
assert(numMicroops);
|
||||
microops = new StaticInstPtr[numMicroops];
|
||||
|
@ -95,8 +97,8 @@ class MacroopBase : public StaticInst
|
|||
return microops[microPC];
|
||||
}
|
||||
|
||||
std::string generateDisassembly(Addr pc,
|
||||
const SymbolTable *symtab) const
|
||||
std::string
|
||||
generateDisassembly(Addr pc, const SymbolTable *symtab) const
|
||||
{
|
||||
return mnemonic;
|
||||
}
|
||||
|
@ -111,7 +113,7 @@ class MacroopBase : public StaticInst
|
|||
X86ISA::EmulEnv
|
||||
getEmulEnv()
|
||||
{
|
||||
return emulEnv;
|
||||
return env;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -76,8 +76,8 @@ output header {{
|
|||
{
|
||||
public:
|
||||
Macroop(const char *mnem, ExtMachInst _machInst,
|
||||
uint32_t _numMicroops, X86ISA::EmulEnv _emulEnv)
|
||||
: MacroopBase(mnem, _machInst, _numMicroops, _emulEnv)
|
||||
uint32_t _numMicroops, X86ISA::EmulEnv _env)
|
||||
: MacroopBase(mnem, _machInst, _numMicroops, _env)
|
||||
{}
|
||||
%(MacroExecPanic)s
|
||||
};
|
||||
|
@ -102,22 +102,42 @@ def template MacroDeclare {{
|
|||
%(declareLabels)s
|
||||
public:
|
||||
// Constructor.
|
||||
%(class_name)s(ExtMachInst machInst, X86ISA::EmulEnv env);
|
||||
%(class_name)s(ExtMachInst machInst, X86ISA::EmulEnv _env);
|
||||
|
||||
std::string
|
||||
generateDisassembly(Addr pc, const SymbolTable *symtab) const;
|
||||
};
|
||||
};
|
||||
}};
|
||||
|
||||
def template MacroDisassembly {{
|
||||
std::string
|
||||
X86Macroop::%(class_name)s::generateDisassembly(Addr pc,
|
||||
const SymbolTable *symtab) const
|
||||
{
|
||||
std::stringstream out;
|
||||
out << mnemonic << "\t";
|
||||
|
||||
int regSize = %(regSize)s;
|
||||
%(disassembly)s
|
||||
// Shut up gcc.
|
||||
regSize = regSize;
|
||||
return out.str();
|
||||
}
|
||||
}};
|
||||
|
||||
// Basic instruction class constructor template.
|
||||
def template MacroConstructor {{
|
||||
inline X86Macroop::%(class_name)s::%(class_name)s(
|
||||
ExtMachInst machInst, EmulEnv env)
|
||||
: %(base_class)s("%(mnemonic)s", machInst, %(num_microops)s, env)
|
||||
ExtMachInst machInst, EmulEnv _env)
|
||||
: %(base_class)s("%(mnemonic)s", machInst, %(num_microops)s, _env)
|
||||
{
|
||||
%(adjust_env)s;
|
||||
%(adjust_imm)s;
|
||||
%(adjust_disp)s;
|
||||
%(do_modrm)s;
|
||||
%(constructor)s;
|
||||
const char *macrocodeBlock = "%(class_name)s";
|
||||
//alloc_microops is the code that sets up the microops
|
||||
//array in the parent class.
|
||||
%(alloc_microops)s;
|
||||
|
@ -158,7 +178,12 @@ let {{
|
|||
adjustedDisp = adjustedDisp;
|
||||
'''
|
||||
def getAllocator(self, env):
|
||||
return "new X86Macroop::%s(machInst, %s)" % (self.name, env.getAllocator())
|
||||
return "new X86Macroop::%s(machInst, %s)" % \
|
||||
(self.name, env.getAllocator())
|
||||
def getMnemonic(self):
|
||||
mnemonic = self.name.lower()
|
||||
mnemonic = re.match(r'[^_]*', mnemonic).group(0)
|
||||
return mnemonic
|
||||
def getDeclaration(self):
|
||||
#FIXME This first parameter should be the mnemonic. I need to
|
||||
#write some code which pulls that out
|
||||
|
@ -166,12 +191,12 @@ let {{
|
|||
for (label, microop) in self.labels.items():
|
||||
declareLabels += "const static uint64_t label_%s = %d;\n" \
|
||||
% (label, microop.micropc)
|
||||
iop = InstObjParams(self.name, self.name, "Macroop",
|
||||
iop = InstObjParams(self.getMnemonic(), self.name, "Macroop",
|
||||
{"code" : "",
|
||||
"declareLabels" : declareLabels
|
||||
})
|
||||
return MacroDeclare.subst(iop);
|
||||
def getDefinition(self):
|
||||
def getDefinition(self, env):
|
||||
#FIXME This first parameter should be the mnemonic. I need to
|
||||
#write some code which pulls that out
|
||||
numMicroops = len(self.microops)
|
||||
|
@ -184,14 +209,28 @@ let {{
|
|||
(micropc, op.getAllocator(True, not isLast,
|
||||
micropc == 0, isLast))
|
||||
micropc += 1
|
||||
iop = InstObjParams(self.name, self.name, "Macroop",
|
||||
if env.useStackSize:
|
||||
useStackSize = "true"
|
||||
else:
|
||||
useStackSize = "false"
|
||||
if env.memoryInst:
|
||||
memoryInst = "true"
|
||||
else:
|
||||
memoryInst = "false"
|
||||
regSize = '''(%s || (env.base == INTREG_RSP && %s) ?
|
||||
env.stackSize :
|
||||
env.dataSize)''' % (useStackSize, memoryInst)
|
||||
iop = InstObjParams(self.getMnemonic(), self.name, "Macroop",
|
||||
{"code" : "", "num_microops" : numMicroops,
|
||||
"alloc_microops" : allocMicroops,
|
||||
"adjust_env" : self.adjust_env,
|
||||
"adjust_imm" : self.adjust_imm,
|
||||
"adjust_disp" : self.adjust_disp,
|
||||
"disassembly" : env.disassembly,
|
||||
"regSize" : regSize,
|
||||
"do_modrm" : self.doModRM})
|
||||
return MacroConstructor.subst(iop);
|
||||
return MacroConstructor.subst(iop) + \
|
||||
MacroDisassembly.subst(iop);
|
||||
}};
|
||||
|
||||
let {{
|
||||
|
@ -207,6 +246,16 @@ let {{
|
|||
self.dataSize = "OPSIZE"
|
||||
self.stackSize = "STACKSIZE"
|
||||
self.doModRM = False
|
||||
self.disassembly = ""
|
||||
self.firstArgument = True
|
||||
self.useStackSize = False
|
||||
self.memoryInst = False
|
||||
|
||||
def addToDisassembly(self, code):
|
||||
if not self.firstArgument:
|
||||
self.disassembly += "out << \", \";\n"
|
||||
self.firstArgument = False
|
||||
self.disassembly += code
|
||||
|
||||
def getAllocator(self):
|
||||
if self.size == 'b':
|
||||
|
@ -264,7 +313,7 @@ let {{
|
|||
if env.doModRM:
|
||||
macroop.doModRM = doModRMString
|
||||
blocks.header_output = macroop.getDeclaration()
|
||||
blocks.decoder_output = macroop.getDefinition()
|
||||
blocks.decoder_output = macroop.getDefinition(env)
|
||||
macroop.declared = True
|
||||
blocks.decode_block = "return %s;\n" % macroop.getAllocator(env)
|
||||
return blocks
|
||||
|
|
|
@ -76,7 +76,7 @@ let {{
|
|||
StaticInstPtr
|
||||
''' + generatorNameTemplate + '''(StaticInstPtr curMacroop)
|
||||
{
|
||||
static const char * mnemonic = romMnemonic;
|
||||
static const char *macrocodeBlock = romMnemonic;
|
||||
static const ExtMachInst dummyExtMachInst;
|
||||
static const EmulEnv dummyEmulEnv(0, 0, 1, 1, 1);
|
||||
|
||||
|
|
|
@ -183,7 +183,7 @@ let {{
|
|||
self.cond = "0"
|
||||
|
||||
def getAllocator(self, *microFlags):
|
||||
allocator = '''new %(class_name)s(machInst, mnemonic
|
||||
allocator = '''new %(class_name)s(machInst, macrocodeBlock
|
||||
%(flags)s, "%(message)s", %(cc)s)''' % {
|
||||
"class_name" : self.className,
|
||||
"flags" : self.microFlagsText(microFlags),
|
||||
|
|
|
@ -245,7 +245,7 @@ let {{
|
|||
self.className += "Top"
|
||||
|
||||
def getAllocator(self, *microFlags):
|
||||
return '''new %(class_name)s(machInst, mnemonic
|
||||
return '''new %(class_name)s(machInst, macrocodeBlock
|
||||
%(flags)s, %(src1)s, %(src2)s, %(dest)s,
|
||||
%(dataSize)s, %(spm)d)''' % {
|
||||
"class_name" : self.className,
|
||||
|
|
|
@ -362,7 +362,7 @@ let {{
|
|||
self.addressSize = addressSize
|
||||
|
||||
def getAllocator(self, *microFlags):
|
||||
allocator = '''new %(class_name)s(machInst, mnemonic
|
||||
allocator = '''new %(class_name)s(machInst, macrocodeBlock
|
||||
%(flags)s, %(scale)s, %(index)s, %(base)s,
|
||||
%(disp)s, %(segment)s, %(data)s,
|
||||
%(dataSize)s, %(addressSize)s)''' % {
|
||||
|
|
|
@ -154,7 +154,7 @@ let {{
|
|||
self.dataSize = dataSize
|
||||
|
||||
def getAllocator(self, *microFlags):
|
||||
allocator = '''new %(class_name)s(machInst, mnemonic
|
||||
allocator = '''new %(class_name)s(machInst, macrocodeBlock
|
||||
%(flags)s, %(dest)s, %(imm)s, %(dataSize)s)''' % {
|
||||
"class_name" : self.className,
|
||||
"mnemonic" : self.mnemonic,
|
||||
|
|
|
@ -438,7 +438,7 @@ let {{
|
|||
className = self.className
|
||||
if self.mnemonic == self.base_mnemonic + 'i':
|
||||
className += "Imm"
|
||||
allocator = '''new %(class_name)s(machInst, mnemonic
|
||||
allocator = '''new %(class_name)s(machInst, macrocodeBlock
|
||||
%(flags)s, %(src1)s, %(op2)s, %(dest)s,
|
||||
%(dataSize)s, %(ext)s)''' % {
|
||||
"class_name" : className,
|
||||
|
|
|
@ -181,7 +181,7 @@ let {{
|
|||
self.cond = "0"
|
||||
|
||||
def getAllocator(self, *microFlags):
|
||||
allocator = '''new %(class_name)s(machInst, mnemonic
|
||||
allocator = '''new %(class_name)s(machInst, macrocodeBlock
|
||||
%(flags)s, %(target)s, %(cc)s)''' % {
|
||||
"class_name" : self.className,
|
||||
"flags" : self.microFlagsText(microFlags),
|
||||
|
|
|
@ -230,7 +230,7 @@ let {{
|
|||
self.cond = "0"
|
||||
|
||||
def getAllocator(self, *microFlags):
|
||||
allocator = '''new %(class_name)s(machInst, mnemonic
|
||||
allocator = '''new %(class_name)s(machInst, macrocodeBlock
|
||||
%(flags)s, %(fault)s, %(cc)s)''' % {
|
||||
"class_name" : self.className,
|
||||
"flags" : self.microFlagsText(microFlags),
|
||||
|
@ -257,7 +257,7 @@ let {{
|
|||
pass
|
||||
|
||||
def getAllocator(self, *microFlags):
|
||||
return "new MicroHalt(machInst, mnemonic %s)" % \
|
||||
return "new MicroHalt(machInst, macrocodeBlock %s)" % \
|
||||
self.microFlagsText(microFlags)
|
||||
|
||||
microopClasses["halt"] = Halt
|
||||
|
|
|
@ -86,8 +86,17 @@ let {{
|
|||
let {{
|
||||
def doRipRelativeDecode(Name, opTypes, env):
|
||||
# print "RIPing %s with opTypes %s" % (Name, opTypes)
|
||||
normBlocks = specializeInst(Name + "_M", copy.copy(opTypes), copy.copy(env))
|
||||
ripBlocks = specializeInst(Name + "_P", copy.copy(opTypes), copy.copy(env))
|
||||
env.memoryInst = True
|
||||
normEnv = copy.copy(env)
|
||||
normEnv.addToDisassembly(
|
||||
'''printMem(out, env.seg, env.scale, env.index, env.base,
|
||||
machInst.displacement, env.addressSize, false);''')
|
||||
normBlocks = specializeInst(Name + "_M", copy.copy(opTypes), normEnv)
|
||||
ripEnv = copy.copy(env)
|
||||
ripEnv.addToDisassembly(
|
||||
'''printMem(out, env.seg, 1, 0, 0,
|
||||
machInst.displacement, env.addressSize, true);''')
|
||||
ripBlocks = specializeInst(Name + "_P", copy.copy(opTypes), ripEnv)
|
||||
|
||||
blocks = OutputBlocks()
|
||||
blocks.append(normBlocks)
|
||||
|
@ -138,12 +147,17 @@ let {{
|
|||
#Figure out what to do with fixed register operands
|
||||
#This is the index to use, so we should stick it some place.
|
||||
if opType.reg in ("A", "B", "C", "D"):
|
||||
env.addReg("INTREG_R%sX" % opType.reg)
|
||||
regString = "INTREG_R%sX" % opType.reg
|
||||
else:
|
||||
env.addReg("INTREG_R%s" % opType.reg)
|
||||
regString = "INTREG_R%s" % opType.reg
|
||||
env.addReg(regString)
|
||||
env.addToDisassembly(
|
||||
"printReg(out, %s, regSize);\n" % regString)
|
||||
Name += "_R"
|
||||
elif opType.tag == "B":
|
||||
# This refers to registers whose index is encoded as part of the opcode
|
||||
env.addToDisassembly(
|
||||
"printReg(out, %s, regSize);\n" % InstRegIndex)
|
||||
Name += "_R"
|
||||
env.addReg(InstRegIndex)
|
||||
elif opType.tag == "M":
|
||||
|
@ -156,24 +170,34 @@ let {{
|
|||
elif opType.tag == "C":
|
||||
# A control register indexed by the "reg" field
|
||||
env.addReg(ModRMRegIndex)
|
||||
env.addToDisassembly(
|
||||
"ccprintf(out, \"CR%%d\", %s);\n" % ModRMRegIndex)
|
||||
Name += "_C"
|
||||
elif opType.tag == "D":
|
||||
# A debug register indexed by the "reg" field
|
||||
env.addReg(ModRMRegIndex)
|
||||
env.addToDisassembly(
|
||||
"ccprintf(out, \"DR%%d\", %s);\n" % ModRMRegIndex)
|
||||
Name += "_D"
|
||||
elif opType.tag == "S":
|
||||
# A segment selector register indexed by the "reg" field
|
||||
env.addReg(ModRMRegIndex)
|
||||
env.addToDisassembly(
|
||||
"printSegment(out, %s);\n" % ModRMRegIndex)
|
||||
Name += "_S"
|
||||
elif opType.tag in ("G", "P", "T", "V"):
|
||||
# Use the "reg" field of the ModRM byte to select the register
|
||||
env.addReg(ModRMRegIndex)
|
||||
env.addToDisassembly(
|
||||
"printReg(out, %s, regSize);\n" % ModRMRegIndex)
|
||||
Name += "_R"
|
||||
elif opType.tag in ("E", "Q", "W"):
|
||||
# This might refer to memory or to a register. We need to
|
||||
# divide it up farther.
|
||||
regEnv = copy.copy(env)
|
||||
regEnv.addReg(ModRMRMIndex)
|
||||
regEnv.addToDisassembly(
|
||||
"printReg(out, %s, regSize);\n" % ModRMRMIndex)
|
||||
# This refers to memory. The macroop constructor should set up
|
||||
# modrm addressing.
|
||||
memEnv = copy.copy(env)
|
||||
|
@ -183,6 +207,8 @@ let {{
|
|||
(doRipRelativeDecode, Name, copy.copy(opTypes), memEnv))
|
||||
elif opType.tag in ("I", "J"):
|
||||
# Immediates
|
||||
env.addToDisassembly(
|
||||
"ccprintf(out, \"%#x\", machInst.immediate);\n")
|
||||
Name += "_I"
|
||||
elif opType.tag == "O":
|
||||
# Immediate containing a memory offset
|
||||
|
@ -190,10 +216,22 @@ let {{
|
|||
elif opType.tag in ("PR", "R", "VR"):
|
||||
# Non register modrm settings should cause an error
|
||||
env.addReg(ModRMRMIndex)
|
||||
env.addToDisassembly(
|
||||
"printReg(out, %s, regSize);\n" % ModRMRMIndex)
|
||||
Name += "_R"
|
||||
elif opType.tag in ("X", "Y"):
|
||||
# This type of memory addressing is for string instructions.
|
||||
# They'll use the right index and segment internally.
|
||||
if opType.tag == "X":
|
||||
env.addToDisassembly(
|
||||
'''printMem(out, env.seg,
|
||||
1, X86ISA::ZeroReg, X86ISA::INTREG_RSI, 0,
|
||||
env.addressSize, false);''')
|
||||
else:
|
||||
env.addToDisassembly(
|
||||
'''printMem(out, SEGMENT_REG_ES,
|
||||
1, X86ISA::ZeroReg, X86ISA::INTREG_RDI, 0,
|
||||
env.addressSize, false);''')
|
||||
Name += "_M"
|
||||
else:
|
||||
raise Exception, "Unrecognized tag %s." % opType.tag
|
||||
|
|
Loading…
Reference in a new issue