specialize.isa (6519:36369ba5fad6) specialize.isa (7087:fb8d5786ff30)
1// -*- mode:c++ -*-
2
3// Copyright (c) 2007 The Hewlett-Packard Development Company
4// All rights reserved.
5//
1// -*- mode:c++ -*-
2
3// Copyright (c) 2007 The Hewlett-Packard Development Company
4// All rights reserved.
5//
6// Redistribution and use of this software in source and binary forms,
7// with or without modification, are permitted provided that the
8// following conditions are met:
6// The license below extends only to copyright in the software and shall
7// not be construed as granting a license to any other intellectual
8// property including but not limited to intellectual property relating
9// to a hardware implementation of the functionality of the software
10// licensed hereunder. You may use the software subject to the license
11// terms below provided that you ensure that this notice is replicated
12// unmodified and in its entirety in all distributions of the software,
13// modified or unmodified, in source code or in binary form.
9//
14//
10// The software must be used only for Non-Commercial Use which means any
11// use which is NOT directed to receiving any direct monetary
12// compensation for, or commercial advantage from such use. Illustrative
13// examples of non-commercial use are academic research, personal study,
14// teaching, education and corporate research & development.
15// Illustrative examples of commercial use are distributing products for
16// commercial advantage and providing services using the software for
17// commercial advantage.
18//
19// If you wish to use this software or functionality therein that may be
20// covered by patents for commercial use, please contact:
21// Director of Intellectual Property Licensing
22// Office of Strategy and Technology
23// Hewlett-Packard Company
24// 1501 Page Mill Road
25// Palo Alto, California 94304
26//
27// Redistributions of source code must retain the above copyright notice,
28// this list of conditions and the following disclaimer. Redistributions
29// in binary form must reproduce the above copyright notice, this list of
30// conditions and the following disclaimer in the documentation and/or
31// other materials provided with the distribution. Neither the name of
32// the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
15// Redistribution and use in source and binary forms, with or without
16// modification, are permitted provided that the following conditions are
17// met: redistributions of source code must retain the above copyright
18// notice, this list of conditions and the following disclaimer;
19// redistributions in binary form must reproduce the above copyright
20// notice, this list of conditions and the following disclaimer in the
21// documentation and/or other materials provided with the distribution;
22// neither the name of the copyright holders nor the names of its
33// contributors may be used to endorse or promote products derived from
23// contributors may be used to endorse or promote products derived from
34// this software without specific prior written permission. No right of
35// sublicense is granted herewith. Derivatives of the software and
36// output created using the software may be prepared, but only for
37// Non-Commercial Uses. Derivatives of the software may be shared with
38// others provided: (i) the others agree to abide by the list of
39// conditions herein which includes the Non-Commercial Use restrictions;
40// and (ii) such Derivatives of the software include the above copyright
41// notice to acknowledge the contribution from this software where
42// applicable, this list of conditions and the disclaimer below.
24// this software without specific prior written permission.
43//
44// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
45// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
46// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
47// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
48// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
49// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
50// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
51// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
52// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
53// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
54// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
55//
56// Authors: Gabe Black
57
58////////////////////////////////////////////////////////////////////
59//
60// Code to "specialize" a microcode sequence to use a particular
61// variety of operands
62//
63
64let {{
65 # This code builds up a decode block which decodes based on switchval.
66 # vals is a dict which matches case values with what should be decoded to.
67 # Each element of the dict is a list containing a function and then the
68 # arguments to pass to it.
69 def doSplitDecode(switchVal, vals, default = None):
70 blocks = OutputBlocks()
71 blocks.decode_block = 'switch(%s) {\n' % switchVal
72 for (val, todo) in vals.items():
73 new_blocks = todo[0](*todo[1:])
74 new_blocks.decode_block = \
75 '\tcase %s: %s\n' % (val, new_blocks.decode_block)
76 blocks.append(new_blocks)
77 if default:
78 new_blocks = default[0](*default[1:])
79 new_blocks.decode_block = \
80 '\tdefault: %s\n' % new_blocks.decode_block
81 blocks.append(new_blocks)
82 blocks.decode_block += '}\n'
83 return blocks
84}};
85
86let {{
87 def doRipRelativeDecode(Name, opTypes, env):
88 # print "RIPing %s with opTypes %s" % (Name, opTypes)
89 env.memoryInst = True
90 normEnv = copy.copy(env)
91 normEnv.addToDisassembly(
92 '''printMem(out, env.seg, env.scale, env.index, env.base,
93 machInst.displacement, env.addressSize, false);''')
94 normBlocks = specializeInst(Name + "_M", copy.copy(opTypes), normEnv)
95 ripEnv = copy.copy(env)
96 ripEnv.addToDisassembly(
97 '''printMem(out, env.seg, 1, 0, 0,
98 machInst.displacement, env.addressSize, true);''')
99 ripBlocks = specializeInst(Name + "_P", copy.copy(opTypes), ripEnv)
100
101 blocks = OutputBlocks()
102 blocks.append(normBlocks)
103 blocks.append(ripBlocks)
104
105 blocks.decode_block = '''
106 if(machInst.modRM.mod == 0 &&
107 machInst.modRM.rm == 5 &&
108 machInst.mode.submode == SixtyFourBitMode)
109 { %s }
110 else
111 { %s }''' % \
112 (ripBlocks.decode_block, normBlocks.decode_block)
113 return blocks
114}};
115
116let {{
117 class OpType(object):
118 parser = re.compile(r"(?P<tag>[A-Z]+)(?P<size>[a-z]*)|(r(?P<reg>[A-Z0-9]+)(?P<rsize>[a-z]*))")
119 def __init__(self, opTypeString):
120 match = OpType.parser.search(opTypeString)
121 if match == None:
122 raise Exception, "Problem parsing operand type %s" % opTypeString
123 self.reg = match.group("reg")
124 self.tag = match.group("tag")
125 self.size = match.group("size")
126 if not self.size:
127 self.size = match.group("rsize")
128
129 ModRMRegIndex = "(MODRM_REG | (REX_R << 3))"
130 ModRMRMIndex = "(MODRM_RM | (REX_B << 3))"
131 InstRegIndex = "(OPCODE_OP_BOTTOM3 | (REX_B << 3))"
132
133 # This function specializes the given piece of code to use a particular
134 # set of argument types described by "opTypes".
135 def specializeInst(Name, opTypes, env):
136 # print "Specializing %s with opTypes %s" % (Name, opTypes)
137 while len(opTypes):
138 # Parse the operand type string we're working with
139 opType = OpType(opTypes[0])
140 opTypes.pop(0)
141
142 if opType.tag not in ("I", "J", "P", "PR", "Q", "V", "VR", "W"):
143 if opType.size:
144 env.setSize(opType.size)
145
146 if opType.reg:
147 #Figure out what to do with fixed register operands
148 #This is the index to use, so we should stick it some place.
149 if opType.reg in ("A", "B", "C", "D"):
150 regString = "INTREG_R%sX" % opType.reg
151 else:
152 regString = "INTREG_R%s" % opType.reg
153 env.addReg(regString)
154 env.addToDisassembly(
155 "printReg(out, %s, regSize);\n" % regString)
156 Name += "_R"
157 elif opType.tag == "B":
158 # This refers to registers whose index is encoded as part of the opcode
159 env.addToDisassembly(
160 "printReg(out, %s, regSize);\n" % InstRegIndex)
161 Name += "_R"
162 env.addReg(InstRegIndex)
163 elif opType.tag == "M":
164 # This refers to memory. The macroop constructor sets up modrm
165 # addressing. Non memory modrm settings should cause an error.
166 env.doModRM = True
167 return doRipRelativeDecode(Name, opTypes, env)
168 elif opType.tag == None or opType.size == None:
169 raise Exception, "Problem parsing operand tag: %s" % opType.tag
170 elif opType.tag == "C":
171 # A control register indexed by the "reg" field
172 env.addReg(ModRMRegIndex)
173 env.addToDisassembly(
174 "ccprintf(out, \"CR%%d\", %s);\n" % ModRMRegIndex)
175 Name += "_C"
176 elif opType.tag == "D":
177 # A debug register indexed by the "reg" field
178 env.addReg(ModRMRegIndex)
179 env.addToDisassembly(
180 "ccprintf(out, \"DR%%d\", %s);\n" % ModRMRegIndex)
181 Name += "_D"
182 elif opType.tag == "S":
183 # A segment selector register indexed by the "reg" field
184 env.addReg(ModRMRegIndex)
185 env.addToDisassembly(
186 "printSegment(out, %s);\n" % ModRMRegIndex)
187 Name += "_S"
188 elif opType.tag in ("G", "P", "T", "V"):
189 # Use the "reg" field of the ModRM byte to select the register
190 env.addReg(ModRMRegIndex)
191 env.addToDisassembly(
192 "printReg(out, %s, regSize);\n" % ModRMRegIndex)
193 if opType.tag == "P":
194 Name += "_MMX"
195 elif opType.tag == "V":
196 Name += "_XMM"
197 else:
198 Name += "_R"
199 elif opType.tag in ("E", "Q", "W"):
200 # This might refer to memory or to a register. We need to
201 # divide it up farther.
202 regEnv = copy.copy(env)
203 regEnv.addReg(ModRMRMIndex)
204 regEnv.addToDisassembly(
205 "printReg(out, %s, regSize);\n" % ModRMRMIndex)
206 # This refers to memory. The macroop constructor should set up
207 # modrm addressing.
208 memEnv = copy.copy(env)
209 memEnv.doModRM = True
210 regSuffix = "_R"
211 if opType.tag == "Q":
212 regSuffix = "_MMX"
213 elif opType.tag == "W":
214 regSuffix = "_XMM"
215 return doSplitDecode("MODRM_MOD",
216 {"3" : (specializeInst, Name + regSuffix,
217 copy.copy(opTypes), regEnv)},
218 (doRipRelativeDecode, Name,
219 copy.copy(opTypes), memEnv))
220 elif opType.tag in ("I", "J"):
221 # Immediates
222 env.addToDisassembly(
223 "ccprintf(out, \"%#x\", machInst.immediate);\n")
224 Name += "_I"
225 elif opType.tag == "O":
226 # Immediate containing a memory offset
227 Name += "_MI"
228 elif opType.tag in ("PR", "R", "VR"):
229 # Non register modrm settings should cause an error
230 env.addReg(ModRMRMIndex)
231 env.addToDisassembly(
232 "printReg(out, %s, regSize);\n" % ModRMRMIndex)
233 if opType.tag == "PR":
234 Name += "_MMX"
235 elif opType.tag == "VR":
236 Name += "_XMM"
237 else:
238 Name += "_R"
239 elif opType.tag in ("X", "Y"):
240 # This type of memory addressing is for string instructions.
241 # They'll use the right index and segment internally.
242 if opType.tag == "X":
243 env.addToDisassembly(
244 '''printMem(out, env.seg,
245 1, X86ISA::ZeroReg, X86ISA::INTREG_RSI, 0,
246 env.addressSize, false);''')
247 else:
248 env.addToDisassembly(
249 '''printMem(out, SEGMENT_REG_ES,
250 1, X86ISA::ZeroReg, X86ISA::INTREG_RDI, 0,
251 env.addressSize, false);''')
252 Name += "_M"
253 else:
254 raise Exception, "Unrecognized tag %s." % opType.tag
255
256 # Generate code to return a macroop of the given name which will
257 # operate in the "emulation environment" env
258 return genMacroop(Name, env)
259}};
25//
26// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37//
38// Authors: Gabe Black
39
40////////////////////////////////////////////////////////////////////
41//
42// Code to "specialize" a microcode sequence to use a particular
43// variety of operands
44//
45
46let {{
47 # This code builds up a decode block which decodes based on switchval.
48 # vals is a dict which matches case values with what should be decoded to.
49 # Each element of the dict is a list containing a function and then the
50 # arguments to pass to it.
51 def doSplitDecode(switchVal, vals, default = None):
52 blocks = OutputBlocks()
53 blocks.decode_block = 'switch(%s) {\n' % switchVal
54 for (val, todo) in vals.items():
55 new_blocks = todo[0](*todo[1:])
56 new_blocks.decode_block = \
57 '\tcase %s: %s\n' % (val, new_blocks.decode_block)
58 blocks.append(new_blocks)
59 if default:
60 new_blocks = default[0](*default[1:])
61 new_blocks.decode_block = \
62 '\tdefault: %s\n' % new_blocks.decode_block
63 blocks.append(new_blocks)
64 blocks.decode_block += '}\n'
65 return blocks
66}};
67
68let {{
69 def doRipRelativeDecode(Name, opTypes, env):
70 # print "RIPing %s with opTypes %s" % (Name, opTypes)
71 env.memoryInst = True
72 normEnv = copy.copy(env)
73 normEnv.addToDisassembly(
74 '''printMem(out, env.seg, env.scale, env.index, env.base,
75 machInst.displacement, env.addressSize, false);''')
76 normBlocks = specializeInst(Name + "_M", copy.copy(opTypes), normEnv)
77 ripEnv = copy.copy(env)
78 ripEnv.addToDisassembly(
79 '''printMem(out, env.seg, 1, 0, 0,
80 machInst.displacement, env.addressSize, true);''')
81 ripBlocks = specializeInst(Name + "_P", copy.copy(opTypes), ripEnv)
82
83 blocks = OutputBlocks()
84 blocks.append(normBlocks)
85 blocks.append(ripBlocks)
86
87 blocks.decode_block = '''
88 if(machInst.modRM.mod == 0 &&
89 machInst.modRM.rm == 5 &&
90 machInst.mode.submode == SixtyFourBitMode)
91 { %s }
92 else
93 { %s }''' % \
94 (ripBlocks.decode_block, normBlocks.decode_block)
95 return blocks
96}};
97
98let {{
99 class OpType(object):
100 parser = re.compile(r"(?P<tag>[A-Z]+)(?P<size>[a-z]*)|(r(?P<reg>[A-Z0-9]+)(?P<rsize>[a-z]*))")
101 def __init__(self, opTypeString):
102 match = OpType.parser.search(opTypeString)
103 if match == None:
104 raise Exception, "Problem parsing operand type %s" % opTypeString
105 self.reg = match.group("reg")
106 self.tag = match.group("tag")
107 self.size = match.group("size")
108 if not self.size:
109 self.size = match.group("rsize")
110
111 ModRMRegIndex = "(MODRM_REG | (REX_R << 3))"
112 ModRMRMIndex = "(MODRM_RM | (REX_B << 3))"
113 InstRegIndex = "(OPCODE_OP_BOTTOM3 | (REX_B << 3))"
114
115 # This function specializes the given piece of code to use a particular
116 # set of argument types described by "opTypes".
117 def specializeInst(Name, opTypes, env):
118 # print "Specializing %s with opTypes %s" % (Name, opTypes)
119 while len(opTypes):
120 # Parse the operand type string we're working with
121 opType = OpType(opTypes[0])
122 opTypes.pop(0)
123
124 if opType.tag not in ("I", "J", "P", "PR", "Q", "V", "VR", "W"):
125 if opType.size:
126 env.setSize(opType.size)
127
128 if opType.reg:
129 #Figure out what to do with fixed register operands
130 #This is the index to use, so we should stick it some place.
131 if opType.reg in ("A", "B", "C", "D"):
132 regString = "INTREG_R%sX" % opType.reg
133 else:
134 regString = "INTREG_R%s" % opType.reg
135 env.addReg(regString)
136 env.addToDisassembly(
137 "printReg(out, %s, regSize);\n" % regString)
138 Name += "_R"
139 elif opType.tag == "B":
140 # This refers to registers whose index is encoded as part of the opcode
141 env.addToDisassembly(
142 "printReg(out, %s, regSize);\n" % InstRegIndex)
143 Name += "_R"
144 env.addReg(InstRegIndex)
145 elif opType.tag == "M":
146 # This refers to memory. The macroop constructor sets up modrm
147 # addressing. Non memory modrm settings should cause an error.
148 env.doModRM = True
149 return doRipRelativeDecode(Name, opTypes, env)
150 elif opType.tag == None or opType.size == None:
151 raise Exception, "Problem parsing operand tag: %s" % opType.tag
152 elif opType.tag == "C":
153 # A control register indexed by the "reg" field
154 env.addReg(ModRMRegIndex)
155 env.addToDisassembly(
156 "ccprintf(out, \"CR%%d\", %s);\n" % ModRMRegIndex)
157 Name += "_C"
158 elif opType.tag == "D":
159 # A debug register indexed by the "reg" field
160 env.addReg(ModRMRegIndex)
161 env.addToDisassembly(
162 "ccprintf(out, \"DR%%d\", %s);\n" % ModRMRegIndex)
163 Name += "_D"
164 elif opType.tag == "S":
165 # A segment selector register indexed by the "reg" field
166 env.addReg(ModRMRegIndex)
167 env.addToDisassembly(
168 "printSegment(out, %s);\n" % ModRMRegIndex)
169 Name += "_S"
170 elif opType.tag in ("G", "P", "T", "V"):
171 # Use the "reg" field of the ModRM byte to select the register
172 env.addReg(ModRMRegIndex)
173 env.addToDisassembly(
174 "printReg(out, %s, regSize);\n" % ModRMRegIndex)
175 if opType.tag == "P":
176 Name += "_MMX"
177 elif opType.tag == "V":
178 Name += "_XMM"
179 else:
180 Name += "_R"
181 elif opType.tag in ("E", "Q", "W"):
182 # This might refer to memory or to a register. We need to
183 # divide it up farther.
184 regEnv = copy.copy(env)
185 regEnv.addReg(ModRMRMIndex)
186 regEnv.addToDisassembly(
187 "printReg(out, %s, regSize);\n" % ModRMRMIndex)
188 # This refers to memory. The macroop constructor should set up
189 # modrm addressing.
190 memEnv = copy.copy(env)
191 memEnv.doModRM = True
192 regSuffix = "_R"
193 if opType.tag == "Q":
194 regSuffix = "_MMX"
195 elif opType.tag == "W":
196 regSuffix = "_XMM"
197 return doSplitDecode("MODRM_MOD",
198 {"3" : (specializeInst, Name + regSuffix,
199 copy.copy(opTypes), regEnv)},
200 (doRipRelativeDecode, Name,
201 copy.copy(opTypes), memEnv))
202 elif opType.tag in ("I", "J"):
203 # Immediates
204 env.addToDisassembly(
205 "ccprintf(out, \"%#x\", machInst.immediate);\n")
206 Name += "_I"
207 elif opType.tag == "O":
208 # Immediate containing a memory offset
209 Name += "_MI"
210 elif opType.tag in ("PR", "R", "VR"):
211 # Non register modrm settings should cause an error
212 env.addReg(ModRMRMIndex)
213 env.addToDisassembly(
214 "printReg(out, %s, regSize);\n" % ModRMRMIndex)
215 if opType.tag == "PR":
216 Name += "_MMX"
217 elif opType.tag == "VR":
218 Name += "_XMM"
219 else:
220 Name += "_R"
221 elif opType.tag in ("X", "Y"):
222 # This type of memory addressing is for string instructions.
223 # They'll use the right index and segment internally.
224 if opType.tag == "X":
225 env.addToDisassembly(
226 '''printMem(out, env.seg,
227 1, X86ISA::ZeroReg, X86ISA::INTREG_RSI, 0,
228 env.addressSize, false);''')
229 else:
230 env.addToDisassembly(
231 '''printMem(out, SEGMENT_REG_ES,
232 1, X86ISA::ZeroReg, X86ISA::INTREG_RDI, 0,
233 env.addressSize, false);''')
234 Name += "_M"
235 else:
236 raise Exception, "Unrecognized tag %s." % opType.tag
237
238 # Generate code to return a macroop of the given name which will
239 # operate in the "emulation environment" env
240 return genMacroop(Name, env)
241}};