arch-power: Fix shift instructions
[gem5.git] / src / arch / power / insts / integer.cc
1 /*
2 * Copyright (c) 2009 The University of Edinburgh
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "arch/power/insts/integer.hh"
30
31 using namespace PowerISA;
32
33 std::string
34 IntOp::generateDisassembly(Addr pc, const Loader::SymbolTable *symtab) const
35 {
36 std::stringstream ss;
37 bool printDest = true;
38 bool printSrcs = true;
39 bool printSecondSrc = true;
40
41 // Generate the correct mnemonic
42 std::string myMnemonic(mnemonic);
43
44 // Special cases
45 if (!myMnemonic.compare("or") && srcRegIdx(0) == srcRegIdx(1)) {
46 myMnemonic = "mr";
47 printSecondSrc = false;
48 } else if (!myMnemonic.compare("mtcrf") ||
49 !myMnemonic.compare("mtxer") ||
50 !myMnemonic.compare("mtlr") ||
51 !myMnemonic.compare("mtctr") ||
52 !myMnemonic.compare("mttar")) {
53 printDest = false;
54 } else if (!myMnemonic.compare("mfcr") ||
55 !myMnemonic.compare("mfxer") ||
56 !myMnemonic.compare("mflr") ||
57 !myMnemonic.compare("mfctr") ||
58 !myMnemonic.compare("mftar")) {
59 printSrcs = false;
60 }
61
62 // Additional characters depending on isa bits being set
63 if (oeSet) myMnemonic = myMnemonic + "o";
64 if (rcSet) myMnemonic = myMnemonic + ".";
65 ccprintf(ss, "%-10s ", myMnemonic);
66
67 // Print the first destination only
68 if (_numDestRegs > 0 && printDest) {
69 printReg(ss, destRegIdx(0));
70 }
71
72 // Print the (possibly) two source registers
73 if (_numSrcRegs > 0 && printSrcs) {
74 if (_numDestRegs > 0 && printDest) {
75 ss << ", ";
76 }
77 printReg(ss, srcRegIdx(0));
78 if (_numSrcRegs > 1 && printSecondSrc) {
79 ss << ", ";
80 printReg(ss, srcRegIdx(1));
81 }
82 }
83
84 return ss.str();
85 }
86
87
88 std::string
89 IntImmOp::generateDisassembly(Addr pc, const Loader::SymbolTable *symtab) const
90 {
91 std::stringstream ss;
92
93 ccprintf(ss, "%-10s ", mnemonic);
94
95 // Print the first destination only
96 if (_numDestRegs > 0) {
97 printReg(ss, destRegIdx(0));
98 }
99
100 // Print the source register
101 if (_numSrcRegs > 0) {
102 if (_numDestRegs > 0) {
103 ss << ", ";
104 }
105 printReg(ss, srcRegIdx(0));
106 }
107
108 // Print the immediate value last
109 ss << ", " << (int32_t)imm;
110
111 return ss.str();
112 }
113
114
115 std::string
116 IntArithOp::generateDisassembly(
117 Addr pc, const Loader::SymbolTable *symtab) const
118 {
119 std::stringstream ss;
120 bool printSecondSrc = true;
121 bool printThirdSrc = false;
122
123 // Generate the correct mnemonic
124 std::string myMnemonic(mnemonic);
125
126 // Special cases
127 if (!myMnemonic.compare("addme") ||
128 !myMnemonic.compare("addze") ||
129 !myMnemonic.compare("subfme") ||
130 !myMnemonic.compare("subfze") ||
131 !myMnemonic.compare("neg")){
132 printSecondSrc = false;
133 } else if (!myMnemonic.compare("maddhd") ||
134 !myMnemonic.compare("maddhdu") ||
135 !myMnemonic.compare("maddld")) {
136 printThirdSrc = true;
137 }
138
139 // Additional characters depending on isa bits being set
140 if (oeSet) myMnemonic = myMnemonic + "o";
141 if (rcSet) myMnemonic = myMnemonic + ".";
142 ccprintf(ss, "%-10s ", myMnemonic);
143
144 // Print the first destination only
145 if (_numDestRegs > 0) {
146 printReg(ss, destRegIdx(0));
147 }
148
149 // Print the first source register
150 if (_numSrcRegs > 0) {
151 if (_numDestRegs > 0) {
152 ss << ", ";
153 }
154 printReg(ss, srcRegIdx(0));
155
156 // Print the second source register
157 if (_numSrcRegs > 1 && printSecondSrc) {
158 ss << ", ";
159 printReg(ss, srcRegIdx(1));
160
161 // Print the third source register
162 if (_numSrcRegs > 2 && printThirdSrc) {
163 ss << ", ";
164 printReg(ss, srcRegIdx(2));
165 }
166 }
167 }
168
169 return ss.str();
170 }
171
172
173 std::string
174 IntImmArithOp::generateDisassembly(
175 Addr pc, const Loader::SymbolTable *symtab) const
176 {
177 std::stringstream ss;
178 bool negateSimm = false;
179
180 // Generate the correct mnemonic
181 std::string myMnemonic(mnemonic);
182
183 // Special cases
184 if (!myMnemonic.compare("addi")) {
185 if (_numSrcRegs == 0) {
186 myMnemonic = "li";
187 } else if (simm < 0) {
188 myMnemonic = "subi";
189 negateSimm = true;
190 }
191 } else if (!myMnemonic.compare("addis")) {
192 if (_numSrcRegs == 0) {
193 myMnemonic = "lis";
194 } else if (simm < 0) {
195 myMnemonic = "subis";
196 negateSimm = true;
197 }
198 } else if (!myMnemonic.compare("addic") && simm < 0) {
199 myMnemonic = "subic";
200 negateSimm = true;
201 } else if (!myMnemonic.compare("addic_")) {
202 if (simm < 0) {
203 myMnemonic = "subic.";
204 negateSimm = true;
205 } else {
206 myMnemonic = "addic.";
207 }
208 }
209
210 ccprintf(ss, "%-10s ", myMnemonic);
211
212 // Print the first destination only
213 if (_numDestRegs > 0) {
214 printReg(ss, destRegIdx(0));
215 }
216
217 // Print the source register
218 if (_numSrcRegs > 0) {
219 if (_numDestRegs > 0) {
220 ss << ", ";
221 }
222 printReg(ss, srcRegIdx(0));
223 }
224
225 // Print the immediate value
226 if (negateSimm) {
227 ss << ", " << -simm;
228 } else {
229 ss << ", " << simm;
230 }
231
232 return ss.str();
233 }
234
235
236 std::string
237 IntDispArithOp::generateDisassembly(
238 Addr pc, const Loader::SymbolTable *symtab) const
239 {
240 std::stringstream ss;
241 bool printSrcs = true;
242 bool printDisp = true;
243 bool negateDisp = false;
244
245 // Generate the correct mnemonic
246 std::string myMnemonic(mnemonic);
247
248 // Special cases
249 if (!myMnemonic.compare("addpcis")) {
250 printSrcs = false;
251 if (disp == 0) {
252 myMnemonic = "lnia";
253 printDisp = false;
254 } else if (disp < 0) {
255 myMnemonic = "subpcis";
256 negateDisp = true;
257 }
258 }
259
260 ccprintf(ss, "%-10s ", myMnemonic);
261
262 // Print the first destination only
263 if (_numDestRegs > 0) {
264 printReg(ss, destRegIdx(0));
265 }
266
267 // Print the source register
268 if (_numSrcRegs > 0 && printSrcs) {
269 if (_numDestRegs > 0) {
270 ss << ", ";
271 }
272 printReg(ss, srcRegIdx(0));
273 }
274
275 // Print the displacement
276 if (printDisp) {
277 if (negateDisp) {
278 ss << ", " << -disp;
279 } else {
280 ss << ", " << disp;
281 }
282 }
283
284 return ss.str();
285 }
286
287
288 std::string
289 IntLogicOp::generateDisassembly(
290 Addr pc, const Loader::SymbolTable *symtab) const
291 {
292 std::stringstream ss;
293 bool printSecondSrc = true;
294
295 // Generate the correct mnemonic
296 std::string myMnemonic(mnemonic);
297
298 // Special cases
299 if (!myMnemonic.compare("or") && srcRegIdx(0) == srcRegIdx(1)) {
300 myMnemonic = "mr";
301 printSecondSrc = false;
302 } else if (!myMnemonic.compare("extsb") ||
303 !myMnemonic.compare("extsh") ||
304 !myMnemonic.compare("extsw") ||
305 !myMnemonic.compare("cntlzw") ||
306 !myMnemonic.compare("cntlzd") ||
307 !myMnemonic.compare("cnttzw") ||
308 !myMnemonic.compare("cnttzd")) {
309 printSecondSrc = false;
310 }
311
312 // Additional characters depending on isa bits being set
313 if (rcSet) myMnemonic = myMnemonic + ".";
314 ccprintf(ss, "%-10s ", myMnemonic);
315
316 // Print the first destination only
317 if (_numDestRegs > 0) {
318 printReg(ss, destRegIdx(0));
319 }
320
321 // Print the first source register
322 if (_numSrcRegs > 0) {
323 if (_numDestRegs > 0) {
324 ss << ", ";
325 }
326 printReg(ss, srcRegIdx(0));
327
328 // Print the second source register
329 if (printSecondSrc) {
330
331 // If the instruction updates the CR, the destination register
332 // Ra is read and thus, it becomes the second source register
333 // due to its higher precedence over Rb. In this case, it must
334 // be skipped.
335 if (rcSet) {
336 if (_numSrcRegs > 2) {
337 ss << ", ";
338 printReg(ss, srcRegIdx(2));
339 }
340 } else {
341 if (_numSrcRegs > 1) {
342 ss << ", ";
343 printReg(ss, srcRegIdx(1));
344 }
345 }
346 }
347 }
348
349 return ss.str();
350 }
351
352
353 std::string
354 IntImmLogicOp::generateDisassembly(
355 Addr pc, const Loader::SymbolTable *symtab) const
356 {
357 std::stringstream ss;
358 bool printRegs = true;
359
360 // Generate the correct mnemonic
361 std::string myMnemonic(mnemonic);
362
363 // Special cases
364 if (!myMnemonic.compare("ori") &&
365 destRegIdx(0).index() == 0 && srcRegIdx(0).index() == 0) {
366 myMnemonic = "nop";
367 printRegs = false;
368 } else if (!myMnemonic.compare("xori") &&
369 destRegIdx(0).index() == 0 && srcRegIdx(0).index() == 0) {
370 myMnemonic = "xnop";
371 printRegs = false;
372 } else if (!myMnemonic.compare("andi_")) {
373 myMnemonic = "andi.";
374 } else if (!myMnemonic.compare("andis_")) {
375 myMnemonic = "andis.";
376 }
377
378 ccprintf(ss, "%-10s ", myMnemonic);
379
380 if (printRegs) {
381
382 // Print the first destination only
383 if (_numDestRegs > 0) {
384 printReg(ss, destRegIdx(0));
385 }
386
387 // Print the source register
388 if (_numSrcRegs > 0) {
389 if (_numDestRegs > 0) {
390 ss << ", ";
391 }
392 printReg(ss, srcRegIdx(0));
393 }
394
395 // Print the immediate value
396 ss << ", " << uimm;
397 }
398
399 return ss.str();
400 }
401
402
403 std::string
404 IntCompOp::generateDisassembly(
405 Addr pc, const Loader::SymbolTable *symtab) const
406 {
407 std::stringstream ss;
408 bool printFieldPrefix = false;
409 bool printLength = true;
410
411 // Generate the correct mnemonic
412 std::string myMnemonic(mnemonic);
413
414 // Special cases
415 if (!myMnemonic.compare("cmp")) {
416 if (length) {
417 myMnemonic = "cmpd";
418 } else {
419 myMnemonic = "cmpw";
420 }
421 printFieldPrefix = true;
422 printLength = false;
423 } else if (!myMnemonic.compare("cmpl")) {
424 if (length) {
425 myMnemonic = "cmpld";
426 } else {
427 myMnemonic = "cmplw";
428 }
429 printFieldPrefix = true;
430 printLength = false;
431 }
432
433 ccprintf(ss, "%-10s ", myMnemonic);
434
435 // Print the first destination only
436 if (printFieldPrefix) {
437 if (field > 0) {
438 ss << "cr" << field;
439 }
440 } else {
441 ss << field;
442 }
443
444 // Print the length
445 if (printLength) {
446 if (!printFieldPrefix || field > 0) {
447 ss << ", ";
448 }
449 ss << length;
450 }
451
452 // Print the first source register
453 if (_numSrcRegs > 0) {
454 if (!printFieldPrefix || field > 0 || printLength) {
455 ss << ", ";
456 }
457 printReg(ss, srcRegIdx(0));
458
459 // Print the second source register
460 if (_numSrcRegs > 1) {
461 ss << ", ";
462 printReg(ss, srcRegIdx(1));
463 }
464 }
465
466 return ss.str();
467 }
468
469
470 std::string
471 IntImmCompOp::generateDisassembly(
472 Addr pc, const Loader::SymbolTable *symtab) const
473 {
474 std::stringstream ss;
475 bool printFieldPrefix = false;
476 bool printLength = true;
477
478 // Generate the correct mnemonic
479 std::string myMnemonic(mnemonic);
480
481 // Special cases
482 if (!myMnemonic.compare("cmpi")) {
483 if (length) {
484 myMnemonic = "cmpdi";
485 } else {
486 myMnemonic = "cmpwi";
487 }
488 printFieldPrefix = true;
489 printLength = false;
490 }
491
492 ccprintf(ss, "%-10s ", myMnemonic);
493
494 // Print the first destination only
495 if (printFieldPrefix) {
496 if (field > 0) {
497 ss << "cr" << field;
498 }
499 } else {
500 ss << field;
501 }
502
503 // Print the length
504 if (printLength) {
505 if (!printFieldPrefix || field > 0) {
506 ss << ", ";
507 }
508 ss << length;
509 }
510
511 // Print the first source register
512 if (_numSrcRegs > 0) {
513 if (!printFieldPrefix || field > 0 || printLength) {
514 ss << ", ";
515 }
516 printReg(ss, srcRegIdx(0));
517 }
518
519 // Print the immediate value
520 ss << ", " << simm;
521
522 return ss.str();
523 }
524
525
526 std::string
527 IntImmCompLogicOp::generateDisassembly(
528 Addr pc, const Loader::SymbolTable *symtab) const
529 {
530 std::stringstream ss;
531 bool printFieldPrefix = false;
532 bool printLength = true;
533
534 // Generate the correct mnemonic
535 std::string myMnemonic(mnemonic);
536
537 // Special cases
538 if (!myMnemonic.compare("cmpli")) {
539 if (length) {
540 myMnemonic = "cmpldi";
541 } else {
542 myMnemonic = "cmplwi";
543 }
544 printFieldPrefix = true;
545 printLength = false;
546 }
547
548 ccprintf(ss, "%-10s ", myMnemonic);
549
550 // Print the first destination only
551 if (printFieldPrefix) {
552 if (field > 0) {
553 ss << "cr" << field;
554 }
555 } else {
556 ss << field;
557 }
558
559 // Print the mode
560 if (printLength) {
561 if (!printFieldPrefix || field > 0) {
562 ss << ", ";
563 }
564 ss << length;
565 }
566
567 // Print the first source register
568 if (_numSrcRegs > 0) {
569 if (!printFieldPrefix || field > 0 || printLength) {
570 ss << ", ";
571 }
572 printReg(ss, srcRegIdx(0));
573 }
574
575 // Print the immediate value
576 ss << ", " << uimm;
577
578 return ss.str();
579 }
580
581
582 std::string
583 IntShiftOp::generateDisassembly(
584 Addr pc, const Loader::SymbolTable *symtab) const
585 {
586 std::stringstream ss;
587
588 ccprintf(ss, "%-10s ", mnemonic);
589
590 // Print the first destination only
591 if (_numDestRegs > 0) {
592 printReg(ss, destRegIdx(0));
593 }
594
595 // Print the first source register
596 if (_numSrcRegs > 0) {
597 if (_numDestRegs > 0) {
598 ss << ", ";
599 }
600 printReg(ss, srcRegIdx(0));
601 }
602
603 // Print the shift
604 ss << ", " << sh;
605
606 return ss.str();
607 }
608
609
610 std::string
611 IntRotateOp::generateDisassembly(
612 Addr pc, const Loader::SymbolTable *symtab) const
613 {
614 std::stringstream ss;
615
616 ccprintf(ss, "%-10s ", mnemonic);
617
618 // Print the first destination only
619 if (_numDestRegs > 0) {
620 printReg(ss, destRegIdx(0));
621 }
622
623 // Print the first source register
624 if (_numSrcRegs > 0) {
625 if (_numDestRegs > 0) {
626 ss << ", ";
627 }
628 printReg(ss, srcRegIdx(0));
629 }
630
631 // Print the shift, mask begin and mask end
632 ss << ", " << sh << ", " << mb << ", " << me;
633
634 return ss.str();
635 }