summaryrefslogtreecommitdiff
path: root/src/arch/x86/isa/formats/multi.isa
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/x86/isa/formats/multi.isa')
-rw-r--r--src/arch/x86/isa/formats/multi.isa217
1 files changed, 137 insertions, 80 deletions
diff --git a/src/arch/x86/isa/formats/multi.isa b/src/arch/x86/isa/formats/multi.isa
index c14e80095..9fceec2b0 100644
--- a/src/arch/x86/isa/formats/multi.isa
+++ b/src/arch/x86/isa/formats/multi.isa
@@ -60,95 +60,152 @@
// Instructions that do the same thing to multiple sets of arguments.
//
-output header {{
-}};
-
-output decoder {{
-}};
-
-output exec {{
+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 {{
- multiops = {}
+ # 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.
+ # builder is called on the exploded contents of "vals" values to generate
+ # whatever code should be used.
+ def doMultiOp(name, Name, builder, switchVal, vals, default = None):
+ header_output = ''
+ decoder_output = ''
+ decode_block = 'switch(%s) {\n' % switchVal
+ exec_output = ''
+ 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
+ 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)
}};
-def format MultiOp(code, switchVal, opTags, *opt_flags) {{
- # These are C++ statements to create each type of static int. Since we
- # don't know what will be microcoded and what won't, we can't assume a
- # particular set of arguments for the constructor.
- instNew = []
- orig_code = code
- opRe = re.compile(r"%(?P<operandNum>[0-9]*)")
- # Get all the labels out of the code and make a dict for them. We'll do
- # this once since the position of labels shouldn't need to change at all.
- ops = assembleMicro(code)
- labels = buildLabelDict(ops)
- for tagSet in opTags:
- # A list of strings which either have the register number to use, or
- # a piece of code for calculating it.
- regNums = []
- code = orig_code
- # Build up a name for this instructions class using the argument
- # types. Each variation will get its own name this way.
- postfix = ''
- for tag in tagSet:
- postfix += '_' + tag
-
- # Figure out what register indexes to use for each operand. This
- # is where loads/stores could be set up. I need to distinguish
- # between inputs and outputs.
- # For right now, the indexes are just an increasing sequence
- counter = 0
- for tag in tagSet:
- regNums.append("%d" % counter)
- counter += 1
+let {{
- # Replace the placeholders %0, %1, etc., with the right register
- # indexes.
- opMatch = opRe.search(code)
- while opMatch:
- opNum = opMatch.group("operandNum")
- opNum = int(opNum)
- if opNum > len(regNums):
- print "No operand type specified for operand %d!" % opNum
- print "I should bail out here too!"
- regNum = regNums[opNum]
- code = opRe.sub(regNum, code, 1)
- opMatch = opRe.search(code)
+ # This function specializes the given piece of code to use a particular
+ # set of argument types described by "opTags". These are "implemented"
+ # in reverse order.
+ def doCompOps(name, Name, code, opTags, postfix):
+ opNum = len(opTags) - 1
+ while len(opTags):
+ # print "Building a composite op with tags", opTags
+ # print "And code", code
+ opNum = len(opTags) - 1
+ # A regular expression to find the operand placeholders we're
+ # interested in.
+ opRe = re.compile("%%(?P<operandNum>%d)(?=[^0-9]|$)" % opNum)
+ tag = opTags[opNum]
+ # Build up a name for this instructions class using the argument
+ # types. Each variation will get its own name this way.
+ postfix = '_' + tag + postfix
+ tagParser = re.compile(r"(?P<tagType>[A-Z][A-Z]*)(?P<tagSize>[a-z][a-z]*)|(r(?P<tagReg>[A-Za-z0-9][A-Za-z0-9]*))")
+ tagMatch = tagParser.search(tag)
+ if tagMatch == None:
+ raise Exception, "Problem parsing operand tag %s" % tag
+ reg = tagMatch.group("tagReg")
+ tagType = tagMatch.group("tagType")
+ tagSize = tagMatch.group("tagSize")
+ if reg:
+ #Figure out what to do with fixed register operands
+ if reg in ("Ax", "Bx", "Cx", "Dx"):
+ code = opRe.sub("{INTREG_R%s}" % reg.upper(), code)
+ elif reg == "Al":
+ # We need a way to specify register width
+ code = opRe.sub("{INTREG_RAX}", code)
+ else:
+ print "Didn't know how to encode fixed register %s!" % reg
+ elif tagType == None or tagSize == None:
+ raise Exception, "Problem parsing operand tag: %s" % tag
+ elif tagType == "C" or tagType == "D" or tagType == "G" or \
+ tagType == "P" or tagType == "S" or \
+ tagType == "T" or tagType == "V":
+ # Use the "reg" field of the ModRM byte to select the register
+ code = opRe.sub("{(uint8_t)MODRM_REG}", code)
+ elif tagType == "E" or tagType == "Q" or tagType == "W":
+ # This might refer to memory or to a register. We need to
+ # divide it up farther.
+ regCode = opRe.sub("{(uint8_t)MODRM_RM}", code)
+ regTags = copy.copy(opTags)
+ regTags.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.
+ memCode = opRe.sub("0", code)
+ memTags = copy.copy(opTags)
+ memTags.pop(-1)
+ return doMultiOp(name, Name, doCompOps, "MODRM_MOD",
+ {"3" : (regCode, regTags, postfix)},
+ (memCode, memTags, postfix))
+ elif tagType == "I" or tagType == "J":
+ # Substitute in an immediate
+ code = opRe.sub("{IMMEDIATE}", code)
+ elif tagType == "M":
+ # This needs to refer to memory, but we'll fill in the details
+ # later. It needs to take into account unaligned memory
+ # addresses.
+ code = opRe.sub("0", code)
+ elif tagType == "PR" or tagType == "R" or tagType == "VR":
+ # There should probably be a check here to verify that mod
+ # is equal to 11b
+ code = opRe.sub("{(uint8_t)MODRM_RM}", code)
+ else:
+ raise Exception, "Unrecognized tag %s." % tag
+ opTags.pop(-1)
- # All the loads which feed this instruction
- loads = []
- # All the ops that make up the instruction proper.
+ # 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 microOp sequence.
ops = assembleMicro(code)
- # Get all the labels out and make a dict for them
- # All the stores for this instruction's results
- stores = []
-
- # Various counts
- numLoads = len(loads)
- numOps = len(ops)
- numStores = len(stores)
- totalOps = numLoads + numOps + numStores
- print "There are %d total ops" % totalOps
- # If we can implement this instruction with exactly one microop, just
- # use that directly.
- newStmnt = ''
- if totalOps == 1:
- newStmnt = ops[0].getAllocator(labels)
- else:
- # Build up a macro op. We'll punt on this for now
- pass
+ # 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 + postfix, ops)
+}};
- instNew.append(newStmnt)
+def format TaggedOp(code, tagSet) {{
+ (header_output,
+ decoder_output,
+ decode_block,
+ exec_output) = doCompOps(name, Name, code, tagSet, '')
+}};
- decodeBlob = 'switch(%s) {\n' % switchVal
- counter = 0
- for newStmnt in instNew:
- decodeBlob += 'case %d: return (X86StaticInst *)(%s);\n' % \
- (counter, newStmnt)
- counter += 1
- decodeBlob += '}\n'
- decode_block = decodeBlob
+def format MultiOp(code, switchVal, opTags, *opt_flags) {{
+ switcher = {}
+ for (count, tagSet) in zip(xrange(len(opTags) - 1), opTags):
+ switcher[count] = (code, tagSet, '')
+ (header_output,
+ decoder_output,
+ decode_block,
+ exec_output) = doMultiOp(name, Name, doCompOps, switchVal, switcher)
}};