isa.hh revision 13395
1/*
2 * Copyright (c) 2010, 2012-2018 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) 2009 The Regents of The University of Michigan
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: Gabe Black
41 */
42
43#ifndef __ARCH_ARM_ISA_HH__
44#define __ARCH_ARM_ISA_HH__
45
46#include "arch/arm/isa_device.hh"
47#include "arch/arm/miscregs.hh"
48#include "arch/arm/registers.hh"
49#include "arch/arm/system.hh"
50#include "arch/arm/tlb.hh"
51#include "arch/arm/types.hh"
52#include "arch/generic/traits.hh"
53#include "debug/Checkpoint.hh"
54#include "enums/VecRegRenameMode.hh"
55#include "sim/sim_object.hh"
56#include "enums/DecoderFlavour.hh"
57
58struct ArmISAParams;
59struct DummyArmISADeviceParams;
60class ThreadContext;
61class Checkpoint;
62class EventManager;
63
64namespace ArmISA
65{
66    class ISA : public SimObject
67    {
68      protected:
69        // Parent system
70        ArmSystem *system;
71
72        // Micro Architecture
73        const Enums::DecoderFlavour _decoderFlavour;
74        const Enums::VecRegRenameMode _vecRegRenameMode;
75
76        /** Dummy device for to handle non-existing ISA devices */
77        DummyISADevice dummyDevice;
78
79        // PMU belonging to this ISA
80        BaseISADevice *pmu;
81
82        // Generic timer interface belonging to this ISA
83        std::unique_ptr<BaseISADevice> timer;
84
85        // Cached copies of system-level properties
86        bool highestELIs64;
87        bool haveSecurity;
88        bool haveLPAE;
89        bool haveVirtualization;
90        bool haveCrypto;
91        bool haveLargeAsid64;
92        uint8_t physAddrRange;
93
94        /**
95         * If true, accesses to IMPLEMENTATION DEFINED registers are treated
96         * as NOP hence not causing UNDEFINED INSTRUCTION.
97         */
98        bool impdefAsNop;
99
100        /** MiscReg metadata **/
101        struct MiscRegLUTEntry {
102            uint32_t lower;  // Lower half mapped to this register
103            uint32_t upper;  // Upper half mapped to this register
104            uint64_t _reset; // value taken on reset (i.e. initialization)
105            uint64_t _res0;  // reserved
106            uint64_t _res1;  // reserved
107            uint64_t _raz;   // read as zero (fixed at 0)
108            uint64_t _rao;   // read as one (fixed at 1)
109          public:
110            MiscRegLUTEntry() :
111              lower(0), upper(0),
112              _reset(0), _res0(0), _res1(0), _raz(0), _rao(0) {}
113            uint64_t reset() const { return _reset; }
114            uint64_t res0()  const { return _res0; }
115            uint64_t res1()  const { return _res1; }
116            uint64_t raz()   const { return _raz; }
117            uint64_t rao()   const { return _rao; }
118            // raz/rao implies writes ignored
119            uint64_t wi()    const { return _raz | _rao; }
120        };
121
122        /** Metadata table accessible via the value of the register */
123        static std::vector<struct MiscRegLUTEntry> lookUpMiscReg;
124
125        class MiscRegLUTEntryInitializer {
126            struct MiscRegLUTEntry &entry;
127            std::bitset<NUM_MISCREG_INFOS> &info;
128            typedef const MiscRegLUTEntryInitializer& chain;
129          public:
130            chain mapsTo(uint32_t l, uint32_t u = 0) const {
131                entry.lower = l;
132                entry.upper = u;
133                return *this;
134            }
135            chain res0(uint64_t mask) const {
136                entry._res0 = mask;
137                return *this;
138            }
139            chain res1(uint64_t mask) const {
140                entry._res1 = mask;
141                return *this;
142            }
143            chain raz(uint64_t mask) const {
144                entry._raz  = mask;
145                return *this;
146            }
147            chain rao(uint64_t mask) const {
148                entry._rao  = mask;
149                return *this;
150            }
151            chain implemented(bool v = true) const {
152                info[MISCREG_IMPLEMENTED] = v;
153                return *this;
154            }
155            chain unimplemented() const {
156                return implemented(false);
157            }
158            chain unverifiable(bool v = true) const {
159                info[MISCREG_UNVERIFIABLE] = v;
160                return *this;
161            }
162            chain warnNotFail(bool v = true) const {
163                info[MISCREG_WARN_NOT_FAIL] = v;
164                return *this;
165            }
166            chain mutex(bool v = true) const {
167                info[MISCREG_MUTEX] = v;
168                return *this;
169            }
170            chain banked(bool v = true) const {
171                info[MISCREG_BANKED] = v;
172                return *this;
173            }
174            chain bankedChild(bool v = true) const {
175                info[MISCREG_BANKED_CHILD] = v;
176                return *this;
177            }
178            chain userNonSecureRead(bool v = true) const {
179                info[MISCREG_USR_NS_RD] = v;
180                return *this;
181            }
182            chain userNonSecureWrite(bool v = true) const {
183                info[MISCREG_USR_NS_WR] = v;
184                return *this;
185            }
186            chain userSecureRead(bool v = true) const {
187                info[MISCREG_USR_S_RD] = v;
188                return *this;
189            }
190            chain userSecureWrite(bool v = true) const {
191                info[MISCREG_USR_S_WR] = v;
192                return *this;
193            }
194            chain user(bool v = true) const {
195                userNonSecureRead(v);
196                userNonSecureWrite(v);
197                userSecureRead(v);
198                userSecureWrite(v);
199                return *this;
200            }
201            chain privNonSecureRead(bool v = true) const {
202                info[MISCREG_PRI_NS_RD] = v;
203                return *this;
204            }
205            chain privNonSecureWrite(bool v = true) const {
206                info[MISCREG_PRI_NS_WR] = v;
207                return *this;
208            }
209            chain privNonSecure(bool v = true) const {
210                privNonSecureRead(v);
211                privNonSecureWrite(v);
212                return *this;
213            }
214            chain privSecureRead(bool v = true) const {
215                info[MISCREG_PRI_S_RD] = v;
216                return *this;
217            }
218            chain privSecureWrite(bool v = true) const {
219                info[MISCREG_PRI_S_WR] = v;
220                return *this;
221            }
222            chain privSecure(bool v = true) const {
223                privSecureRead(v);
224                privSecureWrite(v);
225                return *this;
226            }
227            chain priv(bool v = true) const {
228                privSecure(v);
229                privNonSecure(v);
230                return *this;
231            }
232            chain privRead(bool v = true) const {
233                privSecureRead(v);
234                privNonSecureRead(v);
235                return *this;
236            }
237            chain hypRead(bool v = true) const {
238                info[MISCREG_HYP_RD] = v;
239                return *this;
240            }
241            chain hypWrite(bool v = true) const {
242                info[MISCREG_HYP_WR] = v;
243                return *this;
244            }
245            chain hyp(bool v = true) const {
246                hypRead(v);
247                hypWrite(v);
248                return *this;
249            }
250            chain monSecureRead(bool v = true) const {
251                info[MISCREG_MON_NS0_RD] = v;
252                return *this;
253            }
254            chain monSecureWrite(bool v = true) const {
255                info[MISCREG_MON_NS0_WR] = v;
256                return *this;
257            }
258            chain monNonSecureRead(bool v = true) const {
259                info[MISCREG_MON_NS1_RD] = v;
260                return *this;
261            }
262            chain monNonSecureWrite(bool v = true) const {
263                info[MISCREG_MON_NS1_WR] = v;
264                return *this;
265            }
266            chain mon(bool v = true) const {
267                monSecureRead(v);
268                monSecureWrite(v);
269                monNonSecureRead(v);
270                monNonSecureWrite(v);
271                return *this;
272            }
273            chain monSecure(bool v = true) const {
274                monSecureRead(v);
275                monSecureWrite(v);
276                return *this;
277            }
278            chain monNonSecure(bool v = true) const {
279                monNonSecureRead(v);
280                monNonSecureWrite(v);
281                return *this;
282            }
283            chain allPrivileges(bool v = true) const {
284                userNonSecureRead(v);
285                userNonSecureWrite(v);
286                userSecureRead(v);
287                userSecureWrite(v);
288                privNonSecureRead(v);
289                privNonSecureWrite(v);
290                privSecureRead(v);
291                privSecureWrite(v);
292                hypRead(v);
293                hypWrite(v);
294                monSecureRead(v);
295                monSecureWrite(v);
296                monNonSecureRead(v);
297                monNonSecureWrite(v);
298                return *this;
299            }
300            chain nonSecure(bool v = true) const {
301                userNonSecureRead(v);
302                userNonSecureWrite(v);
303                privNonSecureRead(v);
304                privNonSecureWrite(v);
305                hypRead(v);
306                hypWrite(v);
307                monNonSecureRead(v);
308                monNonSecureWrite(v);
309                return *this;
310            }
311            chain secure(bool v = true) const {
312                userSecureRead(v);
313                userSecureWrite(v);
314                privSecureRead(v);
315                privSecureWrite(v);
316                monSecureRead(v);
317                monSecureWrite(v);
318                return *this;
319            }
320            chain reads(bool v) const {
321                userNonSecureRead(v);
322                userSecureRead(v);
323                privNonSecureRead(v);
324                privSecureRead(v);
325                hypRead(v);
326                monSecureRead(v);
327                monNonSecureRead(v);
328                return *this;
329            }
330            chain writes(bool v) const {
331                userNonSecureWrite(v);
332                userSecureWrite(v);
333                privNonSecureWrite(v);
334                privSecureWrite(v);
335                hypWrite(v);
336                monSecureWrite(v);
337                monNonSecureWrite(v);
338                return *this;
339            }
340            chain exceptUserMode() const {
341                user(0);
342                return *this;
343            }
344            MiscRegLUTEntryInitializer(struct MiscRegLUTEntry &e,
345                                       std::bitset<NUM_MISCREG_INFOS> &i)
346              : entry(e),
347                info(i)
348            {
349                // force unimplemented registers to be thusly declared
350                implemented(1);
351            }
352        };
353
354        const MiscRegLUTEntryInitializer InitReg(uint32_t reg) {
355            return MiscRegLUTEntryInitializer(lookUpMiscReg[reg],
356                                              miscRegInfo[reg]);
357        }
358
359        void initializeMiscRegMetadata();
360
361        MiscReg miscRegs[NumMiscRegs];
362        const IntRegIndex *intRegMap;
363
364        void
365        updateRegMap(CPSR cpsr)
366        {
367            if (cpsr.width == 0) {
368                intRegMap = IntReg64Map;
369            } else {
370                switch (cpsr.mode) {
371                  case MODE_USER:
372                  case MODE_SYSTEM:
373                    intRegMap = IntRegUsrMap;
374                    break;
375                  case MODE_FIQ:
376                    intRegMap = IntRegFiqMap;
377                    break;
378                  case MODE_IRQ:
379                    intRegMap = IntRegIrqMap;
380                    break;
381                  case MODE_SVC:
382                    intRegMap = IntRegSvcMap;
383                    break;
384                  case MODE_MON:
385                    intRegMap = IntRegMonMap;
386                    break;
387                  case MODE_ABORT:
388                    intRegMap = IntRegAbtMap;
389                    break;
390                  case MODE_HYP:
391                    intRegMap = IntRegHypMap;
392                    break;
393                  case MODE_UNDEFINED:
394                    intRegMap = IntRegUndMap;
395                    break;
396                  default:
397                    panic("Unrecognized mode setting in CPSR.\n");
398                }
399            }
400        }
401
402        BaseISADevice &getGenericTimer(ThreadContext *tc);
403
404
405      private:
406        inline void assert32(ThreadContext *tc) {
407            CPSR cpsr M5_VAR_USED = readMiscReg(MISCREG_CPSR, tc);
408            assert(cpsr.width);
409        }
410
411        inline void assert64(ThreadContext *tc) {
412            CPSR cpsr M5_VAR_USED = readMiscReg(MISCREG_CPSR, tc);
413            assert(!cpsr.width);
414        }
415
416      public:
417        void clear();
418
419      protected:
420        void clear32(const ArmISAParams *p, const SCTLR &sctlr_rst);
421        void clear64(const ArmISAParams *p);
422        void initID32(const ArmISAParams *p);
423        void initID64(const ArmISAParams *p);
424
425      public:
426        MiscReg readMiscRegNoEffect(int misc_reg) const;
427        MiscReg readMiscReg(int misc_reg, ThreadContext *tc);
428        void setMiscRegNoEffect(int misc_reg, const MiscReg &val);
429        void setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc);
430
431        RegId
432        flattenRegId(const RegId& regId) const
433        {
434            switch (regId.classValue()) {
435              case IntRegClass:
436                return RegId(IntRegClass, flattenIntIndex(regId.index()));
437              case FloatRegClass:
438                return RegId(FloatRegClass, flattenFloatIndex(regId.index()));
439              case VecRegClass:
440                return RegId(VecRegClass, flattenVecIndex(regId.index()));
441              case VecElemClass:
442                return RegId(VecElemClass, flattenVecElemIndex(regId.index()));
443              case CCRegClass:
444                return RegId(CCRegClass, flattenCCIndex(regId.index()));
445              case MiscRegClass:
446                return RegId(MiscRegClass, flattenMiscIndex(regId.index()));
447            }
448            return RegId();
449        }
450
451        int
452        flattenIntIndex(int reg) const
453        {
454            assert(reg >= 0);
455            if (reg < NUM_ARCH_INTREGS) {
456                return intRegMap[reg];
457            } else if (reg < NUM_INTREGS) {
458                return reg;
459            } else if (reg == INTREG_SPX) {
460                CPSR cpsr = miscRegs[MISCREG_CPSR];
461                ExceptionLevel el = opModeToEL(
462                    (OperatingMode) (uint8_t) cpsr.mode);
463                if (!cpsr.sp && el != EL0)
464                    return INTREG_SP0;
465                switch (el) {
466                  case EL3:
467                    return INTREG_SP3;
468                  case EL2:
469                    return INTREG_SP2;
470                  case EL1:
471                    return INTREG_SP1;
472                  case EL0:
473                    return INTREG_SP0;
474                  default:
475                    panic("Invalid exception level");
476                    return 0;  // Never happens.
477                }
478            } else {
479                return flattenIntRegModeIndex(reg);
480            }
481        }
482
483        int
484        flattenFloatIndex(int reg) const
485        {
486            assert(reg >= 0);
487            return reg;
488        }
489
490        int
491        flattenVecIndex(int reg) const
492        {
493            assert(reg >= 0);
494            return reg;
495        }
496
497        int
498        flattenVecElemIndex(int reg) const
499        {
500            assert(reg >= 0);
501            return reg;
502        }
503
504        int
505        flattenCCIndex(int reg) const
506        {
507            assert(reg >= 0);
508            return reg;
509        }
510
511        int
512        flattenMiscIndex(int reg) const
513        {
514            assert(reg >= 0);
515            int flat_idx = reg;
516
517            if (reg == MISCREG_SPSR) {
518                CPSR cpsr = miscRegs[MISCREG_CPSR];
519                switch (cpsr.mode) {
520                  case MODE_EL0T:
521                    warn("User mode does not have SPSR\n");
522                    flat_idx = MISCREG_SPSR;
523                    break;
524                  case MODE_EL1T:
525                  case MODE_EL1H:
526                    flat_idx = MISCREG_SPSR_EL1;
527                    break;
528                  case MODE_EL2T:
529                  case MODE_EL2H:
530                    flat_idx = MISCREG_SPSR_EL2;
531                    break;
532                  case MODE_EL3T:
533                  case MODE_EL3H:
534                    flat_idx = MISCREG_SPSR_EL3;
535                    break;
536                  case MODE_USER:
537                    warn("User mode does not have SPSR\n");
538                    flat_idx = MISCREG_SPSR;
539                    break;
540                  case MODE_FIQ:
541                    flat_idx = MISCREG_SPSR_FIQ;
542                    break;
543                  case MODE_IRQ:
544                    flat_idx = MISCREG_SPSR_IRQ;
545                    break;
546                  case MODE_SVC:
547                    flat_idx = MISCREG_SPSR_SVC;
548                    break;
549                  case MODE_MON:
550                    flat_idx = MISCREG_SPSR_MON;
551                    break;
552                  case MODE_ABORT:
553                    flat_idx = MISCREG_SPSR_ABT;
554                    break;
555                  case MODE_HYP:
556                    flat_idx = MISCREG_SPSR_HYP;
557                    break;
558                  case MODE_UNDEFINED:
559                    flat_idx = MISCREG_SPSR_UND;
560                    break;
561                  default:
562                    warn("Trying to access SPSR in an invalid mode: %d\n",
563                         cpsr.mode);
564                    flat_idx = MISCREG_SPSR;
565                    break;
566                }
567            } else if (miscRegInfo[reg][MISCREG_MUTEX]) {
568                // Mutually exclusive CP15 register
569                switch (reg) {
570                  case MISCREG_PRRR_MAIR0:
571                  case MISCREG_PRRR_MAIR0_NS:
572                  case MISCREG_PRRR_MAIR0_S:
573                    {
574                        TTBCR ttbcr = readMiscRegNoEffect(MISCREG_TTBCR);
575                        // If the muxed reg has been flattened, work out the
576                        // offset and apply it to the unmuxed reg
577                        int idxOffset = reg - MISCREG_PRRR_MAIR0;
578                        if (ttbcr.eae)
579                            flat_idx = flattenMiscIndex(MISCREG_MAIR0 +
580                                                        idxOffset);
581                        else
582                            flat_idx = flattenMiscIndex(MISCREG_PRRR +
583                                                        idxOffset);
584                    }
585                    break;
586                  case MISCREG_NMRR_MAIR1:
587                  case MISCREG_NMRR_MAIR1_NS:
588                  case MISCREG_NMRR_MAIR1_S:
589                    {
590                        TTBCR ttbcr = readMiscRegNoEffect(MISCREG_TTBCR);
591                        // If the muxed reg has been flattened, work out the
592                        // offset and apply it to the unmuxed reg
593                        int idxOffset = reg - MISCREG_NMRR_MAIR1;
594                        if (ttbcr.eae)
595                            flat_idx = flattenMiscIndex(MISCREG_MAIR1 +
596                                                        idxOffset);
597                        else
598                            flat_idx = flattenMiscIndex(MISCREG_NMRR +
599                                                        idxOffset);
600                    }
601                    break;
602                  case MISCREG_PMXEVTYPER_PMCCFILTR:
603                    {
604                        PMSELR pmselr = miscRegs[MISCREG_PMSELR];
605                        if (pmselr.sel == 31)
606                            flat_idx = flattenMiscIndex(MISCREG_PMCCFILTR);
607                        else
608                            flat_idx = flattenMiscIndex(MISCREG_PMXEVTYPER);
609                    }
610                    break;
611                  default:
612                    panic("Unrecognized misc. register.\n");
613                    break;
614                }
615            } else {
616                if (miscRegInfo[reg][MISCREG_BANKED]) {
617                    bool secureReg = haveSecurity && !highestELIs64 &&
618                                     inSecureState(miscRegs[MISCREG_SCR],
619                                                   miscRegs[MISCREG_CPSR]);
620                    flat_idx += secureReg ? 2 : 1;
621                }
622            }
623            return flat_idx;
624        }
625
626        std::pair<int,int> getMiscIndices(int misc_reg) const
627        {
628            // Note: indexes of AArch64 registers are left unchanged
629            int flat_idx = flattenMiscIndex(misc_reg);
630
631            if (lookUpMiscReg[flat_idx].lower == 0) {
632                return std::make_pair(flat_idx, 0);
633            }
634
635            // do additional S/NS flattenings if mapped to NS while in S
636            bool S = haveSecurity && !highestELIs64 &&
637                     inSecureState(miscRegs[MISCREG_SCR],
638                                   miscRegs[MISCREG_CPSR]);
639            int lower = lookUpMiscReg[flat_idx].lower;
640            int upper = lookUpMiscReg[flat_idx].upper;
641            // upper == 0, which is CPSR, is not MISCREG_BANKED_CHILD (no-op)
642            lower += S && miscRegInfo[lower][MISCREG_BANKED_CHILD];
643            upper += S && miscRegInfo[upper][MISCREG_BANKED_CHILD];
644            return std::make_pair(lower, upper);
645        }
646
647        void serialize(CheckpointOut &cp) const
648        {
649            DPRINTF(Checkpoint, "Serializing Arm Misc Registers\n");
650            SERIALIZE_ARRAY(miscRegs, NUM_PHYS_MISCREGS);
651
652            SERIALIZE_SCALAR(highestELIs64);
653            SERIALIZE_SCALAR(haveSecurity);
654            SERIALIZE_SCALAR(haveLPAE);
655            SERIALIZE_SCALAR(haveVirtualization);
656            SERIALIZE_SCALAR(haveLargeAsid64);
657            SERIALIZE_SCALAR(physAddrRange);
658        }
659        void unserialize(CheckpointIn &cp)
660        {
661            DPRINTF(Checkpoint, "Unserializing Arm Misc Registers\n");
662            UNSERIALIZE_ARRAY(miscRegs, NUM_PHYS_MISCREGS);
663            CPSR tmp_cpsr = miscRegs[MISCREG_CPSR];
664            updateRegMap(tmp_cpsr);
665
666            UNSERIALIZE_SCALAR(highestELIs64);
667            UNSERIALIZE_SCALAR(haveSecurity);
668            UNSERIALIZE_SCALAR(haveLPAE);
669            UNSERIALIZE_SCALAR(haveVirtualization);
670            UNSERIALIZE_SCALAR(haveLargeAsid64);
671            UNSERIALIZE_SCALAR(physAddrRange);
672        }
673
674        void startup(ThreadContext *tc);
675
676        Enums::DecoderFlavour decoderFlavour() const { return _decoderFlavour; }
677
678        Enums::VecRegRenameMode
679        vecRegRenameMode() const
680        {
681            return _vecRegRenameMode;
682        }
683
684        /// Explicitly import the otherwise hidden startup
685        using SimObject::startup;
686
687        typedef ArmISAParams Params;
688
689        const Params *params() const;
690
691        ISA(Params *p);
692    };
693}
694
695template<>
696struct initRenameMode<ArmISA::ISA>
697{
698    static Enums::VecRegRenameMode mode(const ArmISA::ISA* isa)
699    {
700        return isa->vecRegRenameMode();
701    }
702    static bool equals(const ArmISA::ISA* isa1, const ArmISA::ISA* isa2)
703    {
704        return mode(isa1) == mode(isa2);
705    }
706};
707
708#endif
709