Merge zizzer.eecs.umich.edu:/bk/newmem
[gem5.git] / src / arch / x86 / predecoder.cc
1 /*
2 * Copyright (c) 2007 The Hewlett-Packard Development Company
3 * All rights reserved.
4 *
5 * Redistribution and use of this software in source and binary forms,
6 * with or without modification, are permitted provided that the
7 * following conditions are met:
8 *
9 * The software must be used only for Non-Commercial Use which means any
10 * use which is NOT directed to receiving any direct monetary
11 * compensation for, or commercial advantage from such use. Illustrative
12 * examples of non-commercial use are academic research, personal study,
13 * teaching, education and corporate research & development.
14 * Illustrative examples of commercial use are distributing products for
15 * commercial advantage and providing services using the software for
16 * commercial advantage.
17 *
18 * If you wish to use this software or functionality therein that may be
19 * covered by patents for commercial use, please contact:
20 * Director of Intellectual Property Licensing
21 * Office of Strategy and Technology
22 * Hewlett-Packard Company
23 * 1501 Page Mill Road
24 * Palo Alto, California 94304
25 *
26 * Redistributions of source code must retain the above copyright notice,
27 * this list of conditions and the following disclaimer. Redistributions
28 * in binary form must reproduce the above copyright notice, this list of
29 * conditions and the following disclaimer in the documentation and/or
30 * other materials provided with the distribution. Neither the name of
31 * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
32 * contributors may be used to endorse or promote products derived from
33 * this software without specific prior written permission. No right of
34 * sublicense is granted herewith. Derivatives of the software and
35 * output created using the software may be prepared, but only for
36 * Non-Commercial Uses. Derivatives of the software may be shared with
37 * others provided: (i) the others agree to abide by the list of
38 * conditions herein which includes the Non-Commercial Use restrictions;
39 * and (ii) such Derivatives of the software include the above copyright
40 * notice to acknowledge the contribution from this software where
41 * applicable, this list of conditions and the disclaimer below.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
44 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
45 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
46 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
47 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
48 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
49 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
50 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
51 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
52 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
53 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54 *
55 * Authors: Gabe Black
56 */
57
58 #include "arch/x86/predecoder.hh"
59 #include "base/misc.hh"
60 #include "base/trace.hh"
61 #include "sim/host.hh"
62
63 namespace X86ISA
64 {
65 void Predecoder::reset()
66 {
67 origPC = basePC + offset;
68 DPRINTF(Predecoder, "Setting origPC to %#x\n", origPC);
69 emi.rex = 0;
70 emi.legacy = 0;
71 emi.opcode.num = 0;
72
73 immediateCollected = 0;
74 emi.immediate = 0;
75 displacementCollected = 0;
76 emi.displacement = 0;
77
78 emi.modRM = 0;
79 emi.sib = 0;
80 }
81
82 void Predecoder::process()
83 {
84 //This function drives the predecoder state machine.
85
86 //Some sanity checks. You shouldn't try to process more bytes if
87 //there aren't any, and you shouldn't overwrite an already
88 //predecoder ExtMachInst.
89 assert(!outOfBytes);
90 assert(!emiIsReady);
91
92 //While there's still something to do...
93 while(!emiIsReady && !outOfBytes)
94 {
95 uint8_t nextByte = getNextByte();
96 switch(state)
97 {
98 case ResetState:
99 reset();
100 state = PrefixState;
101 case PrefixState:
102 state = doPrefixState(nextByte);
103 break;
104 case OpcodeState:
105 state = doOpcodeState(nextByte);
106 break;
107 case ModRMState:
108 state = doModRMState(nextByte);
109 break;
110 case SIBState:
111 state = doSIBState(nextByte);
112 break;
113 case DisplacementState:
114 state = doDisplacementState();
115 break;
116 case ImmediateState:
117 state = doImmediateState();
118 break;
119 case ErrorState:
120 panic("Went to the error state in the predecoder.\n");
121 default:
122 panic("Unrecognized state! %d\n", state);
123 }
124 }
125 }
126
127 //Either get a prefix and record it in the ExtMachInst, or send the
128 //state machine on to get the opcode(s).
129 Predecoder::State Predecoder::doPrefixState(uint8_t nextByte)
130 {
131 uint8_t prefix = Prefixes[nextByte];
132 State nextState = PrefixState;
133 if(prefix)
134 consumeByte();
135 switch(prefix)
136 {
137 //Operand size override prefixes
138 case OperandSizeOverride:
139 DPRINTF(Predecoder, "Found operand size override prefix.\n");
140 emi.legacy.op = true;
141 break;
142 case AddressSizeOverride:
143 DPRINTF(Predecoder, "Found address size override prefix.\n");
144 emi.legacy.addr = true;
145 break;
146 //Segment override prefixes
147 case CSOverride:
148 case DSOverride:
149 case ESOverride:
150 case FSOverride:
151 case GSOverride:
152 case SSOverride:
153 DPRINTF(Predecoder, "Found segment override.\n");
154 emi.legacy.seg = prefix;
155 break;
156 case Lock:
157 DPRINTF(Predecoder, "Found lock prefix.\n");
158 emi.legacy.lock = true;
159 break;
160 case Rep:
161 DPRINTF(Predecoder, "Found rep prefix.\n");
162 emi.legacy.rep = true;
163 break;
164 case Repne:
165 DPRINTF(Predecoder, "Found repne prefix.\n");
166 emi.legacy.repne = true;
167 break;
168 case RexPrefix:
169 DPRINTF(Predecoder, "Found Rex prefix %#x.\n", nextByte);
170 emi.rex = nextByte;
171 break;
172 case 0:
173 nextState = OpcodeState;
174 break;
175 default:
176 panic("Unrecognized prefix %#x\n", nextByte);
177 }
178 return nextState;
179 }
180
181 //Load all the opcodes (currently up to 2) and then figure out
182 //what immediate and/or ModRM is needed.
183 Predecoder::State Predecoder::doOpcodeState(uint8_t nextByte)
184 {
185 State nextState = ErrorState;
186 emi.opcode.num++;
187 //We can't handle 3+ byte opcodes right now
188 assert(emi.opcode.num < 3);
189 consumeByte();
190 if(emi.opcode.num == 1 && nextByte == 0x0f)
191 {
192 nextState = OpcodeState;
193 DPRINTF(Predecoder, "Found two byte opcode.\n");
194 emi.opcode.prefixA = nextByte;
195 }
196 else if(emi.opcode.num == 2 &&
197 (nextByte == 0x0f ||
198 (nextByte & 0xf8) == 0x38))
199 {
200 panic("Three byte opcodes aren't yet supported!\n");
201 nextState = OpcodeState;
202 DPRINTF(Predecoder, "Found three byte opcode.\n");
203 emi.opcode.prefixB = nextByte;
204 }
205 else
206 {
207 DPRINTF(Predecoder, "Found opcode %#x.\n", nextByte);
208 emi.opcode.op = nextByte;
209
210 //Figure out the effective operand size. This can be overriden to
211 //a fixed value at the decoder level.
212 if(/*FIXME long mode*/1)
213 {
214 if(emi.rex && emi.rex.w)
215 emi.opSize = 3; // 64 bit operand size
216 else if(emi.legacy.op)
217 emi.opSize = 1; // 16 bit operand size
218 else
219 emi.opSize = 2; // 32 bit operand size
220 }
221 else if(/*FIXME default 32*/1)
222 {
223 if(emi.legacy.op)
224 emi.opSize = 1; // 16 bit operand size
225 else
226 emi.opSize = 2; // 32 bit operand size
227 }
228 else // 16 bit default operand size
229 {
230 if(emi.legacy.op)
231 emi.opSize = 2; // 32 bit operand size
232 else
233 emi.opSize = 1; // 16 bit operand size
234 }
235
236 //Figure out how big of an immediate we'll retreive based
237 //on the opcode.
238 int immType = ImmediateType[emi.opcode.num - 1][nextByte];
239 immediateSize = SizeTypeToSize[emi.opSize - 1][immType];
240
241 //Determine what to expect next
242 if (UsesModRM[emi.opcode.num - 1][nextByte]) {
243 nextState = ModRMState;
244 } else {
245 if(immediateSize) {
246 nextState = ImmediateState;
247 } else {
248 emiIsReady = true;
249 nextState = ResetState;
250 }
251 }
252 }
253 return nextState;
254 }
255
256 //Get the ModRM byte and determine what displacement, if any, there is.
257 //Also determine whether or not to get the SIB byte, displacement, or
258 //immediate next.
259 Predecoder::State Predecoder::doModRMState(uint8_t nextByte)
260 {
261 State nextState = ErrorState;
262 emi.modRM = nextByte;
263 DPRINTF(Predecoder, "Found modrm byte %#x.\n", nextByte);
264 if (0) {//FIXME in 16 bit mode
265 //figure out 16 bit displacement size
266 if(nextByte & 0xC7 == 0x06 ||
267 nextByte & 0xC0 == 0x80)
268 displacementSize = 2;
269 else if(nextByte & 0xC0 == 0x40)
270 displacementSize = 1;
271 else
272 displacementSize = 0;
273 } else {
274 //figure out 32/64 bit displacement size
275 if(nextByte & 0xC6 == 0x04 ||
276 nextByte & 0xC0 == 0x80)
277 displacementSize = 4;
278 else if(nextByte & 0xC0 == 0x40)
279 displacementSize = 1;
280 else
281 displacementSize = 0;
282 }
283 //If there's an SIB, get that next.
284 //There is no SIB in 16 bit mode.
285 if(nextByte & 0x7 == 4 &&
286 nextByte & 0xC0 != 0xC0) {
287 // && in 32/64 bit mode)
288 nextState = SIBState;
289 } else if(displacementSize) {
290 nextState = DisplacementState;
291 } else if(immediateSize) {
292 nextState = ImmediateState;
293 } else {
294 emiIsReady = true;
295 nextState = ResetState;
296 }
297 //The ModRM byte is consumed no matter what
298 consumeByte();
299 return nextState;
300 }
301
302 //Get the SIB byte. We don't do anything with it at this point, other
303 //than storing it in the ExtMachInst. Determine if we need to get a
304 //displacement or immediate next.
305 Predecoder::State Predecoder::doSIBState(uint8_t nextByte)
306 {
307 State nextState = ErrorState;
308 emi.sib = nextByte;
309 DPRINTF(Predecoder, "Found SIB byte %#x.\n", nextByte);
310 consumeByte();
311 if(displacementSize) {
312 nextState = DisplacementState;
313 } else if(immediateSize) {
314 nextState = ImmediateState;
315 } else {
316 emiIsReady = true;
317 nextState = ResetState;
318 }
319 return nextState;
320 }
321
322 //Gather up the displacement, or at least as much of it
323 //as we can get.
324 Predecoder::State Predecoder::doDisplacementState()
325 {
326 State nextState = ErrorState;
327
328 getImmediate(displacementCollected,
329 emi.displacement,
330 displacementSize);
331
332 DPRINTF(Predecoder, "Collecting %d byte displacement, got %d bytes.\n",
333 displacementSize, displacementCollected);
334
335 if(displacementSize == displacementCollected) {
336 //Sign extend the displacement
337 switch(displacementSize)
338 {
339 case 1:
340 emi.displacement = sext<8>(emi.displacement);
341 break;
342 case 2:
343 emi.displacement = sext<16>(emi.displacement);
344 break;
345 case 4:
346 emi.displacement = sext<32>(emi.displacement);
347 break;
348 default:
349 panic("Undefined displacement size!\n");
350 }
351 DPRINTF(Predecoder, "Collected displacement %#x.\n",
352 emi.displacement);
353 if(immediateSize) {
354 nextState = ImmediateState;
355 } else {
356 emiIsReady = true;
357 nextState = ResetState;
358 }
359 }
360 else
361 nextState = DisplacementState;
362 return nextState;
363 }
364
365 //Gather up the immediate, or at least as much of it
366 //as we can get
367 Predecoder::State Predecoder::doImmediateState()
368 {
369 State nextState = ErrorState;
370
371 getImmediate(immediateCollected,
372 emi.immediate,
373 immediateSize);
374
375 DPRINTF(Predecoder, "Collecting %d byte immediate, got %d bytes.\n",
376 immediateSize, immediateCollected);
377
378 if(immediateSize == immediateCollected)
379 {
380 //XXX Warning! The following is an observed pattern and might
381 //not always be true!
382
383 //Instructions which use 64 bit operands but 32 bit immediates
384 //need to have the immediate sign extended to 64 bits.
385 //Instructions which use true 64 bit immediates won't be
386 //affected, and instructions that use true 32 bit immediates
387 //won't notice.
388 if(immediateSize == 4)
389 emi.immediate = sext<32>(emi.immediate);
390 DPRINTF(Predecoder, "Collected immediate %#x.\n",
391 emi.immediate);
392 emiIsReady = true;
393 nextState = ResetState;
394 }
395 else
396 nextState = ImmediateState;
397 return nextState;
398 }
399 }