(header_output,
decoder_output,
decode_block,
- exec_output) = doInst(name, Name, list(opTypeSet))
+ exce_output) = doInst(name, Name, list(opTypeSet)).makeList()
}};
def format MultiInst(switchVal, *opTypeSets) {{
(header_output,
decoder_output,
decode_block,
- exec_output) = doSplitDecode(name, Name, doInst, switchVal, switcher)
+ exec_output) = doSplitDecode(name, Name, doInst, switchVal, switcher).makeList()
}};
//
// Authors: Gabe Black
+//////////////////////////////////////////////////////////////////////////////
+//
+// Architecture independent
+//
+
// Execute method for macroops.
def template MacroExecPanic {{
Fault execute(%(CPU_exec_context)s *, Trace::InstRecord *) const
{
panic("Tried to execute macroop directly!");
- M5_DUMMY_RETURN
+ return NoFault;
}
}};
output header {{
- // Base class for most macroops, except ones that need to commit as
- // they go.
- class X86MacroInst : public StaticInst
+ // Base class for macroops
+ class MacroOp : public StaticInst
{
protected:
const uint32_t numMicroOps;
//Constructor.
- X86MacroInst(const char *mnem, ExtMachInst _machInst,
+ MacroOp(const char *mnem, ExtMachInst _machInst,
uint32_t _numMicroOps)
: StaticInst(mnem, _machInst, No_OpClass),
numMicroOps(_numMicroOps)
flags[IsMacroOp] = true;
}
- ~X86MacroInst()
+ ~MacroOp()
{
delete [] microOps;
}
return microOps[microPC];
}
+ std::string generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ return mnemonic;
+ }
+
%(MacroExecPanic)s
};
}};
+// Basic instruction class declaration template.
+def template MacroDeclare {{
+ /**
+ * Static instruction class for "%(mnemonic)s".
+ */
+ class %(class_name)s : public %(base_class)s
+ {
+ public:
+ // Constructor.
+ %(class_name)s(ExtMachInst machInst);
+ };
+}};
+
// Basic instruction class constructor template.
def template MacroConstructor {{
inline %(class_name)s::%(class_name)s(ExtMachInst machInst)
}
}};
+//////////////////////////////////////////////////////////////////////////////
+//
+// X86 specific
+//
+
let {{
def genMacroOp(name, Name, opSeq):
- baseClass = 'X86MacroInst'
- numMicroOps = len(opSeq.ops)
+ numMicroOps = len(opSeq)
allocMicroOps = ''
micropc = 0
- for op in opSeq.ops:
+ for op in opSeq:
allocMicroOps += \
"microOps[%d] = %s;\n" % \
- (micropc, op.getAllocator(True, op.delayed,
+ (micropc, op.getAllocator('"' + name + '"', True, False, #op.delayed,
micropc == 0,
micropc == numMicroOps - 1))
micropc += 1
- iop = InstObjParams(name, Name, baseClass,
+ iop = InstObjParams(name, Name, 'MacroOp',
{'code' : '', 'num_micro_ops' : numMicroOps,
'alloc_micro_ops' : allocMicroOps})
- header_output = BasicDeclare.subst(iop)
+ header_output = MacroDeclare.subst(iop)
decoder_output = MacroConstructor.subst(iop)
decode_block = BasicDecode.subst(iop)
exec_output = ''
text += ", false"
return text
- def getAllocator(self, *microFlags):
+ def getAllocator(self, mnemonic, *microFlags):
args = ''
signature = "<"
emptySig = True
else:
raise Exception, "Unrecognized operand type."
signature += ">"
- return 'new %s%s(machInst%s%s)' % (self.className, signature, self.microFlagsText(microFlags), args)
+ return 'new %s%s(machInst, %s%s%s)' % (self.className, signature, mnemonic, self.microFlagsText(microFlags), args)
}};
let{{
# the beginning of the line, so the previous component is stripped
# before continuing.
labelRe = re.compile(r'^[ \t]*(?P<label>\w\w*)[ \t]:')
- lineRe = re.compile(r'^(?P<line>[^\n][^\n]*)$')
+ lineRe = re.compile(r'^(?P<line>..*)(\n|$)')
classRe = re.compile(r'^[ \t]*(?P<className>[a-zA-Z_]\w*)')
# This recognizes three different flavors of operands:
# 1. Raw decimal numbers composed of digits between 0 and 9
# Get a line and seperate it from the rest of the code
line = lineMatch.group("line")
orig_line = line
- # print "Parsing line %s" % line
+ #print "Parsing line %s" % line
code = lineRe.sub('', code, 1)
# Find the label, if any
labelMatch = labelRe.search(line)
if labelMatch != None:
statement.label = labelMatch.group("label")
- # print "Found label %s." % statement.label
+ #print "Found label %s." % statement.label
# Clear the label from the statement
line = labelRe.sub('', line, 1)
% orig_line
else:
statement.className = classMatch.group("className")
- # print "Found class name %s." % statement.className
+ #print "Found class name %s." % statement.className
# Clear the class name from the statement
line = classRe.sub('', line, 1)
print "Problem parsing operand in statement: %s" \
% orig_line
line = opRe.sub('', line, 1)
- # print "Found operand %s." % statement.args[-1]
+ #print "Found operand %s." % statement.args[-1]
opMatch = opRe.search(line)
- # print "Found operands", statement.args
+ #print "Found operands", statement.args
# Add this statement to our collection
statements.append(statement)
arg["operandImm"] = labels[arg["operandLabel"]] - micropc - 1
micropc += 1
+ if len(statements) == 0:
+ raise Exception, "Didn't find any microops in microcode: \n%s" % orig_code
+
# 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()
+ statements[0].getAllocator('"' + name + '"')
return ('', '', decode_block, '')
else:
# Build a macroop to contain the sequence of microops we've
class X86MicroOpBase : public X86StaticInst
{
protected:
+ const char * instMnem;
uint8_t opSize;
uint8_t addrSize;
- X86MicroOpBase(bool isMicro, bool isDelayed,
+ X86MicroOpBase(ExtMachInst _machInst,
+ const char *mnem, const char *_instMnem,
+ bool isMicro, bool isDelayed,
bool isFirst, bool isLast,
- const char *mnem, ExtMachInst _machInst,
OpClass __opClass) :
- X86StaticInst(mnem, _machInst, __opClass)
+ X86StaticInst(mnem, _machInst, __opClass),
+ instMnem(_instMnem)
{
flags[IsMicroOp] = isMicro;
flags[IsDelayedCommit] = isDelayed;
flags[IsFirstMicroOp] = isFirst;
flags[IsLastMicroOp] = isLast;
}
+
+ std::string generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ std::stringstream ss;
+
+ ccprintf(ss, "\t%s.%s", instMnem, mnemonic);
+
+ return ss.str();
+ }
};
}};
}};
// A tmeplate for building a specialized version of the microcode
-// instruction which knows specifies which arguments it wants
+// instruction which specifies which arguments it wants
def template MicroOpDeclare {{
template<>
class %(class_name)s%(signature)s : public X86MicroOpBase
void buildMe();
public:
- %(class_name)s(bool isMicro, bool isDelayed,
- bool isFirst, bool isLast,
- ExtMachInst _machInst %(param_arg_dec)s);
+ %(class_name)s(ExtMachInst _machInst,
+ const char * instMnem,
+ bool isMicro, bool isDelayed,
+ bool isFirst, bool isLast
+ %(param_arg_dec)s);
- %(class_name)s(ExtMachInst _machInst %(param_arg_dec)s);
+ %(class_name)s(ExtMachInst _machInst,
+ const char * instMnem
+ %(param_arg_dec)s);
%(BasicExecDeclare)s
};
}
inline %(class_name)s%(signature)s::%(class_name)s(
- ExtMachInst machInst %(param_arg_dec)s) :
- %(base_class)s(false, false, false, false,
- "%(mnemonic)s", machInst, %(op_class)s)
+ ExtMachInst machInst, const char * instMnem
+ %(param_arg_dec)s) :
+ %(base_class)s(machInst, "%(mnemonic)s", instMnem,
+ false, false, false, false, %(op_class)s)
%(param_init)s
{
buildMe();
}
inline %(class_name)s%(signature)s::%(class_name)s(
- bool isMicro, bool isDelayed, bool isFirst, bool isLast,
- ExtMachInst machInst %(param_arg_dec)s)
- : %(base_class)s(isMicro, isDelayed, isFirst, isLast,
- "%(mnemonic)s", machInst, %(op_class)s)
+ ExtMachInst machInst, const char * instMnem,
+ bool isMicro, bool isDelayed, bool isFirst, bool isLast
+ %(param_arg_dec)s)
+ : %(base_class)s(machInst, "%(mnemonic)s", instMnem,
+ isMicro, isDelayed, isFirst, isLast, %(op_class)s)
%(param_init)s
{
buildMe();
# builder is called on the exploded contents of "vals" values to generate
# whatever code should be used.
def doSplitDecode(name, Name, builder, switchVal, vals, default = None):
- header_output = ''
- decoder_output = ''
- decode_block = 'switch(%s) {\n' % switchVal
- exec_output = ''
+ blocks = OutputBlocks()
+ blocks.decode_block += 'switch(%s) {\n' % switchVal
for (val, todo) in vals.items():
- (new_header_output,
- new_decoder_output,
- new_decode_block,
- new_exec_output) = builder(name, Name, *todo)
- header_output += new_header_output
- decoder_output += new_decoder_output
- decode_block += '\tcase %s: %s\n' % (val, new_decode_block)
- exec_output += new_exec_output
+ built = builder(name, Name, *todo)
+ built.decode_block = '\tcase %s: %s\n' % (val, built.decode_block)
+ blocks.append(built)
if default:
- (new_header_output,
- new_decoder_output,
- new_decode_block,
- new_exec_output) = builder(name, Name, *default)
- header_output += new_header_output
- decoder_output += new_decoder_output
- decode_block += '\tdefault: %s\n' % new_decode_block
- exec_output += new_exec_output
- decode_block += '}\n'
- return (header_output, decoder_output, decode_block, exec_output)
+ built = builder(name, Name, *default)
+ built.decode_block = '\tdefault: %s\n' % built.decode_block
+ blocks.append(built)
+ blocks.decode_block += '}\n'
+ return blocks
}};
let {{
# This needs to refer to memory, but we'll fill in the details
# later. It needs to take into account unaligned memory
# addresses.
+ code = "GenFault ${new UnimpInstFault}\n" + code
memCode = opRe.sub("%0", code)
memTypes = copy.copy(opTypes)
memTypes.pop(-1)
# This needs to refer to memory, but we'll fill in the details
# later. It needs to take into account unaligned memory
# addresses.
+ code = "GenFault ${new UnimpInstFault}\n" + code
code = opRe.sub("%0", code)
elif opType.tag in ("PR", "R", "VR"):
# There should probably be a check here to verify that mod
# At this point, we've built up "code" to have all the necessary extra
# instructions needed to implement whatever types of operands were
# specified. Now we'll assemble it it into a StaticInst.
- return assembleMicro(name, Name, code)
+ blocks = OutputBlocks()
+ blocks.append(assembleMicro(name, Name, code))
+ return blocks
}};