macromem.cc revision 7639:8c09b7ff5b57
1/*
2 * Copyright (c) 2010 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2007-2008 The Florida State University
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Stephen Hines
41 */
42
43#include "arch/arm/insts/macromem.hh"
44#include "arch/arm/decoder.hh"
45
46using namespace ArmISAInst;
47
48namespace ArmISA
49{
50
51MacroMemOp::MacroMemOp(const char *mnem, ExtMachInst machInst,
52                       OpClass __opClass, IntRegIndex rn,
53                       bool index, bool up, bool user, bool writeback,
54                       bool load, uint32_t reglist) :
55    PredMacroOp(mnem, machInst, __opClass)
56{
57    uint32_t regs = reglist;
58    uint32_t ones = number_of_ones(reglist);
59    // Remember that writeback adds a uop
60    numMicroops = ones + (writeback ? 1 : 0) + 1;
61    microOps = new StaticInstPtr[numMicroops];
62    uint32_t addr = 0;
63
64    if (!up)
65        addr = (ones << 2) - 4;
66
67    if (!index)
68        addr += 4;
69
70    StaticInstPtr *uop = microOps;
71    StaticInstPtr wbUop;
72    if (writeback) {
73        if (up) {
74            wbUop = new MicroAddiUop(machInst, rn, rn, ones * 4);
75        } else {
76            wbUop = new MicroSubiUop(machInst, rn, rn, ones * 4);
77        }
78    }
79
80    // Add 0 to Rn and stick it in ureg0.
81    // This is equivalent to a move.
82    *uop = new MicroAddiUop(machInst, INTREG_UREG0, rn, 0);
83
84    // Write back at the start for loads. This covers the ldm exception return
85    // case where the base needs to be written in the old mode. Stores may need
86    // the original value of the base, but they don't change mode and can
87    // write back at the end like before.
88    if (load && writeback) {
89        *++uop = wbUop;
90    }
91
92    unsigned reg = 0;
93    bool force_user = user & !bits(reglist, 15);
94    bool exception_ret = user & bits(reglist, 15);
95
96    for (int i = 0; i < ones; i++) {
97        // Find the next register.
98        while (!bits(regs, reg))
99            reg++;
100        replaceBits(regs, reg, 0);
101
102        unsigned regIdx = reg;
103        if (force_user) {
104            regIdx = intRegInMode(MODE_USER, regIdx);
105        }
106
107        if (load) {
108            if (reg == INTREG_PC && exception_ret) {
109                // This must be the exception return form of ldm.
110                *++uop = new MicroLdrRetUop(machInst, regIdx,
111                                           INTREG_UREG0, up, addr);
112            } else {
113                *++uop = new MicroLdrUop(machInst, regIdx,
114                                        INTREG_UREG0, up, addr);
115            }
116        } else {
117            *++uop = new MicroStrUop(machInst, regIdx, INTREG_UREG0, up, addr);
118        }
119
120        if (up)
121            addr += 4;
122        else
123            addr -= 4;
124    }
125
126    if (!load && writeback) {
127        *++uop = wbUop;
128    }
129
130    (*uop)->setLastMicroop();
131
132    for (StaticInstPtr *curUop = microOps;
133            !(*curUop)->isLastMicroop(); curUop++) {
134        MicroOp * uopPtr = dynamic_cast<MicroOp *>(curUop->get());
135        assert(uopPtr);
136        uopPtr->setDelayedCommit();
137    }
138}
139
140VldMultOp::VldMultOp(const char *mnem, ExtMachInst machInst, OpClass __opClass,
141                     unsigned elems, RegIndex rn, RegIndex vd, unsigned regs,
142                     unsigned inc, uint32_t size, uint32_t align, RegIndex rm) :
143    PredMacroOp(mnem, machInst, __opClass)
144{
145    assert(regs > 0 && regs <= 4);
146    assert(regs % elems == 0);
147
148    numMicroops = (regs > 2) ? 2 : 1;
149    bool wb = (rm != 15);
150    bool deinterleave = (elems > 1);
151
152    if (wb) numMicroops++;
153    if (deinterleave) numMicroops += (regs / elems);
154    microOps = new StaticInstPtr[numMicroops];
155
156    RegIndex rMid = deinterleave ? NumFloatArchRegs : vd * 2;
157
158    uint32_t noAlign = TLB::MustBeOne;
159
160    unsigned uopIdx = 0;
161    switch (regs) {
162      case 4:
163        microOps[uopIdx++] = newNeonMemInst<MicroLdrNeon16Uop>(
164                size, machInst, rMid, rn, 0, align);
165        microOps[uopIdx++] = newNeonMemInst<MicroLdrNeon16Uop>(
166                size, machInst, rMid + 4, rn, 16, noAlign);
167        break;
168      case 3:
169        microOps[uopIdx++] = newNeonMemInst<MicroLdrNeon16Uop>(
170                size, machInst, rMid, rn, 0, align);
171        microOps[uopIdx++] = newNeonMemInst<MicroLdrNeon8Uop>(
172                size, machInst, rMid + 4, rn, 16, noAlign);
173        break;
174      case 2:
175        microOps[uopIdx++] = newNeonMemInst<MicroLdrNeon16Uop>(
176                size, machInst, rMid, rn, 0, align);
177        break;
178      case 1:
179        microOps[uopIdx++] = newNeonMemInst<MicroLdrNeon8Uop>(
180                size, machInst, rMid, rn, 0, align);
181        break;
182      default:
183        panic("Unrecognized number of registers %d.\n", regs);
184    }
185    if (wb) {
186        if (rm != 15 && rm != 13) {
187            microOps[uopIdx++] =
188                new MicroAddUop(machInst, rn, rn, rm);
189        } else {
190            microOps[uopIdx++] =
191                new MicroAddiUop(machInst, rn, rn, regs * 8);
192        }
193    }
194    if (deinterleave) {
195        switch (elems) {
196          case 4:
197            assert(regs == 4);
198            microOps[uopIdx++] = newNeonMixInst<MicroDeintNeon8Uop>(
199                    size, machInst, vd * 2, rMid, inc * 2);
200            break;
201          case 3:
202            assert(regs == 3);
203            microOps[uopIdx++] = newNeonMixInst<MicroDeintNeon6Uop>(
204                    size, machInst, vd * 2, rMid, inc * 2);
205            break;
206          case 2:
207            assert(regs == 4 || regs == 2);
208            if (regs == 4) {
209                microOps[uopIdx++] = newNeonMixInst<MicroDeintNeon4Uop>(
210                        size, machInst, vd * 2, rMid, inc * 2);
211                microOps[uopIdx++] = newNeonMixInst<MicroDeintNeon4Uop>(
212                        size, machInst, vd * 2 + 2, rMid + 4, inc * 2);
213            } else {
214                microOps[uopIdx++] = newNeonMixInst<MicroDeintNeon4Uop>(
215                        size, machInst, vd * 2, rMid, inc * 2);
216            }
217            break;
218          default:
219            panic("Bad number of elements to deinterleave %d.\n", elems);
220        }
221    }
222    assert(uopIdx == numMicroops);
223
224    for (unsigned i = 0; i < numMicroops - 1; i++) {
225        MicroOp * uopPtr = dynamic_cast<MicroOp *>(microOps[i].get());
226        assert(uopPtr);
227        uopPtr->setDelayedCommit();
228    }
229    microOps[numMicroops - 1]->setLastMicroop();
230}
231
232VldSingleOp::VldSingleOp(const char *mnem, ExtMachInst machInst,
233                         OpClass __opClass, bool all, unsigned elems,
234                         RegIndex rn, RegIndex vd, unsigned regs,
235                         unsigned inc, uint32_t size, uint32_t align,
236                         RegIndex rm, unsigned lane) :
237    PredMacroOp(mnem, machInst, __opClass)
238{
239    assert(regs > 0 && regs <= 4);
240    assert(regs % elems == 0);
241
242    unsigned eBytes = (1 << size);
243    unsigned loadSize = eBytes * elems;
244    unsigned loadRegs M5_VAR_USED = (loadSize + sizeof(FloatRegBits) - 1) /
245                        sizeof(FloatRegBits);
246
247    assert(loadRegs > 0 && loadRegs <= 4);
248
249    numMicroops = 1;
250    bool wb = (rm != 15);
251
252    if (wb) numMicroops++;
253    numMicroops += (regs / elems);
254    microOps = new StaticInstPtr[numMicroops];
255
256    RegIndex ufp0 = NumFloatArchRegs;
257
258    unsigned uopIdx = 0;
259    switch (loadSize) {
260      case 1:
261        microOps[uopIdx++] = new MicroLdrNeon1Uop<uint8_t>(
262                machInst, ufp0, rn, 0, align);
263        break;
264      case 2:
265        if (eBytes == 2) {
266            microOps[uopIdx++] = new MicroLdrNeon2Uop<uint16_t>(
267                    machInst, ufp0, rn, 0, align);
268        } else {
269            microOps[uopIdx++] = new MicroLdrNeon2Uop<uint8_t>(
270                    machInst, ufp0, rn, 0, align);
271        }
272        break;
273      case 3:
274        microOps[uopIdx++] = new MicroLdrNeon3Uop<uint8_t>(
275                machInst, ufp0, rn, 0, align);
276        break;
277      case 4:
278        switch (eBytes) {
279          case 1:
280            microOps[uopIdx++] = new MicroLdrNeon4Uop<uint8_t>(
281                    machInst, ufp0, rn, 0, align);
282            break;
283          case 2:
284            microOps[uopIdx++] = new MicroLdrNeon4Uop<uint16_t>(
285                    machInst, ufp0, rn, 0, align);
286            break;
287          case 4:
288            microOps[uopIdx++] = new MicroLdrNeon4Uop<uint32_t>(
289                    machInst, ufp0, rn, 0, align);
290            break;
291        }
292        break;
293      case 6:
294        microOps[uopIdx++] = new MicroLdrNeon6Uop<uint16_t>(
295                machInst, ufp0, rn, 0, align);
296        break;
297      case 8:
298        switch (eBytes) {
299          case 2:
300            microOps[uopIdx++] = new MicroLdrNeon8Uop<uint16_t>(
301                    machInst, ufp0, rn, 0, align);
302            break;
303          case 4:
304            microOps[uopIdx++] = new MicroLdrNeon8Uop<uint32_t>(
305                    machInst, ufp0, rn, 0, align);
306            break;
307        }
308        break;
309      case 12:
310        microOps[uopIdx++] = new MicroLdrNeon12Uop<uint32_t>(
311                machInst, ufp0, rn, 0, align);
312        break;
313      case 16:
314        microOps[uopIdx++] = new MicroLdrNeon16Uop<uint32_t>(
315                machInst, ufp0, rn, 0, align);
316        break;
317      default:
318        panic("Unrecognized load size %d.\n", regs);
319    }
320    if (wb) {
321        if (rm != 15 && rm != 13) {
322            microOps[uopIdx++] =
323                new MicroAddUop(machInst, rn, rn, rm);
324        } else {
325            microOps[uopIdx++] =
326                new MicroAddiUop(machInst, rn, rn, loadSize);
327        }
328    }
329    switch (elems) {
330      case 4:
331        assert(regs == 4);
332        switch (size) {
333          case 0:
334            if (all) {
335                microOps[uopIdx++] = new MicroUnpackAllNeon2to8Uop<uint8_t>(
336                        machInst, vd * 2, ufp0, inc * 2);
337            } else {
338                microOps[uopIdx++] = new MicroUnpackNeon2to8Uop<uint8_t>(
339                        machInst, vd * 2, ufp0, inc * 2, lane);
340            }
341            break;
342          case 1:
343            if (all) {
344                microOps[uopIdx++] = new MicroUnpackAllNeon2to8Uop<uint16_t>(
345                        machInst, vd * 2, ufp0, inc * 2);
346            } else {
347                microOps[uopIdx++] = new MicroUnpackNeon2to8Uop<uint16_t>(
348                        machInst, vd * 2, ufp0, inc * 2, lane);
349            }
350            break;
351          case 2:
352            if (all) {
353                microOps[uopIdx++] = new MicroUnpackAllNeon4to8Uop<uint32_t>(
354                        machInst, vd * 2, ufp0, inc * 2);
355            } else {
356                microOps[uopIdx++] = new MicroUnpackNeon4to8Uop<uint32_t>(
357                        machInst, vd * 2, ufp0, inc * 2, lane);
358            }
359            break;
360          default:
361            panic("Bad size %d.\n", size);
362            break;
363        }
364        break;
365      case 3:
366        assert(regs == 3);
367        switch (size) {
368          case 0:
369            if (all) {
370                microOps[uopIdx++] = new MicroUnpackAllNeon2to6Uop<uint8_t>(
371                        machInst, vd * 2, ufp0, inc * 2);
372            } else {
373                microOps[uopIdx++] = new MicroUnpackNeon2to6Uop<uint8_t>(
374                        machInst, vd * 2, ufp0, inc * 2, lane);
375            }
376            break;
377          case 1:
378            if (all) {
379                microOps[uopIdx++] = new MicroUnpackAllNeon2to6Uop<uint16_t>(
380                        machInst, vd * 2, ufp0, inc * 2);
381            } else {
382                microOps[uopIdx++] = new MicroUnpackNeon2to6Uop<uint16_t>(
383                        machInst, vd * 2, ufp0, inc * 2, lane);
384            }
385            break;
386          case 2:
387            if (all) {
388                microOps[uopIdx++] = new MicroUnpackAllNeon4to6Uop<uint32_t>(
389                        machInst, vd * 2, ufp0, inc * 2);
390            } else {
391                microOps[uopIdx++] = new MicroUnpackNeon4to6Uop<uint32_t>(
392                        machInst, vd * 2, ufp0, inc * 2, lane);
393            }
394            break;
395          default:
396            panic("Bad size %d.\n", size);
397            break;
398        }
399        break;
400      case 2:
401        assert(regs == 2);
402        assert(loadRegs <= 2);
403        switch (size) {
404          case 0:
405            if (all) {
406                microOps[uopIdx++] = new MicroUnpackAllNeon2to4Uop<uint8_t>(
407                        machInst, vd * 2, ufp0, inc * 2);
408            } else {
409                microOps[uopIdx++] = new MicroUnpackNeon2to4Uop<uint8_t>(
410                        machInst, vd * 2, ufp0, inc * 2, lane);
411            }
412            break;
413          case 1:
414            if (all) {
415                microOps[uopIdx++] = new MicroUnpackAllNeon2to4Uop<uint16_t>(
416                        machInst, vd * 2, ufp0, inc * 2);
417            } else {
418                microOps[uopIdx++] = new MicroUnpackNeon2to4Uop<uint16_t>(
419                        machInst, vd * 2, ufp0, inc * 2, lane);
420            }
421            break;
422          case 2:
423            if (all) {
424                microOps[uopIdx++] = new MicroUnpackAllNeon2to4Uop<uint32_t>(
425                        machInst, vd * 2, ufp0, inc * 2);
426            } else {
427                microOps[uopIdx++] = new MicroUnpackNeon2to4Uop<uint32_t>(
428                        machInst, vd * 2, ufp0, inc * 2, lane);
429            }
430            break;
431          default:
432            panic("Bad size %d.\n", size);
433            break;
434        }
435        break;
436      case 1:
437        assert(regs == 1 || (all && regs == 2));
438        assert(loadRegs <= 2);
439        for (unsigned offset = 0; offset < regs; offset++) {
440            switch (size) {
441              case 0:
442                if (all) {
443                    microOps[uopIdx++] =
444                        new MicroUnpackAllNeon2to2Uop<uint8_t>(
445                            machInst, (vd + offset) * 2, ufp0, inc * 2);
446                } else {
447                    microOps[uopIdx++] =
448                        new MicroUnpackNeon2to2Uop<uint8_t>(
449                            machInst, (vd + offset) * 2, ufp0, inc * 2, lane);
450                }
451                break;
452              case 1:
453                if (all) {
454                    microOps[uopIdx++] =
455                        new MicroUnpackAllNeon2to2Uop<uint16_t>(
456                            machInst, (vd + offset) * 2, ufp0, inc * 2);
457                } else {
458                    microOps[uopIdx++] =
459                        new MicroUnpackNeon2to2Uop<uint16_t>(
460                            machInst, (vd + offset) * 2, ufp0, inc * 2, lane);
461                }
462                break;
463              case 2:
464                if (all) {
465                    microOps[uopIdx++] =
466                        new MicroUnpackAllNeon2to2Uop<uint32_t>(
467                            machInst, (vd + offset) * 2, ufp0, inc * 2);
468                } else {
469                    microOps[uopIdx++] =
470                        new MicroUnpackNeon2to2Uop<uint32_t>(
471                            machInst, (vd + offset) * 2, ufp0, inc * 2, lane);
472                }
473                break;
474              default:
475                panic("Bad size %d.\n", size);
476                break;
477            }
478        }
479        break;
480      default:
481        panic("Bad number of elements to unpack %d.\n", elems);
482    }
483    assert(uopIdx == numMicroops);
484
485    for (unsigned i = 0; i < numMicroops - 1; i++) {
486        MicroOp * uopPtr = dynamic_cast<MicroOp *>(microOps[i].get());
487        assert(uopPtr);
488        uopPtr->setDelayedCommit();
489    }
490    microOps[numMicroops - 1]->setLastMicroop();
491}
492
493VstMultOp::VstMultOp(const char *mnem, ExtMachInst machInst, OpClass __opClass,
494                     unsigned elems, RegIndex rn, RegIndex vd, unsigned regs,
495                     unsigned inc, uint32_t size, uint32_t align, RegIndex rm) :
496    PredMacroOp(mnem, machInst, __opClass)
497{
498    assert(regs > 0 && regs <= 4);
499    assert(regs % elems == 0);
500
501    numMicroops = (regs > 2) ? 2 : 1;
502    bool wb = (rm != 15);
503    bool interleave = (elems > 1);
504
505    if (wb) numMicroops++;
506    if (interleave) numMicroops += (regs / elems);
507    microOps = new StaticInstPtr[numMicroops];
508
509    uint32_t noAlign = TLB::MustBeOne;
510
511    RegIndex rMid = interleave ? NumFloatArchRegs : vd * 2;
512
513    unsigned uopIdx = 0;
514    if (interleave) {
515        switch (elems) {
516          case 4:
517            assert(regs == 4);
518            microOps[uopIdx++] = newNeonMixInst<MicroInterNeon8Uop>(
519                    size, machInst, rMid, vd * 2, inc * 2);
520            break;
521          case 3:
522            assert(regs == 3);
523            microOps[uopIdx++] = newNeonMixInst<MicroInterNeon6Uop>(
524                    size, machInst, rMid, vd * 2, inc * 2);
525            break;
526          case 2:
527            assert(regs == 4 || regs == 2);
528            if (regs == 4) {
529                microOps[uopIdx++] = newNeonMixInst<MicroInterNeon4Uop>(
530                        size, machInst, rMid, vd * 2, inc * 2);
531                microOps[uopIdx++] = newNeonMixInst<MicroInterNeon4Uop>(
532                        size, machInst, rMid + 4, vd * 2 + 2, inc * 2);
533            } else {
534                microOps[uopIdx++] = newNeonMixInst<MicroInterNeon4Uop>(
535                        size, machInst, rMid, vd * 2, inc * 2);
536            }
537            break;
538          default:
539            panic("Bad number of elements to interleave %d.\n", elems);
540        }
541    }
542    switch (regs) {
543      case 4:
544        microOps[uopIdx++] = newNeonMemInst<MicroStrNeon16Uop>(
545                size, machInst, rMid, rn, 0, align);
546        microOps[uopIdx++] = newNeonMemInst<MicroStrNeon16Uop>(
547                size, machInst, rMid + 4, rn, 16, noAlign);
548        break;
549      case 3:
550        microOps[uopIdx++] = newNeonMemInst<MicroStrNeon16Uop>(
551                size, machInst, rMid, rn, 0, align);
552        microOps[uopIdx++] = newNeonMemInst<MicroStrNeon8Uop>(
553                size, machInst, rMid + 4, rn, 16, noAlign);
554        break;
555      case 2:
556        microOps[uopIdx++] = newNeonMemInst<MicroStrNeon16Uop>(
557                size, machInst, rMid, rn, 0, align);
558        break;
559      case 1:
560        microOps[uopIdx++] = newNeonMemInst<MicroStrNeon8Uop>(
561                size, machInst, rMid, rn, 0, align);
562        break;
563      default:
564        panic("Unrecognized number of registers %d.\n", regs);
565    }
566    if (wb) {
567        if (rm != 15 && rm != 13) {
568            microOps[uopIdx++] =
569                new MicroAddUop(machInst, rn, rn, rm);
570        } else {
571            microOps[uopIdx++] =
572                new MicroAddiUop(machInst, rn, rn, regs * 8);
573        }
574    }
575    assert(uopIdx == numMicroops);
576
577    for (unsigned i = 0; i < numMicroops - 1; i++) {
578        MicroOp * uopPtr = dynamic_cast<MicroOp *>(microOps[i].get());
579        assert(uopPtr);
580        uopPtr->setDelayedCommit();
581    }
582    microOps[numMicroops - 1]->setLastMicroop();
583}
584
585VstSingleOp::VstSingleOp(const char *mnem, ExtMachInst machInst,
586                         OpClass __opClass, bool all, unsigned elems,
587                         RegIndex rn, RegIndex vd, unsigned regs,
588                         unsigned inc, uint32_t size, uint32_t align,
589                         RegIndex rm, unsigned lane) :
590    PredMacroOp(mnem, machInst, __opClass)
591{
592    assert(!all);
593    assert(regs > 0 && regs <= 4);
594    assert(regs % elems == 0);
595
596    unsigned eBytes = (1 << size);
597    unsigned storeSize = eBytes * elems;
598    unsigned storeRegs M5_VAR_USED = (storeSize + sizeof(FloatRegBits) - 1) /
599                         sizeof(FloatRegBits);
600
601    assert(storeRegs > 0 && storeRegs <= 4);
602
603    numMicroops = 1;
604    bool wb = (rm != 15);
605
606    if (wb) numMicroops++;
607    numMicroops += (regs / elems);
608    microOps = new StaticInstPtr[numMicroops];
609
610    RegIndex ufp0 = NumFloatArchRegs;
611
612    unsigned uopIdx = 0;
613    switch (elems) {
614      case 4:
615        assert(regs == 4);
616        switch (size) {
617          case 0:
618            microOps[uopIdx++] = new MicroPackNeon8to2Uop<uint8_t>(
619                    machInst, ufp0, vd * 2, inc * 2, lane);
620            break;
621          case 1:
622            microOps[uopIdx++] = new MicroPackNeon8to2Uop<uint16_t>(
623                    machInst, ufp0, vd * 2, inc * 2, lane);
624            break;
625          case 2:
626            microOps[uopIdx++] = new MicroPackNeon8to4Uop<uint32_t>(
627                    machInst, ufp0, vd * 2, inc * 2, lane);
628            break;
629          default:
630            panic("Bad size %d.\n", size);
631            break;
632        }
633        break;
634      case 3:
635        assert(regs == 3);
636        switch (size) {
637          case 0:
638            microOps[uopIdx++] = new MicroPackNeon6to2Uop<uint8_t>(
639                    machInst, ufp0, vd * 2, inc * 2, lane);
640            break;
641          case 1:
642            microOps[uopIdx++] = new MicroPackNeon6to2Uop<uint16_t>(
643                    machInst, ufp0, vd * 2, inc * 2, lane);
644            break;
645          case 2:
646            microOps[uopIdx++] = new MicroPackNeon6to4Uop<uint32_t>(
647                    machInst, ufp0, vd * 2, inc * 2, lane);
648            break;
649          default:
650            panic("Bad size %d.\n", size);
651            break;
652        }
653        break;
654      case 2:
655        assert(regs == 2);
656        assert(storeRegs <= 2);
657        switch (size) {
658          case 0:
659            microOps[uopIdx++] = new MicroPackNeon4to2Uop<uint8_t>(
660                    machInst, ufp0, vd * 2, inc * 2, lane);
661            break;
662          case 1:
663            microOps[uopIdx++] = new MicroPackNeon4to2Uop<uint16_t>(
664                    machInst, ufp0, vd * 2, inc * 2, lane);
665            break;
666          case 2:
667            microOps[uopIdx++] = new MicroPackNeon4to2Uop<uint32_t>(
668                    machInst, ufp0, vd * 2, inc * 2, lane);
669            break;
670          default:
671            panic("Bad size %d.\n", size);
672            break;
673        }
674        break;
675      case 1:
676        assert(regs == 1 || (all && regs == 2));
677        assert(storeRegs <= 2);
678        for (unsigned offset = 0; offset < regs; offset++) {
679            switch (size) {
680              case 0:
681                microOps[uopIdx++] = new MicroPackNeon2to2Uop<uint8_t>(
682                        machInst, ufp0, (vd + offset) * 2, inc * 2, lane);
683                break;
684              case 1:
685                microOps[uopIdx++] = new MicroPackNeon2to2Uop<uint16_t>(
686                        machInst, ufp0, (vd + offset) * 2, inc * 2, lane);
687                break;
688              case 2:
689                microOps[uopIdx++] = new MicroPackNeon2to2Uop<uint32_t>(
690                        machInst, ufp0, (vd + offset) * 2, inc * 2, lane);
691                break;
692              default:
693                panic("Bad size %d.\n", size);
694                break;
695            }
696        }
697        break;
698      default:
699        panic("Bad number of elements to pack %d.\n", elems);
700    }
701    switch (storeSize) {
702      case 1:
703        microOps[uopIdx++] = new MicroStrNeon1Uop<uint8_t>(
704                machInst, ufp0, rn, 0, align);
705        break;
706      case 2:
707        if (eBytes == 2) {
708            microOps[uopIdx++] = new MicroStrNeon2Uop<uint16_t>(
709                    machInst, ufp0, rn, 0, align);
710        } else {
711            microOps[uopIdx++] = new MicroStrNeon2Uop<uint8_t>(
712                    machInst, ufp0, rn, 0, align);
713        }
714        break;
715      case 3:
716        microOps[uopIdx++] = new MicroStrNeon3Uop<uint8_t>(
717                machInst, ufp0, rn, 0, align);
718        break;
719      case 4:
720        switch (eBytes) {
721          case 1:
722            microOps[uopIdx++] = new MicroStrNeon4Uop<uint8_t>(
723                    machInst, ufp0, rn, 0, align);
724            break;
725          case 2:
726            microOps[uopIdx++] = new MicroStrNeon4Uop<uint16_t>(
727                    machInst, ufp0, rn, 0, align);
728            break;
729          case 4:
730            microOps[uopIdx++] = new MicroStrNeon4Uop<uint32_t>(
731                    machInst, ufp0, rn, 0, align);
732            break;
733        }
734        break;
735      case 6:
736        microOps[uopIdx++] = new MicroStrNeon6Uop<uint16_t>(
737                machInst, ufp0, rn, 0, align);
738        break;
739      case 8:
740        switch (eBytes) {
741          case 2:
742            microOps[uopIdx++] = new MicroStrNeon8Uop<uint16_t>(
743                    machInst, ufp0, rn, 0, align);
744            break;
745          case 4:
746            microOps[uopIdx++] = new MicroStrNeon8Uop<uint32_t>(
747                    machInst, ufp0, rn, 0, align);
748            break;
749        }
750        break;
751      case 12:
752        microOps[uopIdx++] = new MicroStrNeon12Uop<uint32_t>(
753                machInst, ufp0, rn, 0, align);
754        break;
755      case 16:
756        microOps[uopIdx++] = new MicroStrNeon16Uop<uint32_t>(
757                machInst, ufp0, rn, 0, align);
758        break;
759      default:
760        panic("Unrecognized store size %d.\n", regs);
761    }
762    if (wb) {
763        if (rm != 15 && rm != 13) {
764            microOps[uopIdx++] =
765                new MicroAddUop(machInst, rn, rn, rm);
766        } else {
767            microOps[uopIdx++] =
768                new MicroAddiUop(machInst, rn, rn, storeSize);
769        }
770    }
771    assert(uopIdx == numMicroops);
772
773    for (unsigned i = 0; i < numMicroops - 1; i++) {
774        MicroOp * uopPtr = dynamic_cast<MicroOp *>(microOps[i].get());
775        assert(uopPtr);
776        uopPtr->setDelayedCommit();
777    }
778    microOps[numMicroops - 1]->setLastMicroop();
779}
780
781MacroVFPMemOp::MacroVFPMemOp(const char *mnem, ExtMachInst machInst,
782                             OpClass __opClass, IntRegIndex rn,
783                             RegIndex vd, bool single, bool up,
784                             bool writeback, bool load, uint32_t offset) :
785    PredMacroOp(mnem, machInst, __opClass)
786{
787    int i = 0;
788
789    // The lowest order bit selects fldmx (set) or fldmd (clear). These seem
790    // to be functionally identical except that fldmx is deprecated. For now
791    // we'll assume they're otherwise interchangable.
792    int count = (single ? offset : (offset / 2));
793    if (count == 0 || count > NumFloatArchRegs)
794        warn_once("Bad offset field for VFP load/store multiple.\n");
795    if (count == 0) {
796        // Force there to be at least one microop so the macroop makes sense.
797        writeback = true;
798    }
799    if (count > NumFloatArchRegs)
800        count = NumFloatArchRegs;
801
802    numMicroops = count * (single ? 1 : 2) + (writeback ? 1 : 0);
803    microOps = new StaticInstPtr[numMicroops];
804
805    int64_t addr = 0;
806
807    if (!up)
808        addr = 4 * offset;
809
810    bool tempUp = up;
811    for (int j = 0; j < count; j++) {
812        if (load) {
813            if (single) {
814                microOps[i++] = new MicroLdrFpUop(machInst, vd++, rn,
815                                                  tempUp, addr);
816            } else {
817                microOps[i++] = new MicroLdrDBFpUop(machInst, vd++, rn,
818                                                    tempUp, addr);
819                microOps[i++] = new MicroLdrDTFpUop(machInst, vd++, rn, tempUp,
820                                                    addr + (up ? 4 : -4));
821            }
822        } else {
823            if (single) {
824                microOps[i++] = new MicroStrFpUop(machInst, vd++, rn,
825                                                  tempUp, addr);
826            } else {
827                microOps[i++] = new MicroStrDBFpUop(machInst, vd++, rn,
828                                                    tempUp, addr);
829                microOps[i++] = new MicroStrDTFpUop(machInst, vd++, rn, tempUp,
830                                                    addr + (up ? 4 : -4));
831            }
832        }
833        if (!tempUp) {
834            addr -= (single ? 4 : 8);
835            // The microops don't handle negative displacement, so turn if we
836            // hit zero, flip polarity and start adding.
837            if (addr <= 0) {
838                tempUp = true;
839                addr = -addr;
840            }
841        } else {
842            addr += (single ? 4 : 8);
843        }
844    }
845
846    if (writeback) {
847        if (up) {
848            microOps[i++] =
849                new MicroAddiUop(machInst, rn, rn, 4 * offset);
850        } else {
851            microOps[i++] =
852                new MicroSubiUop(machInst, rn, rn, 4 * offset);
853        }
854    }
855
856    assert(numMicroops == i);
857    microOps[numMicroops - 1]->setLastMicroop();
858
859    for (StaticInstPtr *curUop = microOps;
860            !(*curUop)->isLastMicroop(); curUop++) {
861        MicroOp * uopPtr = dynamic_cast<MicroOp *>(curUop->get());
862        assert(uopPtr);
863        uopPtr->setDelayedCommit();
864    }
865}
866
867std::string
868MicroIntImmOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
869{
870    std::stringstream ss;
871    printMnemonic(ss);
872    printReg(ss, ura);
873    ss << ", ";
874    printReg(ss, urb);
875    ss << ", ";
876    ccprintf(ss, "#%d", imm);
877    return ss.str();
878}
879
880std::string
881MicroIntOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
882{
883    std::stringstream ss;
884    printMnemonic(ss);
885    printReg(ss, ura);
886    ss << ", ";
887    printReg(ss, urb);
888    ss << ", ";
889    printReg(ss, urc);
890    return ss.str();
891}
892
893std::string
894MicroMemOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
895{
896    std::stringstream ss;
897    printMnemonic(ss);
898    printReg(ss, ura);
899    ss << ", [";
900    printReg(ss, urb);
901    ss << ", ";
902    ccprintf(ss, "#%d", imm);
903    ss << "]";
904    return ss.str();
905}
906
907}
908