macromem.cc revision 9368:3cd40209af8d
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 <sstream>
44
45#include "arch/arm/insts/macromem.hh"
46#include "arch/arm/generated/decoder.hh"
47
48using namespace std;
49using namespace ArmISAInst;
50
51namespace ArmISA
52{
53
54MacroMemOp::MacroMemOp(const char *mnem, ExtMachInst machInst,
55                       OpClass __opClass, IntRegIndex rn,
56                       bool index, bool up, bool user, bool writeback,
57                       bool load, uint32_t reglist) :
58    PredMacroOp(mnem, machInst, __opClass)
59{
60    uint32_t regs = reglist;
61    uint32_t ones = number_of_ones(reglist);
62    // Remember that writeback adds a uop or two and the temp register adds one
63    numMicroops = ones + (writeback ? (load ? 2 : 1) : 0) + 1;
64
65    // It's technically legal to do a lot of nothing
66    if (!ones)
67        numMicroops = 1;
68
69    microOps = new StaticInstPtr[numMicroops];
70    uint32_t addr = 0;
71
72    if (!up)
73        addr = (ones << 2) - 4;
74
75    if (!index)
76        addr += 4;
77
78    StaticInstPtr *uop = microOps;
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    unsigned reg = 0;
85    unsigned regIdx = 0;
86    bool force_user = user & !bits(reglist, 15);
87    bool exception_ret = user & bits(reglist, 15);
88
89    for (int i = 0; i < ones; i++) {
90        // Find the next register.
91        while (!bits(regs, reg))
92            reg++;
93        replaceBits(regs, reg, 0);
94
95        regIdx = reg;
96        if (force_user) {
97            regIdx = intRegInMode(MODE_USER, regIdx);
98        }
99
100        if (load) {
101            if (writeback && i == ones - 1) {
102                // If it's a writeback and this is the last register
103                // do the load into a temporary register which we'll move
104                // into the final one later
105                *++uop = new MicroLdrUop(machInst, INTREG_UREG1, INTREG_UREG0,
106                        up, addr);
107            } else {
108                // Otherwise just do it normally
109                if (reg == INTREG_PC && exception_ret) {
110                    // This must be the exception return form of ldm.
111                    *++uop = new MicroLdrRetUop(machInst, regIdx,
112                                               INTREG_UREG0, up, addr);
113                } else {
114                    *++uop = new MicroLdrUop(machInst, regIdx,
115                                            INTREG_UREG0, up, addr);
116                    if (reg == INTREG_PC) {
117                        (*uop)->setFlag(StaticInst::IsControl);
118                        if (!(condCode == COND_AL || condCode == COND_UC))
119                            (*uop)->setFlag(StaticInst::IsCondControl);
120                        else
121                            (*uop)->setFlag(StaticInst::IsUncondControl);
122                        (*uop)->setFlag(StaticInst::IsIndirectControl);
123                    }
124                }
125            }
126        } else {
127            *++uop = new MicroStrUop(machInst, regIdx, INTREG_UREG0, up, addr);
128        }
129
130        if (up)
131            addr += 4;
132        else
133            addr -= 4;
134    }
135
136    if (writeback && ones) {
137        // put the register update after we're done all loading
138        if (up)
139            *++uop = new MicroAddiUop(machInst, rn, rn, ones * 4);
140        else
141            *++uop = new MicroSubiUop(machInst, rn, rn, ones * 4);
142
143        // If this was a load move the last temporary value into place
144        // this way we can't take an exception after we update the base
145        // register.
146        if (load && reg == INTREG_PC && exception_ret) {
147            *++uop = new MicroUopRegMovRet(machInst, 0, INTREG_UREG1);
148            if (!(condCode == COND_AL || condCode == COND_UC))
149                (*uop)->setFlag(StaticInst::IsCondControl);
150            else
151                (*uop)->setFlag(StaticInst::IsUncondControl);
152        } else if (load) {
153            *++uop = new MicroUopRegMov(machInst, regIdx, INTREG_UREG1);
154            if (reg == INTREG_PC) {
155                (*uop)->setFlag(StaticInst::IsControl);
156                (*uop)->setFlag(StaticInst::IsCondControl);
157                (*uop)->setFlag(StaticInst::IsIndirectControl);
158                // This is created as a RAS POP
159                if (rn == INTREG_SP)
160                    (*uop)->setFlag(StaticInst::IsReturn);
161
162            }
163        }
164    }
165
166    (*uop)->setLastMicroop();
167
168    for (StaticInstPtr *curUop = microOps;
169            !(*curUop)->isLastMicroop(); curUop++) {
170        MicroOp * uopPtr = dynamic_cast<MicroOp *>(curUop->get());
171        assert(uopPtr);
172        uopPtr->setDelayedCommit();
173    }
174}
175
176VldMultOp::VldMultOp(const char *mnem, ExtMachInst machInst, OpClass __opClass,
177                     unsigned elems, RegIndex rn, RegIndex vd, unsigned regs,
178                     unsigned inc, uint32_t size, uint32_t align, RegIndex rm) :
179    PredMacroOp(mnem, machInst, __opClass)
180{
181    assert(regs > 0 && regs <= 4);
182    assert(regs % elems == 0);
183
184    numMicroops = (regs > 2) ? 2 : 1;
185    bool wb = (rm != 15);
186    bool deinterleave = (elems > 1);
187
188    if (wb) numMicroops++;
189    if (deinterleave) numMicroops += (regs / elems);
190    microOps = new StaticInstPtr[numMicroops];
191
192    RegIndex rMid = deinterleave ? NumFloatArchRegs : vd * 2;
193
194    uint32_t noAlign = TLB::MustBeOne;
195
196    unsigned uopIdx = 0;
197    switch (regs) {
198      case 4:
199        microOps[uopIdx++] = newNeonMemInst<MicroLdrNeon16Uop>(
200                size, machInst, rMid, rn, 0, align);
201        microOps[uopIdx++] = newNeonMemInst<MicroLdrNeon16Uop>(
202                size, machInst, rMid + 4, rn, 16, noAlign);
203        break;
204      case 3:
205        microOps[uopIdx++] = newNeonMemInst<MicroLdrNeon16Uop>(
206                size, machInst, rMid, rn, 0, align);
207        microOps[uopIdx++] = newNeonMemInst<MicroLdrNeon8Uop>(
208                size, machInst, rMid + 4, rn, 16, noAlign);
209        break;
210      case 2:
211        microOps[uopIdx++] = newNeonMemInst<MicroLdrNeon16Uop>(
212                size, machInst, rMid, rn, 0, align);
213        break;
214      case 1:
215        microOps[uopIdx++] = newNeonMemInst<MicroLdrNeon8Uop>(
216                size, machInst, rMid, rn, 0, align);
217        break;
218      default:
219        // Unknown number of registers
220        microOps[uopIdx++] = new Unknown(machInst);
221    }
222    if (wb) {
223        if (rm != 15 && rm != 13) {
224            microOps[uopIdx++] =
225                new MicroAddUop(machInst, rn, rn, rm, 0, ArmISA::LSL);
226        } else {
227            microOps[uopIdx++] =
228                new MicroAddiUop(machInst, rn, rn, regs * 8);
229        }
230    }
231    if (deinterleave) {
232        switch (elems) {
233          case 4:
234            assert(regs == 4);
235            microOps[uopIdx++] = newNeonMixInst<MicroDeintNeon8Uop>(
236                    size, machInst, vd * 2, rMid, inc * 2);
237            break;
238          case 3:
239            assert(regs == 3);
240            microOps[uopIdx++] = newNeonMixInst<MicroDeintNeon6Uop>(
241                    size, machInst, vd * 2, rMid, inc * 2);
242            break;
243          case 2:
244            assert(regs == 4 || regs == 2);
245            if (regs == 4) {
246                microOps[uopIdx++] = newNeonMixInst<MicroDeintNeon4Uop>(
247                        size, machInst, vd * 2, rMid, inc * 2);
248                microOps[uopIdx++] = newNeonMixInst<MicroDeintNeon4Uop>(
249                        size, machInst, vd * 2 + 2, rMid + 4, inc * 2);
250            } else {
251                microOps[uopIdx++] = newNeonMixInst<MicroDeintNeon4Uop>(
252                        size, machInst, vd * 2, rMid, inc * 2);
253            }
254            break;
255          default:
256            // Bad number of elements to deinterleave
257            microOps[uopIdx++] = new Unknown(machInst);
258        }
259    }
260    assert(uopIdx == numMicroops);
261
262    for (unsigned i = 0; i < numMicroops - 1; i++) {
263        MicroOp * uopPtr = dynamic_cast<MicroOp *>(microOps[i].get());
264        assert(uopPtr);
265        uopPtr->setDelayedCommit();
266    }
267    microOps[numMicroops - 1]->setLastMicroop();
268}
269
270VldSingleOp::VldSingleOp(const char *mnem, ExtMachInst machInst,
271                         OpClass __opClass, bool all, unsigned elems,
272                         RegIndex rn, RegIndex vd, unsigned regs,
273                         unsigned inc, uint32_t size, uint32_t align,
274                         RegIndex rm, unsigned lane) :
275    PredMacroOp(mnem, machInst, __opClass)
276{
277    assert(regs > 0 && regs <= 4);
278    assert(regs % elems == 0);
279
280    unsigned eBytes = (1 << size);
281    unsigned loadSize = eBytes * elems;
282    unsigned loadRegs M5_VAR_USED = (loadSize + sizeof(FloatRegBits) - 1) /
283                        sizeof(FloatRegBits);
284
285    assert(loadRegs > 0 && loadRegs <= 4);
286
287    numMicroops = 1;
288    bool wb = (rm != 15);
289
290    if (wb) numMicroops++;
291    numMicroops += (regs / elems);
292    microOps = new StaticInstPtr[numMicroops];
293
294    RegIndex ufp0 = NumFloatArchRegs;
295
296    unsigned uopIdx = 0;
297    switch (loadSize) {
298      case 1:
299        microOps[uopIdx++] = new MicroLdrNeon1Uop<uint8_t>(
300                machInst, ufp0, rn, 0, align);
301        break;
302      case 2:
303        if (eBytes == 2) {
304            microOps[uopIdx++] = new MicroLdrNeon2Uop<uint16_t>(
305                    machInst, ufp0, rn, 0, align);
306        } else {
307            microOps[uopIdx++] = new MicroLdrNeon2Uop<uint8_t>(
308                    machInst, ufp0, rn, 0, align);
309        }
310        break;
311      case 3:
312        microOps[uopIdx++] = new MicroLdrNeon3Uop<uint8_t>(
313                machInst, ufp0, rn, 0, align);
314        break;
315      case 4:
316        switch (eBytes) {
317          case 1:
318            microOps[uopIdx++] = new MicroLdrNeon4Uop<uint8_t>(
319                    machInst, ufp0, rn, 0, align);
320            break;
321          case 2:
322            microOps[uopIdx++] = new MicroLdrNeon4Uop<uint16_t>(
323                    machInst, ufp0, rn, 0, align);
324            break;
325          case 4:
326            microOps[uopIdx++] = new MicroLdrNeon4Uop<uint32_t>(
327                    machInst, ufp0, rn, 0, align);
328            break;
329        }
330        break;
331      case 6:
332        microOps[uopIdx++] = new MicroLdrNeon6Uop<uint16_t>(
333                machInst, ufp0, rn, 0, align);
334        break;
335      case 8:
336        switch (eBytes) {
337          case 2:
338            microOps[uopIdx++] = new MicroLdrNeon8Uop<uint16_t>(
339                    machInst, ufp0, rn, 0, align);
340            break;
341          case 4:
342            microOps[uopIdx++] = new MicroLdrNeon8Uop<uint32_t>(
343                    machInst, ufp0, rn, 0, align);
344            break;
345        }
346        break;
347      case 12:
348        microOps[uopIdx++] = new MicroLdrNeon12Uop<uint32_t>(
349                machInst, ufp0, rn, 0, align);
350        break;
351      case 16:
352        microOps[uopIdx++] = new MicroLdrNeon16Uop<uint32_t>(
353                machInst, ufp0, rn, 0, align);
354        break;
355      default:
356        // Unrecognized load size
357        microOps[uopIdx++] = new Unknown(machInst);
358    }
359    if (wb) {
360        if (rm != 15 && rm != 13) {
361            microOps[uopIdx++] =
362                new MicroAddUop(machInst, rn, rn, rm, 0, ArmISA::LSL);
363        } else {
364            microOps[uopIdx++] =
365                new MicroAddiUop(machInst, rn, rn, loadSize);
366        }
367    }
368    switch (elems) {
369      case 4:
370        assert(regs == 4);
371        switch (size) {
372          case 0:
373            if (all) {
374                microOps[uopIdx++] = new MicroUnpackAllNeon2to8Uop<uint8_t>(
375                        machInst, vd * 2, ufp0, inc * 2);
376            } else {
377                microOps[uopIdx++] = new MicroUnpackNeon2to8Uop<uint8_t>(
378                        machInst, vd * 2, ufp0, inc * 2, lane);
379            }
380            break;
381          case 1:
382            if (all) {
383                microOps[uopIdx++] = new MicroUnpackAllNeon2to8Uop<uint16_t>(
384                        machInst, vd * 2, ufp0, inc * 2);
385            } else {
386                microOps[uopIdx++] = new MicroUnpackNeon2to8Uop<uint16_t>(
387                        machInst, vd * 2, ufp0, inc * 2, lane);
388            }
389            break;
390          case 2:
391            if (all) {
392                microOps[uopIdx++] = new MicroUnpackAllNeon4to8Uop<uint32_t>(
393                        machInst, vd * 2, ufp0, inc * 2);
394            } else {
395                microOps[uopIdx++] = new MicroUnpackNeon4to8Uop<uint32_t>(
396                        machInst, vd * 2, ufp0, inc * 2, lane);
397            }
398            break;
399          default:
400            // Bad size
401            microOps[uopIdx++] = new Unknown(machInst);
402            break;
403        }
404        break;
405      case 3:
406        assert(regs == 3);
407        switch (size) {
408          case 0:
409            if (all) {
410                microOps[uopIdx++] = new MicroUnpackAllNeon2to6Uop<uint8_t>(
411                        machInst, vd * 2, ufp0, inc * 2);
412            } else {
413                microOps[uopIdx++] = new MicroUnpackNeon2to6Uop<uint8_t>(
414                        machInst, vd * 2, ufp0, inc * 2, lane);
415            }
416            break;
417          case 1:
418            if (all) {
419                microOps[uopIdx++] = new MicroUnpackAllNeon2to6Uop<uint16_t>(
420                        machInst, vd * 2, ufp0, inc * 2);
421            } else {
422                microOps[uopIdx++] = new MicroUnpackNeon2to6Uop<uint16_t>(
423                        machInst, vd * 2, ufp0, inc * 2, lane);
424            }
425            break;
426          case 2:
427            if (all) {
428                microOps[uopIdx++] = new MicroUnpackAllNeon4to6Uop<uint32_t>(
429                        machInst, vd * 2, ufp0, inc * 2);
430            } else {
431                microOps[uopIdx++] = new MicroUnpackNeon4to6Uop<uint32_t>(
432                        machInst, vd * 2, ufp0, inc * 2, lane);
433            }
434            break;
435          default:
436            // Bad size
437            microOps[uopIdx++] = new Unknown(machInst);
438            break;
439        }
440        break;
441      case 2:
442        assert(regs == 2);
443        assert(loadRegs <= 2);
444        switch (size) {
445          case 0:
446            if (all) {
447                microOps[uopIdx++] = new MicroUnpackAllNeon2to4Uop<uint8_t>(
448                        machInst, vd * 2, ufp0, inc * 2);
449            } else {
450                microOps[uopIdx++] = new MicroUnpackNeon2to4Uop<uint8_t>(
451                        machInst, vd * 2, ufp0, inc * 2, lane);
452            }
453            break;
454          case 1:
455            if (all) {
456                microOps[uopIdx++] = new MicroUnpackAllNeon2to4Uop<uint16_t>(
457                        machInst, vd * 2, ufp0, inc * 2);
458            } else {
459                microOps[uopIdx++] = new MicroUnpackNeon2to4Uop<uint16_t>(
460                        machInst, vd * 2, ufp0, inc * 2, lane);
461            }
462            break;
463          case 2:
464            if (all) {
465                microOps[uopIdx++] = new MicroUnpackAllNeon2to4Uop<uint32_t>(
466                        machInst, vd * 2, ufp0, inc * 2);
467            } else {
468                microOps[uopIdx++] = new MicroUnpackNeon2to4Uop<uint32_t>(
469                        machInst, vd * 2, ufp0, inc * 2, lane);
470            }
471            break;
472          default:
473            // Bad size
474            microOps[uopIdx++] = new Unknown(machInst);
475            break;
476        }
477        break;
478      case 1:
479        assert(regs == 1 || (all && regs == 2));
480        assert(loadRegs <= 2);
481        for (unsigned offset = 0; offset < regs; offset++) {
482            switch (size) {
483              case 0:
484                if (all) {
485                    microOps[uopIdx++] =
486                        new MicroUnpackAllNeon2to2Uop<uint8_t>(
487                            machInst, (vd + offset) * 2, ufp0, inc * 2);
488                } else {
489                    microOps[uopIdx++] =
490                        new MicroUnpackNeon2to2Uop<uint8_t>(
491                            machInst, (vd + offset) * 2, ufp0, inc * 2, lane);
492                }
493                break;
494              case 1:
495                if (all) {
496                    microOps[uopIdx++] =
497                        new MicroUnpackAllNeon2to2Uop<uint16_t>(
498                            machInst, (vd + offset) * 2, ufp0, inc * 2);
499                } else {
500                    microOps[uopIdx++] =
501                        new MicroUnpackNeon2to2Uop<uint16_t>(
502                            machInst, (vd + offset) * 2, ufp0, inc * 2, lane);
503                }
504                break;
505              case 2:
506                if (all) {
507                    microOps[uopIdx++] =
508                        new MicroUnpackAllNeon2to2Uop<uint32_t>(
509                            machInst, (vd + offset) * 2, ufp0, inc * 2);
510                } else {
511                    microOps[uopIdx++] =
512                        new MicroUnpackNeon2to2Uop<uint32_t>(
513                            machInst, (vd + offset) * 2, ufp0, inc * 2, lane);
514                }
515                break;
516              default:
517                // Bad size
518                microOps[uopIdx++] = new Unknown(machInst);
519                break;
520            }
521        }
522        break;
523      default:
524        // Bad number of elements to unpack
525        microOps[uopIdx++] = new Unknown(machInst);
526    }
527    assert(uopIdx == numMicroops);
528
529    for (unsigned i = 0; i < numMicroops - 1; i++) {
530        MicroOp * uopPtr = dynamic_cast<MicroOp *>(microOps[i].get());
531        assert(uopPtr);
532        uopPtr->setDelayedCommit();
533    }
534    microOps[numMicroops - 1]->setLastMicroop();
535}
536
537VstMultOp::VstMultOp(const char *mnem, ExtMachInst machInst, OpClass __opClass,
538                     unsigned elems, RegIndex rn, RegIndex vd, unsigned regs,
539                     unsigned inc, uint32_t size, uint32_t align, RegIndex rm) :
540    PredMacroOp(mnem, machInst, __opClass)
541{
542    assert(regs > 0 && regs <= 4);
543    assert(regs % elems == 0);
544
545    numMicroops = (regs > 2) ? 2 : 1;
546    bool wb = (rm != 15);
547    bool interleave = (elems > 1);
548
549    if (wb) numMicroops++;
550    if (interleave) numMicroops += (regs / elems);
551    microOps = new StaticInstPtr[numMicroops];
552
553    uint32_t noAlign = TLB::MustBeOne;
554
555    RegIndex rMid = interleave ? NumFloatArchRegs : vd * 2;
556
557    unsigned uopIdx = 0;
558    if (interleave) {
559        switch (elems) {
560          case 4:
561            assert(regs == 4);
562            microOps[uopIdx++] = newNeonMixInst<MicroInterNeon8Uop>(
563                    size, machInst, rMid, vd * 2, inc * 2);
564            break;
565          case 3:
566            assert(regs == 3);
567            microOps[uopIdx++] = newNeonMixInst<MicroInterNeon6Uop>(
568                    size, machInst, rMid, vd * 2, inc * 2);
569            break;
570          case 2:
571            assert(regs == 4 || regs == 2);
572            if (regs == 4) {
573                microOps[uopIdx++] = newNeonMixInst<MicroInterNeon4Uop>(
574                        size, machInst, rMid, vd * 2, inc * 2);
575                microOps[uopIdx++] = newNeonMixInst<MicroInterNeon4Uop>(
576                        size, machInst, rMid + 4, vd * 2 + 2, inc * 2);
577            } else {
578                microOps[uopIdx++] = newNeonMixInst<MicroInterNeon4Uop>(
579                        size, machInst, rMid, vd * 2, inc * 2);
580            }
581            break;
582          default:
583            // Bad number of elements to interleave
584            microOps[uopIdx++] = new Unknown(machInst);
585        }
586    }
587    switch (regs) {
588      case 4:
589        microOps[uopIdx++] = newNeonMemInst<MicroStrNeon16Uop>(
590                size, machInst, rMid, rn, 0, align);
591        microOps[uopIdx++] = newNeonMemInst<MicroStrNeon16Uop>(
592                size, machInst, rMid + 4, rn, 16, noAlign);
593        break;
594      case 3:
595        microOps[uopIdx++] = newNeonMemInst<MicroStrNeon16Uop>(
596                size, machInst, rMid, rn, 0, align);
597        microOps[uopIdx++] = newNeonMemInst<MicroStrNeon8Uop>(
598                size, machInst, rMid + 4, rn, 16, noAlign);
599        break;
600      case 2:
601        microOps[uopIdx++] = newNeonMemInst<MicroStrNeon16Uop>(
602                size, machInst, rMid, rn, 0, align);
603        break;
604      case 1:
605        microOps[uopIdx++] = newNeonMemInst<MicroStrNeon8Uop>(
606                size, machInst, rMid, rn, 0, align);
607        break;
608      default:
609        // Unknown number of registers
610        microOps[uopIdx++] = new Unknown(machInst);
611    }
612    if (wb) {
613        if (rm != 15 && rm != 13) {
614            microOps[uopIdx++] =
615                new MicroAddUop(machInst, rn, rn, rm, 0, ArmISA::LSL);
616        } else {
617            microOps[uopIdx++] =
618                new MicroAddiUop(machInst, rn, rn, regs * 8);
619        }
620    }
621    assert(uopIdx == numMicroops);
622
623    for (unsigned i = 0; i < numMicroops - 1; i++) {
624        MicroOp * uopPtr = dynamic_cast<MicroOp *>(microOps[i].get());
625        assert(uopPtr);
626        uopPtr->setDelayedCommit();
627    }
628    microOps[numMicroops - 1]->setLastMicroop();
629}
630
631VstSingleOp::VstSingleOp(const char *mnem, ExtMachInst machInst,
632                         OpClass __opClass, bool all, unsigned elems,
633                         RegIndex rn, RegIndex vd, unsigned regs,
634                         unsigned inc, uint32_t size, uint32_t align,
635                         RegIndex rm, unsigned lane) :
636    PredMacroOp(mnem, machInst, __opClass)
637{
638    assert(!all);
639    assert(regs > 0 && regs <= 4);
640    assert(regs % elems == 0);
641
642    unsigned eBytes = (1 << size);
643    unsigned storeSize = eBytes * elems;
644    unsigned storeRegs M5_VAR_USED = (storeSize + sizeof(FloatRegBits) - 1) /
645                         sizeof(FloatRegBits);
646
647    assert(storeRegs > 0 && storeRegs <= 4);
648
649    numMicroops = 1;
650    bool wb = (rm != 15);
651
652    if (wb) numMicroops++;
653    numMicroops += (regs / elems);
654    microOps = new StaticInstPtr[numMicroops];
655
656    RegIndex ufp0 = NumFloatArchRegs;
657
658    unsigned uopIdx = 0;
659    switch (elems) {
660      case 4:
661        assert(regs == 4);
662        switch (size) {
663          case 0:
664            microOps[uopIdx++] = new MicroPackNeon8to2Uop<uint8_t>(
665                    machInst, ufp0, vd * 2, inc * 2, lane);
666            break;
667          case 1:
668            microOps[uopIdx++] = new MicroPackNeon8to2Uop<uint16_t>(
669                    machInst, ufp0, vd * 2, inc * 2, lane);
670            break;
671          case 2:
672            microOps[uopIdx++] = new MicroPackNeon8to4Uop<uint32_t>(
673                    machInst, ufp0, vd * 2, inc * 2, lane);
674            break;
675          default:
676            // Bad size
677            microOps[uopIdx++] = new Unknown(machInst);
678            break;
679        }
680        break;
681      case 3:
682        assert(regs == 3);
683        switch (size) {
684          case 0:
685            microOps[uopIdx++] = new MicroPackNeon6to2Uop<uint8_t>(
686                    machInst, ufp0, vd * 2, inc * 2, lane);
687            break;
688          case 1:
689            microOps[uopIdx++] = new MicroPackNeon6to2Uop<uint16_t>(
690                    machInst, ufp0, vd * 2, inc * 2, lane);
691            break;
692          case 2:
693            microOps[uopIdx++] = new MicroPackNeon6to4Uop<uint32_t>(
694                    machInst, ufp0, vd * 2, inc * 2, lane);
695            break;
696          default:
697            // Bad size
698            microOps[uopIdx++] = new Unknown(machInst);
699            break;
700        }
701        break;
702      case 2:
703        assert(regs == 2);
704        assert(storeRegs <= 2);
705        switch (size) {
706          case 0:
707            microOps[uopIdx++] = new MicroPackNeon4to2Uop<uint8_t>(
708                    machInst, ufp0, vd * 2, inc * 2, lane);
709            break;
710          case 1:
711            microOps[uopIdx++] = new MicroPackNeon4to2Uop<uint16_t>(
712                    machInst, ufp0, vd * 2, inc * 2, lane);
713            break;
714          case 2:
715            microOps[uopIdx++] = new MicroPackNeon4to2Uop<uint32_t>(
716                    machInst, ufp0, vd * 2, inc * 2, lane);
717            break;
718          default:
719            // Bad size
720            microOps[uopIdx++] = new Unknown(machInst);
721            break;
722        }
723        break;
724      case 1:
725        assert(regs == 1 || (all && regs == 2));
726        assert(storeRegs <= 2);
727        for (unsigned offset = 0; offset < regs; offset++) {
728            switch (size) {
729              case 0:
730                microOps[uopIdx++] = new MicroPackNeon2to2Uop<uint8_t>(
731                        machInst, ufp0, (vd + offset) * 2, inc * 2, lane);
732                break;
733              case 1:
734                microOps[uopIdx++] = new MicroPackNeon2to2Uop<uint16_t>(
735                        machInst, ufp0, (vd + offset) * 2, inc * 2, lane);
736                break;
737              case 2:
738                microOps[uopIdx++] = new MicroPackNeon2to2Uop<uint32_t>(
739                        machInst, ufp0, (vd + offset) * 2, inc * 2, lane);
740                break;
741              default:
742                // Bad size
743                microOps[uopIdx++] = new Unknown(machInst);
744                break;
745            }
746        }
747        break;
748      default:
749        // Bad number of elements to unpack
750        microOps[uopIdx++] = new Unknown(machInst);
751    }
752    switch (storeSize) {
753      case 1:
754        microOps[uopIdx++] = new MicroStrNeon1Uop<uint8_t>(
755                machInst, ufp0, rn, 0, align);
756        break;
757      case 2:
758        if (eBytes == 2) {
759            microOps[uopIdx++] = new MicroStrNeon2Uop<uint16_t>(
760                    machInst, ufp0, rn, 0, align);
761        } else {
762            microOps[uopIdx++] = new MicroStrNeon2Uop<uint8_t>(
763                    machInst, ufp0, rn, 0, align);
764        }
765        break;
766      case 3:
767        microOps[uopIdx++] = new MicroStrNeon3Uop<uint8_t>(
768                machInst, ufp0, rn, 0, align);
769        break;
770      case 4:
771        switch (eBytes) {
772          case 1:
773            microOps[uopIdx++] = new MicroStrNeon4Uop<uint8_t>(
774                    machInst, ufp0, rn, 0, align);
775            break;
776          case 2:
777            microOps[uopIdx++] = new MicroStrNeon4Uop<uint16_t>(
778                    machInst, ufp0, rn, 0, align);
779            break;
780          case 4:
781            microOps[uopIdx++] = new MicroStrNeon4Uop<uint32_t>(
782                    machInst, ufp0, rn, 0, align);
783            break;
784        }
785        break;
786      case 6:
787        microOps[uopIdx++] = new MicroStrNeon6Uop<uint16_t>(
788                machInst, ufp0, rn, 0, align);
789        break;
790      case 8:
791        switch (eBytes) {
792          case 2:
793            microOps[uopIdx++] = new MicroStrNeon8Uop<uint16_t>(
794                    machInst, ufp0, rn, 0, align);
795            break;
796          case 4:
797            microOps[uopIdx++] = new MicroStrNeon8Uop<uint32_t>(
798                    machInst, ufp0, rn, 0, align);
799            break;
800        }
801        break;
802      case 12:
803        microOps[uopIdx++] = new MicroStrNeon12Uop<uint32_t>(
804                machInst, ufp0, rn, 0, align);
805        break;
806      case 16:
807        microOps[uopIdx++] = new MicroStrNeon16Uop<uint32_t>(
808                machInst, ufp0, rn, 0, align);
809        break;
810      default:
811        // Bad store size
812        microOps[uopIdx++] = new Unknown(machInst);
813    }
814    if (wb) {
815        if (rm != 15 && rm != 13) {
816            microOps[uopIdx++] =
817                new MicroAddUop(machInst, rn, rn, rm, 0, ArmISA::LSL);
818        } else {
819            microOps[uopIdx++] =
820                new MicroAddiUop(machInst, rn, rn, storeSize);
821        }
822    }
823    assert(uopIdx == numMicroops);
824
825    for (unsigned i = 0; i < numMicroops - 1; i++) {
826        MicroOp * uopPtr = dynamic_cast<MicroOp *>(microOps[i].get());
827        assert(uopPtr);
828        uopPtr->setDelayedCommit();
829    }
830    microOps[numMicroops - 1]->setLastMicroop();
831}
832
833MacroVFPMemOp::MacroVFPMemOp(const char *mnem, ExtMachInst machInst,
834                             OpClass __opClass, IntRegIndex rn,
835                             RegIndex vd, bool single, bool up,
836                             bool writeback, bool load, uint32_t offset) :
837    PredMacroOp(mnem, machInst, __opClass)
838{
839    int i = 0;
840
841    // The lowest order bit selects fldmx (set) or fldmd (clear). These seem
842    // to be functionally identical except that fldmx is deprecated. For now
843    // we'll assume they're otherwise interchangable.
844    int count = (single ? offset : (offset / 2));
845    if (count == 0 || count > NumFloatArchRegs)
846        warn_once("Bad offset field for VFP load/store multiple.\n");
847    if (count == 0) {
848        // Force there to be at least one microop so the macroop makes sense.
849        writeback = true;
850    }
851    if (count > NumFloatArchRegs)
852        count = NumFloatArchRegs;
853
854    numMicroops = count * (single ? 1 : 2) + (writeback ? 1 : 0);
855    microOps = new StaticInstPtr[numMicroops];
856
857    int64_t addr = 0;
858
859    if (!up)
860        addr = 4 * offset;
861
862    bool tempUp = up;
863    for (int j = 0; j < count; j++) {
864        if (load) {
865            if (single) {
866                microOps[i++] = new MicroLdrFpUop(machInst, vd++, rn,
867                                                  tempUp, addr);
868            } else {
869                microOps[i++] = new MicroLdrDBFpUop(machInst, vd++, rn,
870                                                    tempUp, addr);
871                microOps[i++] = new MicroLdrDTFpUop(machInst, vd++, rn, tempUp,
872                                                    addr + (up ? 4 : -4));
873            }
874        } else {
875            if (single) {
876                microOps[i++] = new MicroStrFpUop(machInst, vd++, rn,
877                                                  tempUp, addr);
878            } else {
879                microOps[i++] = new MicroStrDBFpUop(machInst, vd++, rn,
880                                                    tempUp, addr);
881                microOps[i++] = new MicroStrDTFpUop(machInst, vd++, rn, tempUp,
882                                                    addr + (up ? 4 : -4));
883            }
884        }
885        if (!tempUp) {
886            addr -= (single ? 4 : 8);
887            // The microops don't handle negative displacement, so turn if we
888            // hit zero, flip polarity and start adding.
889            if (addr <= 0) {
890                tempUp = true;
891                addr = -addr;
892            }
893        } else {
894            addr += (single ? 4 : 8);
895        }
896    }
897
898    if (writeback) {
899        if (up) {
900            microOps[i++] =
901                new MicroAddiUop(machInst, rn, rn, 4 * offset);
902        } else {
903            microOps[i++] =
904                new MicroSubiUop(machInst, rn, rn, 4 * offset);
905        }
906    }
907
908    assert(numMicroops == i);
909    microOps[numMicroops - 1]->setLastMicroop();
910
911    for (StaticInstPtr *curUop = microOps;
912            !(*curUop)->isLastMicroop(); curUop++) {
913        MicroOp * uopPtr = dynamic_cast<MicroOp *>(curUop->get());
914        assert(uopPtr);
915        uopPtr->setDelayedCommit();
916    }
917}
918
919std::string
920MicroIntImmOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
921{
922    std::stringstream ss;
923    printMnemonic(ss);
924    printReg(ss, ura);
925    ss << ", ";
926    printReg(ss, urb);
927    ss << ", ";
928    ccprintf(ss, "#%d", imm);
929    return ss.str();
930}
931
932std::string
933MicroSetPCCPSR::generateDisassembly(Addr pc, const SymbolTable *symtab) const
934{
935    std::stringstream ss;
936    printMnemonic(ss);
937    ss << "[PC,CPSR]";
938    return ss.str();
939}
940
941std::string
942MicroIntMov::generateDisassembly(Addr pc, const SymbolTable *symtab) const
943{
944    std::stringstream ss;
945    printMnemonic(ss);
946    printReg(ss, ura);
947    ss << ", ";
948    printReg(ss, urb);
949    return ss.str();
950}
951
952std::string
953MicroIntOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
954{
955    std::stringstream ss;
956    printMnemonic(ss);
957    printReg(ss, ura);
958    ss << ", ";
959    printReg(ss, urb);
960    ss << ", ";
961    printReg(ss, urc);
962    return ss.str();
963}
964
965std::string
966MicroMemOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
967{
968    std::stringstream ss;
969    printMnemonic(ss);
970    printReg(ss, ura);
971    ss << ", [";
972    printReg(ss, urb);
973    ss << ", ";
974    ccprintf(ss, "#%d", imm);
975    ss << "]";
976    return ss.str();
977}
978
979}
980