From 6010c6ded4e6d6c2cdaf5ac08678165580a29008 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Wed, 4 Apr 2007 14:25:36 +0000 Subject: Added all the different variations of the register names. --HG-- extra : convert_revision : ff06bdca556a5e1a0dfe7978575c2277c30c002a --- src/arch/x86/intregs.hh | 84 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 76 insertions(+), 8 deletions(-) diff --git a/src/arch/x86/intregs.hh b/src/arch/x86/intregs.hh index ed801cc48..562539de9 100644 --- a/src/arch/x86/intregs.hh +++ b/src/arch/x86/intregs.hh @@ -63,21 +63,89 @@ namespace X86ISA enum IntRegIndex { INTREG_RAX, + INTREG_EAX = INTREG_RAX, + INTREG_AX = INTREG_RAX, + INTREG_AL = INTREG_RAX, + INTREG_AH = INTREG_RAX, + INTREG_RCX, + INTREG_ECX = INTREG_RCX, + INTREG_CX = INTREG_RCX, + INTREG_CL = INTREG_RCX, + INTREG_CH = INTREG_RCX, + INTREG_RDX, + INTREG_EDX = INTREG_RDX, + INTREG_DX = INTREG_RDX, + INTREG_DL = INTREG_RDX, + INTREG_DH = INTREG_RDX, + INTREG_RBX, + INTREG_EBX = INTREG_RBX, + INTREG_BX = INTREG_RBX, + INTREG_BL = INTREG_RBX, + INTREG_BH = INTREG_RBX, + INTREG_RSP, + INTREG_ESP = INTREG_RSP, + INTREG_SP = INTREG_RSP, + INTREG_SPL = INTREG_RSP, + INTREG_RBP, + INTREG_EBP = INTREG_RBP, + INTREG_BP = INTREG_RBP, + INTREG_BPL = INTREG_RBP, + INTREG_RSI, + INTREG_ESI = INTREG_RSI, + INTREG_SI = INTREG_RSI, + INTREG_SIL = INTREG_RSI, + INTREG_RDI, - INTREG_R8W, - INTREG_R9W, - INTREG_R10W, - INTREG_R11W, - INTREG_R12W, - INTREG_R13W, - INTREG_R14W, - INTREG_R15W, + INTREG_EDI = INTREG_RDI, + INTREG_DI = INTREG_RDI, + INTREG_DIL = INTREG_RDI, + + INTREG_R8, + INTREG_R8D = INTREG_R8, + INTREG_R8W = INTREG_R8, + INTREG_R8B = INTREG_R8, + + INTREG_R9, + INTREG_R9D = INTREG_R9, + INTREG_R9W = INTREG_R9, + INTREG_R9B = INTREG_R9, + + INTREG_R10, + INTREG_R10D = INTREG_R10, + INTREG_R10W = INTREG_R10, + INTREG_R10B = INTREG_R10, + + INTREG_R11, + INTREG_R11D = INTREG_R11, + INTREG_R11W = INTREG_R11, + INTREG_R11B = INTREG_R11, + + INTREG_R12, + INTREG_R12D = INTREG_R12, + INTREG_R12W = INTREG_R12, + INTREG_R12B = INTREG_R12, + + INTREG_R13, + INTREG_R13D = INTREG_R13, + INTREG_R13W = INTREG_R13, + INTREG_R13B = INTREG_R13, + + INTREG_R14, + INTREG_R14D = INTREG_R14, + INTREG_R14W = INTREG_R14, + INTREG_R14B = INTREG_R14, + + INTREG_R15, + INTREG_R15D = INTREG_R15, + INTREG_R15W = INTREG_R15, + INTREG_R15B = INTREG_R15, + NUM_INTREGS }; }; -- cgit v1.2.3 From 65fedeb5a7fd6ebb25379e20845f75635f28fdb6 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Wed, 4 Apr 2007 14:27:00 +0000 Subject: Made x86 ExtMachInsts distinguishable from each other by defining a real == and a real hash function. --HG-- extra : convert_revision : 30f29a36f6ab44e67e62aaf81b685fbe1267c746 --- src/arch/x86/types.hh | 21 ++++++++++++++++++++- src/arch/x86/utility.hh | 11 +++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/arch/x86/types.hh b/src/arch/x86/types.hh index ca4a15d24..cdac3c00e 100644 --- a/src/arch/x86/types.hh +++ b/src/arch/x86/types.hh @@ -161,7 +161,26 @@ namespace X86ISA inline static bool operator == (const ExtMachInst &emi1, const ExtMachInst &emi2) { - //Since this is empty, it's always equal + if(emi1.legacy != emi2.legacy) + return false; + if(emi1.rex != emi2.rex) + return false; + if(emi1.opcode.num != emi2.opcode.num) + return false; + if(emi1.opcode.op != emi2.opcode.op) + return false; + if(emi1.opcode.prefixA != emi2.opcode.prefixA) + return false; + if(emi1.opcode.prefixB != emi2.opcode.prefixB) + return false; + if(emi1.modRM != emi2.modRM) + return false; + if(emi1.sib != emi2.sib) + return false; + if(emi1.immediate != emi2.immediate) + return false; + if(emi1.displacement != emi2.displacement) + return false; return true; } diff --git a/src/arch/x86/utility.hh b/src/arch/x86/utility.hh index d89e223de..e0bd09515 100644 --- a/src/arch/x86/utility.hh +++ b/src/arch/x86/utility.hh @@ -70,8 +70,15 @@ namespace __hash_namespace { template<> struct hash { size_t operator()(const X86ISA::ExtMachInst &emi) const { - //Because these are all the same, return 0 - return 0; + return (((uint64_t)emi.legacy << 56) | + ((uint64_t)emi.rex << 48) | + ((uint64_t)emi.modRM << 40) | + ((uint64_t)emi.sib << 32) | + ((uint64_t)emi.opcode.num << 24) | + ((uint64_t)emi.opcode.prefixA << 16) | + ((uint64_t)emi.opcode.prefixB << 8) | + ((uint64_t)emi.opcode.op)) ^ + emi.immediate ^ emi.displacement; }; }; } -- cgit v1.2.3 From 7f5409f2babd4fe26c364aedf7faf4cdcb0eb3f0 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Wed, 4 Apr 2007 14:28:43 +0000 Subject: Make "Name" really be the same as "name" with only the first letter capitalized. Before, it had the first letter capitalized but all the others lower case --HG-- extra : convert_revision : bcbb28f2bf268765c1d37075a4417a4a6c1b9588 --- src/arch/isa_parser.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/arch/isa_parser.py b/src/arch/isa_parser.py index a0d671da1..0cb7bfc56 100755 --- a/src/arch/isa_parser.py +++ b/src/arch/isa_parser.py @@ -866,7 +866,11 @@ class Format: context = {} updateExportContext() context.update(exportContext) - context.update({ 'name': name, 'Name': string.capitalize(name) }) + if len(name): + Name = name[0].upper() + if len(name) > 1: + Name += name[1:] + context.update({ 'name': name, 'Name': Name }) try: vars = self.func(self.user_code, context, *args[0], **args[1]) except Exception, exc: -- cgit v1.2.3 From 4285990a96bad869bc1046f28f99cf7f4b5c8de0 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Wed, 4 Apr 2007 14:31:59 +0000 Subject: Reworking how x86's isa description works. I'm adopting the following definitions to make figuring out what's what a little easier: MicroOp: A single operation actually implemented in hardware. MacroOp: A collection of microops which are executed as a unit. Instruction: An architected instruction which can be implemented with a macroop or a microop. --HG-- extra : convert_revision : 1cfc8409cc686c75220767839f55a30551aa6f13 --- src/arch/x86/isa/decoder/one_byte_opcodes.isa | 22 ++-- src/arch/x86/isa/formats/multi.isa | 147 ++----------------------- src/arch/x86/isa/main.isa | 3 + src/arch/x86/isa/microasm.isa | 149 +++++++++++++++++++++++++- 4 files changed, 169 insertions(+), 152 deletions(-) diff --git a/src/arch/x86/isa/decoder/one_byte_opcodes.isa b/src/arch/x86/isa/decoder/one_byte_opcodes.isa index f7e6e3994..938904bc1 100644 --- a/src/arch/x86/isa/decoder/one_byte_opcodes.isa +++ b/src/arch/x86/isa/decoder/one_byte_opcodes.isa @@ -61,15 +61,12 @@ 0x1: decode OPCODE_OP_TOP5 { format WarnUnimpl { 0x00: decode OPCODE_OP_BOTTOM3 { - 0x4: TaggedOp::add({{AddI %0 %0}}, [rAl]); - 0x5: TaggedOp::add({{AddI %0 %0}}, [rAx]); + 0x4: Inst::addI(rAl,Ib); + 0x5: Inst::addI(rAx,Iz); 0x6: push_ES(); 0x7: pop_ES(); - default: MultiOp::add( - {{Add %0 %0 %1}}, - OPCODE_OP_BOTTOM3, - [[Eb,Gb],[Ev,Gv], - [Gb,Eb],[Gv,Ev]]); + default: MultiInst::add(OPCODE_OP_BOTTOM3, + [Eb,Gb],[Ev,Gv],[Gb,Eb],[Gv,Ev]); } 0x01: decode OPCODE_OP_BOTTOM3 { 0x0: or_Eb_Gb(); @@ -126,16 +123,13 @@ 0x7: das(); } 0x06: decode OPCODE_OP_BOTTOM3 { - 0x4: TaggedOp::xor({{XorI %0 %0}}, [rAl]); - 0x5: TaggedOp::xor({{XorI %0 %0}}, [rAx]); + 0x4: Inst::xorI(rAl,Ib); + 0x5: Inst::xorI(rAx,Iz); 0x6: M5InternalError::error( {{"Tried to execute the SS segment override prefix!"}}); 0x7: aaa(); - default: MultiOp::xor( - {{Xor %0 %0 %1}}, - OPCODE_OP_BOTTOM3, - [[Eb,Gb],[Ev,Gv], - [Gb,Eb],[Gv,Ev]]); + default: MultiInst::xor(OPCODE_OP_BOTTOM3, + [Eb,Gb],[Ev,Gv],[Gb,Eb],[Gv,Ev]); } 0x07: decode OPCODE_OP_BOTTOM3 { 0x0: cmp_Eb_Gb(); diff --git a/src/arch/x86/isa/formats/multi.isa b/src/arch/x86/isa/formats/multi.isa index 9fceec2b0..7ad5ecd48 100644 --- a/src/arch/x86/isa/formats/multi.isa +++ b/src/arch/x86/isa/formats/multi.isa @@ -61,151 +61,26 @@ // 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) + def doInst(name, Name, opTypeSet): + if not instDict.has_key(Name): + raise Exception, "Unrecognized instruction: %s" % Name + inst = instDict[Name]() + return inst.emit(opTypeSet) }}; -let {{ - # 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) -}}; - -let {{ - - # 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%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[A-Z][A-Z]*)(?P[a-z][a-z]*)|(r(?P[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) - - # 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) - - # 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) -}}; - -def format TaggedOp(code, tagSet) {{ +def format Inst(*opTypeSet) {{ (header_output, decoder_output, decode_block, - exec_output) = doCompOps(name, Name, code, tagSet, '') + exec_output) = doInst(name, Name, list(opTypeSet)) }}; -def format MultiOp(code, switchVal, opTags, *opt_flags) {{ +def format MultiInst(switchVal, *opTypeSets) {{ switcher = {} - for (count, tagSet) in zip(xrange(len(opTags) - 1), opTags): - switcher[count] = (code, tagSet, '') + for (count, opTypeSet) in zip(xrange(len(opTypeSets)), opTypeSets): + switcher[count] = (opTypeSet,) (header_output, decoder_output, decode_block, - exec_output) = doMultiOp(name, Name, doCompOps, switchVal, switcher) + exec_output) = doSplitDecode(name, Name, doInst, switchVal, switcher) }}; diff --git a/src/arch/x86/isa/main.isa b/src/arch/x86/isa/main.isa index fe1d4e515..cc3a9bee4 100644 --- a/src/arch/x86/isa/main.isa +++ b/src/arch/x86/isa/main.isa @@ -84,6 +84,9 @@ namespace X86ISA; //Include the base class for x86 instructions, and some support code ##include "base.isa" +//Include the instruction definitions +##include "insts/insts.isa" + //Include the definitions for the instruction formats ##include "formats/formats.isa" diff --git a/src/arch/x86/isa/microasm.isa b/src/arch/x86/isa/microasm.isa index 711ebf667..6d428881e 100644 --- a/src/arch/x86/isa/microasm.isa +++ b/src/arch/x86/isa/microasm.isa @@ -57,11 +57,154 @@ //////////////////////////////////////////////////////////////////// // -// Code to "assemble" microcode sequences +// Code to "specialize" a microcode sequence to use a particular +// variety of operands // let {{ - class MicroOpStatement: + # 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 {{ + # 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 doSplitDecode(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) +}}; + +let {{ + class OpType(object): + parser = re.compile(r"(?P[A-Z][A-Z]*)(?P[a-z][a-z]*)|(r(?P[A-Za-z0-9][A-Za-z0-9]*))") + def __init__(self, opTypeString): + match = OpType.parser.search(opTypeString) + if match == None: + raise Exception, "Problem parsing operand type %s" % opTypeString + self.reg = match.group("reg") + self.tag = match.group("tag") + self.size = match.group("size") +}}; + +let {{ + + # This function specializes the given piece of code to use a particular + # set of argument types described by "opTypes". These are "implemented" + # in reverse order. + def specializeInst(name, Name, code, opTypes): + opNum = len(opTypes) - 1 + while len(opTypes): + # print "Building a composite op with tags", opTypes + # print "And code", code + opNum = len(opTypes) - 1 + # A regular expression to find the operand placeholders we're + # interested in. + opRe = re.compile("%%(?P%d)(?=[^0-9]|$)" % opNum) + + # Parse the operand type strign we're working with + print "About to parse tag %s" % opTypes[opNum] + opType = OpType(opTypes[opNum]) + + if opType.reg: + #Figure out what to do with fixed register operands + if opType.reg in ("Ax", "Bx", "Cx", "Dx"): + code = opRe.sub("{INTREG_R%s}" % opType.reg.upper(), code) + elif opType.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!" % opType.reg + elif opType.tag == None or opType.size == None: + raise Exception, "Problem parsing operand tag: %s" % opType.tag + elif opType.tag in ("C", "D", "G", "P", "S", "T", "V"): + # Use the "reg" field of the ModRM byte to select the register + code = opRe.sub("{(uint8_t)MODRM_REG}", code) + elif opType.tag in ("E", "Q", "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) + regTypes = copy.copy(opTypes) + regTypes.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) + memTypes = copy.copy(opTypes) + memTypes.pop(-1) + return doSplitDecode(name, Name, specializeInst, "MODRM_MOD", + {"3" : (regCode, regTypes)}, (memCode, memTypes)) + elif opType.tag in ("I", "J"): + # Immediates are already in the instruction, so don't leave in + # those parameters + code = opRe.sub("", code) + elif opType.tag == "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 opType.tag in ("PR", "R", "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." % opType.tag + opTypes.pop(-1) + + # 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) + + # 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) +}}; + +//////////////////////////////////////////////////////////////////// +// +// The microcode assembler +// + +let {{ + class MicroOpStatement(object): def __init__(self): self.className = '' self.label = '' @@ -101,7 +244,9 @@ let {{ labels[op.label] = count micropc += 1 return labels +}}; +let{{ def assembleMicro(code): # This function takes in a block of microcode assembly and returns # a python list of objects which describe it. -- cgit v1.2.3 From ab2bed349b356b4784e1a6c8fdf6f4a86e27f543 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Wed, 4 Apr 2007 23:19:32 +0000 Subject: Fix a regular expression problem when recognizing labels for string substitution. --HG-- extra : convert_revision : ba398e1b434efda28882f159d5a4419302276371 --- src/arch/isa_parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/arch/isa_parser.py b/src/arch/isa_parser.py index 0cb7bfc56..4c8d0706d 100755 --- a/src/arch/isa_parser.py +++ b/src/arch/isa_parser.py @@ -1032,7 +1032,7 @@ def substBitOps(code): # Template objects are format strings that allow substitution from # the attribute spaces of other objects (e.g. InstObjParams instances). -labelRE = re.compile(r'[^%]%\(([^\)]+)\)[sd]') +labelRE = re.compile(r'(? Date: Wed, 4 Apr 2007 23:35:20 +0000 Subject: The process of going from an instruction definition to an instruction to be returned by the decoder has been fleshed out more. The following steps describe how an instruction implementation becomes a StaticInst. 1. Microops are created. These are StaticInsts use templates to provide a basic form of polymorphism without having to make the microassembler smarter. 2. An instruction class is created which has a "templated" microcode program as it's docstring. The template parameters are refernced with ^ following by a number. 3. An instruction in the decoder references an instruction template using it's mnemonic. The parameters to it's format end up replacing the placeholders. These parameters describe a source for an operand which could be memory, a register, or an immediate. It it's a register, the register index is used. If it's memory, eventually a load/store will be pre/postpended to the instruction template and it's destination register will be used in place of the ^. If it's an immediate, the immediate is used. Some operand types, specifically those that come from the ModRM byte, need to be decoded further into memory vs. register versions. This is accomplished by making the decode_block text for these instructions another case statement based off ModRM. 4. Once all of the template parameters have been handled, the instruction goes throw the microcode assembler which resolves labels and creates a list of python op objects. If an operand is a register, it uses a % prefix, an immediate uses $, and a label uses @. If the operand is just letters, numbers, and underscores, it can appear immediately after the prefix. If it's not, it can be encolsed in non nested {}s. 5. If there is a single "op" object (which corresponds to a single microop) the decoder is set up to return it directly. If not, a macroop wrapper is created around it. In the future, I'm considering seperating the operand type specialization from the template substitution step. A problem this introduces is that either the template arguments need to be kept around for the specialization step, or they need to be re-extracted. Re-extraction might be the way to go so that the operand formats can be coded directly into the micro assembler template without having to pass them in as parameters. I don't know if that's actually useful, though. src/arch/x86/isa/decoder/one_byte_opcodes.isa: src/arch/x86/isa/microasm.isa: src/arch/x86/isa/microops/microops.isa: src/arch/x86/isa/operands.isa: src/arch/x86/isa/microops/base.isa: Implemented polymorphic microops and changed around the microcode assembler syntax. --HG-- extra : convert_revision : e341f7b8ea9350a31e586a3d33250137e5954f43 --- src/arch/x86/isa/decoder/one_byte_opcodes.isa | 8 +- src/arch/x86/isa/microasm.isa | 53 +++++--- src/arch/x86/isa/microops/base.isa | 172 ++++++++++++++++++++++++++ src/arch/x86/isa/microops/microops.isa | 5 +- src/arch/x86/isa/operands.isa | 6 +- 5 files changed, 216 insertions(+), 28 deletions(-) create mode 100644 src/arch/x86/isa/microops/base.isa diff --git a/src/arch/x86/isa/decoder/one_byte_opcodes.isa b/src/arch/x86/isa/decoder/one_byte_opcodes.isa index 938904bc1..fed6dda28 100644 --- a/src/arch/x86/isa/decoder/one_byte_opcodes.isa +++ b/src/arch/x86/isa/decoder/one_byte_opcodes.isa @@ -61,8 +61,8 @@ 0x1: decode OPCODE_OP_TOP5 { format WarnUnimpl { 0x00: decode OPCODE_OP_BOTTOM3 { - 0x4: Inst::addI(rAl,Ib); - 0x5: Inst::addI(rAx,Iz); + 0x4: Inst::add(rAl,Ib); + 0x5: Inst::add(rAx,Iz); 0x6: push_ES(); 0x7: pop_ES(); default: MultiInst::add(OPCODE_OP_BOTTOM3, @@ -123,8 +123,8 @@ 0x7: das(); } 0x06: decode OPCODE_OP_BOTTOM3 { - 0x4: Inst::xorI(rAl,Ib); - 0x5: Inst::xorI(rAx,Iz); + 0x4: Inst::xor(rAl,Ib); + 0x5: Inst::xor(rAx,Iz); 0x6: M5InternalError::error( {{"Tried to execute the SS segment override prefix!"}}); 0x7: aaa(); diff --git a/src/arch/x86/isa/microasm.isa b/src/arch/x86/isa/microasm.isa index 6d428881e..b94b55aab 100644 --- a/src/arch/x86/isa/microasm.isa +++ b/src/arch/x86/isa/microasm.isa @@ -135,36 +135,35 @@ let {{ opNum = len(opTypes) - 1 # A regular expression to find the operand placeholders we're # interested in. - opRe = re.compile("%%(?P%d)(?=[^0-9]|$)" % opNum) + opRe = re.compile("\\^(?P%d)(?=[^0-9]|$)" % opNum) # Parse the operand type strign we're working with - print "About to parse tag %s" % opTypes[opNum] opType = OpType(opTypes[opNum]) if opType.reg: #Figure out what to do with fixed register operands if opType.reg in ("Ax", "Bx", "Cx", "Dx"): - code = opRe.sub("{INTREG_R%s}" % opType.reg.upper(), code) + code = opRe.sub("%%{INTREG_R%s}" % opType.reg.upper(), code) elif opType.reg == "Al": # We need a way to specify register width - code = opRe.sub("{INTREG_RAX}", code) + code = opRe.sub("%{INTREG_RAX}", code) else: print "Didn't know how to encode fixed register %s!" % opType.reg elif opType.tag == None or opType.size == None: raise Exception, "Problem parsing operand tag: %s" % opType.tag elif opType.tag in ("C", "D", "G", "P", "S", "T", "V"): # Use the "reg" field of the ModRM byte to select the register - code = opRe.sub("{(uint8_t)MODRM_REG}", code) + code = opRe.sub("%{(uint8_t)MODRM_REG}", code) elif opType.tag in ("E", "Q", "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) + regCode = opRe.sub("%{(uint8_t)MODRM_RM}", code) regTypes = copy.copy(opTypes) regTypes.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) + memCode = opRe.sub("%0", code) memTypes = copy.copy(opTypes) memTypes.pop(-1) return doSplitDecode(name, Name, specializeInst, "MODRM_MOD", @@ -172,16 +171,16 @@ let {{ elif opType.tag in ("I", "J"): # Immediates are already in the instruction, so don't leave in # those parameters - code = opRe.sub("", code) + code = opRe.sub("${IMMEDIATE}", code) elif opType.tag == "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) + code = opRe.sub("%0", code) elif opType.tag in ("PR", "R", "VR"): # There should probably be a check here to verify that mod # is equal to 11b - code = opRe.sub("{(uint8_t)MODRM_RM}", code) + code = opRe.sub("%{(uint8_t)MODRM_RM}", code) else: raise Exception, "Unrecognized tag %s." % opType.tag opTypes.pop(-1) @@ -223,16 +222,24 @@ let {{ def getAllocator(self, *microFlags): args = '' + signature = "<" + emptySig = True for arg in self.args: - if arg.has_key("operandConst"): - args += ", %s" % arg["operandConst"] - elif arg.has_key("operandCode"): - args += ", %s" % arg["operandCode"] + if not emptySig: + signature += ", " + emptySig = False + if arg.has_key("operandImm"): + args += ", %s" % arg["operandImm"] + signature += ImmOpType + elif arg.has_key("operandReg"): + args += ", %s" % arg["operandReg"] + signature += RegOpType elif arg.has_key("operandLabel"): raise Exception, "Found a label while creating allocator string." else: raise Exception, "Unrecognized operand type." - return 'new %s(machInst%s%s)' % (self.className, self.microFlagsText(microFlags), args) + signature += ">" + return 'new %s%s(machInst%s%s)' % (self.className, signature, self.microFlagsText(microFlags), args) }}; let {{ @@ -260,7 +267,7 @@ let{{ # time. Each expression expects the thing it's looking for to be at # the beginning of the line, so the previous component is stripped # before continuing. - labelRe = re.compile(r'^[ \t]*(?P