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