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