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