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