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