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 emi.mode = 0;
81 }
82
83 void Predecoder::process()
84 {
85 //This function drives the predecoder state machine.
86
87 //Some sanity checks. You shouldn't try to process more bytes if
88 //there aren't any, and you shouldn't overwrite an already
89 //predecoder ExtMachInst.
90 assert(!outOfBytes);
91 assert(!emiIsReady);
92
93 //While there's still something to do...
94 while(!emiIsReady && !outOfBytes)
95 {
96 uint8_t nextByte = getNextByte();
97 switch(state)
98 {
99 case ResetState:
100 reset();
101 state = PrefixState;
102 case PrefixState:
103 state = doPrefixState(nextByte);
104 break;
105 case OpcodeState:
106 state = doOpcodeState(nextByte);
107 break;
108 case ModRMState:
109 state = doModRMState(nextByte);
110 break;
111 case SIBState:
112 state = doSIBState(nextByte);
113 break;
114 case DisplacementState:
115 state = doDisplacementState();
116 break;
117 case ImmediateState:
118 state = doImmediateState();
119 break;
120 case ErrorState:
121 panic("Went to the error state in the predecoder.\n");
122 default:
123 panic("Unrecognized state! %d\n", state);
124 }
125 }
126 }
127
128 //Either get a prefix and record it in the ExtMachInst, or send the
129 //state machine on to get the opcode(s).
130 Predecoder::State Predecoder::doPrefixState(uint8_t nextByte)
131 {
132 uint8_t prefix = Prefixes[nextByte];
133 State nextState = PrefixState;
134 if(prefix)
135 consumeByte();
136 switch(prefix)
137 {
138 //Operand size override prefixes
139 case OperandSizeOverride:
140 DPRINTF(Predecoder, "Found operand size override prefix.\n");
141 emi.legacy.op = true;
142 break;
143 case AddressSizeOverride:
144 DPRINTF(Predecoder, "Found address size override prefix.\n");
145 emi.legacy.addr = true;
146 break;
147 //Segment override prefixes
148 case CSOverride:
149 case DSOverride:
150 case ESOverride:
151 case FSOverride:
152 case GSOverride:
153 case SSOverride:
154 DPRINTF(Predecoder, "Found segment override.\n");
155 emi.legacy.seg = prefix;
156 break;
157 case Lock:
158 DPRINTF(Predecoder, "Found lock prefix.\n");
159 emi.legacy.lock = true;
160 break;
161 case Rep:
162 DPRINTF(Predecoder, "Found rep prefix.\n");
163 emi.legacy.rep = true;
164 break;
165 case Repne:
166 DPRINTF(Predecoder, "Found repne prefix.\n");
167 emi.legacy.repne = true;
168 break;
169 case RexPrefix:
170 DPRINTF(Predecoder, "Found Rex prefix %#x.\n", nextByte);
171 emi.rex = nextByte;
172 break;
173 case 0:
174 nextState = OpcodeState;
175 break;
176 default:
177 panic("Unrecognized prefix %#x\n", nextByte);
178 }
179 return nextState;
180 }
181
182 //Load all the opcodes (currently up to 2) and then figure out
183 //what immediate and/or ModRM is needed.
184 Predecoder::State Predecoder::doOpcodeState(uint8_t nextByte)
185 {
186 State nextState = ErrorState;
187 emi.opcode.num++;
188 //We can't handle 3+ byte opcodes right now
189 assert(emi.opcode.num < 3);
190 consumeByte();
191 if(emi.opcode.num == 1 && nextByte == 0x0f)
192 {
193 nextState = OpcodeState;
194 DPRINTF(Predecoder, "Found two byte opcode.\n");
195 emi.opcode.prefixA = nextByte;
196 }
197 else if(emi.opcode.num == 2 &&
198 (nextByte == 0x0f ||
199 (nextByte & 0xf8) == 0x38))
200 {
201 panic("Three byte opcodes aren't yet supported!\n");
202 nextState = OpcodeState;
203 DPRINTF(Predecoder, "Found three byte opcode.\n");
204 emi.opcode.prefixB = nextByte;
205 }
206 else
207 {
208 DPRINTF(Predecoder, "Found opcode %#x.\n", nextByte);
209 emi.opcode.op = nextByte;
210
211 //Figure out the effective operand size. This can be overriden to
212 //a fixed value at the decoder level.
213 int logOpSize;
214 if(/*FIXME long mode*/1)
215 {
216 if(emi.rex.w)
217 logOpSize = 3; // 64 bit operand size
218 else if(emi.legacy.op)
219 logOpSize = 1; // 16 bit operand size
220 else
221 logOpSize = 2; // 32 bit operand size
222 }
223 else if(/*FIXME default 32*/1)
224 {
225 if(emi.legacy.op)
226 logOpSize = 1; // 16 bit operand size
227 else
228 logOpSize = 2; // 32 bit operand size
229 }
230 else // 16 bit default operand size
231 {
232 if(emi.legacy.op)
233 logOpSize = 2; // 32 bit operand size
234 else
235 logOpSize = 1; // 16 bit operand size
236 }
237
238 //Figure out how big of an immediate we'll retreive based
239 //on the opcode.
240 int immType = ImmediateType[emi.opcode.num - 1][nextByte];
241 immediateSize = SizeTypeToSize[logOpSize - 1][immType];
242
243 //Set the actual op size
244 emi.opSize = 1 << logOpSize;
245
246 //Determine what to expect next
247 if (UsesModRM[emi.opcode.num - 1][nextByte]) {
248 nextState = ModRMState;
249 } else {
250 if(immediateSize) {
251 nextState = ImmediateState;
252 } else {
253 emiIsReady = true;
254 nextState = ResetState;
255 }
256 }
257 }
258 return nextState;
259 }
260
261 //Get the ModRM byte and determine what displacement, if any, there is.
262 //Also determine whether or not to get the SIB byte, displacement, or
263 //immediate next.
264 Predecoder::State Predecoder::doModRMState(uint8_t nextByte)
265 {
266 State nextState = ErrorState;
267 ModRM modRM;
268 modRM = nextByte;
269 DPRINTF(Predecoder, "Found modrm byte %#x.\n", nextByte);
270 if (0) {//FIXME in 16 bit mode
271 //figure out 16 bit displacement size
272 if(modRM.mod == 0 && modRM.rm == 6 || modRM.mod == 2)
273 displacementSize = 2;
274 else if(modRM.mod == 1)
275 displacementSize = 1;
276 else
277 displacementSize = 0;
278 } else {
279 //figure out 32/64 bit displacement size
280 if(modRM.mod == 0 && (modRM.rm == 4 || modRM.rm == 5)
281 || modRM.mod == 2)
282 displacementSize = 4;
283 else if(modRM.mod == 1)
284 displacementSize = 1;
285 else
286 displacementSize = 0;
287 }
288 //If there's an SIB, get that next.
289 //There is no SIB in 16 bit mode.
290 if(modRM.rm == 4 && modRM.mod != 3) {
291 // && in 32/64 bit mode)
292 nextState = SIBState;
293 } else if(displacementSize) {
294 nextState = DisplacementState;
295 } else if(immediateSize) {
296 nextState = ImmediateState;
297 } else {
298 emiIsReady = true;
299 nextState = ResetState;
300 }
301 //The ModRM byte is consumed no matter what
302 consumeByte();
303 emi.modRM = modRM;
304 return nextState;
305 }
306
307 //Get the SIB byte. We don't do anything with it at this point, other
308 //than storing it in the ExtMachInst. Determine if we need to get a
309 //displacement or immediate next.
310 Predecoder::State Predecoder::doSIBState(uint8_t nextByte)
311 {
312 State nextState = ErrorState;
313 emi.sib = nextByte;
314 DPRINTF(Predecoder, "Found SIB byte %#x.\n", nextByte);
315 consumeByte();
316 if(displacementSize) {
317 nextState = DisplacementState;
318 } else if(immediateSize) {
319 nextState = ImmediateState;
320 } else {
321 emiIsReady = true;
322 nextState = ResetState;
323 }
324 return nextState;
325 }
326
327 //Gather up the displacement, or at least as much of it
328 //as we can get.
329 Predecoder::State Predecoder::doDisplacementState()
330 {
331 State nextState = ErrorState;
332
333 getImmediate(displacementCollected,
334 emi.displacement,
335 displacementSize);
336
337 DPRINTF(Predecoder, "Collecting %d byte displacement, got %d bytes.\n",
338 displacementSize, displacementCollected);
339
340 if(displacementSize == displacementCollected) {
341 //Sign extend the displacement
342 switch(displacementSize)
343 {
344 case 1:
345 emi.displacement = sext<8>(emi.displacement);
346 break;
347 case 2:
348 emi.displacement = sext<16>(emi.displacement);
349 break;
350 case 4:
351 emi.displacement = sext<32>(emi.displacement);
352 break;
353 default:
354 panic("Undefined displacement size!\n");
355 }
356 DPRINTF(Predecoder, "Collected displacement %#x.\n",
357 emi.displacement);
358 if(immediateSize) {
359 nextState = ImmediateState;
360 } else {
361 emiIsReady = true;
362 nextState = ResetState;
363 }
364 }
365 else
366 nextState = DisplacementState;
367 return nextState;
368 }
369
370 //Gather up the immediate, or at least as much of it
371 //as we can get
372 Predecoder::State Predecoder::doImmediateState()
373 {
374 State nextState = ErrorState;
375
376 getImmediate(immediateCollected,
377 emi.immediate,
378 immediateSize);
379
380 DPRINTF(Predecoder, "Collecting %d byte immediate, got %d bytes.\n",
381 immediateSize, immediateCollected);
382
383 if(immediateSize == immediateCollected)
384 {
385 //XXX Warning! The following is an observed pattern and might
386 //not always be true!
387
388 //Instructions which use 64 bit operands but 32 bit immediates
389 //need to have the immediate sign extended to 64 bits.
390 //Instructions which use true 64 bit immediates won't be
391 //affected, and instructions that use true 32 bit immediates
392 //won't notice.
393 switch(immediateSize)
394 {
395 case 4:
396 emi.immediate = sext<32>(emi.immediate);
397 break;
398 case 1:
399 emi.immediate = sext<8>(emi.immediate);
400 }
401
402 DPRINTF(Predecoder, "Collected immediate %#x.\n",
403 emi.immediate);
404 emiIsReady = true;
405 nextState = ResetState;
406 }
407 else
408 nextState = ImmediateState;
409 return nextState;
410 }
411 }