diff options
145 files changed, 39766 insertions, 2533 deletions
diff --git a/configs/common/FSConfig.py b/configs/common/FSConfig.py index 8905ba2fa..58ad1a7c9 100644 --- a/configs/common/FSConfig.py +++ b/configs/common/FSConfig.py @@ -242,7 +242,8 @@ def makeArmSystem(mem_mode, machine_type, mdesc = None, self.realview = VExpress_ELT() elif machine_type == "VExpress_EMM": self.realview = VExpress_EMM() - self.load_addr_mask = 0xffffffff + elif machine_type == "VExpress_EMM64": + self.realview = VExpress_EMM64() else: print "Unknown Machine Type" sys.exit(1) diff --git a/configs/common/O3_ARM_v7a.py b/configs/common/O3_ARM_v7a.py index aedafaf4d..3b7df9988 100644 --- a/configs/common/O3_ARM_v7a.py +++ b/configs/common/O3_ARM_v7a.py @@ -139,7 +139,7 @@ class O3_ARM_v7a_3(DerivO3CPU): backComSize = 5 forwardComSize = 5 numPhysIntRegs = 128 - numPhysFloatRegs = 128 + numPhysFloatRegs = 192 numIQEntries = 32 numROBEntries = 40 diff --git a/configs/common/Options.py b/configs/common/Options.py index 2cca4ef57..209d24357 100644 --- a/configs/common/Options.py +++ b/configs/common/Options.py @@ -94,6 +94,9 @@ def addCommonOptions(parser): default="512MB", help="Specify the physical memory size (single memory)") + parser.add_option("-l", "--lpae", action="store_true") + parser.add_option("-V", "--virtualisation", action="store_true") + # Cache Options parser.add_option("--caches", action="store_true") parser.add_option("--l2cache", action="store_true") @@ -197,6 +200,14 @@ def addCommonOptions(parser): parser.add_option("--at-instruction", action="store_true", default=False, help="""Treat value of --checkpoint-restore or --take-checkpoint as a number of instructions.""") + parser.add_option("--spec-input", default="ref", type="choice", + choices=["ref", "test", "train", "smred", "mdred", + "lgred"], + help="Input set size for SPEC CPU2000 benchmarks.") + parser.add_option("--arm-iset", default="arm", type="choice", + choices=["arm", "thumb", "aarch64"], + help="ARM instruction set.") + def addSEOptions(parser): # Benchmark options diff --git a/configs/common/cpu2000.py b/configs/common/cpu2000.py index 443399234..5f01d28bf 100644 --- a/configs/common/cpu2000.py +++ b/configs/common/cpu2000.py @@ -663,7 +663,7 @@ class vortex(Benchmark): stdin = None def __init__(self, isa, os, input_set): - if (isa == 'alpha' or isa == 'arm'): + if (isa in ('alpha', 'arm', 'thumb', 'aarch64')): self.endian = 'lendian' elif (isa == 'sparc' or isa == 'sparc32'): self.endian = 'bendian' diff --git a/configs/example/fs.py b/configs/example/fs.py index 4cfb3e8e2..cb9b264d2 100644 --- a/configs/example/fs.py +++ b/configs/example/fs.py @@ -140,6 +140,12 @@ if options.kernel is not None: if options.script is not None: test_sys.readfile = options.script +if options.lpae: + test_sys.have_lpae = True + +if options.virtualisation: + test_sys.have_virtualization = True + test_sys.init_param = options.init_param # For now, assign all the CPUs to the same clock domain diff --git a/configs/example/se.py b/configs/example/se.py index f7e7f1a65..d4f3e2dd9 100644 --- a/configs/example/se.py +++ b/configs/example/se.py @@ -135,9 +135,14 @@ if options.bench: for app in apps: try: if buildEnv['TARGET_ISA'] == 'alpha': - exec("workload = %s('alpha', 'tru64', 'ref')" % app) + exec("workload = %s('alpha', 'tru64', '%s')" % ( + app, options.spec_input)) + elif buildEnv['TARGET_ISA'] == 'arm': + exec("workload = %s('arm_%s', 'linux', '%s')" % ( + app, options.arm_iset, options.spec_input)) else: - exec("workload = %s(buildEnv['TARGET_ISA'], 'linux', 'ref')" % app) + exec("workload = %s(buildEnv['TARGET_ISA', 'linux', '%s')" % ( + app, options.spec_input)) multiprocesses.append(workload.makeLiveProcess()) except: print >>sys.stderr, "Unable to find workload for %s: %s" % (buildEnv['TARGET_ISA'], app) diff --git a/ext/libelf/elf_common.h b/ext/libelf/elf_common.h index c169e7e40..bad988d87 100644 --- a/ext/libelf/elf_common.h +++ b/ext/libelf/elf_common.h @@ -172,6 +172,7 @@ typedef struct { #define EM_TINYJ 61 /* Advanced Logic Corp. TinyJ processor. */ #define EM_X86_64 62 /* Advanced Micro Devices x86-64 */ #define EM_AMD64 EM_X86_64 /* Advanced Micro Devices x86-64 (compat) */ +#define EM_AARCH64 183 /* AArch64 64 bit ARM. */ /* Non-standard or deprecated. */ #define EM_486 6 /* Intel i486. */ diff --git a/src/arch/arm/ArmISA.py b/src/arch/arm/ArmISA.py index 55a589c32..eaec92f4d 100644 --- a/src/arch/arm/ArmISA.py +++ b/src/arch/arm/ArmISA.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 ARM Limited +# Copyright (c) 2012-2013 ARM Limited # All rights reserved. # # The license below extends only to copyright in the software and shall @@ -34,8 +34,10 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # Authors: Andreas Sandberg +# Giacomo Gabrielli from m5.params import * +from m5.proxy import * from m5.SimObject import SimObject class ArmISA(SimObject): @@ -43,12 +45,9 @@ class ArmISA(SimObject): cxx_class = 'ArmISA::ISA' cxx_header = "arch/arm/isa.hh" - # 0x35 Implementor is '5' from "M5" - # 0x0 Variant - # 0xf Architecture from CPUID scheme - # 0xc00 Primary part number ("c" or higher implies ARM v7) - # 0x0 Revision - midr = Param.UInt32(0x350fc000, "Main ID Register") + system = Param.System(Parent.any, "System this ISA object belongs to") + + midr = Param.UInt32(0x410fc0f0, "MIDR value") # See section B4.1.93 - B4.1.94 of the ARM ARM # @@ -56,19 +55,19 @@ class ArmISA(SimObject): # Note: ThumbEE is disabled for now since we don't support CP14 # config registers and jumping to ThumbEE vectors id_pfr0 = Param.UInt32(0x00000031, "Processor Feature Register 0") - # !Timer | !Virti | !M Profile | !TrustZone | ARMv4 - id_pfr1 = Param.UInt32(0x00000001, "Processor Feature Register 1") + # !Timer | Virti | !M Profile | TrustZone | ARMv4 + id_pfr1 = Param.UInt32(0x00001011, "Processor Feature Register 1") # See section B4.1.89 - B4.1.92 of the ARM ARM # VMSAv7 support - id_mmfr0 = Param.UInt32(0x00000003, "Memory Model Feature Register 0") + id_mmfr0 = Param.UInt32(0x10201103, "Memory Model Feature Register 0") id_mmfr1 = Param.UInt32(0x00000000, "Memory Model Feature Register 1") # no HW access | WFI stalling | ISB and DSB | # all TLB maintenance | no Harvard id_mmfr2 = Param.UInt32(0x01230000, "Memory Model Feature Register 2") # SuperSec | Coherent TLB | Bcast Maint | # BP Maint | Cache Maint Set/way | Cache Maint MVA - id_mmfr3 = Param.UInt32(0xF0102211, "Memory Model Feature Register 3") + id_mmfr3 = Param.UInt32(0x02102211, "Memory Model Feature Register 3") # See section B4.1.84 of ARM ARM # All values are latest for ARMv7-A profile @@ -79,5 +78,40 @@ class ArmISA(SimObject): id_isar4 = Param.UInt32(0x10010142, "Instruction Set Attribute Register 4") id_isar5 = Param.UInt32(0x00000000, "Instruction Set Attribute Register 5") + fpsid = Param.UInt32(0x410430a0, "Floating-point System ID Register") + + # [31:0] is implementation defined + id_aa64afr0_el1 = Param.UInt64(0x0000000000000000, + "AArch64 Auxiliary Feature Register 0") + # Reserved for future expansion + id_aa64afr1_el1 = Param.UInt64(0x0000000000000000, + "AArch64 Auxiliary Feature Register 1") + + # 1 CTX CMPs | 2 WRPs | 2 BRPs | !PMU | !Trace | Debug v8-A + id_aa64dfr0_el1 = Param.UInt64(0x0000000000101006, + "AArch64 Debug Feature Register 0") + # Reserved for future expansion + id_aa64dfr1_el1 = Param.UInt64(0x0000000000000000, + "AArch64 Debug Feature Register 1") + + # !CRC32 | !SHA2 | !SHA1 | !AES + id_aa64isar0_el1 = Param.UInt64(0x0000000000000000, + "AArch64 Instruction Set Attribute Register 0") + # Reserved for future expansion + id_aa64isar1_el1 = Param.UInt64(0x0000000000000000, + "AArch64 Instruction Set Attribute Register 1") + + # 4K | 64K | !16K | !BigEndEL0 | !SNSMem | !BigEnd | 8b ASID | 40b PA + id_aa64mmfr0_el1 = Param.UInt64(0x0000000000f00002, + "AArch64 Memory Model Feature Register 0") + # Reserved for future expansion + id_aa64mmfr1_el1 = Param.UInt64(0x0000000000000000, + "AArch64 Memory Model Feature Register 1") - fpsid = Param.UInt32(0x410430A0, "Floating-point System ID Register") + # !GICv3 CP15 | AdvSIMD | FP | !EL3 | !EL2 | EL1 (AArch64) | EL0 (AArch64) + # (no AArch32/64 interprocessing support for now) + id_aa64pfr0_el1 = Param.UInt64(0x0000000000000011, + "AArch64 Processor Feature Register 0") + # Reserved for future expansion + id_aa64pfr1_el1 = Param.UInt64(0x0000000000000000, + "AArch64 Processor Feature Register 1") diff --git a/src/arch/arm/ArmSystem.py b/src/arch/arm/ArmSystem.py index b48c2a29d..39b7ec8ff 100644 --- a/src/arch/arm/ArmSystem.py +++ b/src/arch/arm/ArmSystem.py @@ -1,4 +1,4 @@ -# Copyright (c) 2009 ARM Limited +# Copyright (c) 2009, 2012-2013 ARM Limited # All rights reserved. # # The license below extends only to copyright in the software and shall @@ -44,7 +44,8 @@ class ArmMachineType(Enum): 'RealView_PBX' : 1901, 'VExpress_ELT' : 2272, 'VExpress_CA9' : 2272, - 'VExpress_EMM' : 2272} + 'VExpress_EMM' : 2272, + 'VExpress_EMM64' : 2272} class ArmSystem(System): type = 'ArmSystem' @@ -54,6 +55,23 @@ class ArmSystem(System): boot_loader = Param.String("", "File that contains the boot loader code if any") gic_cpu_addr = Param.Addr(0, "Addres of the GIC CPU interface") flags_addr = Param.Addr(0, "Address of the flags register for MP booting") + have_security = Param.Bool(False, + "True if Security Extensions are implemented") + have_virtualization = Param.Bool(False, + "True if Virtualization Extensions are implemented") + have_lpae = Param.Bool(False, "True if LPAE is implemented") + have_generic_timer = Param.Bool(False, + "True if the Generic Timer extension is implemented") + highest_el_is_64 = Param.Bool(False, + "True if the register width of the highest implemented exception level " + "is 64 bits (ARMv8)") + reset_addr_64 = Param.UInt64(0x0, + "Reset address if the highest implemented exception level is 64 bits " + "(ARMv8)") + phys_addr_range_64 = Param.UInt8(40, + "Supported physical address range in bits when using AArch64 (ARMv8)") + have_large_asid_64 = Param.Bool(False, + "True if ASID is 16 bits in AArch64 (ARMv8)") class LinuxArmSystem(ArmSystem): type = 'LinuxArmSystem' @@ -61,8 +79,10 @@ class LinuxArmSystem(ArmSystem): load_addr_mask = 0x0fffffff machine_type = Param.ArmMachineType('RealView_PBX', "Machine id from http://www.arm.linux.org.uk/developer/machines/") - atags_addr = Param.Addr(0x100, - "Address where default atags structure should be written") + atags_addr = Param.Addr("Address where default atags structure should " \ + "be written") + boot_release_addr = Param.Addr(0xfff8, "Address where secondary CPUs " \ + "spin waiting boot in the loader") dtb_filename = Param.String("", "File that contains the Device Tree Blob. Don't use DTB if empty.") early_kernel_symbols = Param.Bool(False, diff --git a/src/arch/arm/ArmTLB.py b/src/arch/arm/ArmTLB.py index c70dd80c8..01ac8016a 100644 --- a/src/arch/arm/ArmTLB.py +++ b/src/arch/arm/ArmTLB.py @@ -1,6 +1,6 @@ # -*- mode:python -*- -# Copyright (c) 2009 ARM Limited +# Copyright (c) 2009, 2013 ARM Limited # All rights reserved. # # The license below extends only to copyright in the software and shall @@ -42,10 +42,12 @@ from m5.params import * from m5.proxy import * from MemObject import MemObject +# Basic stage 1 translation objects class ArmTableWalker(MemObject): type = 'ArmTableWalker' cxx_class = 'ArmISA::TableWalker' cxx_header = "arch/arm/table_walker.hh" + is_stage2 = Param.Bool(False, "Is this object for stage 2 translation?") port = MasterPort("Port for TableWalker to do walk the translation with") sys = Param.System(Parent.any, "system object parameter") num_squash_per_cycle = Param.Unsigned(2, @@ -57,3 +59,28 @@ class ArmTLB(SimObject): cxx_header = "arch/arm/tlb.hh" size = Param.Int(64, "TLB size") walker = Param.ArmTableWalker(ArmTableWalker(), "HW Table walker") + is_stage2 = Param.Bool(False, "Is this a stage 2 TLB?") + +# Stage 2 translation objects, only used when virtualisation is being used +class ArmStage2TableWalker(ArmTableWalker): + is_stage2 = True + +class ArmStage2TLB(ArmTLB): + size = 32 + walker = ArmStage2TableWalker() + is_stage2 = True + +class ArmStage2MMU(SimObject): + type = 'ArmStage2MMU' + cxx_class = 'ArmISA::Stage2MMU' + cxx_header = 'arch/arm/stage2_mmu.hh' + tlb = Param.ArmTLB("Stage 1 TLB") + stage2_tlb = Param.ArmTLB("Stage 2 TLB") + +class ArmStage2IMMU(ArmStage2MMU): + tlb = Parent.itb + stage2_tlb = ArmStage2TLB(walker = ArmStage2TableWalker()) + +class ArmStage2DMMU(ArmStage2MMU): + tlb = Parent.dtb + stage2_tlb = ArmStage2TLB(walker = ArmStage2TableWalker()) diff --git a/src/arch/arm/SConscript b/src/arch/arm/SConscript index 8d13a9b2d..aa9ce417b 100644 --- a/src/arch/arm/SConscript +++ b/src/arch/arm/SConscript @@ -1,6 +1,6 @@ # -*- mode:python -*- -# Copyright (c) 2009 ARM Limited +# Copyright (c) 2009, 2012-2013 ARM Limited # All rights reserved. # # The license below extends only to copyright in the software and shall @@ -49,12 +49,17 @@ if env['TARGET_ISA'] == 'arm': Dir('isa/formats') Source('decoder.cc') Source('faults.cc') + Source('insts/branch64.cc') + Source('insts/data64.cc') Source('insts/macromem.cc') Source('insts/mem.cc') + Source('insts/mem64.cc') Source('insts/misc.cc') + Source('insts/misc64.cc') Source('insts/pred_inst.cc') Source('insts/static_inst.cc') Source('insts/vfp.cc') + Source('insts/fplib.cc') Source('interrupts.cc') Source('isa.cc') Source('linux/linux.cc') @@ -67,6 +72,8 @@ if env['TARGET_ISA'] == 'arm': Source('stacktrace.cc') Source('system.cc') Source('table_walker.cc') + Source('stage2_mmu.cc') + Source('stage2_lookup.cc') Source('tlb.cc') Source('utility.cc') Source('vtophys.cc') diff --git a/src/arch/arm/decoder.cc b/src/arch/arm/decoder.cc index e957ce0e7..940d85b8e 100644 --- a/src/arch/arm/decoder.cc +++ b/src/arch/arm/decoder.cc @@ -1,4 +1,16 @@ /* + * Copyright (c) 2012-2013 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * * Copyright (c) 2012 Google * All rights reserved. * @@ -47,9 +59,11 @@ Decoder::process() if (!emi.thumb) { emi.instBits = data; - emi.sevenAndFour = bits(data, 7) && bits(data, 4); - emi.isMisc = (bits(data, 24, 23) == 0x2 && - bits(data, 20) == 0); + if (!emi.aarch64) { + emi.sevenAndFour = bits(data, 7) && bits(data, 4); + emi.isMisc = (bits(data, 24, 23) == 0x2 && + bits(data, 20) == 0); + } consumeBytes(4); DPRINTF(Decoder, "Arm inst: %#x.\n", (uint64_t)emi); } else { @@ -112,6 +126,7 @@ Decoder::moreBytes(const PCState &pc, Addr fetchPC, MachInst inst) data = inst; offset = (fetchPC >= pc.instAddr()) ? 0 : pc.instAddr() - fetchPC; emi.thumb = pc.thumb(); + emi.aarch64 = pc.aarch64(); emi.fpscrLen = fpscrLen; emi.fpscrStride = fpscrStride; diff --git a/src/arch/arm/decoder.hh b/src/arch/arm/decoder.hh index 72776bcfd..315a3b6ad 100644 --- a/src/arch/arm/decoder.hh +++ b/src/arch/arm/decoder.hh @@ -1,4 +1,16 @@ /* + * Copyright (c) 2013 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * * Copyright (c) 2012 Google * All rights reserved. * diff --git a/src/arch/arm/faults.cc b/src/arch/arm/faults.cc index be1c7ecc2..f8313efd2 100644 --- a/src/arch/arm/faults.cc +++ b/src/arch/arm/faults.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010, 2012-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -40,9 +40,15 @@ * * Authors: Ali Saidi * Gabe Black + * Giacomo Gabrielli + * Thomas Grocutt */ #include "arch/arm/faults.hh" +#include "arch/arm/system.hh" +#include "arch/arm/utility.hh" +#include "arch/arm/insts/static_inst.hh" +#include "base/compiler.hh" #include "base/trace.hh" #include "cpu/base.hh" #include "cpu/thread_context.hh" @@ -52,61 +58,413 @@ namespace ArmISA { -template<> ArmFault::FaultVals ArmFaultVals<Reset>::vals = -{"reset", 0x00, MODE_SVC, 0, 0, true, true, FaultStat()}; +uint8_t ArmFault::shortDescFaultSources[] = { + 0x01, // AlignmentFault + 0x04, // InstructionCacheMaintenance + 0xff, // SynchExtAbtOnTranslTableWalkL0 (INVALID) + 0x0c, // SynchExtAbtOnTranslTableWalkL1 + 0x0e, // SynchExtAbtOnTranslTableWalkL2 + 0xff, // SynchExtAbtOnTranslTableWalkL3 (INVALID) + 0xff, // SynchPtyErrOnTranslTableWalkL0 (INVALID) + 0x1c, // SynchPtyErrOnTranslTableWalkL1 + 0x1e, // SynchPtyErrOnTranslTableWalkL2 + 0xff, // SynchPtyErrOnTranslTableWalkL3 (INVALID) + 0xff, // TranslationL0 (INVALID) + 0x05, // TranslationL1 + 0x07, // TranslationL2 + 0xff, // TranslationL3 (INVALID) + 0xff, // AccessFlagL0 (INVALID) + 0x03, // AccessFlagL1 + 0x06, // AccessFlagL2 + 0xff, // AccessFlagL3 (INVALID) + 0xff, // DomainL0 (INVALID) + 0x09, // DomainL1 + 0x0b, // DomainL2 + 0xff, // DomainL3 (INVALID) + 0xff, // PermissionL0 (INVALID) + 0x0d, // PermissionL1 + 0x0f, // PermissionL2 + 0xff, // PermissionL3 (INVALID) + 0x02, // DebugEvent + 0x08, // SynchronousExternalAbort + 0x10, // TLBConflictAbort + 0x19, // SynchPtyErrOnMemoryAccess + 0x16, // AsynchronousExternalAbort + 0x18, // AsynchPtyErrOnMemoryAccess + 0xff, // AddressSizeL0 (INVALID) + 0xff, // AddressSizeL1 (INVALID) + 0xff, // AddressSizeL2 (INVALID) + 0xff, // AddressSizeL3 (INVALID) + 0x40, // PrefetchTLBMiss + 0x80 // PrefetchUncacheable +}; -template<> ArmFault::FaultVals ArmFaultVals<UndefinedInstruction>::vals = -{"Undefined Instruction", 0x04, MODE_UNDEFINED, 4 ,2, false, false, - FaultStat()} ; +static_assert(sizeof(ArmFault::shortDescFaultSources) == + ArmFault::NumFaultSources, + "Invalid size of ArmFault::shortDescFaultSources[]"); -template<> ArmFault::FaultVals ArmFaultVals<SupervisorCall>::vals = -{"Supervisor Call", 0x08, MODE_SVC, 4, 2, false, false, FaultStat()}; +uint8_t ArmFault::longDescFaultSources[] = { + 0x21, // AlignmentFault + 0xff, // InstructionCacheMaintenance (INVALID) + 0xff, // SynchExtAbtOnTranslTableWalkL0 (INVALID) + 0x15, // SynchExtAbtOnTranslTableWalkL1 + 0x16, // SynchExtAbtOnTranslTableWalkL2 + 0x17, // SynchExtAbtOnTranslTableWalkL3 + 0xff, // SynchPtyErrOnTranslTableWalkL0 (INVALID) + 0x1d, // SynchPtyErrOnTranslTableWalkL1 + 0x1e, // SynchPtyErrOnTranslTableWalkL2 + 0x1f, // SynchPtyErrOnTranslTableWalkL3 + 0xff, // TranslationL0 (INVALID) + 0x05, // TranslationL1 + 0x06, // TranslationL2 + 0x07, // TranslationL3 + 0xff, // AccessFlagL0 (INVALID) + 0x09, // AccessFlagL1 + 0x0a, // AccessFlagL2 + 0x0b, // AccessFlagL3 + 0xff, // DomainL0 (INVALID) + 0x3d, // DomainL1 + 0x3e, // DomainL2 + 0xff, // DomainL3 (RESERVED) + 0xff, // PermissionL0 (INVALID) + 0x0d, // PermissionL1 + 0x0e, // PermissionL2 + 0x0f, // PermissionL3 + 0x22, // DebugEvent + 0x10, // SynchronousExternalAbort + 0x30, // TLBConflictAbort + 0x18, // SynchPtyErrOnMemoryAccess + 0x11, // AsynchronousExternalAbort + 0x19, // AsynchPtyErrOnMemoryAccess + 0xff, // AddressSizeL0 (INVALID) + 0xff, // AddressSizeL1 (INVALID) + 0xff, // AddressSizeL2 (INVALID) + 0xff, // AddressSizeL3 (INVALID) + 0x40, // PrefetchTLBMiss + 0x80 // PrefetchUncacheable +}; -template<> ArmFault::FaultVals ArmFaultVals<PrefetchAbort>::vals = -{"Prefetch Abort", 0x0C, MODE_ABORT, 4, 4, true, false, FaultStat()}; +static_assert(sizeof(ArmFault::longDescFaultSources) == + ArmFault::NumFaultSources, + "Invalid size of ArmFault::longDescFaultSources[]"); -template<> ArmFault::FaultVals ArmFaultVals<DataAbort>::vals = -{"Data Abort", 0x10, MODE_ABORT, 8, 8, true, false, FaultStat()}; +uint8_t ArmFault::aarch64FaultSources[] = { + 0x21, // AlignmentFault + 0xff, // InstructionCacheMaintenance (INVALID) + 0x14, // SynchExtAbtOnTranslTableWalkL0 + 0x15, // SynchExtAbtOnTranslTableWalkL1 + 0x16, // SynchExtAbtOnTranslTableWalkL2 + 0x17, // SynchExtAbtOnTranslTableWalkL3 + 0x1c, // SynchPtyErrOnTranslTableWalkL0 + 0x1d, // SynchPtyErrOnTranslTableWalkL1 + 0x1e, // SynchPtyErrOnTranslTableWalkL2 + 0x1f, // SynchPtyErrOnTranslTableWalkL3 + 0x04, // TranslationL0 + 0x05, // TranslationL1 + 0x06, // TranslationL2 + 0x07, // TranslationL3 + 0x08, // AccessFlagL0 + 0x09, // AccessFlagL1 + 0x0a, // AccessFlagL2 + 0x0b, // AccessFlagL3 + // @todo: Section & Page Domain Fault in AArch64? + 0xff, // DomainL0 (INVALID) + 0xff, // DomainL1 (INVALID) + 0xff, // DomainL2 (INVALID) + 0xff, // DomainL3 (INVALID) + 0x0c, // PermissionL0 + 0x0d, // PermissionL1 + 0x0e, // PermissionL2 + 0x0f, // PermissionL3 + 0xff, // DebugEvent (INVALID) + 0x10, // SynchronousExternalAbort + 0x30, // TLBConflictAbort + 0x18, // SynchPtyErrOnMemoryAccess + 0xff, // AsynchronousExternalAbort (INVALID) + 0xff, // AsynchPtyErrOnMemoryAccess (INVALID) + 0x00, // AddressSizeL0 + 0x01, // AddressSizeL1 + 0x02, // AddressSizeL2 + 0x03, // AddressSizeL3 + 0x40, // PrefetchTLBMiss + 0x80 // PrefetchUncacheable +}; -template<> ArmFault::FaultVals ArmFaultVals<Interrupt>::vals = -{"IRQ", 0x18, MODE_IRQ, 4, 4, true, false, FaultStat()}; +static_assert(sizeof(ArmFault::aarch64FaultSources) == + ArmFault::NumFaultSources, + "Invalid size of ArmFault::aarch64FaultSources[]"); -template<> ArmFault::FaultVals ArmFaultVals<FastInterrupt>::vals = -{"FIQ", 0x1C, MODE_FIQ, 4, 4, true, true, FaultStat()}; +// Fields: name, offset, cur{ELT,ELH}Offset, lowerEL{64,32}Offset, next mode, +// {ARM, Thumb, ARM_ELR, Thumb_ELR} PC offset, hyp trap, +// {A, F} disable, class, stat +template<> ArmFault::FaultVals ArmFaultVals<Reset>::vals = { + // Some dummy values (the reset vector has an IMPLEMENTATION DEFINED + // location in AArch64) + "Reset", 0x000, 0x000, 0x000, 0x000, 0x000, MODE_SVC, + 0, 0, 0, 0, false, true, true, EC_UNKNOWN, FaultStat() +}; +template<> ArmFault::FaultVals ArmFaultVals<UndefinedInstruction>::vals = { + "Undefined Instruction", 0x004, 0x000, 0x200, 0x400, 0x600, MODE_UNDEFINED, + 4, 2, 0, 0, true, false, false, EC_UNKNOWN, FaultStat() +}; +template<> ArmFault::FaultVals ArmFaultVals<SupervisorCall>::vals = { + "Supervisor Call", 0x008, 0x000, 0x200, 0x400, 0x600, MODE_SVC, + 4, 2, 4, 2, true, false, false, EC_SVC_TO_HYP, FaultStat() +}; +template<> ArmFault::FaultVals ArmFaultVals<SecureMonitorCall>::vals = { + "Secure Monitor Call", 0x008, 0x000, 0x200, 0x400, 0x600, MODE_MON, + 4, 4, 4, 4, false, true, true, EC_SMC_TO_HYP, FaultStat() +}; +template<> ArmFault::FaultVals ArmFaultVals<HypervisorCall>::vals = { + "Hypervisor Call", 0x008, 0x000, 0x200, 0x400, 0x600, MODE_HYP, + 4, 4, 4, 4, true, false, false, EC_HVC, FaultStat() +}; +template<> ArmFault::FaultVals ArmFaultVals<PrefetchAbort>::vals = { + "Prefetch Abort", 0x00C, 0x000, 0x200, 0x400, 0x600, MODE_ABORT, + 4, 4, 0, 0, true, true, false, EC_PREFETCH_ABORT_TO_HYP, FaultStat() +}; +template<> ArmFault::FaultVals ArmFaultVals<DataAbort>::vals = { + "Data Abort", 0x010, 0x000, 0x200, 0x400, 0x600, MODE_ABORT, + 8, 8, 0, 0, true, true, false, EC_DATA_ABORT_TO_HYP, FaultStat() +}; +template<> ArmFault::FaultVals ArmFaultVals<VirtualDataAbort>::vals = { + "Virtual Data Abort", 0x010, 0x000, 0x200, 0x400, 0x600, MODE_ABORT, + 8, 8, 0, 0, true, true, false, EC_INVALID, FaultStat() +}; +template<> ArmFault::FaultVals ArmFaultVals<HypervisorTrap>::vals = { + // @todo: double check these values + "Hypervisor Trap", 0x014, 0x000, 0x200, 0x400, 0x600, MODE_HYP, + 0, 0, 0, 0, false, false, false, EC_UNKNOWN, FaultStat() +}; +template<> ArmFault::FaultVals ArmFaultVals<Interrupt>::vals = { + "IRQ", 0x018, 0x080, 0x280, 0x480, 0x680, MODE_IRQ, + 4, 4, 0, 0, false, true, false, EC_UNKNOWN, FaultStat() +}; +template<> ArmFault::FaultVals ArmFaultVals<VirtualInterrupt>::vals = { + "Virtual IRQ", 0x018, 0x080, 0x280, 0x480, 0x680, MODE_IRQ, + 4, 4, 0, 0, false, true, false, EC_INVALID, FaultStat() +}; +template<> ArmFault::FaultVals ArmFaultVals<FastInterrupt>::vals = { + "FIQ", 0x01C, 0x100, 0x300, 0x500, 0x700, MODE_FIQ, + 4, 4, 0, 0, false, true, true, EC_UNKNOWN, FaultStat() +}; +template<> ArmFault::FaultVals ArmFaultVals<VirtualFastInterrupt>::vals = { + "Virtual FIQ", 0x01C, 0x100, 0x300, 0x500, 0x700, MODE_FIQ, + 4, 4, 0, 0, false, true, true, EC_INVALID, FaultStat() +}; +template<> ArmFault::FaultVals ArmFaultVals<SupervisorTrap>::vals = { + // Some dummy values (SupervisorTrap is AArch64-only) + "Supervisor Trap", 0x014, 0x000, 0x200, 0x400, 0x600, MODE_SVC, + 0, 0, 0, 0, false, false, false, EC_UNKNOWN, FaultStat() +}; +template<> ArmFault::FaultVals ArmFaultVals<SecureMonitorTrap>::vals = { + // Some dummy values (SecureMonitorTrap is AArch64-only) + "Secure Monitor Trap", 0x014, 0x000, 0x200, 0x400, 0x600, MODE_MON, + 0, 0, 0, 0, false, false, false, EC_UNKNOWN, FaultStat() +}; +template<> ArmFault::FaultVals ArmFaultVals<PCAlignmentFault>::vals = { + // Some dummy values (PCAlignmentFault is AArch64-only) + "PC Alignment Fault", 0x000, 0x000, 0x200, 0x400, 0x600, MODE_SVC, + 0, 0, 0, 0, true, false, false, EC_PC_ALIGNMENT, FaultStat() +}; +template<> ArmFault::FaultVals ArmFaultVals<SPAlignmentFault>::vals = { + // Some dummy values (SPAlignmentFault is AArch64-only) + "SP Alignment Fault", 0x000, 0x000, 0x200, 0x400, 0x600, MODE_SVC, + 0, 0, 0, 0, true, false, false, EC_STACK_PTR_ALIGNMENT, FaultStat() +}; +template<> ArmFault::FaultVals ArmFaultVals<SystemError>::vals = { + // Some dummy values (SError is AArch64-only) + "SError", 0x000, 0x180, 0x380, 0x580, 0x780, MODE_SVC, + 0, 0, 0, 0, false, true, true, EC_SERROR, FaultStat() +}; +template<> ArmFault::FaultVals ArmFaultVals<FlushPipe>::vals = { + // Some dummy values + "Pipe Flush", 0x000, 0x000, 0x000, 0x000, 0x000, MODE_SVC, + 0, 0, 0, 0, false, true, true, EC_UNKNOWN, FaultStat() +}; +template<> ArmFault::FaultVals ArmFaultVals<ArmSev>::vals = { + // Some dummy values + "ArmSev Flush", 0x000, 0x000, 0x000, 0x000, 0x000, MODE_SVC, + 0, 0, 0, 0, false, true, true, EC_UNKNOWN, FaultStat() +}; +template<> ArmFault::FaultVals ArmFaultVals<IllegalInstSetStateFault>::vals = { + // Some dummy values (SPAlignmentFault is AArch64-only) + "Illegal Inst Set State Fault", 0x000, 0x000, 0x200, 0x400, 0x600, MODE_SVC, + 0, 0, 0, 0, true, false, false, EC_ILLEGAL_INST, FaultStat() +}; -template<> ArmFault::FaultVals ArmFaultVals<FlushPipe>::vals = -{"Pipe Flush", 0x00, MODE_SVC, 0, 0, true, true, FaultStat()}; // dummy values - -template<> ArmFault::FaultVals ArmFaultVals<ArmSev>::vals = -{"ArmSev Flush", 0x00, MODE_SVC, 0, 0, true, true, FaultStat()}; // dummy values -Addr +Addr ArmFault::getVector(ThreadContext *tc) { - // ARM ARM B1-3 + Addr base; - SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR); + // ARM ARM issue C B1.8.1 + bool haveSecurity = ArmSystem::haveSecurity(tc); // panic if SCTLR.VE because I have no idea what to do with vectored // interrupts + SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR); assert(!sctlr.ve); + // Check for invalid modes + CPSR cpsr = tc->readMiscRegNoEffect(MISCREG_CPSR); + assert(haveSecurity || cpsr.mode != MODE_MON); + assert(ArmSystem::haveVirtualization(tc) || cpsr.mode != MODE_HYP); - if (!sctlr.v) - return offset(); - return offset() + HighVecs; + switch (cpsr.mode) + { + case MODE_MON: + base = tc->readMiscReg(MISCREG_MVBAR); + break; + case MODE_HYP: + base = tc->readMiscReg(MISCREG_HVBAR); + break; + default: + if (sctlr.v) { + base = HighVecs; + } else { + base = haveSecurity ? tc->readMiscReg(MISCREG_VBAR) : 0; + } + break; + } + return base + offset(tc); +} +Addr +ArmFault::getVector64(ThreadContext *tc) +{ + Addr vbar; + switch (toEL) { + case EL3: + assert(ArmSystem::haveSecurity(tc)); + vbar = tc->readMiscReg(MISCREG_VBAR_EL3); + break; + // @todo: uncomment this to enable Virtualization + // case EL2: + // assert(ArmSystem::haveVirtualization(tc)); + // vbar = tc->readMiscReg(MISCREG_VBAR_EL2); + // break; + case EL1: + vbar = tc->readMiscReg(MISCREG_VBAR_EL1); + break; + default: + panic("Invalid target exception level"); + break; + } + return vbar + offset64(); } -void +MiscRegIndex +ArmFault::getSyndromeReg64() const +{ + switch (toEL) { + case EL1: + return MISCREG_ESR_EL1; + case EL2: + return MISCREG_ESR_EL2; + case EL3: + return MISCREG_ESR_EL3; + default: + panic("Invalid exception level"); + break; + } +} + +MiscRegIndex +ArmFault::getFaultAddrReg64() const +{ + switch (toEL) { + case EL1: + return MISCREG_FAR_EL1; + case EL2: + return MISCREG_FAR_EL2; + case EL3: + return MISCREG_FAR_EL3; + default: + panic("Invalid exception level"); + break; + } +} + +void +ArmFault::setSyndrome(ThreadContext *tc, MiscRegIndex syndrome_reg) +{ + uint32_t value; + uint32_t exc_class = (uint32_t) ec(tc); + uint32_t issVal = iss(); + assert(!from64 || ArmSystem::highestELIs64(tc)); + + value = exc_class << 26; + + // HSR.IL not valid for Prefetch Aborts (0x20, 0x21) and Data Aborts (0x24, + // 0x25) for which the ISS information is not valid (ARMv7). + // @todo: ARMv8 revises AArch32 functionality: when HSR.IL is not + // valid it is treated as RES1. + if (to64) { + value |= 1 << 25; + } else if ((bits(exc_class, 5, 3) != 4) || + (bits(exc_class, 2) && bits(issVal, 24))) { + if (!machInst.thumb || machInst.bigThumb) + value |= 1 << 25; + } + // Condition code valid for EC[5:4] nonzero + if (!from64 && ((bits(exc_class, 5, 4) == 0) && + (bits(exc_class, 3, 0) != 0))) { + if (!machInst.thumb) { + uint32_t cond; + ConditionCode condCode = (ConditionCode) (uint32_t) machInst.condCode; + // If its on unconditional instruction report with a cond code of + // 0xE, ie the unconditional code + cond = (condCode == COND_UC) ? COND_AL : condCode; + value |= cond << 20; + value |= 1 << 24; + } + value |= bits(issVal, 19, 0); + } else { + value |= issVal; + } + tc->setMiscReg(syndrome_reg, value); +} + +void ArmFault::invoke(ThreadContext *tc, StaticInstPtr inst) { - // ARM ARM B1.6.3 + CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); + + if (ArmSystem::highestELIs64(tc)) { // ARMv8 + // Determine source exception level and mode + fromMode = (OperatingMode) (uint8_t) cpsr.mode; + fromEL = opModeToEL(fromMode); + if (opModeIs64(fromMode)) + from64 = true; + + // Determine target exception level + if (ArmSystem::haveSecurity(tc) && routeToMonitor(tc)) + toEL = EL3; + else + toEL = opModeToEL(nextMode()); + if (fromEL > toEL) + toEL = fromEL; + + if (toEL == ArmSystem::highestEL(tc) || ELIs64(tc, toEL)) { + // Invoke exception handler in AArch64 state + to64 = true; + invoke64(tc, inst); + return; + } + } + + // ARMv7 (ARM ARM issue C B1.9) + + bool have_security = ArmSystem::haveSecurity(tc); + bool have_virtualization = ArmSystem::haveVirtualization(tc); + FaultBase::invoke(tc); if (!FullSystem) return; countStat()++; SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR); - CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); + SCR scr = tc->readMiscReg(MISCREG_SCR); CPSR saved_cpsr = tc->readMiscReg(MISCREG_CPSR); saved_cpsr.nz = tc->readIntReg(INTREG_CONDCODES_NZ); saved_cpsr.c = tc->readIntReg(INTREG_CONDCODES_C); @@ -118,22 +476,73 @@ ArmFault::invoke(ThreadContext *tc, StaticInstPtr inst) saved_cpsr.it2 = it.top6; saved_cpsr.it1 = it.bottom2; - cpsr.mode = nextMode(); + // if we have a valid instruction then use it to annotate this fault with + // extra information. This is used to generate the correct fault syndrome + // information + if (inst) { + ArmStaticInst *armInst = reinterpret_cast<ArmStaticInst *>(inst.get()); + armInst->annotateFault(this); + } + + if (have_security && routeToMonitor(tc)) + cpsr.mode = MODE_MON; + else if (have_virtualization && routeToHyp(tc)) + cpsr.mode = MODE_HYP; + else + cpsr.mode = nextMode(); + + // Ensure Secure state if initially in Monitor mode + if (have_security && saved_cpsr.mode == MODE_MON) { + SCR scr = tc->readMiscRegNoEffect(MISCREG_SCR); + if (scr.ns) { + scr.ns = 0; + tc->setMiscRegNoEffect(MISCREG_SCR, scr); + } + } + + // some bits are set differently if we have been routed to hyp mode + if (cpsr.mode == MODE_HYP) { + SCTLR hsctlr = tc->readMiscReg(MISCREG_HSCTLR); + cpsr.t = hsctlr.te; + cpsr.e = hsctlr.ee; + if (!scr.ea) {cpsr.a = 1;} + if (!scr.fiq) {cpsr.f = 1;} + if (!scr.irq) {cpsr.i = 1;} + } else if (cpsr.mode == MODE_MON) { + // Special case handling when entering monitor mode + cpsr.t = sctlr.te; + cpsr.e = sctlr.ee; + cpsr.a = 1; + cpsr.f = 1; + cpsr.i = 1; + } else { + cpsr.t = sctlr.te; + cpsr.e = sctlr.ee; + + // The *Disable functions are virtual and different per fault + cpsr.a = cpsr.a | abortDisable(tc); + cpsr.f = cpsr.f | fiqDisable(tc); + cpsr.i = 1; + } cpsr.it1 = cpsr.it2 = 0; cpsr.j = 0; - - cpsr.t = sctlr.te; - cpsr.a = cpsr.a | abortDisable(); - cpsr.f = cpsr.f | fiqDisable(); - cpsr.i = 1; - cpsr.e = sctlr.ee; tc->setMiscReg(MISCREG_CPSR, cpsr); + // Make sure mailbox sets to one always tc->setMiscReg(MISCREG_SEV_MAILBOX, 1); - tc->setIntReg(INTREG_LR, curPc + - (saved_cpsr.t ? thumbPcOffset() : armPcOffset())); - switch (nextMode()) { + // Clear the exclusive monitor + tc->setMiscReg(MISCREG_LOCKFLAG, 0); + + if (cpsr.mode == MODE_HYP) { + tc->setMiscReg(MISCREG_ELR_HYP, curPc + + (saved_cpsr.t ? thumbPcOffset(true) : armPcOffset(true))); + } else { + tc->setIntReg(INTREG_LR, curPc + + (saved_cpsr.t ? thumbPcOffset(false) : armPcOffset(false))); + } + + switch (cpsr.mode) { case MODE_FIQ: tc->setMiscReg(MISCREG_SPSR_FIQ, saved_cpsr); break; @@ -143,12 +552,23 @@ ArmFault::invoke(ThreadContext *tc, StaticInstPtr inst) case MODE_SVC: tc->setMiscReg(MISCREG_SPSR_SVC, saved_cpsr); break; - case MODE_UNDEFINED: - tc->setMiscReg(MISCREG_SPSR_UND, saved_cpsr); + case MODE_MON: + assert(have_security); + tc->setMiscReg(MISCREG_SPSR_MON, saved_cpsr); break; case MODE_ABORT: tc->setMiscReg(MISCREG_SPSR_ABT, saved_cpsr); break; + case MODE_UNDEFINED: + tc->setMiscReg(MISCREG_SPSR_UND, saved_cpsr); + if (ec(tc) != EC_UNKNOWN) + setSyndrome(tc, MISCREG_HSR); + break; + case MODE_HYP: + assert(have_virtualization); + tc->setMiscReg(MISCREG_SPSR_HYP, saved_cpsr); + setSyndrome(tc, MISCREG_HSR); + break; default: panic("unknown Mode\n"); } @@ -161,7 +581,100 @@ ArmFault::invoke(ThreadContext *tc, StaticInstPtr inst) pc.nextThumb(pc.thumb()); pc.jazelle(cpsr.j); pc.nextJazelle(pc.jazelle()); + pc.aarch64(!cpsr.width); + pc.nextAArch64(!cpsr.width); + tc->pcState(pc); +} + +void +ArmFault::invoke64(ThreadContext *tc, StaticInstPtr inst) +{ + // Determine actual misc. register indices for ELR_ELx and SPSR_ELx + MiscRegIndex elr_idx, spsr_idx; + switch (toEL) { + case EL1: + elr_idx = MISCREG_ELR_EL1; + spsr_idx = MISCREG_SPSR_EL1; + break; + // @todo: uncomment this to enable Virtualization + // case EL2: + // assert(ArmSystem::haveVirtualization()); + // elr_idx = MISCREG_ELR_EL2; + // spsr_idx = MISCREG_SPSR_EL2; + // break; + case EL3: + assert(ArmSystem::haveSecurity(tc)); + elr_idx = MISCREG_ELR_EL3; + spsr_idx = MISCREG_SPSR_EL3; + break; + default: + panic("Invalid target exception level"); + break; + } + + // Save process state into SPSR_ELx + CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); + CPSR spsr = cpsr; + spsr.nz = tc->readIntReg(INTREG_CONDCODES_NZ); + spsr.c = tc->readIntReg(INTREG_CONDCODES_C); + spsr.v = tc->readIntReg(INTREG_CONDCODES_V); + if (from64) { + // Force some bitfields to 0 + spsr.q = 0; + spsr.it1 = 0; + spsr.j = 0; + spsr.res0_23_22 = 0; + spsr.ge = 0; + spsr.it2 = 0; + spsr.t = 0; + } else { + spsr.ge = tc->readIntReg(INTREG_CONDCODES_GE); + ITSTATE it = tc->pcState().itstate(); + spsr.it2 = it.top6; + spsr.it1 = it.bottom2; + // Force some bitfields to 0 + spsr.res0_23_22 = 0; + spsr.ss = 0; + } + tc->setMiscReg(spsr_idx, spsr); + + // Save preferred return address into ELR_ELx + Addr curr_pc = tc->pcState().pc(); + Addr ret_addr = curr_pc; + if (from64) + ret_addr += armPcElrOffset(); + else + ret_addr += spsr.t ? thumbPcElrOffset() : armPcElrOffset(); + tc->setMiscReg(elr_idx, ret_addr); + + // Update process state + OperatingMode64 mode = 0; + mode.spX = 1; + mode.el = toEL; + mode.width = 0; + cpsr.mode = mode; + cpsr.daif = 0xf; + cpsr.il = 0; + cpsr.ss = 0; + tc->setMiscReg(MISCREG_CPSR, cpsr); + + // Set PC to start of exception handler + Addr new_pc = purifyTaggedAddr(getVector64(tc), tc, toEL); + DPRINTF(Faults, "Invoking Fault (AArch64 target EL):%s cpsr:%#x PC:%#x " + "elr:%#x newVec: %#x\n", name(), cpsr, curr_pc, ret_addr, new_pc); + PCState pc(new_pc); + pc.aarch64(!cpsr.width); + pc.nextAArch64(!cpsr.width); tc->pcState(pc); + + // If we have a valid instruction then use it to annotate this fault with + // extra information. This is used to generate the correct fault syndrome + // information + if (inst) + reinterpret_cast<ArmStaticInst *>(inst.get())->annotateFault(this); + // Save exception syndrome + if ((nextMode() != MODE_IRQ) && (nextMode() != MODE_FIQ)) + setSyndrome(tc, getSyndromeReg64()); } void @@ -171,7 +684,25 @@ Reset::invoke(ThreadContext *tc, StaticInstPtr inst) tc->getCpuPtr()->clearInterrupts(); tc->clearArchRegs(); } - ArmFault::invoke(tc, inst); + if (!ArmSystem::highestELIs64(tc)) { + ArmFault::invoke(tc, inst); + tc->setMiscReg(MISCREG_VMPIDR, + getMPIDR(dynamic_cast<ArmSystem*>(tc->getSystemPtr()), tc)); + + // Unless we have SMC code to get us there, boot in HYP! + if (ArmSystem::haveVirtualization(tc) && + !ArmSystem::haveSecurity(tc)) { + CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); + cpsr.mode = MODE_HYP; + tc->setMiscReg(MISCREG_CPSR, cpsr); + } + } else { + // Advance the PC to the IMPLEMENTATION DEFINED reset value + PCState pc = ArmSystem::resetAddr64(tc); + pc.aarch64(true); + pc.nextAArch64(true); + tc->pcState(pc); + } } void @@ -196,6 +727,45 @@ UndefinedInstruction::invoke(ThreadContext *tc, StaticInstPtr inst) } } +bool +UndefinedInstruction::routeToHyp(ThreadContext *tc) const +{ + bool toHyp; + + SCR scr = tc->readMiscRegNoEffect(MISCREG_SCR); + HCR hcr = tc->readMiscRegNoEffect(MISCREG_HCR); + CPSR cpsr = tc->readMiscRegNoEffect(MISCREG_CPSR); + + // if in Hyp mode then stay in Hyp mode + toHyp = scr.ns && (cpsr.mode == MODE_HYP); + // if HCR.TGE is set to 1, take to Hyp mode through Hyp Trap vector + toHyp |= !inSecureState(scr, cpsr) && hcr.tge && (cpsr.mode == MODE_USER); + return toHyp; +} + +uint32_t +UndefinedInstruction::iss() const +{ + if (overrideEc == EC_INVALID) + return issRaw; + + uint32_t new_iss = 0; + uint32_t op0, op1, op2, CRn, CRm, Rt, dir; + + dir = bits(machInst, 21, 21); + op0 = bits(machInst, 20, 19); + op1 = bits(machInst, 18, 16); + CRn = bits(machInst, 15, 12); + CRm = bits(machInst, 11, 8); + op2 = bits(machInst, 7, 5); + Rt = bits(machInst, 4, 0); + + new_iss = op0 << 20 | op2 << 17 | op1 << 14 | CRn << 10 | + Rt << 5 | CRm << 1 | dir; + + return new_iss; +} + void SupervisorCall::invoke(ThreadContext *tc, StaticInstPtr inst) { @@ -207,7 +777,12 @@ SupervisorCall::invoke(ThreadContext *tc, StaticInstPtr inst) // As of now, there isn't a 32 bit thumb version of this instruction. assert(!machInst.bigThumb); uint32_t callNum; - callNum = tc->readIntReg(INTREG_R7); + CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); + OperatingMode mode = (OperatingMode)(uint8_t)cpsr.mode; + if (opModeIs64(mode)) + callNum = tc->readIntReg(INTREG_X8); + else + callNum = tc->readIntReg(INTREG_R7); tc->syscall(callNum); // Advance the PC since that won't happen automatically. @@ -217,21 +792,593 @@ SupervisorCall::invoke(ThreadContext *tc, StaticInstPtr inst) tc->pcState(pc); } +bool +SupervisorCall::routeToHyp(ThreadContext *tc) const +{ + bool toHyp; + + SCR scr = tc->readMiscRegNoEffect(MISCREG_SCR); + HCR hcr = tc->readMiscRegNoEffect(MISCREG_HCR); + CPSR cpsr = tc->readMiscRegNoEffect(MISCREG_CPSR); + + // if in Hyp mode then stay in Hyp mode + toHyp = scr.ns && (cpsr.mode == MODE_HYP); + // if HCR.TGE is set to 1, take to Hyp mode through Hyp Trap vector + toHyp |= !inSecureState(scr, cpsr) && hcr.tge && (cpsr.mode == MODE_USER); + return toHyp; +} + +ExceptionClass +SupervisorCall::ec(ThreadContext *tc) const +{ + return (overrideEc != EC_INVALID) ? overrideEc : + (from64 ? EC_SVC_64 : vals.ec); +} + +uint32_t +SupervisorCall::iss() const +{ + // Even if we have a 24 bit imm from an arm32 instruction then we only use + // the bottom 16 bits for the ISS value (it doesn't hurt for AArch64 SVC). + return issRaw & 0xFFFF; +} + +uint32_t +SecureMonitorCall::iss() const +{ + if (from64) + return bits(machInst, 20, 5); + return 0; +} + +ExceptionClass +UndefinedInstruction::ec(ThreadContext *tc) const +{ + return (overrideEc != EC_INVALID) ? overrideEc : vals.ec; +} + + +HypervisorCall::HypervisorCall(ExtMachInst _machInst, uint32_t _imm) : + ArmFaultVals<HypervisorCall>(_machInst, _imm) +{} + +ExceptionClass +HypervisorTrap::ec(ThreadContext *tc) const +{ + return (overrideEc != EC_INVALID) ? overrideEc : vals.ec; +} + +template<class T> +FaultOffset +ArmFaultVals<T>::offset(ThreadContext *tc) +{ + bool isHypTrap = false; + + // Normally we just use the exception vector from the table at the top if + // this file, however if this exception has caused a transition to hype + // mode, and its an exception type that would only do this if it has been + // trapped then we use the hyp trap vector instead of the normal vector + if (vals.hypTrappable) { + CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); + if (cpsr.mode == MODE_HYP) { + CPSR spsr = tc->readMiscReg(MISCREG_SPSR_HYP); + isHypTrap = spsr.mode != MODE_HYP; + } + } + return isHypTrap ? 0x14 : vals.offset; +} + +// void +// SupervisorCall::setSyndrome64(ThreadContext *tc, MiscRegIndex esr_idx) +// { +// ESR esr = 0; +// esr.ec = machInst.aarch64 ? SvcAArch64 : SvcAArch32; +// esr.il = !machInst.thumb; +// if (machInst.aarch64) +// esr.imm16 = bits(machInst.instBits, 20, 5); +// else if (machInst.thumb) +// esr.imm16 = bits(machInst.instBits, 7, 0); +// else +// esr.imm16 = bits(machInst.instBits, 15, 0); +// tc->setMiscReg(esr_idx, esr); +// } + +void +SecureMonitorCall::invoke(ThreadContext *tc, StaticInstPtr inst) +{ + if (FullSystem) { + ArmFault::invoke(tc, inst); + return; + } +} + +ExceptionClass +SecureMonitorCall::ec(ThreadContext *tc) const +{ + return (from64 ? EC_SMC_64 : vals.ec); +} + +ExceptionClass +SupervisorTrap::ec(ThreadContext *tc) const +{ + return (overrideEc != EC_INVALID) ? overrideEc : vals.ec; +} + +ExceptionClass +SecureMonitorTrap::ec(ThreadContext *tc) const +{ + return (overrideEc != EC_INVALID) ? overrideEc : + (from64 ? EC_SMC_64 : vals.ec); +} + template<class T> void AbortFault<T>::invoke(ThreadContext *tc, StaticInstPtr inst) { + if (tranMethod == ArmFault::UnknownTran) { + tranMethod = longDescFormatInUse(tc) ? ArmFault::LpaeTran + : ArmFault::VmsaTran; + + if ((tranMethod == ArmFault::VmsaTran) && this->routeToMonitor(tc)) { + // See ARM ARM B3-1416 + bool override_LPAE = false; + TTBCR ttbcr_s = tc->readMiscReg(MISCREG_TTBCR_S); + TTBCR M5_VAR_USED ttbcr_ns = tc->readMiscReg(MISCREG_TTBCR_NS); + if (ttbcr_s.eae) { + override_LPAE = true; + } else { + // Unimplemented code option, not seen in testing. May need + // extension according to the manual exceprt above. + DPRINTF(Faults, "Warning: Incomplete translation method " + "override detected.\n"); + } + if (override_LPAE) + tranMethod = ArmFault::LpaeTran; + } + } + + if (source == ArmFault::AsynchronousExternalAbort) { + tc->getCpuPtr()->clearInterrupt(INT_ABT, 0); + } + // Get effective fault source encoding + CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); + FSR fsr = getFsr(tc); + + // source must be determined BEFORE invoking generic routines which will + // try to set hsr etc. and are based upon source! ArmFaultVals<T>::invoke(tc, inst); + + if (cpsr.width) { // AArch32 + if (cpsr.mode == MODE_HYP) { + tc->setMiscReg(T::HFarIndex, faultAddr); + } else if (stage2) { + tc->setMiscReg(MISCREG_HPFAR, (faultAddr >> 8) & ~0xf); + tc->setMiscReg(T::HFarIndex, OVAddr); + } else { + tc->setMiscReg(T::FsrIndex, fsr); + tc->setMiscReg(T::FarIndex, faultAddr); + } + DPRINTF(Faults, "Abort Fault source=%#x fsr=%#x faultAddr=%#x "\ + "tranMethod=%#x\n", source, fsr, faultAddr, tranMethod); + } else { // AArch64 + // Set the FAR register. Nothing else to do if we are in AArch64 state + // because the syndrome register has already been set inside invoke64() + tc->setMiscReg(AbortFault<T>::getFaultAddrReg64(), faultAddr); + } +} + +template<class T> +FSR +AbortFault<T>::getFsr(ThreadContext *tc) +{ FSR fsr = 0; - fsr.fsLow = bits(status, 3, 0); - fsr.fsHigh = bits(status, 4); - fsr.domain = domain; - fsr.wnr = (write ? 1 : 0); - fsr.ext = 0; - tc->setMiscReg(T::FsrIndex, fsr); - tc->setMiscReg(T::FarIndex, faultAddr); - DPRINTF(Faults, "Abort Fault fsr=%#x faultAddr=%#x\n", fsr, faultAddr); + if (((CPSR) tc->readMiscRegNoEffect(MISCREG_CPSR)).width) { + // AArch32 + assert(tranMethod != ArmFault::UnknownTran); + if (tranMethod == ArmFault::LpaeTran) { + srcEncoded = ArmFault::longDescFaultSources[source]; + fsr.status = srcEncoded; + fsr.lpae = 1; + } else { + srcEncoded = ArmFault::shortDescFaultSources[source]; + fsr.fsLow = bits(srcEncoded, 3, 0); + fsr.fsHigh = bits(srcEncoded, 4); + fsr.domain = static_cast<uint8_t>(domain); + } + fsr.wnr = (write ? 1 : 0); + fsr.ext = 0; + } else { + // AArch64 + srcEncoded = ArmFault::aarch64FaultSources[source]; + } + if (srcEncoded == ArmFault::FaultSourceInvalid) { + panic("Invalid fault source\n"); + } + return fsr; +} + +template<class T> +bool +AbortFault<T>::abortDisable(ThreadContext *tc) +{ + if (ArmSystem::haveSecurity(tc)) { + SCR scr = tc->readMiscRegNoEffect(MISCREG_SCR); + return (!scr.ns || scr.aw); + } + return true; +} + +template<class T> +void +AbortFault<T>::annotate(ArmFault::AnnotationIDs id, uint64_t val) +{ + switch (id) + { + case ArmFault::S1PTW: + s1ptw = val; + break; + case ArmFault::OVA: + OVAddr = val; + break; + + // Just ignore unknown ID's + default: + break; + } +} + +template<class T> +uint32_t +AbortFault<T>::iss() const +{ + uint32_t val; + + val = srcEncoded & 0x3F; + val |= write << 6; + val |= s1ptw << 7; + return (val); +} + +template<class T> +bool +AbortFault<T>::isMMUFault() const +{ + // NOTE: Not relying on LL information being aligned to lowest bits here + return + (source == ArmFault::AlignmentFault) || + ((source >= ArmFault::TranslationLL) && + (source < ArmFault::TranslationLL + 4)) || + ((source >= ArmFault::AccessFlagLL) && + (source < ArmFault::AccessFlagLL + 4)) || + ((source >= ArmFault::DomainLL) && + (source < ArmFault::DomainLL + 4)) || + ((source >= ArmFault::PermissionLL) && + (source < ArmFault::PermissionLL + 4)); +} + +ExceptionClass +PrefetchAbort::ec(ThreadContext *tc) const +{ + if (to64) { + // AArch64 + if (toEL == fromEL) + return EC_PREFETCH_ABORT_CURR_EL; + else + return EC_PREFETCH_ABORT_LOWER_EL; + } else { + // AArch32 + // Abort faults have different EC codes depending on whether + // the fault originated within HYP mode, or not. So override + // the method and add the extra adjustment of the EC value. + + ExceptionClass ec = ArmFaultVals<PrefetchAbort>::vals.ec; + + CPSR spsr = tc->readMiscReg(MISCREG_SPSR_HYP); + if (spsr.mode == MODE_HYP) { + ec = ((ExceptionClass) (((uint32_t) ec) + 1)); + } + return ec; + } +} + +bool +PrefetchAbort::routeToMonitor(ThreadContext *tc) const +{ + SCR scr = 0; + if (from64) + scr = tc->readMiscRegNoEffect(MISCREG_SCR_EL3); + else + scr = tc->readMiscRegNoEffect(MISCREG_SCR); + + return scr.ea && !isMMUFault(); +} + +bool +PrefetchAbort::routeToHyp(ThreadContext *tc) const +{ + bool toHyp; + + SCR scr = tc->readMiscRegNoEffect(MISCREG_SCR); + HCR hcr = tc->readMiscRegNoEffect(MISCREG_HCR); + CPSR cpsr = tc->readMiscRegNoEffect(MISCREG_CPSR); + HDCR hdcr = tc->readMiscRegNoEffect(MISCREG_HDCR); + + // if in Hyp mode then stay in Hyp mode + toHyp = scr.ns && (cpsr.mode == MODE_HYP); + // otherwise, check whether to take to Hyp mode through Hyp Trap vector + toHyp |= (stage2 || + ( (source == DebugEvent) && hdcr.tde && (cpsr.mode != MODE_HYP)) || + ( (source == SynchronousExternalAbort) && hcr.tge && (cpsr.mode == MODE_USER)) + ) && !inSecureState(scr, cpsr); + return toHyp; +} + +ExceptionClass +DataAbort::ec(ThreadContext *tc) const +{ + if (to64) { + // AArch64 + if (source == ArmFault::AsynchronousExternalAbort) { + panic("Asynchronous External Abort should be handled with \ + SystemErrors (SErrors)!"); + } + if (toEL == fromEL) + return EC_DATA_ABORT_CURR_EL; + else + return EC_DATA_ABORT_LOWER_EL; + } else { + // AArch32 + // Abort faults have different EC codes depending on whether + // the fault originated within HYP mode, or not. So override + // the method and add the extra adjustment of the EC value. + + ExceptionClass ec = ArmFaultVals<DataAbort>::vals.ec; + + CPSR spsr = tc->readMiscReg(MISCREG_SPSR_HYP); + if (spsr.mode == MODE_HYP) { + ec = ((ExceptionClass) (((uint32_t) ec) + 1)); + } + return ec; + } +} + +bool +DataAbort::routeToMonitor(ThreadContext *tc) const +{ + SCR scr = 0; + if (from64) + scr = tc->readMiscRegNoEffect(MISCREG_SCR_EL3); + else + scr = tc->readMiscRegNoEffect(MISCREG_SCR); + + return scr.ea && !isMMUFault(); +} + +bool +DataAbort::routeToHyp(ThreadContext *tc) const +{ + bool toHyp; + + SCR scr = tc->readMiscRegNoEffect(MISCREG_SCR); + HCR hcr = tc->readMiscRegNoEffect(MISCREG_HCR); + CPSR cpsr = tc->readMiscRegNoEffect(MISCREG_CPSR); + HDCR hdcr = tc->readMiscRegNoEffect(MISCREG_HDCR); + + // if in Hyp mode then stay in Hyp mode + toHyp = scr.ns && (cpsr.mode == MODE_HYP); + // otherwise, check whether to take to Hyp mode through Hyp Trap vector + toHyp |= (stage2 || + ( (cpsr.mode != MODE_HYP) && ( ((source == AsynchronousExternalAbort) && hcr.amo) || + ((source == DebugEvent) && hdcr.tde) ) + ) || + ( (cpsr.mode == MODE_USER) && hcr.tge && + ((source == AlignmentFault) || + (source == SynchronousExternalAbort)) + ) + ) && !inSecureState(scr, cpsr); + return toHyp; +} + +uint32_t +DataAbort::iss() const +{ + uint32_t val; + + // Add on the data abort specific fields to the generic abort ISS value + val = AbortFault<DataAbort>::iss(); + // ISS is valid if not caused by a stage 1 page table walk, and when taken + // to AArch64 only when directed to EL2 + if (!s1ptw && (!to64 || toEL == EL2)) { + val |= isv << 24; + if (isv) { + val |= sas << 22; + val |= sse << 21; + val |= srt << 16; + // AArch64 only. These assignments are safe on AArch32 as well + // because these vars are initialized to false + val |= sf << 15; + val |= ar << 14; + } + } + return (val); +} + +void +DataAbort::annotate(AnnotationIDs id, uint64_t val) +{ + AbortFault<DataAbort>::annotate(id, val); + switch (id) + { + case SAS: + isv = true; + sas = val; + break; + case SSE: + isv = true; + sse = val; + break; + case SRT: + isv = true; + srt = val; + break; + case SF: + isv = true; + sf = val; + break; + case AR: + isv = true; + ar = val; + break; + // Just ignore unknown ID's + default: + break; + } +} + +void +VirtualDataAbort::invoke(ThreadContext *tc, StaticInstPtr inst) +{ + AbortFault<VirtualDataAbort>::invoke(tc, inst); + HCR hcr = tc->readMiscRegNoEffect(MISCREG_HCR); + hcr.va = 0; + tc->setMiscRegNoEffect(MISCREG_HCR, hcr); +} + +bool +Interrupt::routeToMonitor(ThreadContext *tc) const +{ + assert(ArmSystem::haveSecurity(tc)); + SCR scr = 0; + if (from64) + scr = tc->readMiscRegNoEffect(MISCREG_SCR_EL3); + else + scr = tc->readMiscRegNoEffect(MISCREG_SCR); + return scr.irq; +} + +bool +Interrupt::routeToHyp(ThreadContext *tc) const +{ + bool toHyp; + + SCR scr = tc->readMiscRegNoEffect(MISCREG_SCR); + HCR hcr = tc->readMiscRegNoEffect(MISCREG_HCR); + CPSR cpsr = tc->readMiscRegNoEffect(MISCREG_CPSR); + // Determine whether IRQs are routed to Hyp mode. + toHyp = (!scr.irq && hcr.imo && !inSecureState(scr, cpsr)) || + (cpsr.mode == MODE_HYP); + return toHyp; +} + +bool +Interrupt::abortDisable(ThreadContext *tc) +{ + if (ArmSystem::haveSecurity(tc)) { + SCR scr = tc->readMiscRegNoEffect(MISCREG_SCR); + return (!scr.ns || scr.aw); + } + return true; +} + +VirtualInterrupt::VirtualInterrupt() +{} + +bool +FastInterrupt::routeToMonitor(ThreadContext *tc) const +{ + assert(ArmSystem::haveSecurity(tc)); + SCR scr = 0; + if (from64) + scr = tc->readMiscRegNoEffect(MISCREG_SCR_EL3); + else + scr = tc->readMiscRegNoEffect(MISCREG_SCR); + return scr.fiq; +} + +bool +FastInterrupt::routeToHyp(ThreadContext *tc) const +{ + bool toHyp; + + SCR scr = tc->readMiscRegNoEffect(MISCREG_SCR); + HCR hcr = tc->readMiscRegNoEffect(MISCREG_HCR); + CPSR cpsr = tc->readMiscRegNoEffect(MISCREG_CPSR); + // Determine whether IRQs are routed to Hyp mode. + toHyp = (!scr.fiq && hcr.fmo && !inSecureState(scr, cpsr)) || + (cpsr.mode == MODE_HYP); + return toHyp; +} + +bool +FastInterrupt::abortDisable(ThreadContext *tc) +{ + if (ArmSystem::haveSecurity(tc)) { + SCR scr = tc->readMiscRegNoEffect(MISCREG_SCR); + return (!scr.ns || scr.aw); + } + return true; +} + +bool +FastInterrupt::fiqDisable(ThreadContext *tc) +{ + if (ArmSystem::haveVirtualization(tc)) { + return true; + } else if (ArmSystem::haveSecurity(tc)) { + SCR scr = tc->readMiscRegNoEffect(MISCREG_SCR); + return (!scr.ns || scr.fw); + } + return true; +} + +VirtualFastInterrupt::VirtualFastInterrupt() +{} + +void +PCAlignmentFault::invoke(ThreadContext *tc, StaticInstPtr inst) +{ + ArmFaultVals<PCAlignmentFault>::invoke(tc, inst); + assert(from64); + // Set the FAR + tc->setMiscReg(getFaultAddrReg64(), faultPC); +} + +SPAlignmentFault::SPAlignmentFault() +{} + +SystemError::SystemError() +{} + +void +SystemError::invoke(ThreadContext *tc, StaticInstPtr inst) +{ + tc->getCpuPtr()->clearInterrupt(INT_ABT, 0); + ArmFault::invoke(tc, inst); +} + +bool +SystemError::routeToMonitor(ThreadContext *tc) const +{ + assert(ArmSystem::haveSecurity(tc)); + assert(from64); + SCR scr = tc->readMiscRegNoEffect(MISCREG_SCR_EL3); + return scr.ea; +} + +bool +SystemError::routeToHyp(ThreadContext *tc) const +{ + bool toHyp; + assert(from64); + + SCR scr = tc->readMiscRegNoEffect(MISCREG_SCR_EL3); + HCR hcr = tc->readMiscRegNoEffect(MISCREG_HCR); + CPSR cpsr = tc->readMiscRegNoEffect(MISCREG_CPSR); + + toHyp = (!scr.ea && hcr.amo && !inSecureState(scr, cpsr)) || + (!scr.ea && !scr.rw && !hcr.amo && !inSecureState(scr,cpsr)); + return toHyp; } void @@ -247,11 +1394,6 @@ FlushPipe::invoke(ThreadContext *tc, StaticInstPtr inst) { tc->pcState(pc); } -template void AbortFault<PrefetchAbort>::invoke(ThreadContext *tc, - StaticInstPtr inst); -template void AbortFault<DataAbort>::invoke(ThreadContext *tc, - StaticInstPtr inst); - void ArmSev::invoke(ThreadContext *tc, StaticInstPtr inst) { DPRINTF(Faults, "Invoking ArmSev Fault\n"); @@ -265,6 +1407,34 @@ ArmSev::invoke(ThreadContext *tc, StaticInstPtr inst) { tc->getCpuPtr()->clearInterrupt(INT_SEV, 0); } -// return via SUBS pc, lr, xxx; rfe, movs, ldm +// Instantiate all the templates to make the linker happy +template class ArmFaultVals<Reset>; +template class ArmFaultVals<UndefinedInstruction>; +template class ArmFaultVals<SupervisorCall>; +template class ArmFaultVals<SecureMonitorCall>; +template class ArmFaultVals<HypervisorCall>; +template class ArmFaultVals<PrefetchAbort>; +template class ArmFaultVals<DataAbort>; +template class ArmFaultVals<VirtualDataAbort>; +template class ArmFaultVals<HypervisorTrap>; +template class ArmFaultVals<Interrupt>; +template class ArmFaultVals<VirtualInterrupt>; +template class ArmFaultVals<FastInterrupt>; +template class ArmFaultVals<VirtualFastInterrupt>; +template class ArmFaultVals<SupervisorTrap>; +template class ArmFaultVals<SecureMonitorTrap>; +template class ArmFaultVals<PCAlignmentFault>; +template class ArmFaultVals<SPAlignmentFault>; +template class ArmFaultVals<SystemError>; +template class ArmFaultVals<FlushPipe>; +template class ArmFaultVals<ArmSev>; +template class AbortFault<PrefetchAbort>; +template class AbortFault<DataAbort>; +template class AbortFault<VirtualDataAbort>; + + +IllegalInstSetStateFault::IllegalInstSetStateFault() +{} + } // namespace ArmISA diff --git a/src/arch/arm/faults.hh b/src/arch/arm/faults.hh index 9858e52ef..a5720f115 100644 --- a/src/arch/arm/faults.hh +++ b/src/arch/arm/faults.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010, 2012-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -40,12 +40,15 @@ * * Authors: Ali Saidi * Gabe Black + * Giacomo Gabrielli + * Thomas Grocutt */ #ifndef __ARM_FAULTS_HH__ #define __ARM_FAULTS_HH__ #include "arch/arm/miscregs.hh" +#include "arch/arm/pagetable.hh" #include "arch/arm/types.hh" #include "base/misc.hh" #include "sim/faults.hh" @@ -60,63 +63,146 @@ typedef const Addr FaultOffset; class ArmFault : public FaultBase { protected: + ExtMachInst machInst; + uint32_t issRaw; + + // Helper variables for ARMv8 exception handling + bool from64; // True if the exception is generated from the AArch64 state + bool to64; // True if the exception is taken in AArch64 state + ExceptionLevel fromEL; // Source exception level + ExceptionLevel toEL; // Target exception level + OperatingMode fromMode; // Source operating mode + Addr getVector(ThreadContext *tc); + Addr getVector64(ThreadContext *tc); public: - enum StatusEncoding + /// Generic fault source enums used to index into + /// {short/long/aarch64}DescFaultSources[] to get the actual encodings based + /// on the current register width state and the translation table format in + /// use + enum FaultSource { - // Fault Status register encodings - // ARM ARM B3.9.4 - AlignmentFault = 0x1, - DebugEvent = 0x2, - AccessFlag0 = 0x3, - InstructionCacheMaintenance = 0x4, - Translation0 = 0x5, - AccessFlag1 = 0x6, - Translation1 = 0x7, - SynchronousExternalAbort0 = 0x8, - Domain0 = 0x9, - SynchronousExternalAbort1 = 0x8, - Domain1 = 0xb, - TranslationTableWalkExtAbt0 = 0xc, - Permission0 = 0xd, - TranslationTableWalkExtAbt1 = 0xe, - Permission1 = 0xf, - AsynchronousExternalAbort = 0x16, - MemoryAccessAsynchronousParityError = 0x18, - MemoryAccessSynchronousParityError = 0x19, - TranslationTableWalkPrtyErr0 = 0x1c, - TranslationTableWalkPrtyErr1 = 0x1e, - - // not a real fault. This is a status code - // to allow the translation function to inform - // the memory access function not to proceed - // for a Prefetch that misses in the TLB. - PrefetchTLBMiss = 0x1f, - PrefetchUncacheable = 0x20 + AlignmentFault = 0, + InstructionCacheMaintenance, // Short-desc. format only + SynchExtAbtOnTranslTableWalkLL, + SynchPtyErrOnTranslTableWalkLL = SynchExtAbtOnTranslTableWalkLL + 4, + TranslationLL = SynchPtyErrOnTranslTableWalkLL + 4, + AccessFlagLL = TranslationLL + 4, + DomainLL = AccessFlagLL + 4, + PermissionLL = DomainLL + 4, + DebugEvent = PermissionLL + 4, + SynchronousExternalAbort, + TLBConflictAbort, // Requires LPAE + SynchPtyErrOnMemoryAccess, + AsynchronousExternalAbort, + AsynchPtyErrOnMemoryAccess, + AddressSizeLL, // AArch64 only + + // Not real faults. These are faults to allow the translation function + // to inform the memory access function not to proceed for a prefetch + // that misses in the TLB or that targets an uncacheable address + PrefetchTLBMiss = AddressSizeLL + 4, + PrefetchUncacheable, + + NumFaultSources, + FaultSourceInvalid = 0xff + }; + + /// Encodings of the fault sources when the short-desc. translation table + /// format is in use (ARM ARM Issue C B3.13.3) + static uint8_t shortDescFaultSources[NumFaultSources]; + /// Encodings of the fault sources when the long-desc. translation table + /// format is in use (ARM ARM Issue C B3.13.3) + static uint8_t longDescFaultSources[NumFaultSources]; + /// Encodings of the fault sources in AArch64 state + static uint8_t aarch64FaultSources[NumFaultSources]; + + enum AnnotationIDs + { + S1PTW, // DataAbort, PrefetchAbort: Stage 1 Page Table Walk, + OVA, // DataAbort, PrefetchAbort: stage 1 Virtual Address for stage 2 faults + SAS, // DataAbort: Syndrome Access Size + SSE, // DataAbort: Syndrome Sign Extend + SRT, // DataAbort: Syndrome Register Transfer + + // AArch64 only + SF, // DataAbort: width of the accessed register is SixtyFour + AR // DataAbort: Acquire/Release semantics + }; + + enum TranMethod + { + LpaeTran, + VmsaTran, + UnknownTran }; struct FaultVals { const FaultName name; + const FaultOffset offset; + + // Offsets used for exceptions taken in AArch64 state + const uint16_t currELTOffset; + const uint16_t currELHOffset; + const uint16_t lowerEL64Offset; + const uint16_t lowerEL32Offset; + const OperatingMode nextMode; + const uint8_t armPcOffset; const uint8_t thumbPcOffset; + // The following two values are used in place of armPcOffset and + // thumbPcOffset when the exception return address is saved into ELR + // registers (exceptions taken in HYP mode or in AArch64 state) + const uint8_t armPcElrOffset; + const uint8_t thumbPcElrOffset; + + const bool hypTrappable; const bool abortDisable; const bool fiqDisable; + + // Exception class used to appropriately set the syndrome register + // (exceptions taken in HYP mode or in AArch64 state) + const ExceptionClass ec; + FaultStat count; }; + ArmFault(ExtMachInst _machInst = 0, uint32_t _iss = 0) : + machInst(_machInst), issRaw(_iss), from64(false), to64(false) {} + + // Returns the actual syndrome register to use based on the target + // exception level + MiscRegIndex getSyndromeReg64() const; + // Returns the actual fault address register to use based on the target + // exception level + MiscRegIndex getFaultAddrReg64() const; + void invoke(ThreadContext *tc, StaticInstPtr inst = StaticInst::nullStaticInstPtr); + void invoke64(ThreadContext *tc, + StaticInstPtr inst = StaticInst::nullStaticInstPtr); + virtual void annotate(AnnotationIDs id, uint64_t val) {} virtual FaultStat& countStat() = 0; - virtual FaultOffset offset() = 0; + virtual FaultOffset offset(ThreadContext *tc) = 0; + virtual FaultOffset offset64() = 0; virtual OperatingMode nextMode() = 0; - virtual uint8_t armPcOffset() = 0; - virtual uint8_t thumbPcOffset() = 0; - virtual bool abortDisable() = 0; - virtual bool fiqDisable() = 0; + virtual bool routeToMonitor(ThreadContext *tc) const = 0; + virtual bool routeToHyp(ThreadContext *tc) const { return false; } + virtual uint8_t armPcOffset(bool isHyp) = 0; + virtual uint8_t thumbPcOffset(bool isHyp) = 0; + virtual uint8_t armPcElrOffset() = 0; + virtual uint8_t thumbPcElrOffset() = 0; + virtual bool abortDisable(ThreadContext *tc) = 0; + virtual bool fiqDisable(ThreadContext *tc) = 0; + virtual ExceptionClass ec(ThreadContext *tc) const = 0; + virtual uint32_t iss() const = 0; + virtual bool isStage2() const { return false; } + virtual FSR getFsr(ThreadContext *tc) { return 0; } + virtual void setSyndrome(ThreadContext *tc, MiscRegIndex syndrome_reg); }; template<typename T> @@ -126,14 +212,38 @@ class ArmFaultVals : public ArmFault static FaultVals vals; public: + ArmFaultVals<T>(ExtMachInst _machInst = 0, uint32_t _iss = 0) : + ArmFault(_machInst, _iss) {} FaultName name() const { return vals.name; } - FaultStat & countStat() {return vals.count;} - FaultOffset offset() { return vals.offset; } + FaultStat & countStat() { return vals.count; } + FaultOffset offset(ThreadContext *tc); + + FaultOffset + offset64() + { + if (toEL == fromEL) { + if (opModeIsT(fromMode)) + return vals.currELTOffset; + return vals.currELHOffset; + } else { + if (from64) + return vals.lowerEL64Offset; + return vals.lowerEL32Offset; + } + } + OperatingMode nextMode() { return vals.nextMode; } - uint8_t armPcOffset() { return vals.armPcOffset; } - uint8_t thumbPcOffset() { return vals.thumbPcOffset; } - bool abortDisable() { return vals.abortDisable; } - bool fiqDisable() { return vals.fiqDisable; } + virtual bool routeToMonitor(ThreadContext *tc) const { return false; } + uint8_t armPcOffset(bool isHyp) { return isHyp ? vals.armPcElrOffset + : vals.armPcOffset; } + uint8_t thumbPcOffset(bool isHyp) { return isHyp ? vals.thumbPcElrOffset + : vals.thumbPcOffset; } + uint8_t armPcElrOffset() { return vals.armPcElrOffset; } + uint8_t thumbPcElrOffset() { return vals.thumbPcElrOffset; } + virtual bool abortDisable(ThreadContext* tc) { return vals.abortDisable; } + virtual bool fiqDisable(ThreadContext* tc) { return vals.fiqDisable; } + virtual ExceptionClass ec(ThreadContext *tc) const { return vals.ec; } + virtual uint32_t iss() const { return issRaw; } }; class Reset : public ArmFaultVals<Reset> @@ -146,87 +256,283 @@ class Reset : public ArmFaultVals<Reset> class UndefinedInstruction : public ArmFaultVals<UndefinedInstruction> { protected: - ExtMachInst machInst; bool unknown; const char *mnemonic; bool disabled; + ExceptionClass overrideEc; public: UndefinedInstruction(ExtMachInst _machInst, bool _unknown, const char *_mnemonic = NULL, bool _disabled = false) : - machInst(_machInst), unknown(_unknown), - mnemonic(_mnemonic), disabled(_disabled) - { - } - UndefinedInstruction() : - machInst(0), unknown(false), mnemonic("undefined"), disabled(false) + ArmFaultVals<UndefinedInstruction>(_machInst), + unknown(_unknown), mnemonic(_mnemonic), disabled(_disabled), + overrideEc(EC_INVALID) + {} + UndefinedInstruction(ExtMachInst _machInst, uint32_t _iss, ExceptionClass _overrideEc) : + ArmFaultVals<UndefinedInstruction>(_machInst, _iss), + overrideEc(_overrideEc) {} void invoke(ThreadContext *tc, StaticInstPtr inst = StaticInst::nullStaticInstPtr); + bool routeToHyp(ThreadContext *tc) const; + ExceptionClass ec(ThreadContext *tc) const; + uint32_t iss() const; }; class SupervisorCall : public ArmFaultVals<SupervisorCall> { protected: - ExtMachInst machInst; - + ExceptionClass overrideEc; public: - SupervisorCall(ExtMachInst _machInst) : machInst(_machInst) + SupervisorCall(ExtMachInst _machInst, uint32_t _iss, + ExceptionClass _overrideEc = EC_INVALID) : + ArmFaultVals<SupervisorCall>(_machInst, _iss), + overrideEc(_overrideEc) {} - SupervisorCall() : machInst(0) + + void invoke(ThreadContext *tc, + StaticInstPtr inst = StaticInst::nullStaticInstPtr); + bool routeToHyp(ThreadContext *tc) const; + ExceptionClass ec(ThreadContext *tc) const; + uint32_t iss() const; +}; + +class SecureMonitorCall : public ArmFaultVals<SecureMonitorCall> +{ + public: + SecureMonitorCall(ExtMachInst _machInst) : + ArmFaultVals<SecureMonitorCall>(_machInst) {} void invoke(ThreadContext *tc, StaticInstPtr inst = StaticInst::nullStaticInstPtr); + ExceptionClass ec(ThreadContext *tc) const; + uint32_t iss() const; +}; + +class SupervisorTrap : public ArmFaultVals<SupervisorTrap> +{ + protected: + ExtMachInst machInst; + ExceptionClass overrideEc; + + public: + SupervisorTrap(ExtMachInst _machInst, uint32_t _iss, + ExceptionClass _overrideEc = EC_INVALID) : + ArmFaultVals<SupervisorTrap>(_machInst, _iss), + overrideEc(_overrideEc) + {} + + ExceptionClass ec(ThreadContext *tc) const; +}; + +class SecureMonitorTrap : public ArmFaultVals<SecureMonitorTrap> +{ + protected: + ExtMachInst machInst; + ExceptionClass overrideEc; + + public: + SecureMonitorTrap(ExtMachInst _machInst, uint32_t _iss, + ExceptionClass _overrideEc = EC_INVALID) : + ArmFaultVals<SecureMonitorTrap>(_machInst, _iss), + overrideEc(_overrideEc) + {} + + ExceptionClass ec(ThreadContext *tc) const; +}; + +class HypervisorCall : public ArmFaultVals<HypervisorCall> +{ + public: + HypervisorCall(ExtMachInst _machInst, uint32_t _imm); +}; + +class HypervisorTrap : public ArmFaultVals<HypervisorTrap> +{ + protected: + ExtMachInst machInst; + ExceptionClass overrideEc; + + public: + HypervisorTrap(ExtMachInst _machInst, uint32_t _iss, + ExceptionClass _overrideEc = EC_INVALID) : + ArmFaultVals<HypervisorTrap>(_machInst, _iss), + overrideEc(_overrideEc) + {} + + ExceptionClass ec(ThreadContext *tc) const; }; template <class T> class AbortFault : public ArmFaultVals<T> { protected: + /** + * The virtual address the fault occured at. If 2 stages of + * translation are being used then this is the intermediate + * physical address that is the starting point for the second + * stage of translation. + */ Addr faultAddr; + /** + * Original virtual address. If the fault was generated on the + * second stage of translation then this variable stores the + * virtual address used in the original stage 1 translation. + */ + Addr OVAddr; bool write; - uint8_t domain; - uint8_t status; + TlbEntry::DomainType domain; + uint8_t source; + uint8_t srcEncoded; + bool stage2; + bool s1ptw; + ArmFault::TranMethod tranMethod; public: - AbortFault(Addr _faultAddr, bool _write, - uint8_t _domain, uint8_t _status) : - faultAddr(_faultAddr), write(_write), - domain(_domain), status(_status) + AbortFault(Addr _faultAddr, bool _write, TlbEntry::DomainType _domain, uint8_t _source, + bool _stage2, ArmFault::TranMethod _tranMethod = ArmFault::UnknownTran) : + faultAddr(_faultAddr), write(_write), domain(_domain), source(_source), + stage2(_stage2), s1ptw(false), tranMethod(_tranMethod) {} void invoke(ThreadContext *tc, StaticInstPtr inst = StaticInst::nullStaticInstPtr); + + FSR getFsr(ThreadContext *tc); + bool abortDisable(ThreadContext *tc); + uint32_t iss() const; + bool isStage2() const { return stage2; } + void annotate(ArmFault::AnnotationIDs id, uint64_t val); + bool isMMUFault() const; }; class PrefetchAbort : public AbortFault<PrefetchAbort> { public: - static const MiscRegIndex FsrIndex = MISCREG_IFSR; - static const MiscRegIndex FarIndex = MISCREG_IFAR; + static const MiscRegIndex FsrIndex = MISCREG_IFSR; + static const MiscRegIndex FarIndex = MISCREG_IFAR; + static const MiscRegIndex HFarIndex = MISCREG_HIFAR; - PrefetchAbort(Addr _addr, uint8_t _status) : - AbortFault<PrefetchAbort>(_addr, false, 0, _status) + PrefetchAbort(Addr _addr, uint8_t _source, bool _stage2 = false, + ArmFault::TranMethod _tranMethod = ArmFault::UnknownTran) : + AbortFault<PrefetchAbort>(_addr, false, TlbEntry::DomainType::NoAccess, + _source, _stage2, _tranMethod) {} + + ExceptionClass ec(ThreadContext *tc) const; + // @todo: external aborts should be routed if SCR.EA == 1 + bool routeToMonitor(ThreadContext *tc) const; + bool routeToHyp(ThreadContext *tc) const; }; class DataAbort : public AbortFault<DataAbort> { public: - static const MiscRegIndex FsrIndex = MISCREG_DFSR; - static const MiscRegIndex FarIndex = MISCREG_DFAR; + static const MiscRegIndex FsrIndex = MISCREG_DFSR; + static const MiscRegIndex FarIndex = MISCREG_DFAR; + static const MiscRegIndex HFarIndex = MISCREG_HDFAR; + bool isv; + uint8_t sas; + uint8_t sse; + uint8_t srt; + + // AArch64 only + bool sf; + bool ar; + + DataAbort(Addr _addr, TlbEntry::DomainType _domain, bool _write, uint8_t _source, + bool _stage2 = false, ArmFault::TranMethod _tranMethod = ArmFault::UnknownTran) : + AbortFault<DataAbort>(_addr, _write, _domain, _source, _stage2, + _tranMethod), + isv(false), sas (0), sse(0), srt(0), sf(false), ar(false) + {} + + ExceptionClass ec(ThreadContext *tc) const; + // @todo: external aborts should be routed if SCR.EA == 1 + bool routeToMonitor(ThreadContext *tc) const; + bool routeToHyp(ThreadContext *tc) const; + uint32_t iss() const; + void annotate(AnnotationIDs id, uint64_t val); +}; + +class VirtualDataAbort : public AbortFault<VirtualDataAbort> +{ + public: + static const MiscRegIndex FsrIndex = MISCREG_DFSR; + static const MiscRegIndex FarIndex = MISCREG_DFAR; + static const MiscRegIndex HFarIndex = MISCREG_HDFAR; - DataAbort(Addr _addr, uint8_t _domain, bool _write, uint8_t _status) : - AbortFault<DataAbort>(_addr, _write, _domain, _status) + VirtualDataAbort(Addr _addr, TlbEntry::DomainType _domain, bool _write, + uint8_t _source) : + AbortFault<VirtualDataAbort>(_addr, _write, _domain, _source, false) {} + + void invoke(ThreadContext *tc, StaticInstPtr inst); }; -class Interrupt : public ArmFaultVals<Interrupt> {}; -class FastInterrupt : public ArmFaultVals<FastInterrupt> {}; +class Interrupt : public ArmFaultVals<Interrupt> +{ + public: + bool routeToMonitor(ThreadContext *tc) const; + bool routeToHyp(ThreadContext *tc) const; + bool abortDisable(ThreadContext *tc); +}; + +class VirtualInterrupt : public ArmFaultVals<VirtualInterrupt> +{ + public: + VirtualInterrupt(); +}; + +class FastInterrupt : public ArmFaultVals<FastInterrupt> +{ + public: + bool routeToMonitor(ThreadContext *tc) const; + bool routeToHyp(ThreadContext *tc) const; + bool abortDisable(ThreadContext *tc); + bool fiqDisable(ThreadContext *tc); +}; + +class VirtualFastInterrupt : public ArmFaultVals<VirtualFastInterrupt> +{ + public: + VirtualFastInterrupt(); +}; + +/// PC alignment fault (AArch64 only) +class PCAlignmentFault : public ArmFaultVals<PCAlignmentFault> +{ + protected: + /// The unaligned value of the PC + Addr faultPC; + public: + PCAlignmentFault(Addr _faultPC) : faultPC(_faultPC) + {} + void invoke(ThreadContext *tc, + StaticInstPtr inst = StaticInst::nullStaticInstPtr); +}; + +/// Stack pointer alignment fault (AArch64 only) +class SPAlignmentFault : public ArmFaultVals<SPAlignmentFault> +{ + public: + SPAlignmentFault(); +}; + +/// System error (AArch64 only) +class SystemError : public ArmFaultVals<SystemError> +{ + public: + SystemError(); + void invoke(ThreadContext *tc, + StaticInstPtr inst = StaticInst::nullStaticInstPtr); + bool routeToMonitor(ThreadContext *tc) const; + bool routeToHyp(ThreadContext *tc) const; +}; // A fault that flushes the pipe, excluding the faulting instructions class FlushPipe : public ArmFaultVals<FlushPipe> @@ -246,6 +552,13 @@ class ArmSev : public ArmFaultVals<ArmSev> StaticInstPtr inst = StaticInst::nullStaticInstPtr); }; +/// Illegal Instruction Set State fault (AArch64 only) +class IllegalInstSetStateFault : public ArmFaultVals<IllegalInstSetStateFault> +{ + public: + IllegalInstSetStateFault(); +}; + } // namespace ArmISA #endif // __ARM_FAULTS_HH__ diff --git a/src/arch/arm/insts/branch64.cc b/src/arch/arm/insts/branch64.cc new file mode 100644 index 000000000..49ba3402a --- /dev/null +++ b/src/arch/arm/insts/branch64.cc @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2011-2013 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "arch/arm/insts/branch64.hh" + +namespace ArmISA +{ + +ArmISA::PCState +BranchImm64::branchTarget(const ArmISA::PCState &branchPC) const +{ + ArmISA::PCState pcs = branchPC; + pcs.instNPC(pcs.pc() + imm); + pcs.advance(); + return pcs; +} + +ArmISA::PCState +BranchImmReg64::branchTarget(const ArmISA::PCState &branchPC) const +{ + ArmISA::PCState pcs = branchPC; + pcs.instNPC(pcs.pc() + imm); + pcs.advance(); + return pcs; +} + +ArmISA::PCState +BranchImmImmReg64::branchTarget(const ArmISA::PCState &branchPC) const +{ + ArmISA::PCState pcs = branchPC; + pcs.instNPC(pcs.pc() + imm2); + pcs.advance(); + return pcs; +} + +std::string +BranchImmCond64::generateDisassembly( + Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss, "", false, true, condCode); + printTarget(ss, pc + imm, symtab); + return ss.str(); +} + +std::string +BranchImm64::generateDisassembly( + Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss, "", false); + printTarget(ss, pc + imm, symtab); + return ss.str(); +} + +std::string +BranchReg64::generateDisassembly( + Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss, "", false); + printReg(ss, op1); + return ss.str(); +} + +std::string +BranchRet64::generateDisassembly( + Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss, "", false); + if (op1 != INTREG_X30) + printReg(ss, op1); + return ss.str(); +} + +std::string +BranchEret64::generateDisassembly( + Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss, "", false); + return ss.str(); +} + +std::string +BranchImmReg64::generateDisassembly( + Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss, "", false); + printReg(ss, op1); + ccprintf(ss, ", "); + printTarget(ss, pc + imm, symtab); + return ss.str(); +} + +std::string +BranchImmImmReg64::generateDisassembly( + Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss, "", false); + printReg(ss, op1); + ccprintf(ss, ", #%#x, ", imm1); + printTarget(ss, pc + imm2, symtab); + return ss.str(); +} + +} // namespace ArmISA diff --git a/src/arch/arm/insts/branch64.hh b/src/arch/arm/insts/branch64.hh new file mode 100644 index 000000000..48881e0c2 --- /dev/null +++ b/src/arch/arm/insts/branch64.hh @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2011-2013 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ +#ifndef __ARCH_ARM_INSTS_BRANCH64_HH__ +#define __ARCH_ARM_INSTS_BRANCH64_HH__ + +#include "arch/arm/insts/static_inst.hh" + +namespace ArmISA +{ +// Branch to a target computed with an immediate +class BranchImm64 : public ArmStaticInst +{ + protected: + int64_t imm; + + public: + BranchImm64(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + int64_t _imm) : + ArmStaticInst(mnem, _machInst, __opClass), imm(_imm) + {} + + ArmISA::PCState branchTarget(const ArmISA::PCState &branchPC) const; + + /// Explicitly import the otherwise hidden branchTarget + using StaticInst::branchTarget; + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +// Conditionally Branch to a target computed with an immediate +class BranchImmCond64 : public BranchImm64 +{ + protected: + ConditionCode condCode; + + public: + BranchImmCond64(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + int64_t _imm, ConditionCode _condCode) : + BranchImm64(mnem, _machInst, __opClass, _imm), condCode(_condCode) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +// Branch to a target computed with a register +class BranchReg64 : public ArmStaticInst +{ + protected: + IntRegIndex op1; + + public: + BranchReg64(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + IntRegIndex _op1) : + ArmStaticInst(mnem, _machInst, __opClass), op1(_op1) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +// Ret instruction +class BranchRet64 : public BranchReg64 +{ + public: + BranchRet64(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + IntRegIndex _op1) : + BranchReg64(mnem, _machInst, __opClass, _op1) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +// Eret instruction +class BranchEret64 : public ArmStaticInst +{ + public: + BranchEret64(const char *mnem, ExtMachInst _machInst, OpClass __opClass) : + ArmStaticInst(mnem, _machInst, __opClass) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +// Branch to a target computed with an immediate and a register +class BranchImmReg64 : public ArmStaticInst +{ + protected: + int64_t imm; + IntRegIndex op1; + + public: + BranchImmReg64(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + int64_t _imm, IntRegIndex _op1) : + ArmStaticInst(mnem, _machInst, __opClass), imm(_imm), op1(_op1) + {} + + ArmISA::PCState branchTarget(const ArmISA::PCState &branchPC) const; + + /// Explicitly import the otherwise hidden branchTarget + using StaticInst::branchTarget; + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +// Branch to a target computed with two immediates +class BranchImmImmReg64 : public ArmStaticInst +{ + protected: + int64_t imm1; + int64_t imm2; + IntRegIndex op1; + + public: + BranchImmImmReg64(const char *mnem, ExtMachInst _machInst, + OpClass __opClass, int64_t _imm1, int64_t _imm2, + IntRegIndex _op1) : + ArmStaticInst(mnem, _machInst, __opClass), + imm1(_imm1), imm2(_imm2), op1(_op1) + {} + + ArmISA::PCState branchTarget(const ArmISA::PCState &branchPC) const; + + /// Explicitly import the otherwise hidden branchTarget + using StaticInst::branchTarget; + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +} + +#endif //__ARCH_ARM_INSTS_BRANCH_HH__ diff --git a/src/arch/arm/insts/data64.cc b/src/arch/arm/insts/data64.cc new file mode 100644 index 000000000..f65219870 --- /dev/null +++ b/src/arch/arm/insts/data64.cc @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2011-2013 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "arch/arm/insts/data64.hh" + +namespace ArmISA +{ + +std::string +DataXImmOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printDataInst(ss, true, false, /*XXX not really s*/ false, dest, op1, + INTREG_ZERO, INTREG_ZERO, 0, LSL, imm); + return ss.str(); +} + +std::string +DataXImmOnlyOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss, "", false); + printReg(ss, dest); + ccprintf(ss, ", #%d", imm); + return ss.str(); +} + +std::string +DataXSRegOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printDataInst(ss, false, true, /*XXX not really s*/ false, dest, op1, + op2, INTREG_ZERO, shiftAmt, shiftType, 0); + return ss.str(); +} + +std::string +DataXERegOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printDataInst(ss, false, true, /*XXX not really s*/ false, dest, op1, + op2, INTREG_ZERO, shiftAmt, LSL, 0); + return ss.str(); +} + +std::string +DataX1RegOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss, "", false); + printReg(ss, dest); + ccprintf(ss, ", "); + printReg(ss, op1); + return ss.str(); +} + +std::string +DataX1RegImmOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss, "", false); + printReg(ss, dest); + ccprintf(ss, ", "); + printReg(ss, op1); + ccprintf(ss, ", #%d", imm); + return ss.str(); +} + +std::string +DataX1Reg2ImmOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss, "", false); + printReg(ss, dest); + ccprintf(ss, ", "); + printReg(ss, op1); + ccprintf(ss, ", #%d, #%d", imm1, imm2); + return ss.str(); +} + +std::string +DataX2RegOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss, "", false); + printReg(ss, dest); + ccprintf(ss, ", "); + printReg(ss, op1); + ccprintf(ss, ", "); + printReg(ss, op2); + return ss.str(); +} + +std::string +DataX2RegImmOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss, "", false); + printReg(ss, dest); + ccprintf(ss, ", "); + printReg(ss, op1); + ccprintf(ss, ", "); + printReg(ss, op2); + ccprintf(ss, ", #%d", imm); + return ss.str(); +} + +std::string +DataX3RegOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss, "", false); + printReg(ss, dest); + ccprintf(ss, ", "); + printReg(ss, op1); + ccprintf(ss, ", "); + printReg(ss, op2); + ccprintf(ss, ", "); + printReg(ss, op3); + return ss.str(); +} + +std::string +DataXCondCompImmOp::generateDisassembly( + Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss, "", false); + printReg(ss, op1); + ccprintf(ss, ", #%d, #%d", imm, defCc); + ccprintf(ss, ", "); + printCondition(ss, condCode, true); + return ss.str(); +} + +std::string +DataXCondCompRegOp::generateDisassembly( + Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss, "", false); + printReg(ss, op1); + ccprintf(ss, ", "); + printReg(ss, op2); + ccprintf(ss, ", #%d", defCc); + ccprintf(ss, ", "); + printCondition(ss, condCode, true); + return ss.str(); +} + +std::string +DataXCondSelOp::generateDisassembly( + Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss, "", false); + printReg(ss, dest); + ccprintf(ss, ", "); + printReg(ss, op1); + ccprintf(ss, ", "); + printReg(ss, op2); + ccprintf(ss, ", "); + printCondition(ss, condCode, true); + return ss.str(); +} + +} diff --git a/src/arch/arm/insts/data64.hh b/src/arch/arm/insts/data64.hh new file mode 100644 index 000000000..8c0677b3d --- /dev/null +++ b/src/arch/arm/insts/data64.hh @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2011-2013 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ +#ifndef __ARCH_ARM_INSTS_DATA64_HH__ +#define __ARCH_ARM_INSTS_DATA64_HH__ + +#include "arch/arm/insts/static_inst.hh" +#include "base/trace.hh" + +namespace ArmISA +{ + +class DataXImmOp : public ArmStaticInst +{ + protected: + IntRegIndex dest, op1; + uint64_t imm; + + DataXImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + IntRegIndex _dest, IntRegIndex _op1, uint64_t _imm) : + ArmStaticInst(mnem, _machInst, __opClass), + dest(_dest), op1(_op1), imm(_imm) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +class DataXImmOnlyOp : public ArmStaticInst +{ + protected: + IntRegIndex dest; + uint64_t imm; + + DataXImmOnlyOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + IntRegIndex _dest, uint64_t _imm) : + ArmStaticInst(mnem, _machInst, __opClass), + dest(_dest), imm(_imm) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +class DataXSRegOp : public ArmStaticInst +{ + protected: + IntRegIndex dest, op1, op2; + int32_t shiftAmt; + ArmShiftType shiftType; + + DataXSRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2, + int32_t _shiftAmt, ArmShiftType _shiftType) : + ArmStaticInst(mnem, _machInst, __opClass), + dest(_dest), op1(_op1), op2(_op2), + shiftAmt(_shiftAmt), shiftType(_shiftType) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +class DataXERegOp : public ArmStaticInst +{ + protected: + IntRegIndex dest, op1, op2; + ArmExtendType extendType; + int32_t shiftAmt; + + DataXERegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2, + ArmExtendType _extendType, int32_t _shiftAmt) : + ArmStaticInst(mnem, _machInst, __opClass), + dest(_dest), op1(_op1), op2(_op2), + extendType(_extendType), shiftAmt(_shiftAmt) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +class DataX1RegOp : public ArmStaticInst +{ + protected: + IntRegIndex dest, op1; + + DataX1RegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + IntRegIndex _dest, IntRegIndex _op1) : + ArmStaticInst(mnem, _machInst, __opClass), dest(_dest), op1(_op1) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +class DataX1RegImmOp : public ArmStaticInst +{ + protected: + IntRegIndex dest, op1; + uint64_t imm; + + DataX1RegImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + IntRegIndex _dest, IntRegIndex _op1, uint64_t _imm) : + ArmStaticInst(mnem, _machInst, __opClass), dest(_dest), op1(_op1), + imm(_imm) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +class DataX1Reg2ImmOp : public ArmStaticInst +{ + protected: + IntRegIndex dest, op1; + uint64_t imm1, imm2; + + DataX1Reg2ImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + IntRegIndex _dest, IntRegIndex _op1, uint64_t _imm1, + uint64_t _imm2) : + ArmStaticInst(mnem, _machInst, __opClass), dest(_dest), op1(_op1), + imm1(_imm1), imm2(_imm2) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +class DataX2RegOp : public ArmStaticInst +{ + protected: + IntRegIndex dest, op1, op2; + + DataX2RegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2) : + ArmStaticInst(mnem, _machInst, __opClass), + dest(_dest), op1(_op1), op2(_op2) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +class DataX2RegImmOp : public ArmStaticInst +{ + protected: + IntRegIndex dest, op1, op2; + uint64_t imm; + + DataX2RegImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2, + uint64_t _imm) : + ArmStaticInst(mnem, _machInst, __opClass), + dest(_dest), op1(_op1), op2(_op2), imm(_imm) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +class DataX3RegOp : public ArmStaticInst +{ + protected: + IntRegIndex dest, op1, op2, op3; + + DataX3RegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2, + IntRegIndex _op3) : + ArmStaticInst(mnem, _machInst, __opClass), + dest(_dest), op1(_op1), op2(_op2), op3(_op3) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +class DataXCondCompImmOp : public ArmStaticInst +{ + protected: + IntRegIndex op1; + uint64_t imm; + ConditionCode condCode; + uint8_t defCc; + + DataXCondCompImmOp(const char *mnem, ExtMachInst _machInst, + OpClass __opClass, IntRegIndex _op1, uint64_t _imm, + ConditionCode _condCode, uint8_t _defCc) : + ArmStaticInst(mnem, _machInst, __opClass), + op1(_op1), imm(_imm), condCode(_condCode), defCc(_defCc) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +class DataXCondCompRegOp : public ArmStaticInst +{ + protected: + IntRegIndex op1, op2; + ConditionCode condCode; + uint8_t defCc; + + DataXCondCompRegOp(const char *mnem, ExtMachInst _machInst, + OpClass __opClass, IntRegIndex _op1, IntRegIndex _op2, + ConditionCode _condCode, uint8_t _defCc) : + ArmStaticInst(mnem, _machInst, __opClass), + op1(_op1), op2(_op2), condCode(_condCode), defCc(_defCc) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +class DataXCondSelOp : public ArmStaticInst +{ + protected: + IntRegIndex dest, op1, op2; + ConditionCode condCode; + + DataXCondSelOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2, + ConditionCode _condCode) : + ArmStaticInst(mnem, _machInst, __opClass), + dest(_dest), op1(_op1), op2(_op2), condCode(_condCode) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +} + +#endif //__ARCH_ARM_INSTS_PREDINST_HH__ diff --git a/src/arch/arm/insts/fplib.cc b/src/arch/arm/insts/fplib.cc new file mode 100644 index 000000000..1f44eed09 --- /dev/null +++ b/src/arch/arm/insts/fplib.cc @@ -0,0 +1,3086 @@ +/* +* Copyright (c) 2012-2013 ARM Limited +* All rights reserved +* +* The license below extends only to copyright in the software and shall +* not be construed as granting a license to any other intellectual +* property including but not limited to intellectual property relating +* to a hardware implementation of the functionality of the software +* licensed hereunder. You may use the software subject to the license +* terms below provided that you ensure that this notice is replicated +* unmodified and in its entirety in all distributions of the software, +* modified or unmodified, in source code or in binary form. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer; +* redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution; +* neither the name of the copyright holders nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +* Authors: Edmund Grimley Evans +* Thomas Grocutt +*/ + +#include <stdint.h> + +#include <cassert> + +#include "fplib.hh" + +namespace ArmISA +{ + +#define FPLIB_RN 0 +#define FPLIB_RP 1 +#define FPLIB_RM 2 +#define FPLIB_RZ 3 +#define FPLIB_FZ 4 +#define FPLIB_DN 8 +#define FPLIB_AHP 16 + +#define FPLIB_IDC 128 // Input Denormal +#define FPLIB_IXC 16 // Inexact +#define FPLIB_UFC 8 // Underflow +#define FPLIB_OFC 4 // Overflow +#define FPLIB_DZC 2 // Division by Zero +#define FPLIB_IOC 1 // Invalid Operation + +static inline uint16_t +lsl16(uint16_t x, uint32_t shift) +{ + return shift < 16 ? x << shift : 0; +} + +static inline uint16_t +lsr16(uint16_t x, uint32_t shift) +{ + return shift < 16 ? x >> shift : 0; +} + +static inline uint32_t +lsl32(uint32_t x, uint32_t shift) +{ + return shift < 32 ? x << shift : 0; +} + +static inline uint32_t +lsr32(uint32_t x, uint32_t shift) +{ + return shift < 32 ? x >> shift : 0; +} + +static inline uint64_t +lsl64(uint64_t x, uint32_t shift) +{ + return shift < 64 ? x << shift : 0; +} + +static inline uint64_t +lsr64(uint64_t x, uint32_t shift) +{ + return shift < 64 ? x >> shift : 0; +} + +static inline void +lsl128(uint64_t *r0, uint64_t *r1, uint64_t x0, uint64_t x1, uint32_t shift) +{ + if (shift < 64) { + *r1 = x1 << shift | x0 >> (64 - shift); + *r0 = x0 << shift; + } else if (shift < 128) { + *r1 = x0 << (shift - 64); + *r0 = 0; + } else { + *r1 = 0; + *r0 = 0; + } +} + +static inline void +lsr128(uint64_t *r0, uint64_t *r1, uint64_t x0, uint64_t x1, uint32_t shift) +{ + if (shift < 64) { + *r0 = x0 >> shift | x1 << (64 - shift); + *r1 = x1 >> shift; + } else if (shift < 128) { + *r0 = x1 >> (shift - 64); + *r1 = 0; + } else { + *r0 = 0; + *r1 = 0; + } +} + +static inline void +mul62x62(uint64_t *x0, uint64_t *x1, uint64_t a, uint64_t b) +{ + uint32_t mask = ((uint32_t)1 << 31) - 1; + uint64_t a0 = a & mask; + uint64_t a1 = a >> 31 & mask; + uint64_t b0 = b & mask; + uint64_t b1 = b >> 31 & mask; + uint64_t p0 = a0 * b0; + uint64_t p2 = a1 * b1; + uint64_t p1 = (a0 + a1) * (b0 + b1) - p0 - p2; + uint64_t s0 = p0; + uint64_t s1 = (s0 >> 31) + p1; + uint64_t s2 = (s1 >> 31) + p2; + *x0 = (s0 & mask) | (s1 & mask) << 31 | s2 << 62; + *x1 = s2 >> 2; +} + +static inline +void mul64x32(uint64_t *x0, uint64_t *x1, uint64_t a, uint32_t b) +{ + uint64_t t0 = (uint64_t)(uint32_t)a * b; + uint64_t t1 = (t0 >> 32) + (a >> 32) * b; + *x0 = t1 << 32 | (uint32_t)t0; + *x1 = t1 >> 32; +} + +static inline void +mul64x64(uint64_t *x0, uint64_t *x1, uint64_t a, uint64_t b) +{ + uint64_t a0 = (uint32_t)a; + uint64_t a1 = a >> 32; + uint64_t b0 = (uint32_t)b; + uint64_t b1 = b >> 32; + uint64_t t1 = (a0 * b0 >> 32) + a1 * b0; + uint64_t t2 = a0 * b1; + uint64_t x = ((uint64_t)(uint32_t)t1 + (uint32_t)t2) >> 32; + x += t1 >> 32; + x += t2 >> 32; + x += a1 * b1; + *x0 = a * b; + *x1 = x; +} + +static inline void +add128(uint64_t *x0, uint64_t *x1, uint64_t a0, uint64_t a1, uint64_t b0, + uint64_t b1) +{ + *x0 = a0 + b0; + *x1 = a1 + b1 + (*x0 < a0); +} + +static inline void +sub128(uint64_t *x0, uint64_t *x1, uint64_t a0, uint64_t a1, uint64_t b0, + uint64_t b1) +{ + *x0 = a0 - b0; + *x1 = a1 - b1 - (*x0 > a0); +} + +static inline int +cmp128(uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1) +{ + return (a1 < b1 ? -1 : a1 > b1 ? 1 : a0 < b0 ? -1 : a0 > b0 ? 1 : 0); +} + +static inline uint16_t +fp16_normalise(uint16_t mnt, int *exp) +{ + int shift; + + if (!mnt) { + return 0; + } + + for (shift = 8; shift; shift >>= 1) { + if (!(mnt >> (16 - shift))) { + mnt <<= shift; + *exp -= shift; + } + } + return mnt; +} + +static inline uint32_t +fp32_normalise(uint32_t mnt, int *exp) +{ + int shift; + + if (!mnt) { + return 0; + } + + for (shift = 16; shift; shift >>= 1) { + if (!(mnt >> (32 - shift))) { + mnt <<= shift; + *exp -= shift; + } + } + return mnt; +} + +static inline uint64_t +fp64_normalise(uint64_t mnt, int *exp) +{ + int shift; + + if (!mnt) { + return 0; + } + + for (shift = 32; shift; shift >>= 1) { + if (!(mnt >> (64 - shift))) { + mnt <<= shift; + *exp -= shift; + } + } + return mnt; +} + +static inline void +fp128_normalise(uint64_t *mnt0, uint64_t *mnt1, int *exp) +{ + uint64_t x0 = *mnt0; + uint64_t x1 = *mnt1; + int shift; + + if (!x0 && !x1) { + return; + } + + if (!x1) { + x1 = x0; + x0 = 0; + *exp -= 64; + } + + for (shift = 32; shift; shift >>= 1) { + if (!(x1 >> (64 - shift))) { + x1 = x1 << shift | x0 >> (64 - shift); + x0 <<= shift; + *exp -= shift; + } + } + + *mnt0 = x0; + *mnt1 = x1; +} + +static inline uint16_t +fp16_pack(uint16_t sgn, uint16_t exp, uint16_t mnt) +{ + return sgn << 15 | exp << 10 | (mnt & (((uint16_t)1 << 10) - 1)); +} + +static inline uint32_t +fp32_pack(uint32_t sgn, uint32_t exp, uint32_t mnt) +{ + return sgn << 31 | exp << 23 | (mnt & (((uint32_t)1 << 23) - 1)); +} + +static inline uint64_t +fp64_pack(uint64_t sgn, uint64_t exp, uint64_t mnt) +{ + return (uint64_t)sgn << 63 | exp << 52 | (mnt & (((uint64_t)1 << 52) - 1)); +} + +static inline uint16_t +fp16_zero(int sgn) +{ + return fp16_pack(sgn, 0, 0); +} + +static inline uint32_t +fp32_zero(int sgn) +{ + return fp32_pack(sgn, 0, 0); +} + +static inline uint64_t +fp64_zero(int sgn) +{ + return fp64_pack(sgn, 0, 0); +} + +static inline uint16_t +fp16_max_normal(int sgn) +{ + return fp16_pack(sgn, 30, -1); +} + +static inline uint32_t +fp32_max_normal(int sgn) +{ + return fp32_pack(sgn, 254, -1); +} + +static inline uint64_t +fp64_max_normal(int sgn) +{ + return fp64_pack(sgn, 2046, -1); +} + +static inline uint16_t +fp16_infinity(int sgn) +{ + return fp16_pack(sgn, 31, 0); +} + +static inline uint32_t +fp32_infinity(int sgn) +{ + return fp32_pack(sgn, 255, 0); +} + +static inline uint64_t +fp64_infinity(int sgn) +{ + return fp64_pack(sgn, 2047, 0); +} + +static inline uint16_t +fp16_defaultNaN() +{ + return fp16_pack(0, 31, (uint16_t)1 << 9); +} + +static inline uint32_t +fp32_defaultNaN() +{ + return fp32_pack(0, 255, (uint32_t)1 << 22); +} + +static inline uint64_t +fp64_defaultNaN() +{ + return fp64_pack(0, 2047, (uint64_t)1 << 51); +} + +static inline void +fp16_unpack(int *sgn, int *exp, uint16_t *mnt, uint16_t x, int mode, + int *flags) +{ + *sgn = x >> 15; + *exp = x >> 10 & 31; + *mnt = x & (((uint16_t)1 << 10) - 1); + + // Handle subnormals: + if (*exp) { + *mnt |= (uint16_t)1 << 10; + } else { + ++*exp; + // There is no flush to zero in this case! + } +} + +static inline void +fp32_unpack(int *sgn, int *exp, uint32_t *mnt, uint32_t x, int mode, + int *flags) +{ + *sgn = x >> 31; + *exp = x >> 23 & 255; + *mnt = x & (((uint32_t)1 << 23) - 1); + + // Handle subnormals: + if (*exp) { + *mnt |= (uint32_t)1 << 23; + } else { + ++*exp; + if ((mode & FPLIB_FZ) && *mnt) { + *flags |= FPLIB_IDC; + *mnt = 0; + } + } +} + +static inline void +fp64_unpack(int *sgn, int *exp, uint64_t *mnt, uint64_t x, int mode, + int *flags) +{ + *sgn = x >> 63; + *exp = x >> 52 & 2047; + *mnt = x & (((uint64_t)1 << 52) - 1); + + // Handle subnormals: + if (*exp) { + *mnt |= (uint64_t)1 << 52; + } else { + ++*exp; + if ((mode & FPLIB_FZ) && *mnt) { + *flags |= FPLIB_IDC; + *mnt = 0; + } + } +} + +static inline uint32_t +fp32_process_NaN(uint32_t a, int mode, int *flags) +{ + if (!(a >> 22 & 1)) { + *flags |= FPLIB_IOC; + a |= (uint32_t)1 << 22; + } + return mode & FPLIB_DN ? fp32_defaultNaN() : a; +} + +static inline uint64_t +fp64_process_NaN(uint64_t a, int mode, int *flags) +{ + if (!(a >> 51 & 1)) { + *flags |= FPLIB_IOC; + a |= (uint64_t)1 << 51; + } + return mode & FPLIB_DN ? fp64_defaultNaN() : a; +} + +static uint32_t +fp32_process_NaNs(uint32_t a, uint32_t b, int mode, int *flags) +{ + int a_exp = a >> 23 & 255; + uint32_t a_mnt = a & (((uint32_t)1 << 23) - 1); + int b_exp = b >> 23 & 255; + uint32_t b_mnt = b & (((uint32_t)1 << 23) - 1); + + // Handle signalling NaNs: + if (a_exp == 255 && a_mnt && !(a_mnt >> 22 & 1)) + return fp32_process_NaN(a, mode, flags); + if (b_exp == 255 && b_mnt && !(b_mnt >> 22 & 1)) + return fp32_process_NaN(b, mode, flags); + + // Handle quiet NaNs: + if (a_exp == 255 && a_mnt) + return fp32_process_NaN(a, mode, flags); + if (b_exp == 255 && b_mnt) + return fp32_process_NaN(b, mode, flags); + + return 0; +} + +static uint64_t +fp64_process_NaNs(uint64_t a, uint64_t b, int mode, int *flags) +{ + int a_exp = a >> 52 & 2047; + uint64_t a_mnt = a & (((uint64_t)1 << 52) - 1); + int b_exp = b >> 52 & 2047; + uint64_t b_mnt = b & (((uint64_t)1 << 52) - 1); + + // Handle signalling NaNs: + if (a_exp == 2047 && a_mnt && !(a_mnt >> 51 & 1)) + return fp64_process_NaN(a, mode, flags); + if (b_exp == 2047 && b_mnt && !(b_mnt >> 51 & 1)) + return fp64_process_NaN(b, mode, flags); + + // Handle quiet NaNs: + if (a_exp == 2047 && a_mnt) + return fp64_process_NaN(a, mode, flags); + if (b_exp == 2047 && b_mnt) + return fp64_process_NaN(b, mode, flags); + + return 0; +} + +static uint32_t +fp32_process_NaNs3(uint32_t a, uint32_t b, uint32_t c, int mode, int *flags) +{ + int a_exp = a >> 23 & 255; + uint32_t a_mnt = a & (((uint32_t)1 << 23) - 1); + int b_exp = b >> 23 & 255; + uint32_t b_mnt = b & (((uint32_t)1 << 23) - 1); + int c_exp = c >> 23 & 255; + uint32_t c_mnt = c & (((uint32_t)1 << 23) - 1); + + // Handle signalling NaNs: + if (a_exp == 255 && a_mnt && !(a_mnt >> 22 & 1)) + return fp32_process_NaN(a, mode, flags); + if (b_exp == 255 && b_mnt && !(b_mnt >> 22 & 1)) + return fp32_process_NaN(b, mode, flags); + if (c_exp == 255 && c_mnt && !(c_mnt >> 22 & 1)) + return fp32_process_NaN(c, mode, flags); + + // Handle quiet NaNs: + if (a_exp == 255 && a_mnt) + return fp32_process_NaN(a, mode, flags); + if (b_exp == 255 && b_mnt) + return fp32_process_NaN(b, mode, flags); + if (c_exp == 255 && c_mnt) + return fp32_process_NaN(c, mode, flags); + + return 0; +} + +static uint64_t +fp64_process_NaNs3(uint64_t a, uint64_t b, uint64_t c, int mode, int *flags) +{ + int a_exp = a >> 52 & 2047; + uint64_t a_mnt = a & (((uint64_t)1 << 52) - 1); + int b_exp = b >> 52 & 2047; + uint64_t b_mnt = b & (((uint64_t)1 << 52) - 1); + int c_exp = c >> 52 & 2047; + uint64_t c_mnt = c & (((uint64_t)1 << 52) - 1); + + // Handle signalling NaNs: + if (a_exp == 2047 && a_mnt && !(a_mnt >> 51 & 1)) + return fp64_process_NaN(a, mode, flags); + if (b_exp == 2047 && b_mnt && !(b_mnt >> 51 & 1)) + return fp64_process_NaN(b, mode, flags); + if (c_exp == 2047 && c_mnt && !(c_mnt >> 51 & 1)) + return fp64_process_NaN(c, mode, flags); + + // Handle quiet NaNs: + if (a_exp == 2047 && a_mnt) + return fp64_process_NaN(a, mode, flags); + if (b_exp == 2047 && b_mnt) + return fp64_process_NaN(b, mode, flags); + if (c_exp == 2047 && c_mnt) + return fp64_process_NaN(c, mode, flags); + + return 0; +} + +static uint16_t +fp16_round_(int sgn, int exp, uint16_t mnt, int rm, int mode, int *flags) +{ + int biased_exp; // non-negative exponent value for result + uint16_t int_mant; // mantissa for result, less than (1 << 11) + int error; // 0, 1, 2 or 3, where 2 means int_mant is wrong by exactly 0.5 + + assert(rm != FPRounding_TIEAWAY); + + // There is no flush to zero in this case! + + // The bottom 5 bits of mnt are orred together: + mnt = (uint16_t)1 << 12 | mnt >> 4 | ((mnt & 31) != 0); + + if (exp > 0) { + biased_exp = exp; + int_mant = mnt >> 2; + error = mnt & 3; + } else { + biased_exp = 0; + int_mant = lsr16(mnt, 3 - exp); + error = (lsr16(mnt, 1 - exp) & 3) | !!(mnt & (lsl16(1, 1 - exp) - 1)); + } + + if (!biased_exp && error) { // xx should also check fpscr_val<11> + *flags |= FPLIB_UFC; + } + + // Round up: + if ((rm == FPLIB_RN && (error == 3 || + (error == 2 && (int_mant & 1)))) || + (((rm == FPLIB_RP && !sgn) || (rm == FPLIB_RM && sgn)) && error)) { + ++int_mant; + if (int_mant == (uint32_t)1 << 10) { + // Rounded up from denormalized to normalized + biased_exp = 1; + } + if (int_mant == (uint32_t)1 << 11) { + // Rounded up to next exponent + ++biased_exp; + int_mant >>= 1; + } + } + + // Handle rounding to odd aka Von Neumann rounding: + if (error && rm == FPRounding_ODD) + int_mant |= 1; + + // Handle overflow: + if (!(mode & FPLIB_AHP)) { + if (biased_exp >= 31) { + *flags |= FPLIB_OFC | FPLIB_IXC; + if (rm == FPLIB_RN || (rm == FPLIB_RP && !sgn) || + (rm == FPLIB_RM && sgn)) { + return fp16_infinity(sgn); + } else { + return fp16_max_normal(sgn); + } + } + } else { + if (biased_exp >= 32) { + *flags |= FPLIB_IOC; + return fp16_pack(sgn, 31, -1); + } + } + + if (error) { + *flags |= FPLIB_IXC; + } + + return fp16_pack(sgn, biased_exp, int_mant); +} + +static uint32_t +fp32_round_(int sgn, int exp, uint32_t mnt, int rm, int mode, int *flags) +{ + int biased_exp; // non-negative exponent value for result + uint32_t int_mant; // mantissa for result, less than (1 << 24) + int error; // 0, 1, 2 or 3, where 2 means int_mant is wrong by exactly 0.5 + + assert(rm != FPRounding_TIEAWAY); + + // Flush to zero: + if ((mode & FPLIB_FZ) && exp < 1) { + *flags |= FPLIB_UFC; + return fp32_zero(sgn); + } + + // The bottom 8 bits of mnt are orred together: + mnt = (uint32_t)1 << 25 | mnt >> 7 | ((mnt & 255) != 0); + + if (exp > 0) { + biased_exp = exp; + int_mant = mnt >> 2; + error = mnt & 3; + } else { + biased_exp = 0; + int_mant = lsr32(mnt, 3 - exp); + error = (lsr32(mnt, 1 - exp) & 3) | !!(mnt & (lsl32(1, 1 - exp) - 1)); + } + + if (!biased_exp && error) { // xx should also check fpscr_val<11> + *flags |= FPLIB_UFC; + } + + // Round up: + if ((rm == FPLIB_RN && (error == 3 || + (error == 2 && (int_mant & 1)))) || + (((rm == FPLIB_RP && !sgn) || (rm == FPLIB_RM && sgn)) && error)) { + ++int_mant; + if (int_mant == (uint32_t)1 << 23) { + // Rounded up from denormalized to normalized + biased_exp = 1; + } + if (int_mant == (uint32_t)1 << 24) { + // Rounded up to next exponent + ++biased_exp; + int_mant >>= 1; + } + } + + // Handle rounding to odd aka Von Neumann rounding: + if (error && rm == FPRounding_ODD) + int_mant |= 1; + + // Handle overflow: + if (biased_exp >= 255) { + *flags |= FPLIB_OFC | FPLIB_IXC; + if (rm == FPLIB_RN || (rm == FPLIB_RP && !sgn) || + (rm == FPLIB_RM && sgn)) { + return fp32_infinity(sgn); + } else { + return fp32_max_normal(sgn); + } + } + + if (error) { + *flags |= FPLIB_IXC; + } + + return fp32_pack(sgn, biased_exp, int_mant); +} + +static uint32_t +fp32_round(int sgn, int exp, uint32_t mnt, int mode, int *flags) +{ + return fp32_round_(sgn, exp, mnt, mode & 3, mode, flags); +} + +static uint64_t +fp64_round_(int sgn, int exp, uint64_t mnt, int rm, int mode, int *flags) +{ + int biased_exp; // non-negative exponent value for result + uint64_t int_mant; // mantissa for result, less than (1 << 52) + int error; // 0, 1, 2 or 3, where 2 means int_mant is wrong by exactly 0.5 + + assert(rm != FPRounding_TIEAWAY); + + // Flush to zero: + if ((mode & FPLIB_FZ) && exp < 1) { + *flags |= FPLIB_UFC; + return fp64_zero(sgn); + } + + // The bottom 11 bits of mnt are orred together: + mnt = (uint64_t)1 << 54 | mnt >> 10 | ((mnt & 0x3ff) != 0); + + if (exp > 0) { + biased_exp = exp; + int_mant = mnt >> 2; + error = mnt & 3; + } else { + biased_exp = 0; + int_mant = lsr64(mnt, 3 - exp); + error = (lsr64(mnt, 1 - exp) & 3) | !!(mnt & (lsl64(1, 1 - exp) - 1)); + } + + if (!biased_exp && error) { // xx should also check fpscr_val<11> + *flags |= FPLIB_UFC; + } + + // Round up: + if ((rm == FPLIB_RN && (error == 3 || + (error == 2 && (int_mant & 1)))) || + (((rm == FPLIB_RP && !sgn) || (rm == FPLIB_RM && sgn)) && error)) { + ++int_mant; + if (int_mant == (uint64_t)1 << 52) { + // Rounded up from denormalized to normalized + biased_exp = 1; + } + if (int_mant == (uint64_t)1 << 53) { + // Rounded up to next exponent + ++biased_exp; + int_mant >>= 1; + } + } + + // Handle rounding to odd aka Von Neumann rounding: + if (error && rm == FPRounding_ODD) + int_mant |= 1; + + // Handle overflow: + if (biased_exp >= 2047) { + *flags |= FPLIB_OFC | FPLIB_IXC; + if (rm == FPLIB_RN || (rm == FPLIB_RP && !sgn) || + (rm == FPLIB_RM && sgn)) { + return fp64_infinity(sgn); + } else { + return fp64_max_normal(sgn); + } + } + + if (error) { + *flags |= FPLIB_IXC; + } + + return fp64_pack(sgn, biased_exp, int_mant); +} + +static uint64_t +fp64_round(int sgn, int exp, uint64_t mnt, int mode, int *flags) +{ + return fp64_round_(sgn, exp, mnt, mode & 3, mode, flags); +} + +static int +fp32_compare_eq(uint32_t a, uint32_t b, int mode, int *flags) +{ + int a_sgn, a_exp, b_sgn, b_exp; + uint32_t a_mnt, b_mnt; + + fp32_unpack(&a_sgn, &a_exp, &a_mnt, a, mode, flags); + fp32_unpack(&b_sgn, &b_exp, &b_mnt, b, mode, flags); + + if ((a_exp == 255 && (uint32_t)(a_mnt << 9)) || + (b_exp == 255 && (uint32_t)(b_mnt << 9))) { + if ((a_exp == 255 && (uint32_t)(a_mnt << 9) && !(a >> 22 & 1)) || + (b_exp == 255 && (uint32_t)(b_mnt << 9) && !(b >> 22 & 1))) + *flags |= FPLIB_IOC; + return 0; + } + return a == b || (!a_mnt && !b_mnt); +} + +static int +fp32_compare_ge(uint32_t a, uint32_t b, int mode, int *flags) +{ + int a_sgn, a_exp, b_sgn, b_exp; + uint32_t a_mnt, b_mnt; + + fp32_unpack(&a_sgn, &a_exp, &a_mnt, a, mode, flags); + fp32_unpack(&b_sgn, &b_exp, &b_mnt, b, mode, flags); + + if ((a_exp == 255 && (uint32_t)(a_mnt << 9)) || + (b_exp == 255 && (uint32_t)(b_mnt << 9))) { + *flags |= FPLIB_IOC; + return 0; + } + if (!a_mnt && !b_mnt) + return 1; + if (a_sgn != b_sgn) + return b_sgn; + if (a_exp != b_exp) + return a_sgn ^ (a_exp > b_exp); + if (a_mnt != b_mnt) + return a_sgn ^ (a_mnt > b_mnt); + return 1; +} + +static int +fp32_compare_gt(uint32_t a, uint32_t b, int mode, int *flags) +{ + int a_sgn, a_exp, b_sgn, b_exp; + uint32_t a_mnt, b_mnt; + + fp32_unpack(&a_sgn, &a_exp, &a_mnt, a, mode, flags); + fp32_unpack(&b_sgn, &b_exp, &b_mnt, b, mode, flags); + + if ((a_exp == 255 && (uint32_t)(a_mnt << 9)) || + (b_exp == 255 && (uint32_t)(b_mnt << 9))) { + *flags |= FPLIB_IOC; + return 0; + } + if (!a_mnt && !b_mnt) + return 0; + if (a_sgn != b_sgn) + return b_sgn; + if (a_exp != b_exp) + return a_sgn ^ (a_exp > b_exp); + if (a_mnt != b_mnt) + return a_sgn ^ (a_mnt > b_mnt); + return 0; +} + +static int +fp64_compare_eq(uint64_t a, uint64_t b, int mode, int *flags) +{ + int a_sgn, a_exp, b_sgn, b_exp; + uint64_t a_mnt, b_mnt; + + fp64_unpack(&a_sgn, &a_exp, &a_mnt, a, mode, flags); + fp64_unpack(&b_sgn, &b_exp, &b_mnt, b, mode, flags); + + if ((a_exp == 2047 && (uint64_t)(a_mnt << 12)) || + (b_exp == 2047 && (uint64_t)(b_mnt << 12))) { + if ((a_exp == 2047 && (uint64_t)(a_mnt << 12) && !(a >> 51 & 1)) || + (b_exp == 2047 && (uint64_t)(b_mnt << 12) && !(b >> 51 & 1))) + *flags |= FPLIB_IOC; + return 0; + } + return a == b || (!a_mnt && !b_mnt); +} + +static int +fp64_compare_ge(uint64_t a, uint64_t b, int mode, int *flags) +{ + int a_sgn, a_exp, b_sgn, b_exp; + uint64_t a_mnt, b_mnt; + + fp64_unpack(&a_sgn, &a_exp, &a_mnt, a, mode, flags); + fp64_unpack(&b_sgn, &b_exp, &b_mnt, b, mode, flags); + + if ((a_exp == 2047 && (uint64_t)(a_mnt << 12)) || + (b_exp == 2047 && (uint64_t)(b_mnt << 12))) { + *flags |= FPLIB_IOC; + return 0; + } + if (!a_mnt && !b_mnt) + return 1; + if (a_sgn != b_sgn) + return b_sgn; + if (a_exp != b_exp) + return a_sgn ^ (a_exp > b_exp); + if (a_mnt != b_mnt) + return a_sgn ^ (a_mnt > b_mnt); + return 1; +} + +static int +fp64_compare_gt(uint64_t a, uint64_t b, int mode, int *flags) +{ + int a_sgn, a_exp, b_sgn, b_exp; + uint64_t a_mnt, b_mnt; + + fp64_unpack(&a_sgn, &a_exp, &a_mnt, a, mode, flags); + fp64_unpack(&b_sgn, &b_exp, &b_mnt, b, mode, flags); + + if ((a_exp == 2047 && (uint64_t)(a_mnt << 12)) || + (b_exp == 2047 && (uint64_t)(b_mnt << 12))) { + *flags |= FPLIB_IOC; + return 0; + } + if (!a_mnt && !b_mnt) + return 0; + if (a_sgn != b_sgn) + return b_sgn; + if (a_exp != b_exp) + return a_sgn ^ (a_exp > b_exp); + if (a_mnt != b_mnt) + return a_sgn ^ (a_mnt > b_mnt); + return 0; +} + +static uint32_t +fp32_add(uint32_t a, uint32_t b, int neg, int mode, int *flags) +{ + int a_sgn, a_exp, b_sgn, b_exp, x_sgn, x_exp; + uint32_t a_mnt, b_mnt, x, x_mnt; + + fp32_unpack(&a_sgn, &a_exp, &a_mnt, a, mode, flags); + fp32_unpack(&b_sgn, &b_exp, &b_mnt, b, mode, flags); + + if ((x = fp32_process_NaNs(a, b, mode, flags))) { + return x; + } + + b_sgn ^= neg; + + // Handle infinities and zeroes: + if (a_exp == 255 && b_exp == 255 && a_sgn != b_sgn) { + *flags |= FPLIB_IOC; + return fp32_defaultNaN(); + } else if (a_exp == 255) { + return fp32_infinity(a_sgn); + } else if (b_exp == 255) { + return fp32_infinity(b_sgn); + } else if (!a_mnt && !b_mnt && a_sgn == b_sgn) { + return fp32_zero(a_sgn); + } + + a_mnt <<= 3; + b_mnt <<= 3; + if (a_exp >= b_exp) { + b_mnt = (lsr32(b_mnt, a_exp - b_exp) | + !!(b_mnt & (lsl32(1, a_exp - b_exp) - 1))); + b_exp = a_exp; + } else { + a_mnt = (lsr32(a_mnt, b_exp - a_exp) | + !!(a_mnt & (lsl32(1, b_exp - a_exp) - 1))); + a_exp = b_exp; + } + x_sgn = a_sgn; + x_exp = a_exp; + if (a_sgn == b_sgn) { + x_mnt = a_mnt + b_mnt; + } else if (a_mnt >= b_mnt) { + x_mnt = a_mnt - b_mnt; + } else { + x_sgn ^= 1; + x_mnt = b_mnt - a_mnt; + } + + if (!x_mnt) { + // Sign of exact zero result depends on rounding mode + return fp32_zero((mode & 3) == 2); + } + + x_mnt = fp32_normalise(x_mnt, &x_exp); + + return fp32_round(x_sgn, x_exp + 5, x_mnt << 1, mode, flags); +} + +static uint64_t +fp64_add(uint64_t a, uint64_t b, int neg, int mode, int *flags) +{ + int a_sgn, a_exp, b_sgn, b_exp, x_sgn, x_exp; + uint64_t a_mnt, b_mnt, x, x_mnt; + + fp64_unpack(&a_sgn, &a_exp, &a_mnt, a, mode, flags); + fp64_unpack(&b_sgn, &b_exp, &b_mnt, b, mode, flags); + + if ((x = fp64_process_NaNs(a, b, mode, flags))) { + return x; + } + + b_sgn ^= neg; + + // Handle infinities and zeroes: + if (a_exp == 2047 && b_exp == 2047 && a_sgn != b_sgn) { + *flags |= FPLIB_IOC; + return fp64_defaultNaN(); + } else if (a_exp == 2047) { + return fp64_infinity(a_sgn); + } else if (b_exp == 2047) { + return fp64_infinity(b_sgn); + } else if (!a_mnt && !b_mnt && a_sgn == b_sgn) { + return fp64_zero(a_sgn); + } + + a_mnt <<= 3; + b_mnt <<= 3; + if (a_exp >= b_exp) { + b_mnt = (lsr64(b_mnt, a_exp - b_exp) | + !!(b_mnt & (lsl64(1, a_exp - b_exp) - 1))); + b_exp = a_exp; + } else { + a_mnt = (lsr64(a_mnt, b_exp - a_exp) | + !!(a_mnt & (lsl64(1, b_exp - a_exp) - 1))); + a_exp = b_exp; + } + x_sgn = a_sgn; + x_exp = a_exp; + if (a_sgn == b_sgn) { + x_mnt = a_mnt + b_mnt; + } else if (a_mnt >= b_mnt) { + x_mnt = a_mnt - b_mnt; + } else { + x_sgn ^= 1; + x_mnt = b_mnt - a_mnt; + } + + if (!x_mnt) { + // Sign of exact zero result depends on rounding mode + return fp64_zero((mode & 3) == 2); + } + + x_mnt = fp64_normalise(x_mnt, &x_exp); + + return fp64_round(x_sgn, x_exp + 8, x_mnt << 1, mode, flags); +} + +static uint32_t +fp32_mul(uint32_t a, uint32_t b, int mode, int *flags) +{ + int a_sgn, a_exp, b_sgn, b_exp, x_sgn, x_exp; + uint32_t a_mnt, b_mnt, x; + uint64_t x_mnt; + + fp32_unpack(&a_sgn, &a_exp, &a_mnt, a, mode, flags); + fp32_unpack(&b_sgn, &b_exp, &b_mnt, b, mode, flags); + + if ((x = fp32_process_NaNs(a, b, mode, flags))) { + return x; + } + + // Handle infinities and zeroes: + if ((a_exp == 255 && !b_mnt) || (b_exp == 255 && !a_mnt)) { + *flags |= FPLIB_IOC; + return fp32_defaultNaN(); + } else if (a_exp == 255 || b_exp == 255) { + return fp32_infinity(a_sgn ^ b_sgn); + } else if (!a_mnt || !b_mnt) { + return fp32_zero(a_sgn ^ b_sgn); + } + + // Multiply and normalise: + x_sgn = a_sgn ^ b_sgn; + x_exp = a_exp + b_exp - 110; + x_mnt = (uint64_t)a_mnt * b_mnt; + x_mnt = fp64_normalise(x_mnt, &x_exp); + + // Convert to 32 bits, collapsing error into bottom bit: + x_mnt = lsr64(x_mnt, 31) | !!lsl64(x_mnt, 33); + + return fp32_round(x_sgn, x_exp, x_mnt, mode, flags); +} + +static uint64_t +fp64_mul(uint64_t a, uint64_t b, int mode, int *flags) +{ + int a_sgn, a_exp, b_sgn, b_exp, x_sgn, x_exp; + uint64_t a_mnt, b_mnt, x; + uint64_t x0_mnt, x1_mnt; + + fp64_unpack(&a_sgn, &a_exp, &a_mnt, a, mode, flags); + fp64_unpack(&b_sgn, &b_exp, &b_mnt, b, mode, flags); + + if ((x = fp64_process_NaNs(a, b, mode, flags))) { + return x; + } + + // Handle infinities and zeroes: + if ((a_exp == 2047 && !b_mnt) || (b_exp == 2047 && !a_mnt)) { + *flags |= FPLIB_IOC; + return fp64_defaultNaN(); + } else if (a_exp == 2047 || b_exp == 2047) { + return fp64_infinity(a_sgn ^ b_sgn); + } else if (!a_mnt || !b_mnt) { + return fp64_zero(a_sgn ^ b_sgn); + } + + // Multiply and normalise: + x_sgn = a_sgn ^ b_sgn; + x_exp = a_exp + b_exp - 1000; + mul62x62(&x0_mnt, &x1_mnt, a_mnt, b_mnt); + fp128_normalise(&x0_mnt, &x1_mnt, &x_exp); + + // Convert to 64 bits, collapsing error into bottom bit: + x0_mnt = x1_mnt << 1 | !!x0_mnt; + + return fp64_round(x_sgn, x_exp, x0_mnt, mode, flags); +} + +static uint32_t +fp32_muladd(uint32_t a, uint32_t b, uint32_t c, int scale, + int mode, int *flags) +{ + int a_sgn, a_exp, b_sgn, b_exp, c_sgn, c_exp, x_sgn, x_exp, y_sgn, y_exp; + uint32_t a_mnt, b_mnt, c_mnt, x; + uint64_t x_mnt, y_mnt; + + fp32_unpack(&a_sgn, &a_exp, &a_mnt, a, mode, flags); + fp32_unpack(&b_sgn, &b_exp, &b_mnt, b, mode, flags); + fp32_unpack(&c_sgn, &c_exp, &c_mnt, c, mode, flags); + + x = fp32_process_NaNs3(a, b, c, mode, flags); + + // Quiet NaN added to product of zero and infinity: + if (a_exp == 255 && (a_mnt >> 22 & 1) && + ((!b_mnt && c_exp == 255 && !(uint32_t)(c_mnt << 9)) || + (!c_mnt && b_exp == 255 && !(uint32_t)(b_mnt << 9)))) { + x = fp32_defaultNaN(); + *flags |= FPLIB_IOC; + } + + if (x) { + return x; + } + + // Handle infinities and zeroes: + if ((b_exp == 255 && !c_mnt) || + (c_exp == 255 && !b_mnt) || + (a_exp == 255 && (b_exp == 255 || c_exp == 255) && + (a_sgn != (b_sgn ^ c_sgn)))) { + *flags |= FPLIB_IOC; + return fp32_defaultNaN(); + } + if (a_exp == 255) + return fp32_infinity(a_sgn); + if (b_exp == 255 || c_exp == 255) + return fp32_infinity(b_sgn ^ c_sgn); + if (!a_mnt && (!b_mnt || !c_mnt) && a_sgn == (b_sgn ^ c_sgn)) + return fp32_zero(a_sgn); + + x_sgn = a_sgn; + x_exp = a_exp + 13; + x_mnt = (uint64_t)a_mnt << 27; + + // Multiply: + y_sgn = b_sgn ^ c_sgn; + y_exp = b_exp + c_exp - 113; + y_mnt = (uint64_t)b_mnt * c_mnt << 3; + if (!y_mnt) { + y_exp = x_exp; + } + + // Add: + if (x_exp >= y_exp) { + y_mnt = (lsr64(y_mnt, x_exp - y_exp) | + !!(y_mnt & (lsl64(1, x_exp - y_exp) - 1))); + y_exp = x_exp; + } else { + x_mnt = (lsr64(x_mnt, y_exp - x_exp) | + !!(x_mnt & (lsl64(1, y_exp - x_exp) - 1))); + x_exp = y_exp; + } + if (x_sgn == y_sgn) { + x_mnt = x_mnt + y_mnt; + } else if (x_mnt >= y_mnt) { + x_mnt = x_mnt - y_mnt; + } else { + x_sgn ^= 1; + x_mnt = y_mnt - x_mnt; + } + + if (!x_mnt) { + // Sign of exact zero result depends on rounding mode + return fp32_zero((mode & 3) == 2); + } + + // Normalise and convert to 32 bits, collapsing error into bottom bit: + x_mnt = fp64_normalise(x_mnt, &x_exp); + x_mnt = x_mnt >> 31 | !!(uint32_t)(x_mnt << 1); + + return fp32_round(x_sgn, x_exp + scale, x_mnt, mode, flags); +} + +static uint64_t +fp64_muladd(uint64_t a, uint64_t b, uint64_t c, int scale, + int mode, int *flags) +{ + int a_sgn, a_exp, b_sgn, b_exp, c_sgn, c_exp, x_sgn, x_exp, y_sgn, y_exp; + uint64_t a_mnt, b_mnt, c_mnt, x; + uint64_t x0_mnt, x1_mnt, y0_mnt, y1_mnt; + + fp64_unpack(&a_sgn, &a_exp, &a_mnt, a, mode, flags); + fp64_unpack(&b_sgn, &b_exp, &b_mnt, b, mode, flags); + fp64_unpack(&c_sgn, &c_exp, &c_mnt, c, mode, flags); + + x = fp64_process_NaNs3(a, b, c, mode, flags); + + // Quiet NaN added to product of zero and infinity: + if (a_exp == 2047 && (a_mnt >> 51 & 1) && + ((!b_mnt && c_exp == 2047 && !(uint64_t)(c_mnt << 12)) || + (!c_mnt && b_exp == 2047 && !(uint64_t)(b_mnt << 12)))) { + x = fp64_defaultNaN(); + *flags |= FPLIB_IOC; + } + + if (x) { + return x; + } + + // Handle infinities and zeroes: + if ((b_exp == 2047 && !c_mnt) || + (c_exp == 2047 && !b_mnt) || + (a_exp == 2047 && (b_exp == 2047 || c_exp == 2047) && + (a_sgn != (b_sgn ^ c_sgn)))) { + *flags |= FPLIB_IOC; + return fp64_defaultNaN(); + } + if (a_exp == 2047) + return fp64_infinity(a_sgn); + if (b_exp == 2047 || c_exp == 2047) + return fp64_infinity(b_sgn ^ c_sgn); + if (!a_mnt && (!b_mnt || !c_mnt) && a_sgn == (b_sgn ^ c_sgn)) + return fp64_zero(a_sgn); + + x_sgn = a_sgn; + x_exp = a_exp + 11; + x0_mnt = 0; + x1_mnt = a_mnt; + + // Multiply: + y_sgn = b_sgn ^ c_sgn; + y_exp = b_exp + c_exp - 1003; + mul62x62(&y0_mnt, &y1_mnt, b_mnt, c_mnt << 3); + if (!y0_mnt && !y1_mnt) { + y_exp = x_exp; + } + + // Add: + if (x_exp >= y_exp) { + uint64_t t0, t1; + lsl128(&t0, &t1, y0_mnt, y1_mnt, + x_exp - y_exp < 128 ? 128 - (x_exp - y_exp) : 0); + lsr128(&y0_mnt, &y1_mnt, y0_mnt, y1_mnt, x_exp - y_exp); + y0_mnt |= !!(t0 | t1); + y_exp = x_exp; + } else { + uint64_t t0, t1; + lsl128(&t0, &t1, x0_mnt, x1_mnt, + y_exp - x_exp < 128 ? 128 - (y_exp - x_exp) : 0); + lsr128(&x0_mnt, &x1_mnt, x0_mnt, x1_mnt, y_exp - x_exp); + x0_mnt |= !!(t0 | t1); + x_exp = y_exp; + } + if (x_sgn == y_sgn) { + add128(&x0_mnt, &x1_mnt, x0_mnt, x1_mnt, y0_mnt, y1_mnt); + } else if (cmp128(x0_mnt, x1_mnt, y0_mnt, y1_mnt) >= 0) { + sub128(&x0_mnt, &x1_mnt, x0_mnt, x1_mnt, y0_mnt, y1_mnt); + } else { + x_sgn ^= 1; + sub128(&x0_mnt, &x1_mnt, y0_mnt, y1_mnt, x0_mnt, x1_mnt); + } + + if (!x0_mnt && !x1_mnt) { + // Sign of exact zero result depends on rounding mode + return fp64_zero((mode & 3) == 2); + } + + // Normalise and convert to 64 bits, collapsing error into bottom bit: + fp128_normalise(&x0_mnt, &x1_mnt, &x_exp); + x0_mnt = x1_mnt << 1 | !!x0_mnt; + + return fp64_round(x_sgn, x_exp + scale, x0_mnt, mode, flags); +} + +static uint32_t +fp32_div(uint32_t a, uint32_t b, int mode, int *flags) +{ + int a_sgn, a_exp, b_sgn, b_exp, x_sgn, x_exp; + uint32_t a_mnt, b_mnt, x; + uint64_t x_mnt; + + fp32_unpack(&a_sgn, &a_exp, &a_mnt, a, mode, flags); + fp32_unpack(&b_sgn, &b_exp, &b_mnt, b, mode, flags); + + if ((x = fp32_process_NaNs(a, b, mode, flags))) + return x; + + // Handle infinities and zeroes: + if ((a_exp == 255 && b_exp == 255) || (!a_mnt && !b_mnt)) { + *flags |= FPLIB_IOC; + return fp32_defaultNaN(); + } + if (a_exp == 255 || !b_mnt) { + if (a_exp != 255) + *flags |= FPLIB_DZC; + return fp32_infinity(a_sgn ^ b_sgn); + } + if (!a_mnt || b_exp == 255) + return fp32_zero(a_sgn ^ b_sgn); + + // Divide, setting bottom bit if inexact: + a_mnt = fp32_normalise(a_mnt, &a_exp); + x_sgn = a_sgn ^ b_sgn; + x_exp = a_exp - b_exp + 172; + x_mnt = ((uint64_t)a_mnt << 18) / b_mnt; + x_mnt |= (x_mnt * b_mnt != (uint64_t)a_mnt << 18); + + // Normalise and convert to 32 bits, collapsing error into bottom bit: + x_mnt = fp64_normalise(x_mnt, &x_exp); + x_mnt = x_mnt >> 31 | !!(uint32_t)(x_mnt << 1); + + return fp32_round(x_sgn, x_exp, x_mnt, mode, flags); +} + +static uint64_t +fp64_div(uint64_t a, uint64_t b, int mode, int *flags) +{ + int a_sgn, a_exp, b_sgn, b_exp, x_sgn, x_exp, c; + uint64_t a_mnt, b_mnt, x, x_mnt, x0_mnt, x1_mnt; + + fp64_unpack(&a_sgn, &a_exp, &a_mnt, a, mode, flags); + fp64_unpack(&b_sgn, &b_exp, &b_mnt, b, mode, flags); + + if ((x = fp64_process_NaNs(a, b, mode, flags))) + return x; + + // Handle infinities and zeroes: + if ((a_exp == 2047 && b_exp == 2047) || (!a_mnt && !b_mnt)) { + *flags |= FPLIB_IOC; + return fp64_defaultNaN(); + } + if (a_exp == 2047 || !b_mnt) { + if (a_exp != 2047) + *flags |= FPLIB_DZC; + return fp64_infinity(a_sgn ^ b_sgn); + } + if (!a_mnt || b_exp == 2047) + return fp64_zero(a_sgn ^ b_sgn); + + // Find reciprocal of divisor with Newton-Raphson: + a_mnt = fp64_normalise(a_mnt, &a_exp); + b_mnt = fp64_normalise(b_mnt, &b_exp); + x_mnt = ~(uint64_t)0 / (b_mnt >> 31); + mul64x32(&x0_mnt, &x1_mnt, b_mnt, x_mnt); + sub128(&x0_mnt, &x1_mnt, 0, (uint64_t)1 << 32, x0_mnt, x1_mnt); + lsr128(&x0_mnt, &x1_mnt, x0_mnt, x1_mnt, 32); + mul64x32(&x0_mnt, &x1_mnt, x0_mnt, x_mnt); + lsr128(&x0_mnt, &x1_mnt, x0_mnt, x1_mnt, 33); + + // Multiply by dividend: + x_sgn = a_sgn ^ b_sgn; + x_exp = a_exp - b_exp + 1031; + mul62x62(&x0_mnt, &x1_mnt, x0_mnt, a_mnt >> 2); // xx 62x62 is enough + lsr128(&x0_mnt, &x1_mnt, x0_mnt, x1_mnt, 4); + x_mnt = x1_mnt; + + // This is an underestimate, so try adding one: + mul62x62(&x0_mnt, &x1_mnt, b_mnt >> 2, x_mnt + 1); // xx 62x62 is enough + c = cmp128(x0_mnt, x1_mnt, 0, a_mnt >> 11); + if (c <= 0) { + ++x_mnt; + } + + x_mnt = fp64_normalise(x_mnt, &x_exp); + + return fp64_round(x_sgn, x_exp, x_mnt << 1 | !!c, mode, flags); +} + +static void +set_fpscr0(FPSCR &fpscr, int flags) +{ + if (flags & FPLIB_IDC) { + fpscr.idc = 1; + } + if (flags & FPLIB_IOC) { + fpscr.ioc = 1; + } + if (flags & FPLIB_DZC) { + fpscr.dzc = 1; + } + if (flags & FPLIB_OFC) { + fpscr.ofc = 1; + } + if (flags & FPLIB_UFC) { + fpscr.ufc = 1; + } + if (flags & FPLIB_IXC) { + fpscr.ixc = 1; + } +} + +static uint32_t +fp32_sqrt(uint32_t a, int mode, int *flags) +{ + int a_sgn, a_exp, x_sgn, x_exp; + uint32_t a_mnt, x, x_mnt; + uint64_t t0, t1; + + fp32_unpack(&a_sgn, &a_exp, &a_mnt, a, mode, flags); + + // Handle NaNs: + if (a_exp == 255 && (uint32_t)(a_mnt << 9)) + return fp32_process_NaN(a, mode, flags); + + // Handle infinities and zeroes: + if (!a_mnt) { + return fp32_zero(a_sgn); + } + if (a_exp == 255 && !a_sgn) { + return fp32_infinity(a_sgn); + } + if (a_sgn) { + *flags |= FPLIB_IOC; + return fp32_defaultNaN(); + } + + a_mnt = fp32_normalise(a_mnt, &a_exp); + if (!(a_exp & 1)) { + ++a_exp; + a_mnt >>= 1; + } + + // x = (a * 3 + 5) / 8 + x = (a_mnt >> 2) + (a_mnt >> 3) + (5 << 28); + + // x = (a / x + x) / 2; // 16-bit accuracy + x = (a_mnt / (x >> 15) + (x >> 16)) << 15; + + // x = (a / x + x) / 2; // 16-bit accuracy + x = (a_mnt / (x >> 15) + (x >> 16)) << 15; + + // x = (a / x + x) / 2; // 32-bit accuracy + x = ((((uint64_t)a_mnt << 32) / x) >> 2) + (x >> 1); + + x_sgn = 0; + x_exp = (a_exp + 147) >> 1; + x_mnt = ((x - (1 << 5)) >> 6) + 1; + t1 = (uint64_t)x_mnt * x_mnt; + t0 = (uint64_t)a_mnt << 19; + if (t1 > t0) { + --x_mnt; + } + + x_mnt = fp32_normalise(x_mnt, &x_exp); + + return fp32_round(x_sgn, x_exp, x_mnt << 1 | (t1 != t0), mode, flags); +} + +static uint64_t +fp64_sqrt(uint64_t a, int mode, int *flags) +{ + int a_sgn, a_exp, x_sgn, x_exp, c; + uint64_t a_mnt, x_mnt, r, x0, x1; + uint32_t x; + + fp64_unpack(&a_sgn, &a_exp, &a_mnt, a, mode, flags); + + // Handle NaNs: + if (a_exp == 2047 && (uint64_t)(a_mnt << 12)) { + return fp64_process_NaN(a, mode, flags); + } + + // Handle infinities and zeroes: + if (!a_mnt) + return fp64_zero(a_sgn); + if (a_exp == 2047 && !a_sgn) + return fp64_infinity(a_sgn); + if (a_sgn) { + *flags |= FPLIB_IOC; + return fp64_defaultNaN(); + } + + a_mnt = fp64_normalise(a_mnt, &a_exp); + if (a_exp & 1) { + ++a_exp; + a_mnt >>= 1; + } + + // x = (a * 3 + 5) / 8 + x = (a_mnt >> 34) + (a_mnt >> 35) + (5 << 28); + + // x = (a / x + x) / 2; // 16-bit accuracy + x = ((a_mnt >> 32) / (x >> 15) + (x >> 16)) << 15; + + // x = (a / x + x) / 2; // 16-bit accuracy + x = ((a_mnt >> 32) / (x >> 15) + (x >> 16)) << 15; + + // x = (a / x + x) / 2; // 32-bit accuracy + x = ((a_mnt / x) >> 2) + (x >> 1); + + // r = 1 / x; // 32-bit accuracy + r = ((uint64_t)1 << 62) / x; + + // r = r * (2 - x * r); // 64-bit accuracy + mul64x32(&x0, &x1, -(uint64_t)x * r << 1, r); + lsr128(&x0, &x1, x0, x1, 31); + + // x = (x + a * r) / 2; // 64-bit accuracy + mul62x62(&x0, &x1, a_mnt >> 10, x0 >> 2); + lsl128(&x0, &x1, x0, x1, 5); + lsr128(&x0, &x1, x0, x1, 56); + + x0 = ((uint64_t)x << 31) + (x0 >> 1); + + x_sgn = 0; + x_exp = (a_exp + 1053) >> 1; + x_mnt = x0; + x_mnt = ((x_mnt - (1 << 8)) >> 9) + 1; + mul62x62(&x0, &x1, x_mnt, x_mnt); + lsl128(&x0, &x1, x0, x1, 19); + c = cmp128(x0, x1, 0, a_mnt); + if (c > 0) + --x_mnt; + + x_mnt = fp64_normalise(x_mnt, &x_exp); + + return fp64_round(x_sgn, x_exp, x_mnt << 1 | !!c, mode, flags); +} + +static int +modeConv(FPSCR fpscr) +{ + return (((int) fpscr) >> 22) & 0xF; +} + +static void +set_fpscr(FPSCR &fpscr, int flags) +{ + // translate back to FPSCR + bool underflow = false; + if (flags & FPLIB_IDC) { + fpscr.idc = 1; + } + if (flags & FPLIB_IOC) { + fpscr.ioc = 1; + } + if (flags & FPLIB_DZC) { + fpscr.dzc = 1; + } + if (flags & FPLIB_OFC) { + fpscr.ofc = 1; + } + if (flags & FPLIB_UFC) { + underflow = true; //xx Why is this required? + fpscr.ufc = 1; + } + if ((flags & FPLIB_IXC) && !(underflow && fpscr.fz)) { + fpscr.ixc = 1; + } +} + +template <> +bool +fplibCompareEQ(uint32_t a, uint32_t b, FPSCR &fpscr) +{ + int flags = 0; + int x = fp32_compare_eq(a, b, modeConv(fpscr), &flags); + set_fpscr(fpscr, flags); + return x; +} + +template <> +bool +fplibCompareGE(uint32_t a, uint32_t b, FPSCR &fpscr) +{ + int flags = 0; + int x = fp32_compare_ge(a, b, modeConv(fpscr), &flags); + set_fpscr(fpscr, flags); + return x; +} + +template <> +bool +fplibCompareGT(uint32_t a, uint32_t b, FPSCR &fpscr) +{ + int flags = 0; + int x = fp32_compare_gt(a, b, modeConv(fpscr), &flags); + set_fpscr(fpscr, flags); + return x; +} + +template <> +bool +fplibCompareEQ(uint64_t a, uint64_t b, FPSCR &fpscr) +{ + int flags = 0; + int x = fp64_compare_eq(a, b, modeConv(fpscr), &flags); + set_fpscr(fpscr, flags); + return x; +} + +template <> +bool +fplibCompareGE(uint64_t a, uint64_t b, FPSCR &fpscr) +{ + int flags = 0; + int x = fp64_compare_ge(a, b, modeConv(fpscr), &flags); + set_fpscr(fpscr, flags); + return x; +} + +template <> +bool +fplibCompareGT(uint64_t a, uint64_t b, FPSCR &fpscr) +{ + int flags = 0; + int x = fp64_compare_gt(a, b, modeConv(fpscr), &flags); + set_fpscr(fpscr, flags); + return x; +} + +template <> +uint32_t +fplibAbs(uint32_t op) +{ + return op & ~((uint32_t)1 << 31); +} + +template <> +uint64_t +fplibAbs(uint64_t op) +{ + return op & ~((uint64_t)1 << 63); +} + +template <> +uint32_t +fplibAdd(uint32_t op1, uint32_t op2, FPSCR &fpscr) +{ + int flags = 0; + uint32_t result = fp32_add(op1, op2, 0, modeConv(fpscr), &flags); + set_fpscr0(fpscr, flags); + return result; +} + +template <> +uint64_t +fplibAdd(uint64_t op1, uint64_t op2, FPSCR &fpscr) +{ + int flags = 0; + uint64_t result = fp64_add(op1, op2, 0, modeConv(fpscr), &flags); + set_fpscr0(fpscr, flags); + return result; +} + +template <> +int +fplibCompare(uint32_t op1, uint32_t op2, bool signal_nans, FPSCR &fpscr) +{ + int mode = modeConv(fpscr); + int flags = 0; + int sgn1, exp1, sgn2, exp2, result; + uint32_t mnt1, mnt2; + + fp32_unpack(&sgn1, &exp1, &mnt1, op1, mode, &flags); + fp32_unpack(&sgn2, &exp2, &mnt2, op2, mode, &flags); + + if ((exp1 == 255 && (uint32_t)(mnt1 << 9)) || + (exp2 == 255 && (uint32_t)(mnt2 << 9))) { + result = 3; + if ((exp1 == 255 && (uint32_t)(mnt1 << 9) && !(mnt1 >> 22 & 1)) || + (exp2 == 255 && (uint32_t)(mnt2 << 9) && !(mnt2 >> 22 & 1)) || + signal_nans) + flags |= FPLIB_IOC; + } else { + if (op1 == op2 || (!mnt1 && !mnt2)) { + result = 6; + } else if (sgn1 != sgn2) { + result = sgn1 ? 8 : 2; + } else if (exp1 != exp2) { + result = sgn1 ^ (exp1 < exp2) ? 8 : 2; + } else { + result = sgn1 ^ (mnt1 < mnt2) ? 8 : 2; + } + } + + set_fpscr0(fpscr, flags); + + return result; +} + +template <> +int +fplibCompare(uint64_t op1, uint64_t op2, bool signal_nans, FPSCR &fpscr) +{ + int mode = modeConv(fpscr); + int flags = 0; + int sgn1, exp1, sgn2, exp2, result; + uint64_t mnt1, mnt2; + + fp64_unpack(&sgn1, &exp1, &mnt1, op1, mode, &flags); + fp64_unpack(&sgn2, &exp2, &mnt2, op2, mode, &flags); + + if ((exp1 == 2047 && (uint64_t)(mnt1 << 12)) || + (exp2 == 2047 && (uint64_t)(mnt2 << 12))) { + result = 3; + if ((exp1 == 2047 && (uint64_t)(mnt1 << 12) && !(mnt1 >> 51 & 1)) || + (exp2 == 2047 && (uint64_t)(mnt2 << 12) && !(mnt2 >> 51 & 1)) || + signal_nans) + flags |= FPLIB_IOC; + } else { + if (op1 == op2 || (!mnt1 && !mnt2)) { + result = 6; + } else if (sgn1 != sgn2) { + result = sgn1 ? 8 : 2; + } else if (exp1 != exp2) { + result = sgn1 ^ (exp1 < exp2) ? 8 : 2; + } else { + result = sgn1 ^ (mnt1 < mnt2) ? 8 : 2; + } + } + + set_fpscr0(fpscr, flags); + + return result; +} + +static uint16_t +fp16_FPConvertNaN_32(uint32_t op) +{ + return fp16_pack(op >> 31, 31, (uint16_t)1 << 9 | op >> 13); +} + +static uint16_t +fp16_FPConvertNaN_64(uint64_t op) +{ + return fp16_pack(op >> 63, 31, (uint16_t)1 << 9 | op >> 42); +} + +static uint32_t +fp32_FPConvertNaN_16(uint16_t op) +{ + return fp32_pack(op >> 15, 255, (uint32_t)1 << 22 | (uint32_t)op << 13); +} + +static uint32_t +fp32_FPConvertNaN_64(uint64_t op) +{ + return fp32_pack(op >> 63, 255, (uint32_t)1 << 22 | op >> 29); +} + +static uint64_t +fp64_FPConvertNaN_16(uint16_t op) +{ + return fp64_pack(op >> 15, 2047, (uint64_t)1 << 51 | (uint64_t)op << 42); +} + +static uint64_t +fp64_FPConvertNaN_32(uint32_t op) +{ + return fp64_pack(op >> 31, 2047, (uint64_t)1 << 51 | (uint64_t)op << 29); +} + +static uint32_t +fp32_FPOnePointFive(int sgn) +{ + return fp32_pack(sgn, 127, (uint64_t)1 << 22); +} + +static uint64_t +fp64_FPOnePointFive(int sgn) +{ + return fp64_pack(sgn, 1023, (uint64_t)1 << 51); +} + +static uint32_t +fp32_FPThree(int sgn) +{ + return fp32_pack(sgn, 128, (uint64_t)1 << 22); +} + +static uint64_t +fp64_FPThree(int sgn) +{ + return fp64_pack(sgn, 1024, (uint64_t)1 << 51); +} + +static uint32_t +fp32_FPTwo(int sgn) +{ + return fp32_pack(sgn, 128, 0); +} + +static uint64_t +fp64_FPTwo(int sgn) +{ + return fp64_pack(sgn, 1024, 0); +} + +template <> +uint16_t +fplibConvert(uint32_t op, FPRounding rounding, FPSCR &fpscr) +{ + int mode = modeConv(fpscr); + int flags = 0; + int sgn, exp; + uint32_t mnt; + uint16_t result; + + // Unpack floating-point operand optionally with flush-to-zero: + fp32_unpack(&sgn, &exp, &mnt, op, mode, &flags); + + bool alt_hp = fpscr.ahp; + + if (exp == 255 && (uint32_t)(mnt << 9)) { + if (alt_hp) { + result = fp16_zero(sgn); + } else if (fpscr.dn) { + result = fp16_defaultNaN(); + } else { + result = fp16_FPConvertNaN_32(op); + } + if (!(mnt >> 22 & 1) || alt_hp) { + flags |= FPLIB_IOC; + } + } else if (exp == 255) { + if (alt_hp) { + result = sgn << 15 | (uint16_t)0x7fff; + flags |= FPLIB_IOC; + } else { + result = fp16_infinity(sgn); + } + } else if (!mnt) { + result = fp16_zero(sgn); + } else { + result = fp16_round_(sgn, exp - 127 + 15, + mnt >> 7 | !!(uint32_t)(mnt << 25), + rounding, mode | alt_hp << 4, &flags); + } + + set_fpscr0(fpscr, flags); + + return result; +} + +template <> +uint16_t +fplibConvert(uint64_t op, FPRounding rounding, FPSCR &fpscr) +{ + int mode = modeConv(fpscr); + int flags = 0; + int sgn, exp; + uint64_t mnt; + uint16_t result; + + // Unpack floating-point operand optionally with flush-to-zero: + fp64_unpack(&sgn, &exp, &mnt, op, mode, &flags); + + bool alt_hp = fpscr.ahp; + + if (exp == 2047 && (uint64_t)(mnt << 12)) { + if (alt_hp) { + result = fp16_zero(sgn); + } else if (fpscr.dn) { + result = fp16_defaultNaN(); + } else { + result = fp16_FPConvertNaN_64(op); + } + if (!(mnt >> 51 & 1) || alt_hp) { + flags |= FPLIB_IOC; + } + } else if (exp == 2047) { + if (alt_hp) { + result = sgn << 15 | (uint16_t)0x7fff; + flags |= FPLIB_IOC; + } else { + result = fp16_infinity(sgn); + } + } else if (!mnt) { + result = fp16_zero(sgn); + } else { + result = fp16_round_(sgn, exp - 1023 + 15, + mnt >> 36 | !!(uint64_t)(mnt << 28), + rounding, mode | alt_hp << 4, &flags); + } + + set_fpscr0(fpscr, flags); + + return result; +} + +template <> +uint32_t +fplibConvert(uint16_t op, FPRounding rounding, FPSCR &fpscr) +{ + int mode = modeConv(fpscr); + int flags = 0; + int sgn, exp; + uint16_t mnt; + uint32_t result; + + // Unpack floating-point operand optionally with flush-to-zero: + fp16_unpack(&sgn, &exp, &mnt, op, mode, &flags); + + if (exp == 31 && !fpscr.ahp && (uint16_t)(mnt << 6)) { + if (fpscr.dn) { + result = fp32_defaultNaN(); + } else { + result = fp32_FPConvertNaN_16(op); + } + if (!(mnt >> 9 & 1)) { + flags |= FPLIB_IOC; + } + } else if (exp == 31 && !fpscr.ahp) { + result = fp32_infinity(sgn); + } else if (!mnt) { + result = fp32_zero(sgn); + } else { + mnt = fp16_normalise(mnt, &exp); + result = fp32_pack(sgn, exp - 15 + 127 + 5, (uint32_t)mnt << 8); + } + + set_fpscr0(fpscr, flags); + + return result; +} + +template <> +uint32_t +fplibConvert(uint64_t op, FPRounding rounding, FPSCR &fpscr) +{ + int mode = modeConv(fpscr); + int flags = 0; + int sgn, exp; + uint64_t mnt; + uint32_t result; + + // Unpack floating-point operand optionally with flush-to-zero: + fp64_unpack(&sgn, &exp, &mnt, op, mode, &flags); + + if (exp == 2047 && (uint64_t)(mnt << 12)) { + if (fpscr.dn) { + result = fp32_defaultNaN(); + } else { + result = fp32_FPConvertNaN_64(op); + } + if (!(mnt >> 51 & 1)) { + flags |= FPLIB_IOC; + } + } else if (exp == 2047) { + result = fp32_infinity(sgn); + } else if (!mnt) { + result = fp32_zero(sgn); + } else { + result = fp32_round_(sgn, exp - 1023 + 127, + mnt >> 20 | !!(uint64_t)(mnt << 44), + rounding, mode, &flags); + } + + set_fpscr0(fpscr, flags); + + return result; +} + +template <> +uint64_t +fplibConvert(uint16_t op, FPRounding rounding, FPSCR &fpscr) +{ + int mode = modeConv(fpscr); + int flags = 0; + int sgn, exp; + uint16_t mnt; + uint64_t result; + + // Unpack floating-point operand optionally with flush-to-zero: + fp16_unpack(&sgn, &exp, &mnt, op, mode, &flags); + + if (exp == 31 && !fpscr.ahp && (uint16_t)(mnt << 6)) { + if (fpscr.dn) { + result = fp64_defaultNaN(); + } else { + result = fp64_FPConvertNaN_16(op); + } + if (!(mnt >> 9 & 1)) { + flags |= FPLIB_IOC; + } + } else if (exp == 31 && !fpscr.ahp) { + result = fp64_infinity(sgn); + } else if (!mnt) { + result = fp64_zero(sgn); + } else { + mnt = fp16_normalise(mnt, &exp); + result = fp64_pack(sgn, exp - 15 + 1023 + 5, (uint64_t)mnt << 37); + } + + set_fpscr0(fpscr, flags); + + return result; +} + +template <> +uint64_t +fplibConvert(uint32_t op, FPRounding rounding, FPSCR &fpscr) +{ + int mode = modeConv(fpscr); + int flags = 0; + int sgn, exp; + uint32_t mnt; + uint64_t result; + + // Unpack floating-point operand optionally with flush-to-zero: + fp32_unpack(&sgn, &exp, &mnt, op, mode, &flags); + + if (exp == 255 && (uint32_t)(mnt << 9)) { + if (fpscr.dn) { + result = fp64_defaultNaN(); + } else { + result = fp64_FPConvertNaN_32(op); + } + if (!(mnt >> 22 & 1)) { + flags |= FPLIB_IOC; + } + } else if (exp == 255) { + result = fp64_infinity(sgn); + } else if (!mnt) { + result = fp64_zero(sgn); + } else { + mnt = fp32_normalise(mnt, &exp); + result = fp64_pack(sgn, exp - 127 + 1023 + 8, (uint64_t)mnt << 21); + } + + set_fpscr0(fpscr, flags); + + return result; +} + +template <> +uint32_t +fplibMulAdd(uint32_t addend, uint32_t op1, uint32_t op2, FPSCR &fpscr) +{ + int flags = 0; + uint32_t result = fp32_muladd(addend, op1, op2, 0, modeConv(fpscr), &flags); + set_fpscr0(fpscr, flags); + return result; +} + +template <> +uint64_t +fplibMulAdd(uint64_t addend, uint64_t op1, uint64_t op2, FPSCR &fpscr) +{ + int flags = 0; + uint64_t result = fp64_muladd(addend, op1, op2, 0, modeConv(fpscr), &flags); + set_fpscr0(fpscr, flags); + return result; +} + +template <> +uint32_t +fplibDiv(uint32_t op1, uint32_t op2, FPSCR &fpscr) +{ + int flags = 0; + uint32_t result = fp32_div(op1, op2, modeConv(fpscr), &flags); + set_fpscr0(fpscr, flags); + return result; +} + +template <> +uint64_t +fplibDiv(uint64_t op1, uint64_t op2, FPSCR &fpscr) +{ + int flags = 0; + uint64_t result = fp64_div(op1, op2, modeConv(fpscr), &flags); + set_fpscr0(fpscr, flags); + return result; +} + +static uint32_t +fp32_repack(int sgn, int exp, uint32_t mnt) +{ + return fp32_pack(sgn, mnt >> 23 ? exp : 0, mnt); +} + +static uint64_t +fp64_repack(int sgn, int exp, uint64_t mnt) +{ + return fp64_pack(sgn, mnt >> 52 ? exp : 0, mnt); +} + +static void +fp32_minmaxnum(uint32_t *op1, uint32_t *op2, int sgn) +{ + // Treat a single quiet-NaN as +Infinity/-Infinity + if (!((uint32_t)~(*op1 << 1) >> 23) && (uint32_t)~(*op2 << 1) >> 23) + *op1 = fp32_infinity(sgn); + if (!((uint32_t)~(*op2 << 1) >> 23) && (uint32_t)~(*op1 << 1) >> 23) + *op2 = fp32_infinity(sgn); +} + +static void +fp64_minmaxnum(uint64_t *op1, uint64_t *op2, int sgn) +{ + // Treat a single quiet-NaN as +Infinity/-Infinity + if (!((uint64_t)~(*op1 << 1) >> 52) && (uint64_t)~(*op2 << 1) >> 52) + *op1 = fp64_infinity(sgn); + if (!((uint64_t)~(*op2 << 1) >> 52) && (uint64_t)~(*op1 << 1) >> 52) + *op2 = fp64_infinity(sgn); +} + +template <> +uint32_t +fplibMax(uint32_t op1, uint32_t op2, FPSCR &fpscr) +{ + int mode = modeConv(fpscr); + int flags = 0; + int sgn1, exp1, sgn2, exp2; + uint32_t mnt1, mnt2, x, result; + + fp32_unpack(&sgn1, &exp1, &mnt1, op1, mode, &flags); + fp32_unpack(&sgn2, &exp2, &mnt2, op2, mode, &flags); + + if ((x = fp32_process_NaNs(op1, op2, mode, &flags))) { + result = x; + } else { + result = ((sgn1 != sgn2 ? sgn2 : sgn1 ^ (op1 > op2)) ? + fp32_repack(sgn1, exp1, mnt1) : + fp32_repack(sgn2, exp2, mnt2)); + } + set_fpscr0(fpscr, flags); + return result; +} + +template <> +uint64_t +fplibMax(uint64_t op1, uint64_t op2, FPSCR &fpscr) +{ + int mode = modeConv(fpscr); + int flags = 0; + int sgn1, exp1, sgn2, exp2; + uint64_t mnt1, mnt2, x, result; + + fp64_unpack(&sgn1, &exp1, &mnt1, op1, mode, &flags); + fp64_unpack(&sgn2, &exp2, &mnt2, op2, mode, &flags); + + if ((x = fp64_process_NaNs(op1, op2, mode, &flags))) { + result = x; + } else { + result = ((sgn1 != sgn2 ? sgn2 : sgn1 ^ (op1 > op2)) ? + fp64_repack(sgn1, exp1, mnt1) : + fp64_repack(sgn2, exp2, mnt2)); + } + set_fpscr0(fpscr, flags); + return result; +} + +template <> +uint32_t +fplibMaxNum(uint32_t op1, uint32_t op2, FPSCR &fpscr) +{ + fp32_minmaxnum(&op1, &op2, 1); + return fplibMax<uint32_t>(op1, op2, fpscr); +} + +template <> +uint64_t +fplibMaxNum(uint64_t op1, uint64_t op2, FPSCR &fpscr) +{ + fp64_minmaxnum(&op1, &op2, 1); + return fplibMax<uint64_t>(op1, op2, fpscr); +} + +template <> +uint32_t +fplibMin(uint32_t op1, uint32_t op2, FPSCR &fpscr) +{ + int mode = modeConv(fpscr); + int flags = 0; + int sgn1, exp1, sgn2, exp2; + uint32_t mnt1, mnt2, x, result; + + fp32_unpack(&sgn1, &exp1, &mnt1, op1, mode, &flags); + fp32_unpack(&sgn2, &exp2, &mnt2, op2, mode, &flags); + + if ((x = fp32_process_NaNs(op1, op2, mode, &flags))) { + result = x; + } else { + result = ((sgn1 != sgn2 ? sgn1 : sgn1 ^ (op1 < op2)) ? + fp32_repack(sgn1, exp1, mnt1) : + fp32_repack(sgn2, exp2, mnt2)); + } + set_fpscr0(fpscr, flags); + return result; +} + +template <> +uint64_t +fplibMin(uint64_t op1, uint64_t op2, FPSCR &fpscr) +{ + int mode = modeConv(fpscr); + int flags = 0; + int sgn1, exp1, sgn2, exp2; + uint64_t mnt1, mnt2, x, result; + + fp64_unpack(&sgn1, &exp1, &mnt1, op1, mode, &flags); + fp64_unpack(&sgn2, &exp2, &mnt2, op2, mode, &flags); + + if ((x = fp64_process_NaNs(op1, op2, mode, &flags))) { + result = x; + } else { + result = ((sgn1 != sgn2 ? sgn1 : sgn1 ^ (op1 < op2)) ? + fp64_repack(sgn1, exp1, mnt1) : + fp64_repack(sgn2, exp2, mnt2)); + } + set_fpscr0(fpscr, flags); + return result; +} + +template <> +uint32_t +fplibMinNum(uint32_t op1, uint32_t op2, FPSCR &fpscr) +{ + fp32_minmaxnum(&op1, &op2, 0); + return fplibMin<uint32_t>(op1, op2, fpscr); +} + +template <> +uint64_t +fplibMinNum(uint64_t op1, uint64_t op2, FPSCR &fpscr) +{ + fp64_minmaxnum(&op1, &op2, 0); + return fplibMin<uint64_t>(op1, op2, fpscr); +} + +template <> +uint32_t +fplibMul(uint32_t op1, uint32_t op2, FPSCR &fpscr) +{ + int flags = 0; + uint32_t result = fp32_mul(op1, op2, modeConv(fpscr), &flags); + set_fpscr0(fpscr, flags); + return result; +} + +template <> +uint64_t +fplibMul(uint64_t op1, uint64_t op2, FPSCR &fpscr) +{ + int flags = 0; + uint64_t result = fp64_mul(op1, op2, modeConv(fpscr), &flags); + set_fpscr0(fpscr, flags); + return result; +} + +template <> +uint32_t +fplibMulX(uint32_t op1, uint32_t op2, FPSCR &fpscr) +{ + int mode = modeConv(fpscr); + int flags = 0; + int sgn1, exp1, sgn2, exp2; + uint32_t mnt1, mnt2, result; + + fp32_unpack(&sgn1, &exp1, &mnt1, op1, mode, &flags); + fp32_unpack(&sgn2, &exp2, &mnt2, op2, mode, &flags); + + result = fp32_process_NaNs(op1, op2, mode, &flags); + if (!result) { + if ((exp1 == 255 && !mnt2) || (exp2 == 255 && !mnt1)) { + result = fp32_FPTwo(sgn1 ^ sgn2); + } else if (exp1 == 255 || exp2 == 255) { + result = fp32_infinity(sgn1 ^ sgn2); + } else if (!mnt1 || !mnt2) { + result = fp32_zero(sgn1 ^ sgn2); + } else { + result = fp32_mul(op1, op2, mode, &flags); + } + } + + set_fpscr0(fpscr, flags); + + return result; +} + +template <> +uint64_t +fplibMulX(uint64_t op1, uint64_t op2, FPSCR &fpscr) +{ + int mode = modeConv(fpscr); + int flags = 0; + int sgn1, exp1, sgn2, exp2; + uint64_t mnt1, mnt2, result; + + fp64_unpack(&sgn1, &exp1, &mnt1, op1, mode, &flags); + fp64_unpack(&sgn2, &exp2, &mnt2, op2, mode, &flags); + + result = fp64_process_NaNs(op1, op2, mode, &flags); + if (!result) { + if ((exp1 == 2047 && !mnt2) || (exp2 == 2047 && !mnt1)) { + result = fp64_FPTwo(sgn1 ^ sgn2); + } else if (exp1 == 2047 || exp2 == 2047) { + result = fp64_infinity(sgn1 ^ sgn2); + } else if (!mnt1 || !mnt2) { + result = fp64_zero(sgn1 ^ sgn2); + } else { + result = fp64_mul(op1, op2, mode, &flags); + } + } + + set_fpscr0(fpscr, flags); + + return result; +} + +template <> +uint32_t +fplibNeg(uint32_t op) +{ + return op ^ (uint32_t)1 << 31; +} + +template <> +uint64_t +fplibNeg(uint64_t op) +{ + return op ^ (uint64_t)1 << 63; +} + +static const uint8_t recip_sqrt_estimate[256] = { + 255, 253, 251, 249, 247, 245, 243, 242, 240, 238, 236, 234, 233, 231, 229, 228, + 226, 224, 223, 221, 219, 218, 216, 215, 213, 212, 210, 209, 207, 206, 204, 203, + 201, 200, 198, 197, 196, 194, 193, 192, 190, 189, 188, 186, 185, 184, 183, 181, + 180, 179, 178, 176, 175, 174, 173, 172, 170, 169, 168, 167, 166, 165, 164, 163, + 162, 160, 159, 158, 157, 156, 155, 154, 153, 152, 151, 150, 149, 148, 147, 146, + 145, 144, 143, 142, 141, 140, 140, 139, 138, 137, 136, 135, 134, 133, 132, 131, + 131, 130, 129, 128, 127, 126, 126, 125, 124, 123, 122, 121, 121, 120, 119, 118, + 118, 117, 116, 115, 114, 114, 113, 112, 111, 111, 110, 109, 109, 108, 107, 106, + 105, 104, 103, 101, 100, 99, 97, 96, 95, 93, 92, 91, 90, 88, 87, 86, + 85, 84, 82, 81, 80, 79, 78, 77, 76, 75, 74, 72, 71, 70, 69, 68, + 67, 66, 65, 64, 63, 62, 61, 60, 60, 59, 58, 57, 56, 55, 54, 53, + 52, 51, 51, 50, 49, 48, 47, 46, 46, 45, 44, 43, 42, 42, 41, 40, + 39, 38, 38, 37, 36, 35, 35, 34, 33, 33, 32, 31, 30, 30, 29, 28, + 28, 27, 26, 26, 25, 24, 24, 23, 22, 22, 21, 20, 20, 19, 19, 18, + 17, 17, 16, 16, 15, 14, 14, 13, 13, 12, 11, 11, 10, 10, 9, 9, + 8, 8, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0 +}; + +template <> +uint32_t +fplibRSqrtEstimate(uint32_t op, FPSCR &fpscr) +{ + int mode = modeConv(fpscr); + int flags = 0; + int sgn, exp; + uint32_t mnt, result; + + fp32_unpack(&sgn, &exp, &mnt, op, mode, &flags); + + if (exp == 255 && (uint32_t)(mnt << 9)) { + result = fp32_process_NaN(op, mode, &flags); + } else if (!mnt) { + result = fp32_infinity(sgn); + flags |= FPLIB_DZC; + } else if (sgn) { + result = fp32_defaultNaN(); + flags |= FPLIB_IOC; + } else if (exp == 255) { + result = fp32_zero(0); + } else { + exp += 8; + mnt = fp32_normalise(mnt, &exp); + mnt = recip_sqrt_estimate[(~exp & 1) << 7 | (mnt >> 24 & 127)]; + result = fp32_pack(0, (380 - exp) >> 1, mnt << 15); + } + + set_fpscr0(fpscr, flags); + + return result; +} + +template <> +uint64_t +fplibRSqrtEstimate(uint64_t op, FPSCR &fpscr) +{ + int mode = modeConv(fpscr); + int flags = 0; + int sgn, exp; + uint64_t mnt, result; + + fp64_unpack(&sgn, &exp, &mnt, op, mode, &flags); + + if (exp == 2047 && (uint64_t)(mnt << 12)) { + result = fp64_process_NaN(op, mode, &flags); + } else if (!mnt) { + result = fp64_infinity(sgn); + flags |= FPLIB_DZC; + } else if (sgn) { + result = fp64_defaultNaN(); + flags |= FPLIB_IOC; + } else if (exp == 2047) { + result = fp32_zero(0); + } else { + exp += 11; + mnt = fp64_normalise(mnt, &exp); + mnt = recip_sqrt_estimate[(~exp & 1) << 7 | (mnt >> 56 & 127)]; + result = fp64_pack(0, (3068 - exp) >> 1, mnt << 44); + } + + set_fpscr0(fpscr, flags); + + return result; +} + +template <> +uint32_t +fplibRSqrtStepFused(uint32_t op1, uint32_t op2, FPSCR &fpscr) +{ + int mode = modeConv(fpscr); + int flags = 0; + int sgn1, exp1, sgn2, exp2; + uint32_t mnt1, mnt2, result; + + op1 = fplibNeg<uint32_t>(op1); + fp32_unpack(&sgn1, &exp1, &mnt1, op1, mode, &flags); + fp32_unpack(&sgn2, &exp2, &mnt2, op2, mode, &flags); + + result = fp32_process_NaNs(op1, op2, mode, &flags); + if (!result) { + if ((exp1 == 255 && !mnt2) || (exp2 == 255 && !mnt1)) { + result = fp32_FPOnePointFive(0); + } else if (exp1 == 255 || exp2 == 255) { + result = fp32_infinity(sgn1 ^ sgn2); + } else { + result = fp32_muladd(fp32_FPThree(0), op1, op2, -1, mode, &flags); + } + } + + set_fpscr0(fpscr, flags); + + return result; +} + +template <> +uint64_t +fplibRSqrtStepFused(uint64_t op1, uint64_t op2, FPSCR &fpscr) +{ + int mode = modeConv(fpscr); + int flags = 0; + int sgn1, exp1, sgn2, exp2; + uint64_t mnt1, mnt2, result; + + op1 = fplibNeg<uint64_t>(op1); + fp64_unpack(&sgn1, &exp1, &mnt1, op1, mode, &flags); + fp64_unpack(&sgn2, &exp2, &mnt2, op2, mode, &flags); + + result = fp64_process_NaNs(op1, op2, mode, &flags); + if (!result) { + if ((exp1 == 2047 && !mnt2) || (exp2 == 2047 && !mnt1)) { + result = fp64_FPOnePointFive(0); + } else if (exp1 == 2047 || exp2 == 2047) { + result = fp64_infinity(sgn1 ^ sgn2); + } else { + result = fp64_muladd(fp64_FPThree(0), op1, op2, -1, mode, &flags); + } + } + + set_fpscr0(fpscr, flags); + + return result; +} + +template <> +uint32_t +fplibRecipStepFused(uint32_t op1, uint32_t op2, FPSCR &fpscr) +{ + int mode = modeConv(fpscr); + int flags = 0; + int sgn1, exp1, sgn2, exp2; + uint32_t mnt1, mnt2, result; + + op1 = fplibNeg<uint32_t>(op1); + fp32_unpack(&sgn1, &exp1, &mnt1, op1, mode, &flags); + fp32_unpack(&sgn2, &exp2, &mnt2, op2, mode, &flags); + + result = fp32_process_NaNs(op1, op2, mode, &flags); + if (!result) { + if ((exp1 == 255 && !mnt2) || (exp2 == 255 && !mnt1)) { + result = fp32_FPTwo(0); + } else if (exp1 == 255 || exp2 == 255) { + result = fp32_infinity(sgn1 ^ sgn2); + } else { + result = fp32_muladd(fp32_FPTwo(0), op1, op2, 0, mode, &flags); + } + } + + set_fpscr0(fpscr, flags); + + return result; +} + +template <> +uint32_t +fplibRecipEstimate(uint32_t op, FPSCR &fpscr) +{ + int mode = modeConv(fpscr); + int flags = 0; + int sgn, exp; + uint32_t mnt, result; + + fp32_unpack(&sgn, &exp, &mnt, op, mode, &flags); + + if (exp == 255 && (uint32_t)(mnt << 9)) { + result = fp32_process_NaN(op, mode, &flags); + } else if (exp == 255) { + result = fp32_zero(sgn); + } else if (!mnt) { + result = fp32_infinity(sgn); + flags |= FPLIB_DZC; + } else if (!((uint32_t)(op << 1) >> 22)) { + bool overflow_to_inf; + switch (FPCRRounding(fpscr)) { + case FPRounding_TIEEVEN: + overflow_to_inf = true; + break; + case FPRounding_POSINF: + overflow_to_inf = !sgn; + break; + case FPRounding_NEGINF: + overflow_to_inf = sgn; + break; + case FPRounding_ZERO: + overflow_to_inf = false; + break; + default: + assert(0); + } + result = overflow_to_inf ? fp32_infinity(sgn) : fp32_max_normal(sgn); + flags |= FPLIB_OFC | FPLIB_IXC; + } else if (fpscr.fz && exp >= 253) { + result = fp32_zero(sgn); + flags |= FPLIB_UFC; + } else { + exp += 8; + mnt = fp32_normalise(mnt, &exp); + int result_exp = 253 - exp; + uint32_t fraction = (((uint32_t)1 << 19) / (mnt >> 22 | 1) + 1) >> 1; + fraction <<= 15; + if (result_exp == 0) { + fraction >>= 1; + } else if (result_exp == -1) { + fraction >>= 2; + result_exp = 0; + } + result = fp32_pack(sgn, result_exp, fraction); + } + + set_fpscr0(fpscr, flags); + + return result; +} + +template <> +uint64_t +fplibRecipEstimate(uint64_t op, FPSCR &fpscr) +{ + int mode = modeConv(fpscr); + int flags = 0; + int sgn, exp; + uint64_t mnt, result; + + fp64_unpack(&sgn, &exp, &mnt, op, mode, &flags); + + if (exp == 2047 && (uint64_t)(mnt << 12)) { + result = fp64_process_NaN(op, mode, &flags); + } else if (exp == 2047) { + result = fp64_zero(sgn); + } else if (!mnt) { + result = fp64_infinity(sgn); + flags |= FPLIB_DZC; + } else if (!((uint64_t)(op << 1) >> 51)) { + bool overflow_to_inf; + switch (FPCRRounding(fpscr)) { + case FPRounding_TIEEVEN: + overflow_to_inf = true; + break; + case FPRounding_POSINF: + overflow_to_inf = !sgn; + break; + case FPRounding_NEGINF: + overflow_to_inf = sgn; + break; + case FPRounding_ZERO: + overflow_to_inf = false; + break; + default: + assert(0); + } + result = overflow_to_inf ? fp64_infinity(sgn) : fp64_max_normal(sgn); + flags |= FPLIB_OFC | FPLIB_IXC; + } else if (fpscr.fz && exp >= 2045) { + result = fp64_zero(sgn); + flags |= FPLIB_UFC; + } else { + exp += 11; + mnt = fp64_normalise(mnt, &exp); + int result_exp = 2045 - exp; + uint64_t fraction = (((uint32_t)1 << 19) / (mnt >> 54 | 1) + 1) >> 1; + fraction <<= 44; + if (result_exp == 0) { + fraction >>= 1; + } else if (result_exp == -1) { + fraction >>= 2; + result_exp = 0; + } + result = fp64_pack(sgn, result_exp, fraction); + } + + set_fpscr0(fpscr, flags); + + return result; +} + +template <> +uint64_t +fplibRecipStepFused(uint64_t op1, uint64_t op2, FPSCR &fpscr) +{ + int mode = modeConv(fpscr); + int flags = 0; + int sgn1, exp1, sgn2, exp2; + uint64_t mnt1, mnt2, result; + + op1 = fplibNeg<uint64_t>(op1); + fp64_unpack(&sgn1, &exp1, &mnt1, op1, mode, &flags); + fp64_unpack(&sgn2, &exp2, &mnt2, op2, mode, &flags); + + result = fp64_process_NaNs(op1, op2, mode, &flags); + if (!result) { + if ((exp1 == 2047 && !mnt2) || (exp2 == 2047 && !mnt1)) { + result = fp64_FPTwo(0); + } else if (exp1 == 2047 || exp2 == 2047) { + result = fp64_infinity(sgn1 ^ sgn2); + } else { + result = fp64_muladd(fp64_FPTwo(0), op1, op2, 0, mode, &flags); + } + } + + set_fpscr0(fpscr, flags); + + return result; +} + +template <> +uint32_t +fplibRecpX(uint32_t op, FPSCR &fpscr) +{ + int mode = modeConv(fpscr); + int flags = 0; + int sgn, exp; + uint32_t mnt, result; + + fp32_unpack(&sgn, &exp, &mnt, op, mode, &flags); + + if (exp == 255 && (uint32_t)(mnt << 9)) { + result = fp32_process_NaN(op, mode, &flags); + } + else { + if (!mnt) { // Zero and denormals + result = fp32_pack(sgn, 254, 0); + } else { // Infinities and normals + result = fp32_pack(sgn, exp ^ 255, 0); + } + } + + set_fpscr0(fpscr, flags); + + return result; +} + +template <> +uint64_t +fplibRecpX(uint64_t op, FPSCR &fpscr) +{ + int mode = modeConv(fpscr); + int flags = 0; + int sgn, exp; + uint64_t mnt, result; + + fp64_unpack(&sgn, &exp, &mnt, op, mode, &flags); + + if (exp == 2047 && (uint64_t)(mnt << 12)) { + result = fp64_process_NaN(op, mode, &flags); + } + else { + if (!mnt) { // Zero and denormals + result = fp64_pack(sgn, 2046, 0); + } else { // Infinities and normals + result = fp64_pack(sgn, exp ^ 2047, 0); + } + } + + set_fpscr0(fpscr, flags); + + return result; +} + +template <> +uint32_t +fplibRoundInt(uint32_t op, FPRounding rounding, bool exact, FPSCR &fpscr) +{ + int mode = modeConv(fpscr); + int flags = 0; + int sgn, exp; + uint32_t mnt, result; + + // Unpack using FPCR to determine if subnormals are flushed-to-zero: + fp32_unpack(&sgn, &exp, &mnt, op, mode, &flags); + + // Handle NaNs, infinities and zeroes: + if (exp == 255 && (uint32_t)(mnt << 9)) { + result = fp32_process_NaN(op, mode, &flags); + } else if (exp == 255) { + result = fp32_infinity(sgn); + } else if (!mnt) { + result = fp32_zero(sgn); + } else if (exp >= 150) { + // There are no fractional bits + result = op; + } else { + // Truncate towards zero: + uint32_t x = 150 - exp >= 32 ? 0 : mnt >> (150 - exp); + int err = exp < 118 ? 1 : + (mnt << 1 >> (149 - exp) & 3) | (mnt << 2 << (exp - 118) != 0); + switch (rounding) { + case FPRounding_TIEEVEN: + x += (err == 3 || (err == 2 && (x & 1))); + break; + case FPRounding_POSINF: + x += err && !sgn; + break; + case FPRounding_NEGINF: + x += err && sgn; + break; + case FPRounding_ZERO: + break; + case FPRounding_TIEAWAY: + x += err >> 1; + break; + default: + assert(0); + } + + if (x == 0) { + result = fp32_zero(sgn); + } else { + exp = 150; + mnt = fp32_normalise(x, &exp); + result = fp32_pack(sgn, exp + 8, mnt >> 8); + } + + if (err && exact) + flags |= FPLIB_IXC; + } + + set_fpscr0(fpscr, flags); + + return result; +} + +template <> +uint64_t +fplibRoundInt(uint64_t op, FPRounding rounding, bool exact, FPSCR &fpscr) +{ + int mode = modeConv(fpscr); + int flags = 0; + int sgn, exp; + uint64_t mnt, result; + + // Unpack using FPCR to determine if subnormals are flushed-to-zero: + fp64_unpack(&sgn, &exp, &mnt, op, mode, &flags); + + // Handle NaNs, infinities and zeroes: + if (exp == 2047 && (uint64_t)(mnt << 12)) { + result = fp64_process_NaN(op, mode, &flags); + } else if (exp == 2047) { + result = fp64_infinity(sgn); + } else if (!mnt) { + result = fp64_zero(sgn); + } else if (exp >= 1075) { + // There are no fractional bits + result = op; + } else { + // Truncate towards zero: + uint64_t x = 1075 - exp >= 64 ? 0 : mnt >> (1075 - exp); + int err = exp < 1011 ? 1 : + (mnt << 1 >> (1074 - exp) & 3) | (mnt << 2 << (exp - 1011) != 0); + switch (rounding) { + case FPRounding_TIEEVEN: + x += (err == 3 || (err == 2 && (x & 1))); + break; + case FPRounding_POSINF: + x += err && !sgn; + break; + case FPRounding_NEGINF: + x += err && sgn; + break; + case FPRounding_ZERO: + break; + case FPRounding_TIEAWAY: + x += err >> 1; + break; + default: + assert(0); + } + + if (x == 0) { + result = fp64_zero(sgn); + } else { + exp = 1075; + mnt = fp64_normalise(x, &exp); + result = fp64_pack(sgn, exp + 11, mnt >> 11); + } + + if (err && exact) + flags |= FPLIB_IXC; + } + + set_fpscr0(fpscr, flags); + + return result; +} + +template <> +uint32_t +fplibSqrt(uint32_t op, FPSCR &fpscr) +{ + int flags = 0; + uint32_t result = fp32_sqrt(op, modeConv(fpscr), &flags); + set_fpscr0(fpscr, flags); + return result; +} + +template <> +uint64_t +fplibSqrt(uint64_t op, FPSCR &fpscr) +{ + int flags = 0; + uint64_t result = fp64_sqrt(op, modeConv(fpscr), &flags); + set_fpscr0(fpscr, flags); + return result; +} + +template <> +uint32_t +fplibSub(uint32_t op1, uint32_t op2, FPSCR &fpscr) +{ + int flags = 0; + uint32_t result = fp32_add(op1, op2, 1, modeConv(fpscr), &flags); + set_fpscr0(fpscr, flags); + return result; +} + +template <> +uint64_t +fplibSub(uint64_t op1, uint64_t op2, FPSCR &fpscr) +{ + int flags = 0; + uint64_t result = fp64_add(op1, op2, 1, modeConv(fpscr), &flags); + set_fpscr0(fpscr, flags); + return result; +} + +static uint64_t +FPToFixed_64(int sgn, int exp, uint64_t mnt, bool u, FPRounding rounding, + int *flags) +{ + uint64_t x; + int err; + + if (exp > 1023 + 63) { + *flags = FPLIB_IOC; + return ((uint64_t)!u << 63) - !sgn; + } + + x = lsr64(mnt << 11, 1023 + 63 - exp); + err = (exp > 1023 + 63 - 2 ? 0 : + (lsr64(mnt << 11, 1023 + 63 - 2 - exp) & 3) | + !!(mnt << 11 & (lsl64(1, 1023 + 63 - 2 - exp) - 1))); + + switch (rounding) { + case FPRounding_TIEEVEN: + x += (err == 3 || (err == 2 && (x & 1))); + break; + case FPRounding_POSINF: + x += err && !sgn; + break; + case FPRounding_NEGINF: + x += err && sgn; + break; + case FPRounding_ZERO: + break; + case FPRounding_TIEAWAY: + x += err >> 1; + break; + default: + assert(0); + } + + if (u ? sgn && x : x > ((uint64_t)1 << 63) - !sgn) { + *flags = FPLIB_IOC; + return ((uint64_t)!u << 63) - !sgn; + } + + if (err) { + *flags = FPLIB_IXC; + } + + return sgn ? -x : x; +} + +static uint32_t +FPToFixed_32(int sgn, int exp, uint64_t mnt, bool u, FPRounding rounding, + int *flags) +{ + uint64_t x = FPToFixed_64(sgn, exp, mnt, u, rounding, flags); + if (u ? x >= (uint64_t)1 << 32 : + !(x < (uint64_t)1 << 31 || + (uint64_t)-x <= (uint64_t)1 << 31)) { + *flags = FPLIB_IOC; + x = ((uint32_t)!u << 31) - !sgn; + } + return x; +} + +template <> +uint32_t +fplibFPToFixed(uint32_t op, int fbits, bool u, FPRounding rounding, FPSCR &fpscr) +{ + int flags = 0; + int sgn, exp; + uint32_t mnt, result; + + // Unpack using FPCR to determine if subnormals are flushed-to-zero: + fp32_unpack(&sgn, &exp, &mnt, op, modeConv(fpscr), &flags); + + // If NaN, set cumulative flag or take exception: + if (exp == 255 && (uint32_t)(mnt << 9)) { + flags = FPLIB_IOC; + result = 0; + } else { + result = FPToFixed_32(sgn, exp + 1023 - 127 + fbits, + (uint64_t)mnt << (52 - 23), u, rounding, &flags); + } + + set_fpscr0(fpscr, flags); + + return result; +} + +template <> +uint32_t +fplibFPToFixed(uint64_t op, int fbits, bool u, FPRounding rounding, FPSCR &fpscr) +{ + int flags = 0; + int sgn, exp; + uint64_t mnt; + uint32_t result; + + // Unpack using FPCR to determine if subnormals are flushed-to-zero: + fp64_unpack(&sgn, &exp, &mnt, op, modeConv(fpscr), &flags); + + // If NaN, set cumulative flag or take exception: + if (exp == 2047 && (uint64_t)(mnt << 12)) { + flags = FPLIB_IOC; + result = 0; + } else { + result = FPToFixed_32(sgn, exp + fbits, mnt, u, rounding, &flags); + } + + set_fpscr0(fpscr, flags); + + return result; +} + +template <> +uint64_t +fplibFPToFixed(uint32_t op, int fbits, bool u, FPRounding rounding, FPSCR &fpscr) +{ + int flags = 0; + int sgn, exp; + uint32_t mnt; + uint64_t result; + + // Unpack using FPCR to determine if subnormals are flushed-to-zero: + fp32_unpack(&sgn, &exp, &mnt, op, modeConv(fpscr), &flags); + + // If NaN, set cumulative flag or take exception: + if (exp == 255 && (uint32_t)(mnt << 9)) { + flags = FPLIB_IOC; + result = 0; + } else { + result = FPToFixed_64(sgn, exp + 1023 - 127 + fbits, + (uint64_t)mnt << (52 - 23), u, rounding, &flags); + } + + set_fpscr0(fpscr, flags); + + return result; +} + +template <> +uint64_t +fplibFPToFixed(uint64_t op, int fbits, bool u, FPRounding rounding, FPSCR &fpscr) +{ + int flags = 0; + int sgn, exp; + uint64_t mnt, result; + + // Unpack using FPCR to determine if subnormals are flushed-to-zero: + fp64_unpack(&sgn, &exp, &mnt, op, modeConv(fpscr), &flags); + + // If NaN, set cumulative flag or take exception: + if (exp == 2047 && (uint64_t)(mnt << 12)) { + flags = FPLIB_IOC; + result = 0; + } else { + result = FPToFixed_64(sgn, exp + fbits, mnt, u, rounding, &flags); + } + + set_fpscr0(fpscr, flags); + + return result; +} + +static uint32_t +fp32_cvtf(uint64_t a, int fbits, int u, int mode, int *flags) +{ + int x_sgn = !u && a >> 63; + int x_exp = 190 - fbits; + uint64_t x_mnt = x_sgn ? -a : a; + + // Handle zero: + if (!x_mnt) { + return fp32_zero(0); + } + + // Normalise and convert to 32 bits, collapsing error into bottom bit: + x_mnt = fp64_normalise(x_mnt, &x_exp); + x_mnt = x_mnt >> 31 | !!(uint32_t)(x_mnt << 1); + + return fp32_round(x_sgn, x_exp, x_mnt, mode, flags); +} + +static uint64_t +fp64_cvtf(uint64_t a, int fbits, int u, int mode, int *flags) +{ + int x_sgn = !u && a >> 63; + int x_exp = 1024 + 62 - fbits; + uint64_t x_mnt = x_sgn ? -a : a; + + // Handle zero: + if (!x_mnt) { + return fp64_zero(0); + } + + x_mnt = fp64_normalise(x_mnt, &x_exp); + + return fp64_round(x_sgn, x_exp, x_mnt << 1, mode, flags); +} + +template <> +uint32_t +fplibFixedToFP(uint64_t op, int fbits, bool u, FPRounding rounding, FPSCR &fpscr) +{ + int flags = 0; + uint32_t res = fp32_cvtf(op, fbits, u, + (int)rounding | ((uint32_t)fpscr >> 22 & 12), + &flags); + set_fpscr0(fpscr, flags); + return res; +} + +template <> +uint64_t +fplibFixedToFP(uint64_t op, int fbits, bool u, FPRounding rounding, FPSCR &fpscr) +{ + int flags = 0; + uint64_t res = fp64_cvtf(op, fbits, u, + (int)rounding | ((uint32_t)fpscr >> 22 & 12), + &flags); + set_fpscr0(fpscr, flags); + return res; +} + +} diff --git a/src/arch/arm/insts/fplib.hh b/src/arch/arm/insts/fplib.hh new file mode 100644 index 000000000..6263687fc --- /dev/null +++ b/src/arch/arm/insts/fplib.hh @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2012-2013 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Edmund Grimley Evans + * Thomas Grocutt + */ + +/** + * @file + * Floating-point library code, which will gradually replace vfp.hh. For + * portability, this library does not use floating-point data types. Currently, + * C's standard integer types are used in the API, though this could be changed + * to something like class Fp32 { uint32_t x; }, etc. + */ + +#ifndef __ARCH_ARM_INSTS_FPLIB_HH__ +#define __ARCH_ARM_INSTS_FPLIB_HH__ + +#include <stdint.h> + +#include "arch/arm/miscregs.hh" + +namespace ArmISA +{ + +enum FPRounding { + FPRounding_TIEEVEN = 0, + FPRounding_POSINF = 1, + FPRounding_NEGINF = 2, + FPRounding_ZERO = 3, + FPRounding_TIEAWAY = 4, + FPRounding_ODD = 5 +}; + +static inline FPRounding +FPCRRounding(FPSCR &fpscr) +{ + return (FPRounding)((uint32_t)fpscr >> 22 & 3); +} + +/** Floating-point absolute value. */ +template <class T> +T fplibAbs(T op); +/** Floating-point add. */ +template <class T> +T fplibAdd(T op1, T op2, FPSCR &fpscr); +/** Floating-point compare (quiet and signaling). */ +template <class T> +int fplibCompare(T op1, T op2, bool signal_nans, FPSCR &fpscr); +/** Floating-point compare equal. */ +template <class T> +bool fplibCompareEQ(T op1, T op2, FPSCR &fpscr); +/** Floating-point compare greater than or equal. */ +template <class T> +bool fplibCompareGE(T op1, T op2, FPSCR &fpscr); +/** Floating-point compare greater than. */ +template <class T> +bool fplibCompareGT(T op1, T op2, FPSCR &fpscr); +/** Floating-point convert precision. */ +template <class T1, class T2> +T2 fplibConvert(T1 op, FPRounding rounding, FPSCR &fpscr); +/** Floating-point division. */ +template <class T> +T fplibDiv(T op1, T op2, FPSCR &fpscr); +/** Floating-point maximum. */ +template <class T> +T fplibMax(T op1, T op2, FPSCR &fpscr); +/** Floating-point maximum number. */ +template <class T> +T fplibMaxNum(T op1, T op2, FPSCR &fpscr); +/** Floating-point minimum. */ +template <class T> +T fplibMin(T op1, T op2, FPSCR &fpscr); +/** Floating-point minimum number. */ +template <class T> +T fplibMinNum(T op1, T op2, FPSCR &fpscr); +/** Floating-point multiply. */ +template <class T> +T fplibMul(T op1, T op2, FPSCR &fpscr); +/** Floating-point multiply-add. */ +template <class T> +T fplibMulAdd(T addend, T op1, T op2, FPSCR &fpscr); +/** Floating-point multiply extended. */ +template <class T> +T fplibMulX(T op1, T op2, FPSCR &fpscr); +/** Floating-point negate. */ +template <class T> +T fplibNeg(T op); +/** Floating-point reciprocal square root estimate. */ +template <class T> +T fplibRSqrtEstimate(T op, FPSCR &fpscr); +/** Floating-point reciprocal square root step. */ +template <class T> +T fplibRSqrtStepFused(T op1, T op2, FPSCR &fpscr); +/** Floating-point reciprocal estimate. */ +template <class T> +T fplibRecipEstimate(T op, FPSCR &fpscr); +/** Floating-point reciprocal step. */ +template <class T> +T fplibRecipStepFused(T op1, T op2, FPSCR &fpscr); +/** Floating-point reciprocal exponent. */ +template <class T> +T fplibRecpX(T op, FPSCR &fpscr); +/** Floating-point convert to integer. */ +template <class T> +T fplibRoundInt(T op, FPRounding rounding, bool exact, FPSCR &fpscr); +/** Floating-point square root. */ +template <class T> +T fplibSqrt(T op, FPSCR &fpscr); +/** Floating-point subtract. */ +template <class T> +T fplibSub(T op1, T op2, FPSCR &fpscr); +/** Floating-point convert to fixed-point. */ +template <class T1, class T2> +T2 fplibFPToFixed(T1 op, int fbits, bool u, FPRounding rounding, FPSCR &fpscr); +/** Floating-point convert from fixed-point. */ +template <class T> +T fplibFixedToFP(uint64_t op, int fbits, bool u, FPRounding rounding, + FPSCR &fpscr); + +/* Function specializations... */ +template <> +uint32_t fplibAbs(uint32_t op); +template <> +uint64_t fplibAbs(uint64_t op); +template <> +uint32_t fplibAdd(uint32_t op1, uint32_t op2, FPSCR &fpscr); +template <> +uint64_t fplibAdd(uint64_t op1, uint64_t op2, FPSCR &fpscr); +template <> +int fplibCompare(uint32_t op1, uint32_t op2, bool signal_nans, FPSCR &fpscr); +template <> +int fplibCompare(uint64_t op1, uint64_t op2, bool signal_nans, FPSCR &fpscr); +template <> +bool fplibCompareEQ(uint32_t op1, uint32_t op2, FPSCR &fpscr); +template <> +bool fplibCompareEQ(uint64_t op1, uint64_t op2, FPSCR &fpscr); +template <> +bool fplibCompareGE(uint32_t op1, uint32_t op2, FPSCR &fpscr); +template <> +bool fplibCompareGE(uint64_t op1, uint64_t op2, FPSCR &fpscr); +template <> +bool fplibCompareGT(uint32_t op1, uint32_t op2, FPSCR &fpscr); +template <> +bool fplibCompareGT(uint64_t op1, uint64_t op2, FPSCR &fpscr); +template <> +uint16_t fplibConvert(uint32_t op, FPRounding rounding, FPSCR &fpscr); +template <> +uint16_t fplibConvert(uint64_t op, FPRounding rounding, FPSCR &fpscr); +template <> +uint32_t fplibConvert(uint16_t op, FPRounding rounding, FPSCR &fpscr); +template <> +uint32_t fplibConvert(uint64_t op, FPRounding rounding, FPSCR &fpscr); +template <> +uint64_t fplibConvert(uint16_t op, FPRounding rounding, FPSCR &fpscr); +template <> +uint64_t fplibConvert(uint32_t op, FPRounding rounding, FPSCR &fpscr); +template <> +uint32_t fplibDiv(uint32_t op1, uint32_t op2, FPSCR &fpscr); +template <> +uint64_t fplibDiv(uint64_t op1, uint64_t op2, FPSCR &fpscr); +template <> +uint32_t fplibMax(uint32_t op1, uint32_t op2, FPSCR &fpscr); +template <> +uint64_t fplibMax(uint64_t op1, uint64_t op2, FPSCR &fpscr); +template <> +uint32_t fplibMaxNum(uint32_t op1, uint32_t op2, FPSCR &fpscr); +template <> +uint64_t fplibMaxNum(uint64_t op1, uint64_t op2, FPSCR &fpscr); +template <> +uint32_t fplibMin(uint32_t op1, uint32_t op2, FPSCR &fpscr); +template <> +uint64_t fplibMin(uint64_t op1, uint64_t op2, FPSCR &fpscr); +template <> +uint32_t fplibMinNum(uint32_t op1, uint32_t op2, FPSCR &fpscr); +template <> +uint64_t fplibMinNum(uint64_t op1, uint64_t op2, FPSCR &fpscr); +template <> +uint32_t fplibMul(uint32_t op1, uint32_t op2, FPSCR &fpscr); +template <> +uint64_t fplibMul(uint64_t op1, uint64_t op2, FPSCR &fpscr); +template <> +uint32_t fplibMulAdd(uint32_t addend, uint32_t op1, uint32_t op2, + FPSCR &fpscr); +template <> +uint64_t fplibMulAdd(uint64_t addend, uint64_t op1, uint64_t op2, + FPSCR &fpscr); +template <> +uint32_t fplibMulX(uint32_t op1, uint32_t op2, FPSCR &fpscr); +template <> +uint64_t fplibMulX(uint64_t op1, uint64_t op2, FPSCR &fpscr); +template <> +uint32_t fplibNeg(uint32_t op); +template <> +uint64_t fplibNeg(uint64_t op); +template <> +uint32_t fplibRSqrtEstimate(uint32_t op, FPSCR &fpscr); +template<> +uint64_t fplibRSqrtEstimate(uint64_t op, FPSCR &fpscr); +template <> +uint32_t fplibRSqrtStepFused(uint32_t op1, uint32_t op2, FPSCR &fpscr); +template <> +uint64_t fplibRSqrtStepFused(uint64_t op1, uint64_t op2, FPSCR &fpscr); +template <> +uint32_t fplibRecipEstimate(uint32_t op, FPSCR &fpscr); +template <> +uint64_t fplibRecipEstimate(uint64_t op, FPSCR &fpscr); +template <> +uint32_t fplibRecipStepFused(uint32_t op1, uint32_t op2, FPSCR &fpscr); +template <> +uint64_t fplibRecipStepFused(uint64_t op1, uint64_t op2, FPSCR &fpscr); +template <> +uint32_t fplibRecpX(uint32_t op, FPSCR &fpscr); +template <> +uint64_t fplibRecpX(uint64_t op, FPSCR &fpscr); +template <> +uint32_t fplibRoundInt(uint32_t op, FPRounding rounding, bool exact, + FPSCR &fpscr); +template <> +uint64_t fplibRoundInt(uint64_t op, FPRounding rounding, bool exact, + FPSCR &fpscr); +template <> +uint32_t fplibSqrt(uint32_t op, FPSCR &fpscr); +template <> +uint64_t fplibSqrt(uint64_t op, FPSCR &fpscr); +template <> +uint32_t fplibSub(uint32_t op1, uint32_t op2, FPSCR &fpscr); +template <> +uint64_t fplibSub(uint64_t op1, uint64_t op2, FPSCR &fpscr); +template <> +uint32_t fplibFPToFixed(uint32_t op, int fbits, bool u, FPRounding rounding, + FPSCR &fpscr); +template <> +uint32_t fplibFPToFixed(uint64_t op, int fbits, bool u, FPRounding rounding, + FPSCR &fpscr); +template <> +uint64_t fplibFPToFixed(uint32_t op, int fbits, bool u, FPRounding rounding, + FPSCR &fpscr); +template <> +uint64_t fplibFPToFixed(uint64_t op, int fbits, bool u, FPRounding rounding, + FPSCR &fpscr); +template <> +uint32_t fplibFixedToFP(uint64_t op, int fbits, bool u, FPRounding rounding, + FPSCR &fpscr); +template <> +uint64_t fplibFixedToFP(uint64_t op, int fbits, bool u, FPRounding rounding, + FPSCR &fpscr); +} + +#endif diff --git a/src/arch/arm/insts/macromem.cc b/src/arch/arm/insts/macromem.cc index 26a916fc7..42cb98a7c 100644 --- a/src/arch/arm/insts/macromem.cc +++ b/src/arch/arm/insts/macromem.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -43,7 +43,9 @@ #include <sstream> #include "arch/arm/insts/macromem.hh" + #include "arch/arm/generated/decoder.hh" +#include "arch/arm/insts/neon64_mem.hh" using namespace std; using namespace ArmISAInst; @@ -177,6 +179,212 @@ MacroMemOp::MacroMemOp(const char *mnem, ExtMachInst machInst, } } +PairMemOp::PairMemOp(const char *mnem, ExtMachInst machInst, OpClass __opClass, + uint32_t size, bool fp, bool load, bool noAlloc, + bool signExt, bool exclusive, bool acrel, + int64_t imm, AddrMode mode, + IntRegIndex rn, IntRegIndex rt, IntRegIndex rt2) : + PredMacroOp(mnem, machInst, __opClass) +{ + bool writeback = (mode != AddrMd_Offset); + numMicroops = 1 + (size / 4) + (writeback ? 1 : 0); + microOps = new StaticInstPtr[numMicroops]; + + StaticInstPtr *uop = microOps; + + bool post = (mode == AddrMd_PostIndex); + + rn = makeSP(rn); + + *uop = new MicroAddXiSpAlignUop(machInst, INTREG_UREG0, rn, post ? 0 : imm); + + if (fp) { + if (size == 16) { + if (load) { + *++uop = new MicroLdrQBFpXImmUop(machInst, rt, + INTREG_UREG0, 0, noAlloc, exclusive, acrel); + *++uop = new MicroLdrQTFpXImmUop(machInst, rt, + INTREG_UREG0, 0, noAlloc, exclusive, acrel); + *++uop = new MicroLdrQBFpXImmUop(machInst, rt2, + INTREG_UREG0, 16, noAlloc, exclusive, acrel); + *++uop = new MicroLdrQTFpXImmUop(machInst, rt2, + INTREG_UREG0, 16, noAlloc, exclusive, acrel); + } else { + *++uop = new MicroStrQBFpXImmUop(machInst, rt, + INTREG_UREG0, 0, noAlloc, exclusive, acrel); + *++uop = new MicroStrQTFpXImmUop(machInst, rt, + INTREG_UREG0, 0, noAlloc, exclusive, acrel); + *++uop = new MicroStrQBFpXImmUop(machInst, rt2, + INTREG_UREG0, 16, noAlloc, exclusive, acrel); + *++uop = new MicroStrQTFpXImmUop(machInst, rt2, + INTREG_UREG0, 16, noAlloc, exclusive, acrel); + } + } else if (size == 8) { + if (load) { + *++uop = new MicroLdrFpXImmUop(machInst, rt, + INTREG_UREG0, 0, noAlloc, exclusive, acrel); + *++uop = new MicroLdrFpXImmUop(machInst, rt2, + INTREG_UREG0, 8, noAlloc, exclusive, acrel); + } else { + *++uop = new MicroStrFpXImmUop(machInst, rt, + INTREG_UREG0, 0, noAlloc, exclusive, acrel); + *++uop = new MicroStrFpXImmUop(machInst, rt2, + INTREG_UREG0, 8, noAlloc, exclusive, acrel); + } + } else if (size == 4) { + if (load) { + *++uop = new MicroLdrDFpXImmUop(machInst, rt, rt2, + INTREG_UREG0, 0, noAlloc, exclusive, acrel); + } else { + *++uop = new MicroStrDFpXImmUop(machInst, rt, rt2, + INTREG_UREG0, 0, noAlloc, exclusive, acrel); + } + } + } else { + if (size == 8) { + if (load) { + *++uop = new MicroLdrXImmUop(machInst, rt, INTREG_UREG0, + 0, noAlloc, exclusive, acrel); + *++uop = new MicroLdrXImmUop(machInst, rt2, INTREG_UREG0, + size, noAlloc, exclusive, acrel); + } else { + *++uop = new MicroStrXImmUop(machInst, rt, INTREG_UREG0, + 0, noAlloc, exclusive, acrel); + *++uop = new MicroStrXImmUop(machInst, rt2, INTREG_UREG0, + size, noAlloc, exclusive, acrel); + } + } else if (size == 4) { + if (load) { + if (signExt) { + *++uop = new MicroLdrDSXImmUop(machInst, rt, rt2, + INTREG_UREG0, 0, noAlloc, exclusive, acrel); + } else { + *++uop = new MicroLdrDUXImmUop(machInst, rt, rt2, + INTREG_UREG0, 0, noAlloc, exclusive, acrel); + } + } else { + *++uop = new MicroStrDXImmUop(machInst, rt, rt2, + INTREG_UREG0, 0, noAlloc, exclusive, acrel); + } + } + } + + if (writeback) { + *++uop = new MicroAddXiUop(machInst, rn, INTREG_UREG0, + post ? imm : 0); + } + + (*uop)->setLastMicroop(); + + for (StaticInstPtr *curUop = microOps; + !(*curUop)->isLastMicroop(); curUop++) { + (*curUop)->setDelayedCommit(); + } +} + +BigFpMemImmOp::BigFpMemImmOp(const char *mnem, ExtMachInst machInst, + OpClass __opClass, bool load, IntRegIndex dest, + IntRegIndex base, int64_t imm) : + PredMacroOp(mnem, machInst, __opClass) +{ + numMicroops = 2; + microOps = new StaticInstPtr[numMicroops]; + + if (load) { + microOps[0] = new MicroLdrQBFpXImmUop(machInst, dest, base, imm); + microOps[1] = new MicroLdrQTFpXImmUop(machInst, dest, base, imm); + } else { + microOps[0] = new MicroStrQBFpXImmUop(machInst, dest, base, imm); + microOps[1] = new MicroStrQTFpXImmUop(machInst, dest, base, imm); + } + microOps[0]->setDelayedCommit(); + microOps[1]->setLastMicroop(); +} + +BigFpMemPostOp::BigFpMemPostOp(const char *mnem, ExtMachInst machInst, + OpClass __opClass, bool load, IntRegIndex dest, + IntRegIndex base, int64_t imm) : + PredMacroOp(mnem, machInst, __opClass) +{ + numMicroops = 3; + microOps = new StaticInstPtr[numMicroops]; + + if (load) { + microOps[0] = new MicroLdrQBFpXImmUop(machInst, dest, base, 0); + microOps[1] = new MicroLdrQTFpXImmUop(machInst, dest, base, 0); + } else { + microOps[0] = new MicroStrQBFpXImmUop(machInst, dest, base, 0); + microOps[1] = new MicroStrQTFpXImmUop(machInst, dest, base, 0); + } + microOps[2] = new MicroAddXiUop(machInst, base, base, imm); + + microOps[0]->setDelayedCommit(); + microOps[1]->setDelayedCommit(); + microOps[2]->setLastMicroop(); +} + +BigFpMemPreOp::BigFpMemPreOp(const char *mnem, ExtMachInst machInst, + OpClass __opClass, bool load, IntRegIndex dest, + IntRegIndex base, int64_t imm) : + PredMacroOp(mnem, machInst, __opClass) +{ + numMicroops = 3; + microOps = new StaticInstPtr[numMicroops]; + + if (load) { + microOps[0] = new MicroLdrQBFpXImmUop(machInst, dest, base, imm); + microOps[1] = new MicroLdrQTFpXImmUop(machInst, dest, base, imm); + } else { + microOps[0] = new MicroStrQBFpXImmUop(machInst, dest, base, imm); + microOps[1] = new MicroStrQTFpXImmUop(machInst, dest, base, imm); + } + microOps[2] = new MicroAddXiUop(machInst, base, base, imm); + + microOps[0]->setDelayedCommit(); + microOps[1]->setDelayedCommit(); + microOps[2]->setLastMicroop(); +} + +BigFpMemRegOp::BigFpMemRegOp(const char *mnem, ExtMachInst machInst, + OpClass __opClass, bool load, IntRegIndex dest, + IntRegIndex base, IntRegIndex offset, + ArmExtendType type, int64_t imm) : + PredMacroOp(mnem, machInst, __opClass) +{ + numMicroops = 2; + microOps = new StaticInstPtr[numMicroops]; + + if (load) { + microOps[0] = new MicroLdrQBFpXRegUop(machInst, dest, base, + offset, type, imm); + microOps[1] = new MicroLdrQTFpXRegUop(machInst, dest, base, + offset, type, imm); + } else { + microOps[0] = new MicroStrQBFpXRegUop(machInst, dest, base, + offset, type, imm); + microOps[1] = new MicroStrQTFpXRegUop(machInst, dest, base, + offset, type, imm); + } + + microOps[0]->setDelayedCommit(); + microOps[1]->setLastMicroop(); +} + +BigFpMemLitOp::BigFpMemLitOp(const char *mnem, ExtMachInst machInst, + OpClass __opClass, IntRegIndex dest, + int64_t imm) : + PredMacroOp(mnem, machInst, __opClass) +{ + numMicroops = 2; + microOps = new StaticInstPtr[numMicroops]; + + microOps[0] = new MicroLdrQBFpXLitUop(machInst, dest, imm); + microOps[1] = new MicroLdrQTFpXLitUop(machInst, dest, imm); + + microOps[0]->setDelayedCommit(); + microOps[1]->setLastMicroop(); +} + VldMultOp::VldMultOp(const char *mnem, ExtMachInst machInst, OpClass __opClass, unsigned elems, RegIndex rn, RegIndex vd, unsigned regs, unsigned inc, uint32_t size, uint32_t align, RegIndex rm) : @@ -193,7 +401,7 @@ VldMultOp::VldMultOp(const char *mnem, ExtMachInst machInst, OpClass __opClass, if (deinterleave) numMicroops += (regs / elems); microOps = new StaticInstPtr[numMicroops]; - RegIndex rMid = deinterleave ? NumFloatArchRegs : vd * 2; + RegIndex rMid = deinterleave ? NumFloatV7ArchRegs : vd * 2; uint32_t noAlign = TLB::MustBeOne; @@ -295,7 +503,7 @@ VldSingleOp::VldSingleOp(const char *mnem, ExtMachInst machInst, numMicroops += (regs / elems); microOps = new StaticInstPtr[numMicroops]; - RegIndex ufp0 = NumFloatArchRegs; + RegIndex ufp0 = NumFloatV7ArchRegs; unsigned uopIdx = 0; switch (loadSize) { @@ -556,7 +764,7 @@ VstMultOp::VstMultOp(const char *mnem, ExtMachInst machInst, OpClass __opClass, uint32_t noAlign = TLB::MustBeOne; - RegIndex rMid = interleave ? NumFloatArchRegs : vd * 2; + RegIndex rMid = interleave ? NumFloatV7ArchRegs : vd * 2; unsigned uopIdx = 0; if (interleave) { @@ -657,7 +865,7 @@ VstSingleOp::VstSingleOp(const char *mnem, ExtMachInst machInst, numMicroops += (regs / elems); microOps = new StaticInstPtr[numMicroops]; - RegIndex ufp0 = NumFloatArchRegs; + RegIndex ufp0 = NumFloatV7ArchRegs; unsigned uopIdx = 0; switch (elems) { @@ -834,6 +1042,285 @@ VstSingleOp::VstSingleOp(const char *mnem, ExtMachInst machInst, microOps[numMicroops - 1]->setLastMicroop(); } +VldMultOp64::VldMultOp64(const char *mnem, ExtMachInst machInst, + OpClass __opClass, RegIndex rn, RegIndex vd, + RegIndex rm, uint8_t eSize, uint8_t dataSize, + uint8_t numStructElems, uint8_t numRegs, bool wb) : + PredMacroOp(mnem, machInst, __opClass) +{ + RegIndex vx = NumFloatV8ArchRegs / 4; + RegIndex rnsp = (RegIndex) makeSP((IntRegIndex) rn); + bool baseIsSP = isSP((IntRegIndex) rnsp); + + numMicroops = wb ? 1 : 0; + + int totNumBytes = numRegs * dataSize / 8; + assert(totNumBytes <= 64); + + // The guiding principle here is that no more than 16 bytes can be + // transferred at a time + int numMemMicroops = totNumBytes / 16; + int residuum = totNumBytes % 16; + if (residuum) + ++numMemMicroops; + numMicroops += numMemMicroops; + + int numMarshalMicroops = numRegs / 2 + (numRegs % 2 ? 1 : 0); + numMicroops += numMarshalMicroops; + + microOps = new StaticInstPtr[numMicroops]; + unsigned uopIdx = 0; + uint32_t memaccessFlags = TLB::MustBeOne | (TLB::ArmFlags) eSize | + TLB::AllowUnaligned; + + int i = 0; + for(; i < numMemMicroops - 1; ++i) { + microOps[uopIdx++] = new MicroNeonLoad64( + machInst, vx + (RegIndex) i, rnsp, 16 * i, memaccessFlags, + baseIsSP, 16 /* accSize */, eSize); + } + microOps[uopIdx++] = new MicroNeonLoad64( + machInst, vx + (RegIndex) i, rnsp, 16 * i, memaccessFlags, baseIsSP, + residuum ? residuum : 16 /* accSize */, eSize); + + // Writeback microop: the post-increment amount is encoded in "Rm": a + // 64-bit general register OR as '11111' for an immediate value equal to + // the total number of bytes transferred (i.e. 8, 16, 24, 32, 48 or 64) + if (wb) { + if (rm != ((RegIndex) INTREG_X31)) { + microOps[uopIdx++] = new MicroAddXERegUop(machInst, rnsp, rnsp, rm, + UXTX, 0); + } else { + microOps[uopIdx++] = new MicroAddXiUop(machInst, rnsp, rnsp, + totNumBytes); + } + } + + for (int i = 0; i < numMarshalMicroops; ++i) { + microOps[uopIdx++] = new MicroDeintNeon64( + machInst, vd + (RegIndex) (2 * i), vx, eSize, dataSize, + numStructElems, numRegs, i /* step */); + } + + assert(uopIdx == numMicroops); + + for (int i = 0; i < numMicroops - 1; ++i) { + microOps[i]->setDelayedCommit(); + } + microOps[numMicroops - 1]->setLastMicroop(); +} + +VstMultOp64::VstMultOp64(const char *mnem, ExtMachInst machInst, + OpClass __opClass, RegIndex rn, RegIndex vd, + RegIndex rm, uint8_t eSize, uint8_t dataSize, + uint8_t numStructElems, uint8_t numRegs, bool wb) : + PredMacroOp(mnem, machInst, __opClass) +{ + RegIndex vx = NumFloatV8ArchRegs / 4; + RegIndex rnsp = (RegIndex) makeSP((IntRegIndex) rn); + bool baseIsSP = isSP((IntRegIndex) rnsp); + + numMicroops = wb ? 1 : 0; + + int totNumBytes = numRegs * dataSize / 8; + assert(totNumBytes <= 64); + + // The guiding principle here is that no more than 16 bytes can be + // transferred at a time + int numMemMicroops = totNumBytes / 16; + int residuum = totNumBytes % 16; + if (residuum) + ++numMemMicroops; + numMicroops += numMemMicroops; + + int numMarshalMicroops = totNumBytes > 32 ? 2 : 1; + numMicroops += numMarshalMicroops; + + microOps = new StaticInstPtr[numMicroops]; + unsigned uopIdx = 0; + + for(int i = 0; i < numMarshalMicroops; ++i) { + microOps[uopIdx++] = new MicroIntNeon64( + machInst, vx + (RegIndex) (2 * i), vd, eSize, dataSize, + numStructElems, numRegs, i /* step */); + } + + uint32_t memaccessFlags = TLB::MustBeOne | (TLB::ArmFlags) eSize | + TLB::AllowUnaligned; + + int i = 0; + for(; i < numMemMicroops - 1; ++i) { + microOps[uopIdx++] = new MicroNeonStore64( + machInst, vx + (RegIndex) i, rnsp, 16 * i, memaccessFlags, + baseIsSP, 16 /* accSize */, eSize); + } + microOps[uopIdx++] = new MicroNeonStore64( + machInst, vx + (RegIndex) i, rnsp, 16 * i, memaccessFlags, baseIsSP, + residuum ? residuum : 16 /* accSize */, eSize); + + // Writeback microop: the post-increment amount is encoded in "Rm": a + // 64-bit general register OR as '11111' for an immediate value equal to + // the total number of bytes transferred (i.e. 8, 16, 24, 32, 48 or 64) + if (wb) { + if (rm != ((RegIndex) INTREG_X31)) { + microOps[uopIdx++] = new MicroAddXERegUop(machInst, rnsp, rnsp, rm, + UXTX, 0); + } else { + microOps[uopIdx++] = new MicroAddXiUop(machInst, rnsp, rnsp, + totNumBytes); + } + } + + assert(uopIdx == numMicroops); + + for (int i = 0; i < numMicroops - 1; i++) { + microOps[i]->setDelayedCommit(); + } + microOps[numMicroops - 1]->setLastMicroop(); +} + +VldSingleOp64::VldSingleOp64(const char *mnem, ExtMachInst machInst, + OpClass __opClass, RegIndex rn, RegIndex vd, + RegIndex rm, uint8_t eSize, uint8_t dataSize, + uint8_t numStructElems, uint8_t index, bool wb, + bool replicate) : + PredMacroOp(mnem, machInst, __opClass) +{ + RegIndex vx = NumFloatV8ArchRegs / 4; + RegIndex rnsp = (RegIndex) makeSP((IntRegIndex) rn); + bool baseIsSP = isSP((IntRegIndex) rnsp); + + numMicroops = wb ? 1 : 0; + + int eSizeBytes = 1 << eSize; + int totNumBytes = numStructElems * eSizeBytes; + assert(totNumBytes <= 64); + + // The guiding principle here is that no more than 16 bytes can be + // transferred at a time + int numMemMicroops = totNumBytes / 16; + int residuum = totNumBytes % 16; + if (residuum) + ++numMemMicroops; + numMicroops += numMemMicroops; + + int numMarshalMicroops = numStructElems / 2 + (numStructElems % 2 ? 1 : 0); + numMicroops += numMarshalMicroops; + + microOps = new StaticInstPtr[numMicroops]; + unsigned uopIdx = 0; + + uint32_t memaccessFlags = TLB::MustBeOne | (TLB::ArmFlags) eSize | + TLB::AllowUnaligned; + + int i = 0; + for (; i < numMemMicroops - 1; ++i) { + microOps[uopIdx++] = new MicroNeonLoad64( + machInst, vx + (RegIndex) i, rnsp, 16 * i, memaccessFlags, + baseIsSP, 16 /* accSize */, eSize); + } + microOps[uopIdx++] = new MicroNeonLoad64( + machInst, vx + (RegIndex) i, rnsp, 16 * i, memaccessFlags, baseIsSP, + residuum ? residuum : 16 /* accSize */, eSize); + + // Writeback microop: the post-increment amount is encoded in "Rm": a + // 64-bit general register OR as '11111' for an immediate value equal to + // the total number of bytes transferred (i.e. 8, 16, 24, 32, 48 or 64) + if (wb) { + if (rm != ((RegIndex) INTREG_X31)) { + microOps[uopIdx++] = new MicroAddXERegUop(machInst, rnsp, rnsp, rm, + UXTX, 0); + } else { + microOps[uopIdx++] = new MicroAddXiUop(machInst, rnsp, rnsp, + totNumBytes); + } + } + + for(int i = 0; i < numMarshalMicroops; ++i) { + microOps[uopIdx++] = new MicroUnpackNeon64( + machInst, vd + (RegIndex) (2 * i), vx, eSize, dataSize, + numStructElems, index, i /* step */, replicate); + } + + assert(uopIdx == numMicroops); + + for (int i = 0; i < numMicroops - 1; i++) { + microOps[i]->setDelayedCommit(); + } + microOps[numMicroops - 1]->setLastMicroop(); +} + +VstSingleOp64::VstSingleOp64(const char *mnem, ExtMachInst machInst, + OpClass __opClass, RegIndex rn, RegIndex vd, + RegIndex rm, uint8_t eSize, uint8_t dataSize, + uint8_t numStructElems, uint8_t index, bool wb, + bool replicate) : + PredMacroOp(mnem, machInst, __opClass) +{ + RegIndex vx = NumFloatV8ArchRegs / 4; + RegIndex rnsp = (RegIndex) makeSP((IntRegIndex) rn); + bool baseIsSP = isSP((IntRegIndex) rnsp); + + numMicroops = wb ? 1 : 0; + + int eSizeBytes = 1 << eSize; + int totNumBytes = numStructElems * eSizeBytes; + assert(totNumBytes <= 64); + + // The guiding principle here is that no more than 16 bytes can be + // transferred at a time + int numMemMicroops = totNumBytes / 16; + int residuum = totNumBytes % 16; + if (residuum) + ++numMemMicroops; + numMicroops += numMemMicroops; + + int numMarshalMicroops = totNumBytes > 32 ? 2 : 1; + numMicroops += numMarshalMicroops; + + microOps = new StaticInstPtr[numMicroops]; + unsigned uopIdx = 0; + + for(int i = 0; i < numMarshalMicroops; ++i) { + microOps[uopIdx++] = new MicroPackNeon64( + machInst, vx + (RegIndex) (2 * i), vd, eSize, dataSize, + numStructElems, index, i /* step */, replicate); + } + + uint32_t memaccessFlags = TLB::MustBeOne | (TLB::ArmFlags) eSize | + TLB::AllowUnaligned; + + int i = 0; + for(; i < numMemMicroops - 1; ++i) { + microOps[uopIdx++] = new MicroNeonStore64( + machInst, vx + (RegIndex) i, rnsp, 16 * i, memaccessFlags, + baseIsSP, 16 /* accsize */, eSize); + } + microOps[uopIdx++] = new MicroNeonStore64( + machInst, vx + (RegIndex) i, rnsp, 16 * i, memaccessFlags, baseIsSP, + residuum ? residuum : 16 /* accSize */, eSize); + + // Writeback microop: the post-increment amount is encoded in "Rm": a + // 64-bit general register OR as '11111' for an immediate value equal to + // the total number of bytes transferred (i.e. 8, 16, 24, 32, 48 or 64) + if (wb) { + if (rm != ((RegIndex) INTREG_X31)) { + microOps[uopIdx++] = new MicroAddXERegUop(machInst, rnsp, rnsp, rm, + UXTX, 0); + } else { + microOps[uopIdx++] = new MicroAddXiUop(machInst, rnsp, rnsp, + totNumBytes); + } + } + + assert(uopIdx == numMicroops); + + for (int i = 0; i < numMicroops - 1; i++) { + microOps[i]->setDelayedCommit(); + } + microOps[numMicroops - 1]->setLastMicroop(); +} + MacroVFPMemOp::MacroVFPMemOp(const char *mnem, ExtMachInst machInst, OpClass __opClass, IntRegIndex rn, RegIndex vd, bool single, bool up, @@ -846,14 +1333,14 @@ MacroVFPMemOp::MacroVFPMemOp(const char *mnem, ExtMachInst machInst, // to be functionally identical except that fldmx is deprecated. For now // we'll assume they're otherwise interchangable. int count = (single ? offset : (offset / 2)); - if (count == 0 || count > NumFloatArchRegs) + if (count == 0 || count > NumFloatV7ArchRegs) warn_once("Bad offset field for VFP load/store multiple.\n"); if (count == 0) { // Force there to be at least one microop so the macroop makes sense. writeback = true; } - if (count > NumFloatArchRegs) - count = NumFloatArchRegs; + if (count > NumFloatV7ArchRegs) + count = NumFloatV7ArchRegs; numMicroops = count * (single ? 1 : 2) + (writeback ? 1 : 0); microOps = new StaticInstPtr[numMicroops]; @@ -934,6 +1421,19 @@ MicroIntImmOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const } std::string +MicroIntImmXOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss); + printReg(ss, ura); + ss << ", "; + printReg(ss, urb); + ss << ", "; + ccprintf(ss, "#%d", imm); + return ss.str(); +} + +std::string MicroSetPCCPSR::generateDisassembly(Addr pc, const SymbolTable *symtab) const { std::stringstream ss; @@ -943,6 +1443,18 @@ MicroSetPCCPSR::generateDisassembly(Addr pc, const SymbolTable *symtab) const } std::string +MicroIntRegXOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss); + printReg(ss, ura); + ccprintf(ss, ", "); + printReg(ss, urb); + printExtendOperand(false, ss, (IntRegIndex)urc, type, shiftAmt); + return ss.str(); +} + +std::string MicroIntMov::generateDisassembly(Addr pc, const SymbolTable *symtab) const { std::stringstream ss; diff --git a/src/arch/arm/insts/macromem.hh b/src/arch/arm/insts/macromem.hh index 4933a1e7c..fc8e3e1b7 100644 --- a/src/arch/arm/insts/macromem.hh +++ b/src/arch/arm/insts/macromem.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -85,6 +85,27 @@ class MicroOp : public PredOp } }; +class MicroOpX : public ArmStaticInst +{ + protected: + MicroOpX(const char *mnem, ExtMachInst machInst, OpClass __opClass) + : ArmStaticInst(mnem, machInst, __opClass) + {} + + public: + void + advancePC(PCState &pcState) const + { + if (flags[IsLastMicroop]) { + pcState.uEnd(); + } else if (flags[IsMicroop]) { + pcState.uAdvance(); + } else { + pcState.advance(); + } + } +}; + /** * Microops for Neon loads/stores */ @@ -136,6 +157,96 @@ class MicroNeonMixLaneOp : public MicroNeonMixOp }; /** + * Microops for AArch64 NEON load/store (de)interleaving + */ +class MicroNeonMixOp64 : public MicroOp +{ + protected: + RegIndex dest, op1; + uint8_t eSize, dataSize, numStructElems, numRegs, step; + + MicroNeonMixOp64(const char *mnem, ExtMachInst machInst, OpClass __opClass, + RegIndex _dest, RegIndex _op1, uint8_t _eSize, + uint8_t _dataSize, uint8_t _numStructElems, + uint8_t _numRegs, uint8_t _step) + : MicroOp(mnem, machInst, __opClass), dest(_dest), op1(_op1), + eSize(_eSize), dataSize(_dataSize), numStructElems(_numStructElems), + numRegs(_numRegs), step(_step) + { + } +}; + +class MicroNeonMixLaneOp64 : public MicroOp +{ + protected: + RegIndex dest, op1; + uint8_t eSize, dataSize, numStructElems, lane, step; + bool replicate; + + MicroNeonMixLaneOp64(const char *mnem, ExtMachInst machInst, + OpClass __opClass, RegIndex _dest, RegIndex _op1, + uint8_t _eSize, uint8_t _dataSize, + uint8_t _numStructElems, uint8_t _lane, uint8_t _step, + bool _replicate = false) + : MicroOp(mnem, machInst, __opClass), dest(_dest), op1(_op1), + eSize(_eSize), dataSize(_dataSize), numStructElems(_numStructElems), + lane(_lane), step(_step), replicate(_replicate) + { + } +}; + +/** + * Base classes for microcoded AArch64 NEON memory instructions. + */ +class VldMultOp64 : public PredMacroOp +{ + protected: + uint8_t eSize, dataSize, numStructElems, numRegs; + bool wb; + + VldMultOp64(const char *mnem, ExtMachInst machInst, OpClass __opClass, + RegIndex rn, RegIndex vd, RegIndex rm, uint8_t eSize, + uint8_t dataSize, uint8_t numStructElems, uint8_t numRegs, + bool wb); +}; + +class VstMultOp64 : public PredMacroOp +{ + protected: + uint8_t eSize, dataSize, numStructElems, numRegs; + bool wb; + + VstMultOp64(const char *mnem, ExtMachInst machInst, OpClass __opClass, + RegIndex rn, RegIndex vd, RegIndex rm, uint8_t eSize, + uint8_t dataSize, uint8_t numStructElems, uint8_t numRegs, + bool wb); +}; + +class VldSingleOp64 : public PredMacroOp +{ + protected: + uint8_t eSize, dataSize, numStructElems, index; + bool wb, replicate; + + VldSingleOp64(const char *mnem, ExtMachInst machInst, OpClass __opClass, + RegIndex rn, RegIndex vd, RegIndex rm, uint8_t eSize, + uint8_t dataSize, uint8_t numStructElems, uint8_t index, + bool wb, bool replicate = false); +}; + +class VstSingleOp64 : public PredMacroOp +{ + protected: + uint8_t eSize, dataSize, numStructElems, index; + bool wb, replicate; + + VstSingleOp64(const char *mnem, ExtMachInst machInst, OpClass __opClass, + RegIndex rn, RegIndex vd, RegIndex rm, uint8_t eSize, + uint8_t dataSize, uint8_t numStructElems, uint8_t index, + bool wb, bool replicate = false); +}; + +/** * Microops of the form * PC = IntRegA * CPSR = IntRegB @@ -180,10 +291,10 @@ class MicroIntImmOp : public MicroOp { protected: RegIndex ura, urb; - uint32_t imm; + int32_t imm; MicroIntImmOp(const char *mnem, ExtMachInst machInst, OpClass __opClass, - RegIndex _ura, RegIndex _urb, uint32_t _imm) + RegIndex _ura, RegIndex _urb, int32_t _imm) : MicroOp(mnem, machInst, __opClass), ura(_ura), urb(_urb), imm(_imm) { @@ -192,6 +303,22 @@ class MicroIntImmOp : public MicroOp std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; }; +class MicroIntImmXOp : public MicroOpX +{ + protected: + RegIndex ura, urb; + int64_t imm; + + MicroIntImmXOp(const char *mnem, ExtMachInst machInst, OpClass __opClass, + RegIndex _ura, RegIndex _urb, int64_t _imm) + : MicroOpX(mnem, machInst, __opClass), + ura(_ura), urb(_urb), imm(_imm) + { + } + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + /** * Microops of the form IntRegA = IntRegB op IntRegC */ @@ -210,6 +337,25 @@ class MicroIntOp : public MicroOp std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; }; +class MicroIntRegXOp : public MicroOp +{ + protected: + RegIndex ura, urb, urc; + ArmExtendType type; + uint32_t shiftAmt; + + MicroIntRegXOp(const char *mnem, ExtMachInst machInst, OpClass __opClass, + RegIndex _ura, RegIndex _urb, RegIndex _urc, + ArmExtendType _type, uint32_t _shiftAmt) + : MicroOp(mnem, machInst, __opClass), + ura(_ura), urb(_urb), urc(_urc), + type(_type), shiftAmt(_shiftAmt) + { + } + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + /** * Microops of the form IntRegA = IntRegB op shifted IntRegC */ @@ -261,6 +407,61 @@ class MacroMemOp : public PredMacroOp }; /** + * Base class for pair load/store instructions. + */ +class PairMemOp : public PredMacroOp +{ + public: + enum AddrMode { + AddrMd_Offset, + AddrMd_PreIndex, + AddrMd_PostIndex + }; + + protected: + PairMemOp(const char *mnem, ExtMachInst machInst, OpClass __opClass, + uint32_t size, bool fp, bool load, bool noAlloc, bool signExt, + bool exclusive, bool acrel, int64_t imm, AddrMode mode, + IntRegIndex rn, IntRegIndex rt, IntRegIndex rt2); +}; + +class BigFpMemImmOp : public PredMacroOp +{ + protected: + BigFpMemImmOp(const char *mnem, ExtMachInst machInst, OpClass __opClass, + bool load, IntRegIndex dest, IntRegIndex base, int64_t imm); +}; + +class BigFpMemPostOp : public PredMacroOp +{ + protected: + BigFpMemPostOp(const char *mnem, ExtMachInst machInst, OpClass __opClass, + bool load, IntRegIndex dest, IntRegIndex base, int64_t imm); +}; + +class BigFpMemPreOp : public PredMacroOp +{ + protected: + BigFpMemPreOp(const char *mnem, ExtMachInst machInst, OpClass __opClass, + bool load, IntRegIndex dest, IntRegIndex base, int64_t imm); +}; + +class BigFpMemRegOp : public PredMacroOp +{ + protected: + BigFpMemRegOp(const char *mnem, ExtMachInst machInst, OpClass __opClass, + bool load, IntRegIndex dest, IntRegIndex base, + IntRegIndex offset, ArmExtendType type, int64_t imm); +}; + +class BigFpMemLitOp : public PredMacroOp +{ + protected: + BigFpMemLitOp(const char *mnem, ExtMachInst machInst, OpClass __opClass, + IntRegIndex dest, int64_t imm); +}; + +/** * Base classes for microcoded integer memory instructions. */ class VldMultOp : public PredMacroOp diff --git a/src/arch/arm/insts/mem.cc b/src/arch/arm/insts/mem.cc index 552803b6a..15702ff83 100644 --- a/src/arch/arm/insts/mem.cc +++ b/src/arch/arm/insts/mem.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010, 2012 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -157,6 +157,9 @@ SrsOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const case MODE_ABORT: ss << "abort"; break; + case MODE_HYP: + ss << "hyp"; + break; case MODE_UNDEFINED: ss << "undefined"; break; diff --git a/src/arch/arm/insts/mem64.cc b/src/arch/arm/insts/mem64.cc new file mode 100644 index 000000000..4d1fdd302 --- /dev/null +++ b/src/arch/arm/insts/mem64.cc @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2011-2013 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "arch/arm/insts/mem64.hh" +#include "arch/arm/tlb.hh" +#include "base/loader/symtab.hh" +#include "mem/request.hh" + +using namespace std; + +namespace ArmISA +{ + +std::string +SysDC64::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss, "", false); + ccprintf(ss, ", ["); + printReg(ss, base); + ccprintf(ss, "]"); + return ss.str(); +} + + + +void +Memory64::startDisassembly(std::ostream &os) const +{ + printMnemonic(os, "", false); + printReg(os, dest); + ccprintf(os, ", ["); + printReg(os, base); +} + +void +Memory64::setExcAcRel(bool exclusive, bool acrel) +{ + if (exclusive) + memAccessFlags |= Request::LLSC; + else + memAccessFlags |= ArmISA::TLB::AllowUnaligned; + if (acrel) { + flags[IsMemBarrier] = true; + flags[IsWriteBarrier] = true; + flags[IsReadBarrier] = true; + } +} + +std::string +MemoryImm64::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + startDisassembly(ss); + if (imm) + ccprintf(ss, ", #%d", imm); + ccprintf(ss, "]"); + return ss.str(); +} + +std::string +MemoryDImm64::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss, "", false); + printReg(ss, dest); + ccprintf(ss, ", "); + printReg(ss, dest2); + ccprintf(ss, ", ["); + printReg(ss, base); + if (imm) + ccprintf(ss, ", #%d", imm); + ccprintf(ss, "]"); + return ss.str(); +} + +std::string +MemoryDImmEx64::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss, "", false); + printReg(ss, result); + ccprintf(ss, ", "); + printReg(ss, dest); + ccprintf(ss, ", "); + printReg(ss, dest2); + ccprintf(ss, ", ["); + printReg(ss, base); + if (imm) + ccprintf(ss, ", #%d", imm); + ccprintf(ss, "]"); + return ss.str(); +} + +std::string +MemoryPreIndex64::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + startDisassembly(ss); + ccprintf(ss, ", #%d]!", imm); + return ss.str(); +} + +std::string +MemoryPostIndex64::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + startDisassembly(ss); + if (imm) + ccprintf(ss, "], #%d", imm); + ccprintf(ss, "]"); + return ss.str(); +} + +std::string +MemoryReg64::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + startDisassembly(ss); + printExtendOperand(false, ss, offset, type, shiftAmt); + ccprintf(ss, "]"); + return ss.str(); +} + +std::string +MemoryRaw64::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + startDisassembly(ss); + ccprintf(ss, "]"); + return ss.str(); +} + +std::string +MemoryEx64::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss, "", false); + printReg(ss, dest); + ccprintf(ss, ", "); + printReg(ss, result); + ccprintf(ss, ", ["); + printReg(ss, base); + ccprintf(ss, "]"); + return ss.str(); +} + +std::string +MemoryLiteral64::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss, "", false); + printReg(ss, dest); + ccprintf(ss, ", #%d", pc + imm); + return ss.str(); +} +} diff --git a/src/arch/arm/insts/mem64.hh b/src/arch/arm/insts/mem64.hh new file mode 100644 index 000000000..21c1e1ea8 --- /dev/null +++ b/src/arch/arm/insts/mem64.hh @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2011-2013 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ +#ifndef __ARCH_ARM_MEM64_HH__ +#define __ARCH_ARM_MEM64_HH__ + +#include "arch/arm/insts/static_inst.hh" + +namespace ArmISA +{ + +class SysDC64 : public ArmStaticInst +{ + protected: + IntRegIndex base; + IntRegIndex dest; + uint64_t imm; + + SysDC64(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + IntRegIndex _base, IntRegIndex _dest, uint64_t _imm) + : ArmStaticInst(mnem, _machInst, __opClass), base(_base), dest(_dest), + imm(_imm) + {} + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +class MightBeMicro64 : public ArmStaticInst +{ + protected: + MightBeMicro64(const char *mnem, ExtMachInst _machInst, OpClass __opClass) + : ArmStaticInst(mnem, _machInst, __opClass) + {} + + void + advancePC(PCState &pcState) const + { + if (flags[IsLastMicroop]) { + pcState.uEnd(); + } else if (flags[IsMicroop]) { + pcState.uAdvance(); + } else { + pcState.advance(); + } + } +}; + +class Memory64 : public MightBeMicro64 +{ + public: + enum AddrMode { + AddrMd_Offset, + AddrMd_PreIndex, + AddrMd_PostIndex + }; + + protected: + + IntRegIndex dest; + IntRegIndex base; + /// True if the base register is SP (used for SP alignment checking). + bool baseIsSP; + static const unsigned numMicroops = 3; + + StaticInstPtr *uops; + + Memory64(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + IntRegIndex _dest, IntRegIndex _base) + : MightBeMicro64(mnem, _machInst, __opClass), + dest(_dest), base(_base), uops(NULL) + { + baseIsSP = isSP(_base); + } + + virtual + ~Memory64() + { + delete [] uops; + } + + StaticInstPtr + fetchMicroop(MicroPC microPC) const + { + assert(uops != NULL && microPC < numMicroops); + return uops[microPC]; + } + + void startDisassembly(std::ostream &os) const; + + unsigned memAccessFlags; + + void setExcAcRel(bool exclusive, bool acrel); +}; + +class MemoryImm64 : public Memory64 +{ + protected: + int64_t imm; + + MemoryImm64(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + IntRegIndex _dest, IntRegIndex _base, int64_t _imm) + : Memory64(mnem, _machInst, __opClass, _dest, _base), imm(_imm) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +class MemoryDImm64 : public MemoryImm64 +{ + protected: + IntRegIndex dest2; + + MemoryDImm64(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + IntRegIndex _dest, IntRegIndex _dest2, IntRegIndex _base, + int64_t _imm) + : MemoryImm64(mnem, _machInst, __opClass, _dest, _base, _imm), + dest2(_dest2) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +class MemoryDImmEx64 : public MemoryDImm64 +{ + protected: + IntRegIndex result; + + MemoryDImmEx64(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + IntRegIndex _result, IntRegIndex _dest, IntRegIndex _dest2, + IntRegIndex _base, int32_t _imm) + : MemoryDImm64(mnem, _machInst, __opClass, _dest, _dest2, + _base, _imm), result(_result) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +class MemoryPreIndex64 : public MemoryImm64 +{ + protected: + MemoryPreIndex64(const char *mnem, ExtMachInst _machInst, + OpClass __opClass, IntRegIndex _dest, IntRegIndex _base, + int64_t _imm) + : MemoryImm64(mnem, _machInst, __opClass, _dest, _base, _imm) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +class MemoryPostIndex64 : public MemoryImm64 +{ + protected: + MemoryPostIndex64(const char *mnem, ExtMachInst _machInst, + OpClass __opClass, IntRegIndex _dest, IntRegIndex _base, + int64_t _imm) + : MemoryImm64(mnem, _machInst, __opClass, _dest, _base, _imm) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +class MemoryReg64 : public Memory64 +{ + protected: + IntRegIndex offset; + ArmExtendType type; + uint64_t shiftAmt; + + MemoryReg64(const char *mnem, ExtMachInst _machInst, + OpClass __opClass, IntRegIndex _dest, IntRegIndex _base, + IntRegIndex _offset, ArmExtendType _type, + uint64_t _shiftAmt) + : Memory64(mnem, _machInst, __opClass, _dest, _base), + offset(_offset), type(_type), shiftAmt(_shiftAmt) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +class MemoryRaw64 : public Memory64 +{ + protected: + MemoryRaw64(const char *mnem, ExtMachInst _machInst, + OpClass __opClass, IntRegIndex _dest, IntRegIndex _base) + : Memory64(mnem, _machInst, __opClass, _dest, _base) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +class MemoryEx64 : public Memory64 +{ + protected: + IntRegIndex result; + + MemoryEx64(const char *mnem, ExtMachInst _machInst, + OpClass __opClass, IntRegIndex _dest, IntRegIndex _base, + IntRegIndex _result) + : Memory64(mnem, _machInst, __opClass, _dest, _base), result(_result) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +class MemoryLiteral64 : public Memory64 +{ + protected: + int64_t imm; + + MemoryLiteral64(const char *mnem, ExtMachInst _machInst, + OpClass __opClass, IntRegIndex _dest, int64_t _imm) + : Memory64(mnem, _machInst, __opClass, _dest, INTREG_ZERO), imm(_imm) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; +} + +#endif //__ARCH_ARM_INSTS_MEM_HH__ diff --git a/src/arch/arm/insts/misc.cc b/src/arch/arm/insts/misc.cc index 6320bb6da..efc334c4b 100644 --- a/src/arch/arm/insts/misc.cc +++ b/src/arch/arm/insts/misc.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010, 2012-2013 ARM Limited * Copyright (c) 2013 Advanced Micro Devices, Inc. * All rights reserved * @@ -146,6 +146,32 @@ MsrRegOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const } std::string +MrrcOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss); + printReg(ss, dest); + ss << ", "; + printReg(ss, dest2); + ss << ", "; + printReg(ss, op1); + return ss.str(); +} + +std::string +McrrOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss); + printReg(ss, dest); + ss << ", "; + printReg(ss, op1); + ss << ", "; + printReg(ss, op2); + return ss.str(); +} + +std::string ImmOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const { std::stringstream ss; @@ -230,6 +256,16 @@ RegRegImmOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const } std::string +RegImmImmOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss); + printReg(ss, dest); + ccprintf(ss, ", #%d, #%d", imm1, imm2); + return ss.str(); +} + +std::string RegRegImmImmOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const { std::stringstream ss; diff --git a/src/arch/arm/insts/misc.hh b/src/arch/arm/insts/misc.hh index c9e114f85..3d947a272 100644 --- a/src/arch/arm/insts/misc.hh +++ b/src/arch/arm/insts/misc.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010, 2012-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -94,6 +94,42 @@ class MsrRegOp : public MsrBase std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; }; +class MrrcOp : public PredOp +{ + protected: + IntRegIndex op1; + IntRegIndex dest; + IntRegIndex dest2; + uint32_t imm; + + MrrcOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + IntRegIndex _op1, IntRegIndex _dest, IntRegIndex _dest2, + uint32_t _imm) : + PredOp(mnem, _machInst, __opClass), op1(_op1), dest(_dest), + dest2(_dest2), imm(_imm) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +class McrrOp : public PredOp +{ + protected: + IntRegIndex op1; + IntRegIndex op2; + IntRegIndex dest; + uint32_t imm; + + McrrOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + IntRegIndex _op1, IntRegIndex _op2, IntRegIndex _dest, + uint32_t _imm) : + PredOp(mnem, _machInst, __opClass), op1(_op1), op2(_op2), + dest(_dest), imm(_imm) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + class ImmOp : public PredOp { protected: @@ -220,6 +256,23 @@ class RegRegImmOp : public PredOp std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; }; +class RegImmImmOp : public PredOp +{ + protected: + IntRegIndex dest; + IntRegIndex op1; + uint64_t imm1; + uint64_t imm2; + + RegImmImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + IntRegIndex _dest, uint64_t _imm1, uint64_t _imm2) : + PredOp(mnem, _machInst, __opClass), + dest(_dest), imm1(_imm1), imm2(_imm2) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + class RegRegImmImmOp : public PredOp { protected: diff --git a/src/arch/arm/insts/misc64.cc b/src/arch/arm/insts/misc64.cc new file mode 100644 index 000000000..3553020da --- /dev/null +++ b/src/arch/arm/insts/misc64.cc @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011-2013 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "arch/arm/insts/misc64.hh" + +std::string +RegRegImmImmOp64::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss, "", false); + printReg(ss, dest); + ss << ", "; + printReg(ss, op1); + ccprintf(ss, ", #%d, #%d", imm1, imm2); + return ss.str(); +} + +std::string +RegRegRegImmOp64::generateDisassembly( + Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss, "", false); + printReg(ss, dest); + ss << ", "; + printReg(ss, op1); + ss << ", "; + printReg(ss, op2); + ccprintf(ss, ", #%d", imm); + return ss.str(); +} + +std::string +UnknownOp64::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + return csprintf("%-10s (inst %#08x)", "unknown", machInst); +} diff --git a/src/arch/arm/insts/misc64.hh b/src/arch/arm/insts/misc64.hh new file mode 100644 index 000000000..5a0e18224 --- /dev/null +++ b/src/arch/arm/insts/misc64.hh @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2011-2013 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __ARCH_ARM_INSTS_MISC64_HH__ +#define __ARCH_ARM_INSTS_MISC64_HH__ + +#include "arch/arm/insts/static_inst.hh" + +class RegRegImmImmOp64 : public ArmStaticInst +{ + protected: + IntRegIndex dest; + IntRegIndex op1; + uint64_t imm1; + uint64_t imm2; + + RegRegImmImmOp64(const char *mnem, ExtMachInst _machInst, + OpClass __opClass, IntRegIndex _dest, IntRegIndex _op1, + uint64_t _imm1, uint64_t _imm2) : + ArmStaticInst(mnem, _machInst, __opClass), + dest(_dest), op1(_op1), imm1(_imm1), imm2(_imm2) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +class RegRegRegImmOp64 : public ArmStaticInst +{ + protected: + IntRegIndex dest; + IntRegIndex op1; + IntRegIndex op2; + uint64_t imm; + + RegRegRegImmOp64(const char *mnem, ExtMachInst _machInst, + OpClass __opClass, IntRegIndex _dest, IntRegIndex _op1, + IntRegIndex _op2, uint64_t _imm) : + ArmStaticInst(mnem, _machInst, __opClass), + dest(_dest), op1(_op1), op2(_op2), imm(_imm) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +class UnknownOp64 : public ArmStaticInst +{ + protected: + + UnknownOp64(const char *mnem, ExtMachInst _machInst, OpClass __opClass) : + ArmStaticInst(mnem, _machInst, __opClass) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +#endif diff --git a/src/arch/arm/insts/neon64_mem.hh b/src/arch/arm/insts/neon64_mem.hh new file mode 100644 index 000000000..01ce1b624 --- /dev/null +++ b/src/arch/arm/insts/neon64_mem.hh @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2012-2013 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Mbou Eyole + * Giacomo Gabrielli + */ + +/// @file +/// Utility functions and datatypes used by AArch64 NEON memory instructions. + +#ifndef __ARCH_ARM_INSTS_NEON64_MEM_HH__ +#define __ARCH_ARM_INSTS_NEON64_MEM_HH__ + +namespace ArmISA +{ + +typedef uint64_t XReg; + +/// 128-bit NEON vector register. +struct VReg { + XReg hi; + XReg lo; +}; + +/// Write a single NEON vector element leaving the others untouched. +inline void +writeVecElem(VReg *dest, XReg src, int index, int eSize) +{ + // eSize must be less than 4: + // 0 -> 8-bit elems, + // 1 -> 16-bit elems, + // 2 -> 32-bit elems, + // 3 -> 64-bit elems + assert(eSize <= 3); + + int eBits = 8 << eSize; + int lsbPos = index * eBits; + assert(lsbPos < 128); + int shiftAmt = lsbPos % 64; + + XReg maskBits = -1; + if (eBits == 64) { + maskBits = 0; + } else { + maskBits = maskBits << eBits; + } + maskBits = ~maskBits; + + XReg sMask = maskBits; + maskBits = sMask << shiftAmt; + + if (lsbPos < 64) { + dest->lo = (dest->lo & (~maskBits)) | ((src & sMask) << shiftAmt); + } else { + dest->hi = (dest->hi & (~maskBits)) | ((src & sMask) << shiftAmt); + } +} + +/// Read a single NEON vector element. +inline XReg +readVecElem(VReg src, int index, int eSize) +{ + // eSize must be less than 4: + // 0 -> 8-bit elems, + // 1 -> 16-bit elems, + // 2 -> 32-bit elems, + // 3 -> 64-bit elems + assert(eSize <= 3); + + XReg data; + + int eBits = 8 << eSize; + int lsbPos = index * eBits; + assert(lsbPos < 128); + int shiftAmt = lsbPos % 64; + + XReg maskBits = -1; + if (eBits == 64) { + maskBits = 0; + } else { + maskBits = maskBits << eBits; + } + maskBits = ~maskBits; + + if (lsbPos < 64) { + data = (src.lo >> shiftAmt) & maskBits; + } else { + data = (src.hi >> shiftAmt) & maskBits; + } + return data; +} + +} // namespace ArmISA + +#endif // __ARCH_ARM_INSTS_NEON64_MEM_HH__ diff --git a/src/arch/arm/insts/pred_inst.hh b/src/arch/arm/insts/pred_inst.hh index c441d1f32..c5e2ab386 100644 --- a/src/arch/arm/insts/pred_inst.hh +++ b/src/arch/arm/insts/pred_inst.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010, 2012-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -78,7 +78,8 @@ modified_imm(uint8_t ctrlImm, uint8_t dataImm) } static inline uint64_t -simd_modified_imm(bool op, uint8_t cmode, uint8_t data, bool &immValid) +simd_modified_imm(bool op, uint8_t cmode, uint8_t data, bool &immValid, + bool isAarch64 = false) { uint64_t bigData = data; immValid = true; @@ -133,12 +134,20 @@ simd_modified_imm(bool op, uint8_t cmode, uint8_t data, bool &immValid) } break; case 0xf: - if (!op) { - uint64_t bVal = bits(bigData, 6) ? (0x1F) : (0x20); - bigData = (bits(bigData, 5, 0) << 19) | - (bVal << 25) | (bits(bigData, 7) << 31); - bigData |= (bigData << 32); - break; + { + uint64_t bVal = 0; + if (!op) { + bVal = bits(bigData, 6) ? (0x1F) : (0x20); + bigData = (bits(bigData, 5, 0) << 19) | + (bVal << 25) | (bits(bigData, 7) << 31); + bigData |= (bigData << 32); + break; + } else if (isAarch64) { + bVal = bits(bigData, 6) ? (0x0FF) : (0x100); + bigData = (bits(bigData, 5, 0) << 48) | + (bVal << 54) | (bits(bigData, 7) << 63); + break; + } } // Fall through, immediate encoding is invalid. default: @@ -179,11 +188,14 @@ class PredOp : public ArmStaticInst /// Constructor PredOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass) : - ArmStaticInst(mnem, _machInst, __opClass), - condCode(machInst.itstateMask ? - (ConditionCode)(uint8_t)machInst.itstateCond : - (ConditionCode)(unsigned)machInst.condCode) + ArmStaticInst(mnem, _machInst, __opClass) { + if (machInst.aarch64) + condCode = COND_UC; + else if (machInst.itstateMask) + condCode = (ConditionCode)(uint8_t)machInst.itstateCond; + else + condCode = (ConditionCode)(unsigned)machInst.condCode; } }; diff --git a/src/arch/arm/insts/static_inst.cc b/src/arch/arm/insts/static_inst.cc index 2a8dee162..260c29a84 100644 --- a/src/arch/arm/insts/static_inst.cc +++ b/src/arch/arm/insts/static_inst.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010-2013 ARM Limited * Copyright (c) 2013 Advanced Micro Devices, Inc. * All rights reserved * @@ -86,6 +86,90 @@ ArmStaticInst::shift_rm_imm(uint32_t base, uint32_t shamt, return 0; } +int64_t +ArmStaticInst::shiftReg64(uint64_t base, uint64_t shiftAmt, + ArmShiftType type, uint8_t width) const +{ + shiftAmt = shiftAmt % width; + ArmShiftType shiftType; + shiftType = (ArmShiftType)type; + + switch (shiftType) + { + case LSL: + return base << shiftAmt; + case LSR: + if (shiftAmt == 0) + return base; + else + return (base & mask(width)) >> shiftAmt; + case ASR: + if (shiftAmt == 0) { + return base; + } else { + int sign_bit = bits(base, intWidth - 1); + base >>= shiftAmt; + base = sign_bit ? (base | ~mask(intWidth - shiftAmt)) : base; + return base & mask(intWidth); + } + case ROR: + if (shiftAmt == 0) + return base; + else + return (base << (width - shiftAmt)) | (base >> shiftAmt); + default: + ccprintf(std::cerr, "Unhandled shift type\n"); + exit(1); + break; + } + return 0; +} + +int64_t +ArmStaticInst::extendReg64(uint64_t base, ArmExtendType type, + uint64_t shiftAmt, uint8_t width) const +{ + bool sign_extend = false; + int len = 0; + switch (type) { + case UXTB: + len = 8; + break; + case UXTH: + len = 16; + break; + case UXTW: + len = 32; + break; + case UXTX: + len = 64; + break; + case SXTB: + len = 8; + sign_extend = true; + break; + case SXTH: + len = 16; + sign_extend = true; + break; + case SXTW: + len = 32; + sign_extend = true; + break; + case SXTX: + len = 64; + sign_extend = true; + break; + } + len = len <= width - shiftAmt ? len : width - shiftAmt; + uint64_t tmp = (uint64_t) bits(base, len - 1, 0) << shiftAmt; + if (sign_extend) { + int sign_bit = bits(tmp, len + shiftAmt - 1); + tmp = sign_bit ? (tmp | ~mask(len + shiftAmt)) : tmp; + } + return tmp & mask(width); +} + // Shift Rm by Rs int32_t ArmStaticInst::shift_rm_rs(uint32_t base, uint32_t shamt, @@ -214,22 +298,33 @@ ArmStaticInst::printReg(std::ostream &os, int reg) const switch (regIdxToClass(reg, &rel_reg)) { case IntRegClass: - switch (rel_reg) { - case PCReg: - ccprintf(os, "pc"); - break; - case StackPointerReg: - ccprintf(os, "sp"); - break; - case FramePointerReg: - ccprintf(os, "fp"); - break; - case ReturnAddressReg: - ccprintf(os, "lr"); - break; - default: - ccprintf(os, "r%d", reg); - break; + if (aarch64) { + if (reg == INTREG_UREG0) + ccprintf(os, "ureg0"); + else if (reg == INTREG_SPX) + ccprintf(os, "%s%s", (intWidth == 32) ? "w" : "", "sp"); + else if (reg == INTREG_X31) + ccprintf(os, "%szr", (intWidth == 32) ? "w" : "x"); + else + ccprintf(os, "%s%d", (intWidth == 32) ? "w" : "x", reg); + } else { + switch (rel_reg) { + case PCReg: + ccprintf(os, "pc"); + break; + case StackPointerReg: + ccprintf(os, "sp"); + break; + case FramePointerReg: + ccprintf(os, "fp"); + break; + case ReturnAddressReg: + ccprintf(os, "lr"); + break; + default: + ccprintf(os, "r%d", reg); + break; + } } break; case FloatRegClass: @@ -247,67 +342,102 @@ ArmStaticInst::printReg(std::ostream &os, int reg) const void ArmStaticInst::printMnemonic(std::ostream &os, const std::string &suffix, - bool withPred) const + bool withPred, + bool withCond64, + ConditionCode cond64) const { os << " " << mnemonic; - if (withPred) { - unsigned condCode = machInst.condCode; - switch (condCode) { - case COND_EQ: - os << "eq"; - break; - case COND_NE: - os << "ne"; - break; - case COND_CS: - os << "cs"; - break; - case COND_CC: - os << "cc"; - break; - case COND_MI: - os << "mi"; - break; - case COND_PL: - os << "pl"; - break; - case COND_VS: - os << "vs"; - break; - case COND_VC: - os << "vc"; - break; - case COND_HI: - os << "hi"; - break; - case COND_LS: - os << "ls"; - break; - case COND_GE: - os << "ge"; - break; - case COND_LT: - os << "lt"; - break; - case COND_GT: - os << "gt"; - break; - case COND_LE: - os << "le"; - break; - case COND_AL: - // This one is implicit. - break; - case COND_UC: - // Unconditional. - break; - default: - panic("Unrecognized condition code %d.\n", condCode); - } + if (withPred && !aarch64) { + printCondition(os, machInst.condCode); + os << suffix; + } else if (withCond64) { + os << "."; + printCondition(os, cond64); os << suffix; - if (machInst.bigThumb) - os << ".w"; - os << " "; + } + if (machInst.bigThumb) + os << ".w"; + os << " "; +} + +void +ArmStaticInst::printTarget(std::ostream &os, Addr target, + const SymbolTable *symtab) const +{ + Addr symbolAddr; + std::string symbol; + + if (symtab && symtab->findNearestSymbol(target, symbol, symbolAddr)) { + ccprintf(os, "<%s", symbol); + if (symbolAddr != target) + ccprintf(os, "+%d>", target - symbolAddr); + else + ccprintf(os, ">"); + } else { + ccprintf(os, "%#x", target); + } +} + +void +ArmStaticInst::printCondition(std::ostream &os, + unsigned code, + bool noImplicit) const +{ + switch (code) { + case COND_EQ: + os << "eq"; + break; + case COND_NE: + os << "ne"; + break; + case COND_CS: + os << "cs"; + break; + case COND_CC: + os << "cc"; + break; + case COND_MI: + os << "mi"; + break; + case COND_PL: + os << "pl"; + break; + case COND_VS: + os << "vs"; + break; + case COND_VC: + os << "vc"; + break; + case COND_HI: + os << "hi"; + break; + case COND_LS: + os << "ls"; + break; + case COND_GE: + os << "ge"; + break; + case COND_LT: + os << "lt"; + break; + case COND_GT: + os << "gt"; + break; + case COND_LE: + os << "le"; + break; + case COND_AL: + // This one is implicit. + if (noImplicit) + os << "al"; + break; + case COND_UC: + // Unconditional. + if (noImplicit) + os << "uc"; + break; + default: + panic("Unrecognized condition code %d.\n", code); } } @@ -393,6 +523,38 @@ ArmStaticInst::printShiftOperand(std::ostream &os, } void +ArmStaticInst::printExtendOperand(bool firstOperand, std::ostream &os, + IntRegIndex rm, ArmExtendType type, + int64_t shiftAmt) const +{ + if (!firstOperand) + ccprintf(os, ", "); + printReg(os, rm); + if (type == UXTX && shiftAmt == 0) + return; + switch (type) { + case UXTB: ccprintf(os, ", UXTB"); + break; + case UXTH: ccprintf(os, ", UXTH"); + break; + case UXTW: ccprintf(os, ", UXTW"); + break; + case UXTX: ccprintf(os, ", LSL"); + break; + case SXTB: ccprintf(os, ", SXTB"); + break; + case SXTH: ccprintf(os, ", SXTH"); + break; + case SXTW: ccprintf(os, ", SXTW"); + break; + case SXTX: ccprintf(os, ", SXTW"); + break; + } + if (type == UXTX || shiftAmt) + ccprintf(os, " #%d", shiftAmt); +} + +void ArmStaticInst::printDataInst(std::ostream &os, bool withImm, bool immShift, bool s, IntRegIndex rd, IntRegIndex rn, IntRegIndex rm, IntRegIndex rs, uint32_t shiftAmt, diff --git a/src/arch/arm/insts/static_inst.hh b/src/arch/arm/insts/static_inst.hh index c36024ecd..aeec67ec2 100644 --- a/src/arch/arm/insts/static_inst.hh +++ b/src/arch/arm/insts/static_inst.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -44,6 +44,7 @@ #include "arch/arm/faults.hh" #include "arch/arm/utility.hh" +#include "arch/arm/system.hh" #include "base/trace.hh" #include "cpu/static_inst.hh" #include "sim/byteswap.hh" @@ -55,6 +56,9 @@ namespace ArmISA class ArmStaticInst : public StaticInst { protected: + bool aarch64; + uint8_t intWidth; + int32_t shift_rm_imm(uint32_t base, uint32_t shamt, uint32_t type, uint32_t cfval) const; int32_t shift_rm_rs(uint32_t base, uint32_t shamt, @@ -65,6 +69,11 @@ class ArmStaticInst : public StaticInst bool shift_carry_rs(uint32_t base, uint32_t shamt, uint32_t type, uint32_t cfval) const; + int64_t shiftReg64(uint64_t base, uint64_t shiftAmt, + ArmShiftType type, uint8_t width) const; + int64_t extendReg64(uint64_t base, ArmExtendType type, + uint64_t shiftAmt, uint8_t width) const; + template<int width> static inline bool saturateOp(int32_t &res, int64_t op1, int64_t op2, bool sub=false) @@ -135,6 +144,11 @@ class ArmStaticInst : public StaticInst OpClass __opClass) : StaticInst(mnem, _machInst, __opClass) { + aarch64 = machInst.aarch64; + if (bits(machInst, 28, 24) == 0x10) + intWidth = 64; // Force 64-bit width for ADR/ADRP + else + intWidth = (aarch64 && bits(machInst, 31)) ? 64 : 32; } /// Print a register name for disassembly given the unique @@ -142,13 +156,22 @@ class ArmStaticInst : public StaticInst void printReg(std::ostream &os, int reg) const; void printMnemonic(std::ostream &os, const std::string &suffix = "", - bool withPred = true) const; + bool withPred = true, + bool withCond64 = false, + ConditionCode cond64 = COND_UC) const; + void printTarget(std::ostream &os, Addr target, + const SymbolTable *symtab) const; + void printCondition(std::ostream &os, unsigned code, + bool noImplicit=false) const; void printMemSymbol(std::ostream &os, const SymbolTable *symtab, const std::string &prefix, const Addr addr, const std::string &suffix) const; void printShiftOperand(std::ostream &os, IntRegIndex rm, bool immShift, uint32_t shiftAmt, IntRegIndex rs, ArmShiftType type) const; + void printExtendOperand(bool firstOperand, std::ostream &os, + IntRegIndex rm, ArmExtendType type, + int64_t shiftAmt) const; void printDataInst(std::ostream &os, bool withImm) const; @@ -166,10 +189,13 @@ class ArmStaticInst : public StaticInst std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; static inline uint32_t - cpsrWriteByInstr(CPSR cpsr, uint32_t val, - uint8_t byteMask, bool affectState, bool nmfi) + cpsrWriteByInstr(CPSR cpsr, uint32_t val, SCR scr, NSACR nsacr, + uint8_t byteMask, bool affectState, bool nmfi, ThreadContext *tc) { - bool privileged = (cpsr.mode != MODE_USER); + bool privileged = (cpsr.mode != MODE_USER); + bool haveVirt = ArmSystem::haveVirtualization(tc); + bool haveSecurity = ArmSystem::haveSecurity(tc); + bool isSecure = inSecureState(scr, cpsr) || !haveSecurity; uint32_t bitMask = 0; @@ -182,14 +208,53 @@ class ArmStaticInst : public StaticInst } if (bits(byteMask, 1)) { unsigned highIdx = affectState ? 15 : 9; - unsigned lowIdx = privileged ? 8 : 9; + unsigned lowIdx = (privileged && (isSecure || scr.aw || haveVirt)) + ? 8 : 9; bitMask = bitMask | mask(highIdx, lowIdx); } if (bits(byteMask, 0)) { if (privileged) { - bitMask = bitMask | mask(7, 6); - if (!badMode((OperatingMode)(val & mask(5)))) { - bitMask = bitMask | mask(5); + bitMask |= 1 << 7; + if ( (!nmfi || !((val >> 6) & 0x1)) && + (isSecure || scr.fw || haveVirt) ) { + bitMask |= 1 << 6; + } + // Now check the new mode is allowed + OperatingMode newMode = (OperatingMode) (val & mask(5)); + OperatingMode oldMode = (OperatingMode)(uint32_t)cpsr.mode; + if (!badMode(newMode)) { + bool validModeChange = true; + // Check for attempts to enter modes only permitted in + // Secure state from Non-secure state. These are Monitor + // mode ('10110'), and FIQ mode ('10001') if the Security + // Extensions have reserved it. + if (!isSecure && newMode == MODE_MON) + validModeChange = false; + if (!isSecure && newMode == MODE_FIQ && nsacr.rfr == '1') + validModeChange = false; + // There is no Hyp mode ('11010') in Secure state, so that + // is UNPREDICTABLE + if (scr.ns == '0' && newMode == MODE_HYP) + validModeChange = false; + // Cannot move into Hyp mode directly from a Non-secure + // PL1 mode + if (!isSecure && oldMode != MODE_HYP && newMode == MODE_HYP) + validModeChange = false; + // Cannot move out of Hyp mode with this function except + // on an exception return + if (oldMode == MODE_HYP && newMode != MODE_HYP && !affectState) + validModeChange = false; + // Must not change to 64 bit when running in 32 bit mode + if (!opModeIs64(oldMode) && opModeIs64(newMode)) + validModeChange = false; + + // If we passed all of the above then set the bit mask to + // copy the mode accross + if (validModeChange) { + bitMask = bitMask | mask(5); + } else { + warn_once("Illegal change to CPSR mode attempted\n"); + } } else { warn_once("Ignoring write of bad mode to CPSR.\n"); } @@ -198,11 +263,7 @@ class ArmStaticInst : public StaticInst bitMask = bitMask | (1 << 5); } - bool cpsr_f = cpsr.f; - uint32_t new_cpsr = ((uint32_t)cpsr & ~bitMask) | (val & bitMask); - if (nmfi && !cpsr_f) - new_cpsr &= ~(1 << 6); - return new_cpsr; + return ((uint32_t)cpsr & ~bitMask) | (val & bitMask); } static inline uint32_t @@ -296,12 +357,12 @@ class ArmStaticInst : public StaticInst inline Fault disabledFault() const { - if (FullSystem) { - return new UndefinedInstruction(); - } else { - return new UndefinedInstruction(machInst, false, mnemonic, true); - } + return new UndefinedInstruction(machInst, false, mnemonic, true); } + + public: + virtual void + annotateFault(ArmFault *fault) {} }; } diff --git a/src/arch/arm/insts/vfp.cc b/src/arch/arm/insts/vfp.cc index ca0f58226..03fdc83fa 100644 --- a/src/arch/arm/insts/vfp.cc +++ b/src/arch/arm/insts/vfp.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -46,6 +46,37 @@ */ std::string +FpCondCompRegOp::generateDisassembly( + Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss, "", false); + printReg(ss, op1); + ccprintf(ss, ", "); + printReg(ss, op2); + ccprintf(ss, ", #%d", defCc); + ccprintf(ss, ", "); + printCondition(ss, condCode, true); + return ss.str(); +} + +std::string +FpCondSelOp::generateDisassembly( + Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss, "", false); + printReg(ss, dest); + ccprintf(ss, ", "); + printReg(ss, op1); + ccprintf(ss, ", "); + printReg(ss, op2); + ccprintf(ss, ", "); + printCondition(ss, condCode, true); + return ss.str(); +} + +std::string FpRegRegOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const { std::stringstream ss; @@ -92,6 +123,21 @@ FpRegRegRegOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const } std::string +FpRegRegRegRegOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss); + printReg(ss, dest + FP_Reg_Base); + ss << ", "; + printReg(ss, op1 + FP_Reg_Base); + ss << ", "; + printReg(ss, op2 + FP_Reg_Base); + ss << ", "; + printReg(ss, op3 + FP_Reg_Base); + return ss.str(); +} + +std::string FpRegRegRegImmOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const { std::stringstream ss; @@ -131,24 +177,25 @@ prepFpState(uint32_t rMode) } void -finishVfp(FPSCR &fpscr, VfpSavedState state, bool flush) +finishVfp(FPSCR &fpscr, VfpSavedState state, bool flush, FPSCR mask) { int exceptions = fetestexcept(FeAllExceptions); bool underflow = false; - if (exceptions & FeInvalid) { + if ((exceptions & FeInvalid) && mask.ioc) { fpscr.ioc = 1; } - if (exceptions & FeDivByZero) { + if ((exceptions & FeDivByZero) && mask.dzc) { fpscr.dzc = 1; } - if (exceptions & FeOverflow) { + if ((exceptions & FeOverflow) && mask.ofc) { fpscr.ofc = 1; } if (exceptions & FeUnderflow) { underflow = true; - fpscr.ufc = 1; + if (mask.ufc) + fpscr.ufc = 1; } - if ((exceptions & FeInexact) && !(underflow && flush)) { + if ((exceptions & FeInexact) && !(underflow && flush) && mask.ixc) { fpscr.ixc = 1; } fesetround(state); @@ -329,19 +376,33 @@ fixFpSFpDDest(FPSCR fpscr, float val) return mid; } -uint16_t -vcvtFpSFpH(FPSCR &fpscr, bool flush, bool defaultNan, - uint32_t rMode, bool ahp, float op) +static inline uint16_t +vcvtFpFpH(FPSCR &fpscr, bool flush, bool defaultNan, + uint32_t rMode, bool ahp, uint64_t opBits, bool isDouble) { - uint32_t opBits = fpToBits(op); + uint32_t mWidth; + uint32_t eWidth; + uint32_t eHalfRange; + uint32_t sBitPos; + + if (isDouble) { + mWidth = 52; + eWidth = 11; + } else { + mWidth = 23; + eWidth = 8; + } + sBitPos = eWidth + mWidth; + eHalfRange = (1 << (eWidth-1)) - 1; + // Extract the operand. - bool neg = bits(opBits, 31); - uint32_t exponent = bits(opBits, 30, 23); - uint32_t oldMantissa = bits(opBits, 22, 0); - uint32_t mantissa = oldMantissa >> (23 - 10); + bool neg = bits(opBits, sBitPos); + uint32_t exponent = bits(opBits, sBitPos-1, mWidth); + uint64_t oldMantissa = bits(opBits, mWidth-1, 0); + uint32_t mantissa = oldMantissa >> (mWidth - 10); // Do the conversion. - uint32_t extra = oldMantissa & mask(23 - 10); - if (exponent == 0xff) { + uint64_t extra = oldMantissa & mask(mWidth - 10); + if (exponent == mask(eWidth)) { if (oldMantissa != 0) { // Nans. if (bits(mantissa, 9) == 0) { @@ -379,7 +440,6 @@ vcvtFpSFpH(FPSCR &fpscr, bool flush, bool defaultNan, if (exponent == 0) { // Denormalized. - // If flush to zero is on, this shouldn't happen. assert(!flush); @@ -407,13 +467,13 @@ vcvtFpSFpH(FPSCR &fpscr, bool flush, bool defaultNan, // We need to track the dropped bits differently since // more can be dropped by denormalizing. - bool topOne = bits(extra, 12); - bool restZeros = bits(extra, 11, 0) == 0; + bool topOne = bits(extra, mWidth - 10 - 1); + bool restZeros = bits(extra, mWidth - 10 - 2, 0) == 0; - if (exponent <= (127 - 15)) { + if (exponent <= (eHalfRange - 15)) { // The result is too small. Denormalize. mantissa |= (1 << 10); - while (mantissa && exponent <= (127 - 15)) { + while (mantissa && exponent <= (eHalfRange - 15)) { restZeros = restZeros && !topOne; topOne = bits(mantissa, 0); mantissa = mantissa >> 1; @@ -424,7 +484,7 @@ vcvtFpSFpH(FPSCR &fpscr, bool flush, bool defaultNan, exponent = 0; } else { // Change bias. - exponent -= (127 - 15); + exponent -= (eHalfRange - 15); } if (exponent == 0 && (inexact || fpscr.ufe)) { @@ -488,155 +548,115 @@ vcvtFpSFpH(FPSCR &fpscr, bool flush, bool defaultNan, return result; } -float -vcvtFpHFpS(FPSCR &fpscr, bool defaultNan, bool ahp, uint16_t op) +uint16_t +vcvtFpSFpH(FPSCR &fpscr, bool flush, bool defaultNan, + uint32_t rMode, bool ahp, float op) { - float junk = 0.0; + uint64_t opBits = fpToBits(op); + return vcvtFpFpH(fpscr, flush, defaultNan, rMode, ahp, opBits, false); +} + +uint16_t +vcvtFpDFpH(FPSCR &fpscr, bool flush, bool defaultNan, + uint32_t rMode, bool ahp, double op) +{ + uint64_t opBits = fpToBits(op); + return vcvtFpFpH(fpscr, flush, defaultNan, rMode, ahp, opBits, true); +} + +static inline uint64_t +vcvtFpHFp(FPSCR &fpscr, bool defaultNan, bool ahp, uint16_t op, bool isDouble) +{ + uint32_t mWidth; + uint32_t eWidth; + uint32_t eHalfRange; + uint32_t sBitPos; + + if (isDouble) { + mWidth = 52; + eWidth = 11; + } else { + mWidth = 23; + eWidth = 8; + } + sBitPos = eWidth + mWidth; + eHalfRange = (1 << (eWidth-1)) - 1; + // Extract the bitfields. bool neg = bits(op, 15); uint32_t exponent = bits(op, 14, 10); - uint32_t mantissa = bits(op, 9, 0); + uint64_t mantissa = bits(op, 9, 0); // Do the conversion. if (exponent == 0) { if (mantissa != 0) { // Normalize the value. - exponent = exponent + (127 - 15) + 1; + exponent = exponent + (eHalfRange - 15) + 1; while (mantissa < (1 << 10)) { mantissa = mantissa << 1; exponent--; } } - mantissa = mantissa << (23 - 10); + mantissa = mantissa << (mWidth - 10); } else if (exponent == 0x1f && !ahp) { // Infinities and nans. - exponent = 0xff; + exponent = mask(eWidth); if (mantissa != 0) { // Nans. - mantissa = mantissa << (23 - 10); - if (bits(mantissa, 22) == 0) { + mantissa = mantissa << (mWidth - 10); + if (bits(mantissa, mWidth-1) == 0) { // Signalling nan. fpscr.ioc = 1; - mantissa |= (1 << 22); + mantissa |= (((uint64_t) 1) << (mWidth-1)); } if (defaultNan) { - mantissa &= ~mask(22); + mantissa &= ~mask(mWidth-1); neg = false; } } } else { - exponent = exponent + (127 - 15); - mantissa = mantissa << (23 - 10); + exponent = exponent + (eHalfRange - 15); + mantissa = mantissa << (mWidth - 10); } // Reassemble the result. - uint32_t result = bits(mantissa, 22, 0); - replaceBits(result, 30, 23, exponent); - if (neg) - result |= (1 << 31); + uint64_t result = bits(mantissa, mWidth-1, 0); + replaceBits(result, sBitPos-1, mWidth, exponent); + if (neg) { + result |= (((uint64_t) 1) << sBitPos); + } + return result; +} + +double +vcvtFpHFpD(FPSCR &fpscr, bool defaultNan, bool ahp, uint16_t op) +{ + double junk = 0.0; + uint64_t result; + + result = vcvtFpHFp(fpscr, defaultNan, ahp, op, true); return bitsToFp(result, junk); } -uint64_t -vfpFpSToFixed(float val, bool isSigned, bool half, - uint8_t imm, bool rzero) +float +vcvtFpHFpS(FPSCR &fpscr, bool defaultNan, bool ahp, uint16_t op) { - int rmode = rzero ? FeRoundZero : fegetround(); - __asm__ __volatile__("" : "=m" (rmode) : "m" (rmode)); - fesetround(FeRoundNearest); - val = val * powf(2.0, imm); - __asm__ __volatile__("" : "=m" (val) : "m" (val)); - fesetround(rmode); - feclearexcept(FeAllExceptions); - __asm__ __volatile__("" : "=m" (val) : "m" (val)); - float origVal = val; - val = rintf(val); - int fpType = std::fpclassify(val); - if (fpType == FP_SUBNORMAL || fpType == FP_NAN) { - if (fpType == FP_NAN) { - feraiseexcept(FeInvalid); - } - val = 0.0; - } else if (origVal != val) { - switch (rmode) { - case FeRoundNearest: - if (origVal - val > 0.5) - val += 1.0; - else if (val - origVal > 0.5) - val -= 1.0; - break; - case FeRoundDown: - if (origVal < val) - val -= 1.0; - break; - case FeRoundUpward: - if (origVal > val) - val += 1.0; - break; - } - feraiseexcept(FeInexact); - } + float junk = 0.0; + uint64_t result; - if (isSigned) { - if (half) { - if ((double)val < (int16_t)(1 << 15)) { - feraiseexcept(FeInvalid); - feclearexcept(FeInexact); - return (int16_t)(1 << 15); - } - if ((double)val > (int16_t)mask(15)) { - feraiseexcept(FeInvalid); - feclearexcept(FeInexact); - return (int16_t)mask(15); - } - return (int16_t)val; - } else { - if ((double)val < (int32_t)(1 << 31)) { - feraiseexcept(FeInvalid); - feclearexcept(FeInexact); - return (int32_t)(1 << 31); - } - if ((double)val > (int32_t)mask(31)) { - feraiseexcept(FeInvalid); - feclearexcept(FeInexact); - return (int32_t)mask(31); - } - return (int32_t)val; - } - } else { - if (half) { - if ((double)val < 0) { - feraiseexcept(FeInvalid); - feclearexcept(FeInexact); - return 0; - } - if ((double)val > (mask(16))) { - feraiseexcept(FeInvalid); - feclearexcept(FeInexact); - return mask(16); - } - return (uint16_t)val; - } else { - if ((double)val < 0) { - feraiseexcept(FeInvalid); - feclearexcept(FeInexact); - return 0; - } - if ((double)val > (mask(32))) { - feraiseexcept(FeInvalid); - feclearexcept(FeInexact); - return mask(32); - } - return (uint32_t)val; - } - } + result = vcvtFpHFp(fpscr, defaultNan, ahp, op, false); + return bitsToFp(result, junk); } float vfpUFixedToFpS(bool flush, bool defaultNan, - uint32_t val, bool half, uint8_t imm) + uint64_t val, uint8_t width, uint8_t imm) { fesetround(FeRoundNearest); - if (half) + if (width == 16) val = (uint16_t)val; + else if (width == 32) + val = (uint32_t)val; + else if (width != 64) + panic("Unsupported width %d", width); float scale = powf(2.0, imm); __asm__ __volatile__("" : "=m" (scale) : "m" (scale)); feclearexcept(FeAllExceptions); @@ -646,11 +666,16 @@ vfpUFixedToFpS(bool flush, bool defaultNan, float vfpSFixedToFpS(bool flush, bool defaultNan, - int32_t val, bool half, uint8_t imm) + int64_t val, uint8_t width, uint8_t imm) { fesetround(FeRoundNearest); - if (half) + if (width == 16) val = sext<16>(val & mask(16)); + else if (width == 32) + val = sext<32>(val & mask(32)); + else if (width != 64) + panic("Unsupported width %d", width); + float scale = powf(2.0, imm); __asm__ __volatile__("" : "=m" (scale) : "m" (scale)); feclearexcept(FeAllExceptions); @@ -658,106 +683,19 @@ vfpSFixedToFpS(bool flush, bool defaultNan, return fixDivDest(flush, defaultNan, val / scale, (float)val, scale); } -uint64_t -vfpFpDToFixed(double val, bool isSigned, bool half, - uint8_t imm, bool rzero) -{ - int rmode = rzero ? FeRoundZero : fegetround(); - fesetround(FeRoundNearest); - val = val * pow(2.0, imm); - __asm__ __volatile__("" : "=m" (val) : "m" (val)); - fesetround(rmode); - feclearexcept(FeAllExceptions); - __asm__ __volatile__("" : "=m" (val) : "m" (val)); - double origVal = val; - val = rint(val); - int fpType = std::fpclassify(val); - if (fpType == FP_SUBNORMAL || fpType == FP_NAN) { - if (fpType == FP_NAN) { - feraiseexcept(FeInvalid); - } - val = 0.0; - } else if (origVal != val) { - switch (rmode) { - case FeRoundNearest: - if (origVal - val > 0.5) - val += 1.0; - else if (val - origVal > 0.5) - val -= 1.0; - break; - case FeRoundDown: - if (origVal < val) - val -= 1.0; - break; - case FeRoundUpward: - if (origVal > val) - val += 1.0; - break; - } - feraiseexcept(FeInexact); - } - if (isSigned) { - if (half) { - if (val < (int16_t)(1 << 15)) { - feraiseexcept(FeInvalid); - feclearexcept(FeInexact); - return (int16_t)(1 << 15); - } - if (val > (int16_t)mask(15)) { - feraiseexcept(FeInvalid); - feclearexcept(FeInexact); - return (int16_t)mask(15); - } - return (int16_t)val; - } else { - if (val < (int32_t)(1 << 31)) { - feraiseexcept(FeInvalid); - feclearexcept(FeInexact); - return (int32_t)(1 << 31); - } - if (val > (int32_t)mask(31)) { - feraiseexcept(FeInvalid); - feclearexcept(FeInexact); - return (int32_t)mask(31); - } - return (int32_t)val; - } - } else { - if (half) { - if (val < 0) { - feraiseexcept(FeInvalid); - feclearexcept(FeInexact); - return 0; - } - if (val > mask(16)) { - feraiseexcept(FeInvalid); - feclearexcept(FeInexact); - return mask(16); - } - return (uint16_t)val; - } else { - if (val < 0) { - feraiseexcept(FeInvalid); - feclearexcept(FeInexact); - return 0; - } - if (val > mask(32)) { - feraiseexcept(FeInvalid); - feclearexcept(FeInexact); - return mask(32); - } - return (uint32_t)val; - } - } -} double vfpUFixedToFpD(bool flush, bool defaultNan, - uint32_t val, bool half, uint8_t imm) + uint64_t val, uint8_t width, uint8_t imm) { fesetround(FeRoundNearest); - if (half) + if (width == 16) val = (uint16_t)val; + else if (width == 32) + val = (uint32_t)val; + else if (width != 64) + panic("Unsupported width %d", width); + double scale = pow(2.0, imm); __asm__ __volatile__("" : "=m" (scale) : "m" (scale)); feclearexcept(FeAllExceptions); @@ -767,11 +705,16 @@ vfpUFixedToFpD(bool flush, bool defaultNan, double vfpSFixedToFpD(bool flush, bool defaultNan, - int32_t val, bool half, uint8_t imm) + int64_t val, uint8_t width, uint8_t imm) { fesetround(FeRoundNearest); - if (half) + if (width == 16) val = sext<16>(val & mask(16)); + else if (width == 32) + val = sext<32>(val & mask(32)); + else if (width != 64) + panic("Unsupported width %d", width); + double scale = pow(2.0, imm); __asm__ __volatile__("" : "=m" (scale) : "m" (scale)); feclearexcept(FeAllExceptions); @@ -976,6 +919,85 @@ template double FpOp::processNans(FPSCR &fpscr, bool &done, bool defaultNan, double op1, double op2) const; +// @TODO remove this function when we've finished switching all FMA code to use the new FPLIB +template <class fpType> +fpType +FpOp::ternaryOp(FPSCR &fpscr, fpType op1, fpType op2, fpType op3, + fpType (*func)(fpType, fpType, fpType), + bool flush, bool defaultNan, uint32_t rMode) const +{ + const bool single = (sizeof(fpType) == sizeof(float)); + fpType junk = 0.0; + + if (flush && (flushToZero(op1, op2) || flushToZero(op3))) + fpscr.idc = 1; + VfpSavedState state = prepFpState(rMode); + __asm__ __volatile__ ("" : "=m" (op1), "=m" (op2), "=m" (op3), "=m" (state) + : "m" (op1), "m" (op2), "m" (op3), "m" (state)); + fpType dest = func(op1, op2, op3); + __asm__ __volatile__ ("" : "=m" (dest) : "m" (dest)); + + int fpClass = std::fpclassify(dest); + // Get NAN behavior right. This varies between x86 and ARM. + if (fpClass == FP_NAN) { + const uint64_t qnan = + single ? 0x7fc00000 : ULL(0x7ff8000000000000); + const bool nan1 = std::isnan(op1); + const bool nan2 = std::isnan(op2); + const bool nan3 = std::isnan(op3); + const bool signal1 = nan1 && ((fpToBits(op1) & qnan) != qnan); + const bool signal2 = nan2 && ((fpToBits(op2) & qnan) != qnan); + const bool signal3 = nan3 && ((fpToBits(op3) & qnan) != qnan); + if ((!nan1 && !nan2 && !nan3) || (defaultNan == 1)) { + dest = bitsToFp(qnan, junk); + } else if (signal1) { + dest = bitsToFp(fpToBits(op1) | qnan, junk); + } else if (signal2) { + dest = bitsToFp(fpToBits(op2) | qnan, junk); + } else if (signal3) { + dest = bitsToFp(fpToBits(op3) | qnan, junk); + } else if (nan1) { + dest = op1; + } else if (nan2) { + dest = op2; + } else if (nan3) { + dest = op3; + } + } else if (flush && flushToZero(dest)) { + feraiseexcept(FeUnderflow); + } else if (( + (single && (dest == bitsToFp(0x00800000, junk) || + dest == bitsToFp(0x80800000, junk))) || + (!single && + (dest == bitsToFp(ULL(0x0010000000000000), junk) || + dest == bitsToFp(ULL(0x8010000000000000), junk))) + ) && rMode != VfpRoundZero) { + /* + * Correct for the fact that underflow is detected -before- rounding + * in ARM and -after- rounding in x86. + */ + fesetround(FeRoundZero); + __asm__ __volatile__ ("" : "=m" (op1), "=m" (op2), "=m" (op3) + : "m" (op1), "m" (op2), "m" (op3)); + fpType temp = func(op1, op2, op2); + __asm__ __volatile__ ("" : "=m" (temp) : "m" (temp)); + if (flush && flushToZero(temp)) { + dest = temp; + } + } + finishVfp(fpscr, state, flush); + return dest; +} + +template +float FpOp::ternaryOp(FPSCR &fpscr, float op1, float op2, float op3, + float (*func)(float, float, float), + bool flush, bool defaultNan, uint32_t rMode) const; +template +double FpOp::ternaryOp(FPSCR &fpscr, double op1, double op2, double op3, + double (*func)(double, double, double), + bool flush, bool defaultNan, uint32_t rMode) const; + template <class fpType> fpType FpOp::binaryOp(FPSCR &fpscr, fpType op1, fpType op2, diff --git a/src/arch/arm/insts/vfp.hh b/src/arch/arm/insts/vfp.hh index 9babaae04..f17f90973 100644 --- a/src/arch/arm/insts/vfp.hh +++ b/src/arch/arm/insts/vfp.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -104,7 +104,8 @@ enum VfpRoundingMode VfpRoundNearest = 0, VfpRoundUpward = 1, VfpRoundDown = 2, - VfpRoundZero = 3 + VfpRoundZero = 3, + VfpRoundAway = 4 }; static inline float bitsToFp(uint64_t, float); @@ -212,7 +213,7 @@ isSnan(fpType val) typedef int VfpSavedState; VfpSavedState prepFpState(uint32_t rMode); -void finishVfp(FPSCR &fpscr, VfpSavedState state, bool flush); +void finishVfp(FPSCR &fpscr, VfpSavedState state, bool flush, FPSCR mask = FpscrExcMask); template <class fpType> fpType fixDest(FPSCR fpscr, fpType val, fpType op1); @@ -228,7 +229,11 @@ double fixFpSFpDDest(FPSCR fpscr, float val); uint16_t vcvtFpSFpH(FPSCR &fpscr, bool flush, bool defaultNan, uint32_t rMode, bool ahp, float op); -float vcvtFpHFpS(FPSCR &fpscr, bool defaultNan, bool ahp, uint16_t op); +uint16_t vcvtFpDFpH(FPSCR &fpscr, bool flush, bool defaultNan, + uint32_t rMode, bool ahp, double op); + +float vcvtFpHFpS(FPSCR &fpscr, bool defaultNan, bool ahp, uint16_t op); +double vcvtFpHFpD(FPSCR &fpscr, bool defaultNan, bool ahp, uint16_t op); static inline double makeDouble(uint32_t low, uint32_t high) @@ -249,19 +254,192 @@ highFromDouble(double val) return fpToBits(val) >> 32; } -uint64_t vfpFpSToFixed(float val, bool isSigned, bool half, - uint8_t imm, bool rzero = true); +static inline void +setFPExceptions(int exceptions) { + feclearexcept(FeAllExceptions); + feraiseexcept(exceptions); +} + +template <typename T> +uint64_t +vfpFpToFixed(T val, bool isSigned, uint8_t width, uint8_t imm, bool + useRmode = true, VfpRoundingMode roundMode = VfpRoundZero, + bool aarch64 = false) +{ + int rmode; + bool roundAwayFix = false; + + if (!useRmode) { + rmode = fegetround(); + } else { + switch (roundMode) + { + case VfpRoundNearest: + rmode = FeRoundNearest; + break; + case VfpRoundUpward: + rmode = FeRoundUpward; + break; + case VfpRoundDown: + rmode = FeRoundDown; + break; + case VfpRoundZero: + rmode = FeRoundZero; + break; + case VfpRoundAway: + // There is no equivalent rounding mode, use round down and we'll + // fix it later + rmode = FeRoundDown; + roundAwayFix = true; + break; + default: + panic("Unsupported roundMode %d\n", roundMode); + } + } + __asm__ __volatile__("" : "=m" (rmode) : "m" (rmode)); + fesetround(FeRoundNearest); + val = val * pow(2.0, imm); + __asm__ __volatile__("" : "=m" (val) : "m" (val)); + fesetround(rmode); + feclearexcept(FeAllExceptions); + __asm__ __volatile__("" : "=m" (val) : "m" (val)); + T origVal = val; + val = rint(val); + __asm__ __volatile__("" : "=m" (val) : "m" (val)); + + int exceptions = fetestexcept(FeAllExceptions); + + int fpType = std::fpclassify(val); + if (fpType == FP_SUBNORMAL || fpType == FP_NAN) { + if (fpType == FP_NAN) { + exceptions |= FeInvalid; + } + val = 0.0; + } else if (origVal != val) { + switch (rmode) { + case FeRoundNearest: + if (origVal - val > 0.5) + val += 1.0; + else if (val - origVal > 0.5) + val -= 1.0; + break; + case FeRoundDown: + if (roundAwayFix) { + // The ordering on the subtraction looks a bit odd in that we + // don't do the obvious origVal - val, instead we do + // -(val - origVal). This is required to get the corruct bit + // exact behaviour when very close to the 0.5 threshold. + volatile T error = val; + error -= origVal; + error = -error; + if ( (error > 0.5) || + ((error == 0.5) && (val >= 0)) ) + val += 1.0; + } else { + if (origVal < val) + val -= 1.0; + } + break; + case FeRoundUpward: + if (origVal > val) + val += 1.0; + break; + } + exceptions |= FeInexact; + } + + __asm__ __volatile__("" : "=m" (val) : "m" (val)); + + if (isSigned) { + bool outOfRange = false; + int64_t result = (int64_t) val; + uint64_t finalVal; + + if (!aarch64) { + if (width == 16) { + finalVal = (int16_t)val; + } else if (width == 32) { + finalVal =(int32_t)val; + } else if (width == 64) { + finalVal = result; + } else { + panic("Unsupported width %d\n", width); + } + + // check if value is in range + int64_t minVal = ~mask(width-1); + if ((double)val < minVal) { + outOfRange = true; + finalVal = minVal; + } + int64_t maxVal = mask(width-1); + if ((double)val > maxVal) { + outOfRange = true; + finalVal = maxVal; + } + } else { + bool isNeg = val < 0; + finalVal = result & mask(width); + // If the result is supposed to be less than 64 bits check that the + // upper bits that got thrown away are just sign extension bits + if (width != 64) { + outOfRange = ((uint64_t) result >> (width - 1)) != + (isNeg ? mask(64-width+1) : 0); + } + // Check if the original floating point value doesn't matches the + // integer version we are also out of range. So create a saturated + // result. + if (isNeg) { + outOfRange |= val < result; + if (outOfRange) { + finalVal = 1LL << (width-1); + } + } else { + outOfRange |= val > result; + if (outOfRange) { + finalVal = mask(width-1); + } + } + } + + // Raise an exception if the value was out of range + if (outOfRange) { + exceptions |= FeInvalid; + exceptions &= ~FeInexact; + } + setFPExceptions(exceptions); + return finalVal; + } else { + if ((double)val < 0) { + exceptions |= FeInvalid; + exceptions &= ~FeInexact; + setFPExceptions(exceptions); + return 0; + } + + uint64_t result = ((uint64_t) val) & mask(width); + if (val > result) { + exceptions |= FeInvalid; + exceptions &= ~FeInexact; + setFPExceptions(exceptions); + return mask(width); + } + + setFPExceptions(exceptions); + return result; + } +}; + + float vfpUFixedToFpS(bool flush, bool defaultNan, - uint32_t val, bool half, uint8_t imm); + uint64_t val, uint8_t width, uint8_t imm); float vfpSFixedToFpS(bool flush, bool defaultNan, - int32_t val, bool half, uint8_t imm); + int64_t val, uint8_t width, uint8_t imm); -uint64_t vfpFpDToFixed(double val, bool isSigned, bool half, - uint8_t imm, bool rzero = true); double vfpUFixedToFpD(bool flush, bool defaultNan, - uint32_t val, bool half, uint8_t imm); + uint64_t val, uint8_t width, uint8_t imm); double vfpSFixedToFpD(bool flush, bool defaultNan, - int32_t val, bool half, uint8_t imm); + int64_t val, uint8_t width, uint8_t imm); float fprSqrtEstimate(FPSCR &fpscr, float op); uint32_t unsignedRSqrtEstimate(uint32_t op); @@ -292,6 +470,20 @@ class VfpMacroOp : public PredMacroOp void nextIdxs(IntRegIndex &dest); }; +template <typename T> +static inline T +fpAdd(T a, T b) +{ + return a + b; +}; + +template <typename T> +static inline T +fpSub(T a, T b) +{ + return a - b; +}; + static inline float fpAddS(float a, float b) { @@ -328,6 +520,54 @@ fpDivD(double a, double b) return a / b; } +template <typename T> +static inline T +fpDiv(T a, T b) +{ + return a / b; +}; + +template <typename T> +static inline T +fpMulX(T a, T b) +{ + uint64_t opData; + uint32_t sign1; + uint32_t sign2; + const bool single = (sizeof(T) == sizeof(float)); + if (single) { + opData = (fpToBits(a)); + sign1 = opData>>31; + opData = (fpToBits(b)); + sign2 = opData>>31; + } else { + opData = (fpToBits(a)); + sign1 = opData>>63; + opData = (fpToBits(b)); + sign2 = opData>>63; + } + bool inf1 = (std::fpclassify(a) == FP_INFINITE); + bool inf2 = (std::fpclassify(b) == FP_INFINITE); + bool zero1 = (std::fpclassify(a) == FP_ZERO); + bool zero2 = (std::fpclassify(b) == FP_ZERO); + if ((inf1 && zero2) || (zero1 && inf2)) { + if(sign1 ^ sign2) + return (T)(-2.0); + else + return (T)(2.0); + } else { + return (a * b); + } +}; + + +template <typename T> +static inline T +fpMul(T a, T b) +{ + return a * b; +}; + static inline float fpMulS(float a, float b) { @@ -340,23 +580,140 @@ fpMulD(double a, double b) return a * b; } -static inline float -fpMaxS(float a, float b) +template <typename T> +static inline T +// @todo remove this when all calls to it have been replaced with the new fplib implementation +fpMulAdd(T op1, T op2, T addend) +{ + T result; + + if (sizeof(T) == sizeof(float)) + result = fmaf(op1, op2, addend); + else + result = fma(op1, op2, addend); + + // ARM doesn't generate signed nan's from this opperation, so fix up the result + if (std::isnan(result) && !std::isnan(op1) && + !std::isnan(op2) && !std::isnan(addend)) + { + uint64_t bitMask = ULL(0x1) << ((sizeof(T) * 8) - 1); + result = bitsToFp(fpToBits(result) & ~bitMask, op1); + } + return result; +} + +template <typename T> +static inline T +fpRIntX(T a, FPSCR &fpscr) +{ + T rVal; + + rVal = rint(a); + if (rVal != a && !std::isnan(a)) + fpscr.ixc = 1; + return (rVal); +}; + +template <typename T> +static inline T +fpMaxNum(T a, T b) { + const bool single = (sizeof(T) == sizeof(float)); + const uint64_t qnan = single ? 0x7fc00000 : ULL(0x7ff8000000000000); + + if (std::isnan(a)) + return ((fpToBits(a) & qnan) == qnan) ? b : a; + if (std::isnan(b)) + return ((fpToBits(b) & qnan) == qnan) ? a : b; // Handle comparisons of +0 and -0. if (!std::signbit(a) && std::signbit(b)) return a; - return fmaxf(a, b); -} + return fmax(a, b); +}; -static inline float -fpMinS(float a, float b) +template <typename T> +static inline T +fpMax(T a, T b) { + if (std::isnan(a)) + return a; + if (std::isnan(b)) + return b; + return fpMaxNum<T>(a, b); +}; + +template <typename T> +static inline T +fpMinNum(T a, T b) +{ + const bool single = (sizeof(T) == sizeof(float)); + const uint64_t qnan = single ? 0x7fc00000 : ULL(0x7ff8000000000000); + + if (std::isnan(a)) + return ((fpToBits(a) & qnan) == qnan) ? b : a; + if (std::isnan(b)) + return ((fpToBits(b) & qnan) == qnan) ? a : b; // Handle comparisons of +0 and -0. if (std::signbit(a) && !std::signbit(b)) return a; - return fminf(a, b); -} + return fmin(a, b); +}; + +template <typename T> +static inline T +fpMin(T a, T b) +{ + if (std::isnan(a)) + return a; + if (std::isnan(b)) + return b; + return fpMinNum<T>(a, b); +}; + +template <typename T> +static inline T +fpRSqrts(T a, T b) +{ + int fpClassA = std::fpclassify(a); + int fpClassB = std::fpclassify(b); + T aXb; + int fpClassAxB; + + if ((fpClassA == FP_ZERO && fpClassB == FP_INFINITE) || + (fpClassA == FP_INFINITE && fpClassB == FP_ZERO)) { + return 1.5; + } + aXb = a*b; + fpClassAxB = std::fpclassify(aXb); + if(fpClassAxB == FP_SUBNORMAL) { + feraiseexcept(FeUnderflow); + return 1.5; + } + return (3.0 - (a * b)) / 2.0; +}; + +template <typename T> +static inline T +fpRecps(T a, T b) +{ + int fpClassA = std::fpclassify(a); + int fpClassB = std::fpclassify(b); + T aXb; + int fpClassAxB; + + if ((fpClassA == FP_ZERO && fpClassB == FP_INFINITE) || + (fpClassA == FP_INFINITE && fpClassB == FP_ZERO)) { + return 2.0; + } + aXb = a*b; + fpClassAxB = std::fpclassify(aXb); + if(fpClassAxB == FP_SUBNORMAL) { + feraiseexcept(FeUnderflow); + return 2.0; + } + return 2.0 - (a * b); +}; + static inline float fpRSqrtsS(float a, float b) @@ -400,6 +757,23 @@ fpRecpsS(float a, float b) return 2.0 - (a * b); } +template <typename T> +static inline T +roundNEven(T a) { + T val; + + val = round(a); + if (a - val == 0.5) { + if ( (((int) a) & 1) == 0 ) val += 1.0; + } + else if (a - val == -0.5) { + if ( (((int) a) & 1) == 0 ) val -= 1.0; + } + return val; +} + + + class FpOp : public PredOp { protected: @@ -457,6 +831,12 @@ class FpOp : public PredOp template <class fpType> fpType + ternaryOp(FPSCR &fpscr, fpType op1, fpType op2, fpType op3, + fpType (*func)(fpType, fpType, fpType), + bool flush, bool defaultNan, uint32_t rMode) const; + + template <class fpType> + fpType binaryOp(FPSCR &fpscr, fpType op1, fpType op2, fpType (*func)(fpType, fpType), bool flush, bool defaultNan, uint32_t rMode) const; @@ -478,6 +858,55 @@ class FpOp : public PredOp pcState.advance(); } } + + float + fpSqrt (FPSCR fpscr,float x) const + { + + return unaryOp(fpscr,x,sqrtf,fpscr.fz,fpscr.rMode); + + } + + double + fpSqrt (FPSCR fpscr,double x) const + { + + return unaryOp(fpscr,x,sqrt,fpscr.fz,fpscr.rMode); + + } +}; + +class FpCondCompRegOp : public FpOp +{ + protected: + IntRegIndex op1, op2; + ConditionCode condCode; + uint8_t defCc; + + FpCondCompRegOp(const char *mnem, ExtMachInst _machInst, + OpClass __opClass, IntRegIndex _op1, IntRegIndex _op2, + ConditionCode _condCode, uint8_t _defCc) : + FpOp(mnem, _machInst, __opClass), + op1(_op1), op2(_op2), condCode(_condCode), defCc(_defCc) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + +class FpCondSelOp : public FpOp +{ + protected: + IntRegIndex dest, op1, op2; + ConditionCode condCode; + + FpCondSelOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2, + ConditionCode _condCode) : + FpOp(mnem, _machInst, __opClass), + dest(_dest), op1(_op1), op2(_op2), condCode(_condCode) + {} + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; }; class FpRegRegOp : public FpOp @@ -550,6 +979,26 @@ class FpRegRegRegOp : public FpOp std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; }; +class FpRegRegRegRegOp : public FpOp +{ + protected: + IntRegIndex dest; + IntRegIndex op1; + IntRegIndex op2; + IntRegIndex op3; + + FpRegRegRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2, + IntRegIndex _op3, VfpMicroMode mode = VfpNotAMicroop) : + FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1), op2(_op2), + op3(_op3) + { + setVfpMicroFlags(mode, flags); + } + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + class FpRegRegRegImmOp : public FpOp { protected: diff --git a/src/arch/arm/interrupts.cc b/src/arch/arm/interrupts.cc index c05ae984e..6682b75a0 100644 --- a/src/arch/arm/interrupts.cc +++ b/src/arch/arm/interrupts.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009 ARM Limited + * Copyright (c) 2009, 2012-2013 ARM Limited * All rights reserved. * * The license below extends only to copyright in the software and shall @@ -38,9 +38,128 @@ */ #include "arch/arm/interrupts.hh" +#include "arch/arm/system.hh" ArmISA::Interrupts * ArmInterruptsParams::create() { return new ArmISA::Interrupts(this); } + +bool +ArmISA::Interrupts::takeInt(ThreadContext *tc, InterruptTypes int_type) const +{ + // Table G1-17~19 of ARM V8 ARM + InterruptMask mask; + bool highest_el_is_64 = ArmSystem::highestELIs64(tc); + + CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); + SCR scr; + HCR hcr; + hcr = tc->readMiscReg(MISCREG_HCR); + ExceptionLevel el = (ExceptionLevel) ((uint32_t) cpsr.el); + bool cpsr_mask_bit, scr_routing_bit, scr_fwaw_bit, hcr_mask_override_bit; + + if (!highest_el_is_64) + scr = tc->readMiscReg(MISCREG_SCR); + else + scr = tc->readMiscReg(MISCREG_SCR_EL3); + + bool is_secure = inSecureState(scr, cpsr); + + switch(int_type) { + case INT_FIQ: + cpsr_mask_bit = cpsr.f; + scr_routing_bit = scr.fiq; + scr_fwaw_bit = scr.fw; + hcr_mask_override_bit = hcr.fmo; + break; + case INT_IRQ: + cpsr_mask_bit = cpsr.i; + scr_routing_bit = scr.irq; + scr_fwaw_bit = 1; + hcr_mask_override_bit = hcr.imo; + break; + case INT_ABT: + cpsr_mask_bit = cpsr.a; + scr_routing_bit = scr.ea; + scr_fwaw_bit = scr.aw; + hcr_mask_override_bit = hcr.amo; + break; + default: + panic("Unhandled interrupt type!"); + } + + if (hcr.tge) + hcr_mask_override_bit = 1; + + if (!highest_el_is_64) { + // AArch32 + if (!scr_routing_bit) { + // SCR IRQ == 0 + if (!hcr_mask_override_bit) + mask = INT_MASK_M; + else { + if (!is_secure && (el == EL0 || el == EL1)) + mask = INT_MASK_T; + else + mask = INT_MASK_M; + } + } else { + // SCR IRQ == 1 + if ((!is_secure) && + (hcr_mask_override_bit || + (!scr_fwaw_bit && !hcr_mask_override_bit))) + mask = INT_MASK_T; + else + mask = INT_MASK_M; + } + } else { + // AArch64 + if (!scr_routing_bit) { + // SCR IRQ == 0 + if (!scr.rw) { + // SCR RW == 0 + if (!hcr_mask_override_bit) { + if (el == EL3) + mask = INT_MASK_P; + else + mask = INT_MASK_M; + } else { + if (el == EL3) + mask = INT_MASK_T; + else if (is_secure || el == EL2) + mask = INT_MASK_M; + else + mask = INT_MASK_T; + } + } else { + // SCR RW == 1 + if (!hcr_mask_override_bit) { + if (el == EL3 || el == EL2) + mask = INT_MASK_P; + else + mask = INT_MASK_M; + } else { + if (el == EL3) + mask = INT_MASK_P; + else if (is_secure || el == EL2) + mask = INT_MASK_M; + else + mask = INT_MASK_T; + } + } + } else { + // SCR IRQ == 1 + if (el == EL3) + mask = INT_MASK_M; + else + mask = INT_MASK_T; + } + } + + return ((mask == INT_MASK_T) || + ((mask == INT_MASK_M) && !cpsr_mask_bit)) && + (mask != INT_MASK_P); +} + diff --git a/src/arch/arm/interrupts.hh b/src/arch/arm/interrupts.hh index 7def6ddd6..8e6c2b261 100644 --- a/src/arch/arm/interrupts.hh +++ b/src/arch/arm/interrupts.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010,2012 ARM Limited + * Copyright (c) 2010, 2012-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -47,6 +47,7 @@ #include "arch/arm/isa_traits.hh" #include "arch/arm/miscregs.hh" #include "arch/arm/registers.hh" +#include "arch/arm/utility.hh" #include "cpu/thread_context.hh" #include "debug/Interrupt.hh" #include "params/ArmInterrupts.hh" @@ -123,31 +124,79 @@ class Interrupts : public SimObject memset(interrupts, 0, sizeof(interrupts)); } + enum InterruptMask { + INT_MASK_M, // masked (subject to PSTATE.{A,I,F} mask bit + INT_MASK_T, // taken regardless of mask + INT_MASK_P // pending + }; + + bool takeInt(ThreadContext *tc, InterruptTypes int_type) const; + bool checkInterrupts(ThreadContext *tc) const { - if (!intStatus) + HCR hcr = tc->readMiscReg(MISCREG_HCR); + + if (!(intStatus || hcr.va || hcr.vi || hcr.vf)) return false; CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); - - return ((interrupts[INT_IRQ] && !cpsr.i) || - (interrupts[INT_FIQ] && !cpsr.f) || - (interrupts[INT_ABT] && !cpsr.a) || - (interrupts[INT_RST]) || - (interrupts[INT_SEV])); + SCR scr = tc->readMiscReg(MISCREG_SCR); + + bool isHypMode = cpsr.mode == MODE_HYP; + bool isSecure = inSecureState(scr, cpsr); + bool allowVIrq = !cpsr.i && hcr.imo && !isSecure && !isHypMode; + bool allowVFiq = !cpsr.f && hcr.fmo && !isSecure && !isHypMode; + bool allowVAbort = !cpsr.a && hcr.amo && !isSecure && !isHypMode; + + bool take_irq = takeInt(tc, INT_IRQ); + bool take_fiq = takeInt(tc, INT_FIQ); + bool take_ea = takeInt(tc, INT_ABT); + + return ((interrupts[INT_IRQ] && take_irq) || + (interrupts[INT_FIQ] && take_fiq) || + (interrupts[INT_ABT] && take_ea) || + ((interrupts[INT_VIRT_IRQ] || hcr.vi) && allowVIrq) || + ((interrupts[INT_VIRT_FIQ] || hcr.vf) && allowVFiq) || + (hcr.va && allowVAbort) || + (interrupts[INT_RST]) || + (interrupts[INT_SEV]) + ); } /** - * Check the raw interrupt state. * This function is used to check if a wfi operation should sleep. If there * is an interrupt pending, even if it's masked, wfi doesn't sleep. * @return any interrupts pending */ bool - checkRaw() const + checkWfiWake(HCR hcr, CPSR cpsr, SCR scr) const + { + uint64_t maskedIntStatus; + bool virtWake; + + maskedIntStatus = intStatus & ~((1 << INT_VIRT_IRQ) | + (1 << INT_VIRT_FIQ)); + virtWake = (hcr.vi || interrupts[INT_VIRT_IRQ]) && hcr.imo; + virtWake |= (hcr.vf || interrupts[INT_VIRT_FIQ]) && hcr.fmo; + virtWake |= hcr.va && hcr.amo; + virtWake &= (cpsr.mode != MODE_HYP) && !inSecureState(scr, cpsr); + return maskedIntStatus || virtWake; + } + + uint32_t + getISR(HCR hcr, CPSR cpsr, SCR scr) { - return intStatus; + bool useHcrMux; + CPSR isr = 0; // ARM ARM states ISR reg uses same bit possitions as CPSR + + useHcrMux = (cpsr.mode != MODE_HYP) && !inSecureState(scr, cpsr); + isr.i = (useHcrMux & hcr.imo) ? (interrupts[INT_VIRT_IRQ] || hcr.vi) + : interrupts[INT_IRQ]; + isr.f = (useHcrMux & hcr.fmo) ? (interrupts[INT_VIRT_FIQ] || hcr.vf) + : interrupts[INT_FIQ]; + isr.a = (useHcrMux & hcr.amo) ? hcr.va : interrupts[INT_ABT]; + return isr; } /** @@ -172,22 +221,45 @@ class Interrupts : public SimObject Fault getInterrupt(ThreadContext *tc) { - if (!intStatus) + HCR hcr = tc->readMiscReg(MISCREG_HCR); + CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); + SCR scr = tc->readMiscReg(MISCREG_SCR); + + // Calculate a few temp vars so we can work out if there's a pending + // virtual interrupt, and if its allowed to happen + // ARM ARM Issue C section B1.9.9, B1.9.11, and B1.9.13 + bool isHypMode = cpsr.mode == MODE_HYP; + bool isSecure = inSecureState(scr, cpsr); + bool allowVIrq = !cpsr.i && hcr.imo && !isSecure && !isHypMode; + bool allowVFiq = !cpsr.f && hcr.fmo && !isSecure && !isHypMode; + bool allowVAbort = !cpsr.a && hcr.amo && !isSecure && !isHypMode; + + if ( !(intStatus || (hcr.vi && allowVIrq) || (hcr.vf && allowVFiq) || + (hcr.va && allowVAbort)) ) return NoFault; - CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); + bool take_irq = takeInt(tc, INT_IRQ); + bool take_fiq = takeInt(tc, INT_FIQ); + bool take_ea = takeInt(tc, INT_ABT); + - if (interrupts[INT_IRQ] && !cpsr.i) + if (interrupts[INT_IRQ] && take_irq) return new Interrupt; - if (interrupts[INT_FIQ] && !cpsr.f) + if ((interrupts[INT_VIRT_IRQ] || hcr.vi) && allowVIrq) + return new VirtualInterrupt; + if (interrupts[INT_FIQ] && take_fiq) return new FastInterrupt; - if (interrupts[INT_ABT] && !cpsr.a) - return new DataAbort(0, false, 0, - ArmFault::AsynchronousExternalAbort); + if ((interrupts[INT_VIRT_FIQ] || hcr.vf) && allowVFiq) + return new VirtualFastInterrupt; + if (interrupts[INT_ABT] && take_ea) + return new SystemError; + if (hcr.va && allowVAbort) + return new VirtualDataAbort(0, TlbEntry::DomainType::NoAccess, false, + ArmFault::AsynchronousExternalAbort); if (interrupts[INT_RST]) - return new Reset; + return new Reset; if (interrupts[INT_SEV]) - return new ArmSev; + return new ArmSev; panic("intStatus and interrupts not in sync\n"); } diff --git a/src/arch/arm/intregs.hh b/src/arch/arm/intregs.hh index 3fe00b765..fa18aa68d 100644 --- a/src/arch/arm/intregs.hh +++ b/src/arch/arm/intregs.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -83,6 +83,9 @@ enum IntRegIndex INTREG_R14_MON, INTREG_LR_MON = INTREG_R14_MON, + INTREG_R13_HYP, + INTREG_SP_HYP = INTREG_R13_HYP, + INTREG_R13_ABT, INTREG_SP_ABT = INTREG_R13_ABT, INTREG_R14_ABT, @@ -108,7 +111,7 @@ enum IntRegIndex INTREG_R14_FIQ, INTREG_LR_FIQ = INTREG_R14_FIQ, - INTREG_ZERO, // Dummy zero reg since there has to be one. + INTREG_ZERO, INTREG_UREG0, INTREG_UREG1, INTREG_UREG2, @@ -117,12 +120,54 @@ enum IntRegIndex INTREG_CONDCODES_V, INTREG_CONDCODES_GE, INTREG_FPCONDCODES, + INTREG_DUMMY, // Dummy reg used to throw away int reg results + + INTREG_SP0, + INTREG_SP1, + INTREG_SP2, + INTREG_SP3, NUM_INTREGS, - NUM_ARCH_INTREGS = INTREG_PC + 1, + NUM_ARCH_INTREGS = 32, + + /* AArch64 registers */ + INTREG_X0 = 0, + INTREG_X1, + INTREG_X2, + INTREG_X3, + INTREG_X4, + INTREG_X5, + INTREG_X6, + INTREG_X7, + INTREG_X8, + INTREG_X9, + INTREG_X10, + INTREG_X11, + INTREG_X12, + INTREG_X13, + INTREG_X14, + INTREG_X15, + INTREG_X16, + INTREG_X17, + INTREG_X18, + INTREG_X19, + INTREG_X20, + INTREG_X21, + INTREG_X22, + INTREG_X23, + INTREG_X24, + INTREG_X25, + INTREG_X26, + INTREG_X27, + INTREG_X28, + INTREG_X29, + INTREG_X30, + INTREG_X31, + + INTREG_SPX = NUM_INTREGS, /* All the aliased indexes. */ - + /* USR mode */ INTREG_R0_USR = INTREG_R0, INTREG_R1_USR = INTREG_R1, @@ -195,6 +240,25 @@ enum IntRegIndex INTREG_PC_ABT = INTREG_PC, INTREG_R15_ABT = INTREG_R15, + /* HYP mode */ + INTREG_R0_HYP = INTREG_R0, + INTREG_R1_HYP = INTREG_R1, + INTREG_R2_HYP = INTREG_R2, + INTREG_R3_HYP = INTREG_R3, + INTREG_R4_HYP = INTREG_R4, + INTREG_R5_HYP = INTREG_R5, + INTREG_R6_HYP = INTREG_R6, + INTREG_R7_HYP = INTREG_R7, + INTREG_R8_HYP = INTREG_R8, + INTREG_R9_HYP = INTREG_R9, + INTREG_R10_HYP = INTREG_R10, + INTREG_R11_HYP = INTREG_R11, + INTREG_R12_HYP = INTREG_R12, + INTREG_LR_HYP = INTREG_LR, + INTREG_R14_HYP = INTREG_R14, + INTREG_PC_HYP = INTREG_PC, + INTREG_R15_HYP = INTREG_R15, + /* UND mode */ INTREG_R0_UND = INTREG_R0, INTREG_R1_UND = INTREG_R1, @@ -244,11 +308,26 @@ enum IntRegIndex typedef IntRegIndex IntRegMap[NUM_ARCH_INTREGS]; +const IntRegMap IntReg64Map = { + INTREG_R0, INTREG_R1, INTREG_R2, INTREG_R3, + INTREG_R4, INTREG_R5, INTREG_R6, INTREG_R7, + INTREG_R8_USR, INTREG_R9_USR, INTREG_R10_USR, INTREG_R11_USR, + INTREG_R12_USR, INTREG_R13_USR, INTREG_R14_USR, INTREG_R13_HYP, + INTREG_R14_IRQ, INTREG_R13_IRQ, INTREG_R14_SVC, INTREG_R13_SVC, + INTREG_R14_ABT, INTREG_R13_ABT, INTREG_R14_UND, INTREG_R13_UND, + INTREG_R8_FIQ, INTREG_R9_FIQ, INTREG_R10_FIQ, INTREG_R11_FIQ, + INTREG_R12_FIQ, INTREG_R13_FIQ, INTREG_R14_FIQ, INTREG_ZERO +}; + const IntRegMap IntRegUsrMap = { INTREG_R0_USR, INTREG_R1_USR, INTREG_R2_USR, INTREG_R3_USR, INTREG_R4_USR, INTREG_R5_USR, INTREG_R6_USR, INTREG_R7_USR, INTREG_R8_USR, INTREG_R9_USR, INTREG_R10_USR, INTREG_R11_USR, - INTREG_R12_USR, INTREG_R13_USR, INTREG_R14_USR, INTREG_R15_USR + INTREG_R12_USR, INTREG_R13_USR, INTREG_R14_USR, INTREG_R15_USR, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO }; static inline IntRegIndex @@ -258,11 +337,33 @@ INTREG_USR(unsigned index) return IntRegUsrMap[index]; } +const IntRegMap IntRegHypMap = { + INTREG_R0_HYP, INTREG_R1_HYP, INTREG_R2_HYP, INTREG_R3_HYP, + INTREG_R4_HYP, INTREG_R5_HYP, INTREG_R6_HYP, INTREG_R7_HYP, + INTREG_R8_HYP, INTREG_R9_HYP, INTREG_R10_HYP, INTREG_R11_HYP, + INTREG_R12_HYP, INTREG_R13_HYP, INTREG_R14_HYP, INTREG_R15_HYP, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO +}; + +static inline IntRegIndex +INTREG_HYP(unsigned index) +{ + assert(index < NUM_ARCH_INTREGS); + return IntRegHypMap[index]; +} + const IntRegMap IntRegSvcMap = { INTREG_R0_SVC, INTREG_R1_SVC, INTREG_R2_SVC, INTREG_R3_SVC, INTREG_R4_SVC, INTREG_R5_SVC, INTREG_R6_SVC, INTREG_R7_SVC, INTREG_R8_SVC, INTREG_R9_SVC, INTREG_R10_SVC, INTREG_R11_SVC, - INTREG_R12_SVC, INTREG_R13_SVC, INTREG_R14_SVC, INTREG_R15_SVC + INTREG_R12_SVC, INTREG_R13_SVC, INTREG_R14_SVC, INTREG_R15_SVC, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO }; static inline IntRegIndex @@ -276,7 +377,11 @@ const IntRegMap IntRegMonMap = { INTREG_R0_MON, INTREG_R1_MON, INTREG_R2_MON, INTREG_R3_MON, INTREG_R4_MON, INTREG_R5_MON, INTREG_R6_MON, INTREG_R7_MON, INTREG_R8_MON, INTREG_R9_MON, INTREG_R10_MON, INTREG_R11_MON, - INTREG_R12_MON, INTREG_R13_MON, INTREG_R14_MON, INTREG_R15_MON + INTREG_R12_MON, INTREG_R13_MON, INTREG_R14_MON, INTREG_R15_MON, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO }; static inline IntRegIndex @@ -290,7 +395,11 @@ const IntRegMap IntRegAbtMap = { INTREG_R0_ABT, INTREG_R1_ABT, INTREG_R2_ABT, INTREG_R3_ABT, INTREG_R4_ABT, INTREG_R5_ABT, INTREG_R6_ABT, INTREG_R7_ABT, INTREG_R8_ABT, INTREG_R9_ABT, INTREG_R10_ABT, INTREG_R11_ABT, - INTREG_R12_ABT, INTREG_R13_ABT, INTREG_R14_ABT, INTREG_R15_ABT + INTREG_R12_ABT, INTREG_R13_ABT, INTREG_R14_ABT, INTREG_R15_ABT, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO }; static inline IntRegIndex @@ -304,7 +413,11 @@ const IntRegMap IntRegUndMap = { INTREG_R0_UND, INTREG_R1_UND, INTREG_R2_UND, INTREG_R3_UND, INTREG_R4_UND, INTREG_R5_UND, INTREG_R6_UND, INTREG_R7_UND, INTREG_R8_UND, INTREG_R9_UND, INTREG_R10_UND, INTREG_R11_UND, - INTREG_R12_UND, INTREG_R13_UND, INTREG_R14_UND, INTREG_R15_UND + INTREG_R12_UND, INTREG_R13_UND, INTREG_R14_UND, INTREG_R15_UND, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO }; static inline IntRegIndex @@ -318,7 +431,11 @@ const IntRegMap IntRegIrqMap = { INTREG_R0_IRQ, INTREG_R1_IRQ, INTREG_R2_IRQ, INTREG_R3_IRQ, INTREG_R4_IRQ, INTREG_R5_IRQ, INTREG_R6_IRQ, INTREG_R7_IRQ, INTREG_R8_IRQ, INTREG_R9_IRQ, INTREG_R10_IRQ, INTREG_R11_IRQ, - INTREG_R12_IRQ, INTREG_R13_IRQ, INTREG_R14_IRQ, INTREG_R15_IRQ + INTREG_R12_IRQ, INTREG_R13_IRQ, INTREG_R14_IRQ, INTREG_R15_IRQ, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO }; static inline IntRegIndex @@ -332,7 +449,11 @@ const IntRegMap IntRegFiqMap = { INTREG_R0_FIQ, INTREG_R1_FIQ, INTREG_R2_FIQ, INTREG_R3_FIQ, INTREG_R4_FIQ, INTREG_R5_FIQ, INTREG_R6_FIQ, INTREG_R7_FIQ, INTREG_R8_FIQ, INTREG_R9_FIQ, INTREG_R10_FIQ, INTREG_R11_FIQ, - INTREG_R12_FIQ, INTREG_R13_FIQ, INTREG_R14_FIQ, INTREG_R15_FIQ + INTREG_R12_FIQ, INTREG_R13_FIQ, INTREG_R14_FIQ, INTREG_R15_FIQ, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, + INTREG_ZERO, INTREG_ZERO, INTREG_ZERO, INTREG_ZERO }; static inline IntRegIndex @@ -351,6 +472,51 @@ intRegInMode(OperatingMode mode, int reg) return mode * intRegsPerMode + reg; } +static inline int +flattenIntRegModeIndex(int reg) +{ + int mode = reg / intRegsPerMode; + reg = reg % intRegsPerMode; + switch (mode) { + case MODE_USER: + case MODE_SYSTEM: + return INTREG_USR(reg); + case MODE_FIQ: + return INTREG_FIQ(reg); + case MODE_IRQ: + return INTREG_IRQ(reg); + case MODE_SVC: + return INTREG_SVC(reg); + case MODE_MON: + return INTREG_MON(reg); + case MODE_ABORT: + return INTREG_ABT(reg); + case MODE_HYP: + return INTREG_HYP(reg); + case MODE_UNDEFINED: + return INTREG_UND(reg); + default: + panic("%d: Flattening into an unknown mode: reg:%#x mode:%#x\n", + curTick(), reg, mode); + } +} + + +static inline IntRegIndex +makeSP(IntRegIndex reg) +{ + if (reg == INTREG_X31) + reg = INTREG_SPX; + return reg; +} + + +static inline bool +isSP(IntRegIndex reg) +{ + return reg == INTREG_SPX; +} + } #endif diff --git a/src/arch/arm/isa.cc b/src/arch/arm/isa.cc index 86be2803d..4f1ef91ec 100644 --- a/src/arch/arm/isa.cc +++ b/src/arch/arm/isa.cc @@ -51,12 +51,111 @@ namespace ArmISA { + +/** + * Some registers aliase with others, and therefore need to be translated. + * For each entry: + * The first value is the misc register that is to be looked up + * the second value is the lower part of the translation + * the third the upper part + */ +const struct ISA::MiscRegInitializerEntry + ISA::MiscRegSwitch[miscRegTranslateMax] = { + {MISCREG_CSSELR_EL1, {MISCREG_CSSELR, 0}}, + {MISCREG_SCTLR_EL1, {MISCREG_SCTLR, 0}}, + {MISCREG_SCTLR_EL2, {MISCREG_HSCTLR, 0}}, + {MISCREG_ACTLR_EL1, {MISCREG_ACTLR, 0}}, + {MISCREG_ACTLR_EL2, {MISCREG_HACTLR, 0}}, + {MISCREG_CPACR_EL1, {MISCREG_CPACR, 0}}, + {MISCREG_CPTR_EL2, {MISCREG_HCPTR, 0}}, + {MISCREG_HCR_EL2, {MISCREG_HCR, 0}}, + {MISCREG_MDCR_EL2, {MISCREG_HDCR, 0}}, + {MISCREG_HSTR_EL2, {MISCREG_HSTR, 0}}, + {MISCREG_HACR_EL2, {MISCREG_HACR, 0}}, + {MISCREG_TTBR0_EL1, {MISCREG_TTBR0, 0}}, + {MISCREG_TTBR1_EL1, {MISCREG_TTBR1, 0}}, + {MISCREG_TTBR0_EL2, {MISCREG_HTTBR, 0}}, + {MISCREG_VTTBR_EL2, {MISCREG_VTTBR, 0}}, + {MISCREG_TCR_EL1, {MISCREG_TTBCR, 0}}, + {MISCREG_TCR_EL2, {MISCREG_HTCR, 0}}, + {MISCREG_VTCR_EL2, {MISCREG_VTCR, 0}}, + {MISCREG_AFSR0_EL1, {MISCREG_ADFSR, 0}}, + {MISCREG_AFSR1_EL1, {MISCREG_AIFSR, 0}}, + {MISCREG_AFSR0_EL2, {MISCREG_HADFSR, 0}}, + {MISCREG_AFSR1_EL2, {MISCREG_HAIFSR, 0}}, + {MISCREG_ESR_EL2, {MISCREG_HSR, 0}}, + {MISCREG_FAR_EL1, {MISCREG_DFAR, MISCREG_IFAR}}, + {MISCREG_FAR_EL2, {MISCREG_HDFAR, MISCREG_HIFAR}}, + {MISCREG_HPFAR_EL2, {MISCREG_HPFAR, 0}}, + {MISCREG_PAR_EL1, {MISCREG_PAR, 0}}, + {MISCREG_MAIR_EL1, {MISCREG_PRRR, MISCREG_NMRR}}, + {MISCREG_MAIR_EL2, {MISCREG_HMAIR0, MISCREG_HMAIR1}}, + {MISCREG_AMAIR_EL1, {MISCREG_AMAIR0, MISCREG_AMAIR1}}, + {MISCREG_VBAR_EL1, {MISCREG_VBAR, 0}}, + {MISCREG_VBAR_EL2, {MISCREG_HVBAR, 0}}, + {MISCREG_CONTEXTIDR_EL1, {MISCREG_CONTEXTIDR, 0}}, + {MISCREG_TPIDR_EL0, {MISCREG_TPIDRURW, 0}}, + {MISCREG_TPIDRRO_EL0, {MISCREG_TPIDRURO, 0}}, + {MISCREG_TPIDR_EL1, {MISCREG_TPIDRPRW, 0}}, + {MISCREG_TPIDR_EL2, {MISCREG_HTPIDR, 0}}, + {MISCREG_TEECR32_EL1, {MISCREG_TEECR, 0}}, + {MISCREG_CNTFRQ_EL0, {MISCREG_CNTFRQ, 0}}, + {MISCREG_CNTPCT_EL0, {MISCREG_CNTPCT, 0}}, + {MISCREG_CNTVCT_EL0, {MISCREG_CNTVCT, 0}}, + {MISCREG_CNTVOFF_EL2, {MISCREG_CNTVOFF, 0}}, + {MISCREG_CNTKCTL_EL1, {MISCREG_CNTKCTL, 0}}, + {MISCREG_CNTHCTL_EL2, {MISCREG_CNTHCTL, 0}}, + {MISCREG_CNTP_TVAL_EL0, {MISCREG_CNTP_TVAL, 0}}, + {MISCREG_CNTP_CTL_EL0, {MISCREG_CNTP_CTL, 0}}, + {MISCREG_CNTP_CVAL_EL0, {MISCREG_CNTP_CVAL, 0}}, + {MISCREG_CNTV_TVAL_EL0, {MISCREG_CNTV_TVAL, 0}}, + {MISCREG_CNTV_CTL_EL0, {MISCREG_CNTV_CTL, 0}}, + {MISCREG_CNTV_CVAL_EL0, {MISCREG_CNTV_CVAL, 0}}, + {MISCREG_CNTHP_TVAL_EL2, {MISCREG_CNTHP_TVAL, 0}}, + {MISCREG_CNTHP_CTL_EL2, {MISCREG_CNTHP_CTL, 0}}, + {MISCREG_CNTHP_CVAL_EL2, {MISCREG_CNTHP_CVAL, 0}}, + {MISCREG_DACR32_EL2, {MISCREG_DACR, 0}}, + {MISCREG_IFSR32_EL2, {MISCREG_IFSR, 0}}, + {MISCREG_TEEHBR32_EL1, {MISCREG_TEEHBR, 0}}, + {MISCREG_SDER32_EL3, {MISCREG_SDER, 0}} +}; + + ISA::ISA(Params *p) - : SimObject(p) + : SimObject(p), system(NULL), lookUpMiscReg(NUM_MISCREGS, {0,0}) { SCTLR sctlr; sctlr = 0; miscRegs[MISCREG_SCTLR_RST] = sctlr; + + system = dynamic_cast<ArmSystem *>(p->system); + DPRINTFN("ISA system set to: %p %p\n", system, p->system); + + // Cache system-level properties + if (FullSystem && system) { + haveSecurity = system->haveSecurity(); + haveLPAE = system->haveLPAE(); + haveVirtualization = system->haveVirtualization(); + haveLargeAsid64 = system->haveLargeAsid64(); + physAddrRange64 = system->physAddrRange64(); + } else { + haveSecurity = haveLPAE = haveVirtualization = false; + haveLargeAsid64 = false; + physAddrRange64 = 32; // dummy value + } + + /** Fill in the miscReg translation table */ + for (uint32_t i = 0; i < miscRegTranslateMax; i++) { + struct MiscRegLUTEntry new_entry; + + uint32_t select = MiscRegSwitch[i].index; + new_entry = MiscRegSwitch[i].entry; + + lookUpMiscReg[select] = new_entry; + } + + preUnflattenMiscReg(); + clear(); } @@ -73,27 +172,42 @@ ISA::clear() SCTLR sctlr_rst = miscRegs[MISCREG_SCTLR_RST]; memset(miscRegs, 0, sizeof(miscRegs)); + + // Initialize configurable default values + miscRegs[MISCREG_MIDR] = p->midr; + miscRegs[MISCREG_MIDR_EL1] = p->midr; + miscRegs[MISCREG_VPIDR] = p->midr; + + if (FullSystem && system->highestELIs64()) { + // Initialize AArch64 state + clear64(p); + return; + } + + // Initialize AArch32 state... + CPSR cpsr = 0; cpsr.mode = MODE_USER; miscRegs[MISCREG_CPSR] = cpsr; updateRegMap(cpsr); SCTLR sctlr = 0; - sctlr.te = (bool)sctlr_rst.te; - sctlr.nmfi = (bool)sctlr_rst.nmfi; - sctlr.v = (bool)sctlr_rst.v; - sctlr.u = 1; + sctlr.te = (bool) sctlr_rst.te; + sctlr.nmfi = (bool) sctlr_rst.nmfi; + sctlr.v = (bool) sctlr_rst.v; + sctlr.u = 1; sctlr.xp = 1; sctlr.rao2 = 1; sctlr.rao3 = 1; - sctlr.rao4 = 1; - miscRegs[MISCREG_SCTLR] = sctlr; + sctlr.rao4 = 0xf; // SCTLR[6:3] + miscRegs[MISCREG_SCTLR_NS] = sctlr; miscRegs[MISCREG_SCTLR_RST] = sctlr_rst; + miscRegs[MISCREG_HCPTR] = 0; - /* Start with an event in the mailbox */ + // Start with an event in the mailbox miscRegs[MISCREG_SEV_MAILBOX] = 1; - // Separate Instruction and Data TLBs. + // Separate Instruction and Data TLBs miscRegs[MISCREG_TLBTR] = 1; MVFR0 mvfr0 = 0; @@ -119,7 +233,8 @@ ISA::clear() // Reset values of PRRR and NMRR are implementation dependent - miscRegs[MISCREG_PRRR] = + // @todo: PRRR and NMRR in secure state? + miscRegs[MISCREG_PRRR_NS] = (1 << 19) | // 19 (0 << 18) | // 18 (0 << 17) | // 17 @@ -132,7 +247,7 @@ ISA::clear() (2 << 4) | // 5:4 (1 << 2) | // 3:2 0; // 1:0 - miscRegs[MISCREG_NMRR] = + miscRegs[MISCREG_NMRR_NS] = (1 << 30) | // 31:30 (0 << 26) | // 27:26 (0 << 24) | // 25:24 @@ -151,8 +266,6 @@ ISA::clear() miscRegs[MISCREG_CPACR] = 0; - // Initialize configurable default values - miscRegs[MISCREG_MIDR] = p->midr; miscRegs[MISCREG_ID_PFR0] = p->id_pfr0; miscRegs[MISCREG_ID_PFR1] = p->id_pfr1; @@ -169,27 +282,132 @@ ISA::clear() miscRegs[MISCREG_ID_ISAR4] = p->id_isar4; miscRegs[MISCREG_ID_ISAR5] = p->id_isar5; - miscRegs[MISCREG_FPSID] = p->fpsid; + if (haveLPAE) { + TTBCR ttbcr = miscRegs[MISCREG_TTBCR_NS]; + ttbcr.eae = 0; + miscRegs[MISCREG_TTBCR_NS] = ttbcr; + // Enforce consistency with system-level settings + miscRegs[MISCREG_ID_MMFR0] = (miscRegs[MISCREG_ID_MMFR0] & ~0xf) | 0x5; + } + + if (haveSecurity) { + miscRegs[MISCREG_SCTLR_S] = sctlr; + miscRegs[MISCREG_SCR] = 0; + miscRegs[MISCREG_VBAR_S] = 0; + } else { + // we're always non-secure + miscRegs[MISCREG_SCR] = 1; + } //XXX We need to initialize the rest of the state. } +void +ISA::clear64(const ArmISAParams *p) +{ + CPSR cpsr = 0; + Addr rvbar = system->resetAddr64(); + switch (system->highestEL()) { + // Set initial EL to highest implemented EL using associated stack + // pointer (SP_ELx); set RVBAR_ELx to implementation defined reset + // value + case EL3: + cpsr.mode = MODE_EL3H; + miscRegs[MISCREG_RVBAR_EL3] = rvbar; + break; + case EL2: + cpsr.mode = MODE_EL2H; + miscRegs[MISCREG_RVBAR_EL2] = rvbar; + break; + case EL1: + cpsr.mode = MODE_EL1H; + miscRegs[MISCREG_RVBAR_EL1] = rvbar; + break; + default: + panic("Invalid highest implemented exception level"); + break; + } + + // Initialize rest of CPSR + cpsr.daif = 0xf; // Mask all interrupts + cpsr.ss = 0; + cpsr.il = 0; + miscRegs[MISCREG_CPSR] = cpsr; + updateRegMap(cpsr); + + // Initialize other control registers + miscRegs[MISCREG_MPIDR_EL1] = 0x80000000; + if (haveSecurity) { + miscRegs[MISCREG_SCTLR_EL3] = 0x30c50870; + miscRegs[MISCREG_SCR_EL3] = 0x00000030; // RES1 fields + // @todo: uncomment this to enable Virtualization + // } else if (haveVirtualization) { + // miscRegs[MISCREG_SCTLR_EL2] = 0x30c50870; + } else { + miscRegs[MISCREG_SCTLR_EL1] = 0x30c50870; + // Always non-secure + miscRegs[MISCREG_SCR_EL3] = 1; + } + + // Initialize configurable id registers + miscRegs[MISCREG_ID_AA64AFR0_EL1] = p->id_aa64afr0_el1; + miscRegs[MISCREG_ID_AA64AFR1_EL1] = p->id_aa64afr1_el1; + miscRegs[MISCREG_ID_AA64DFR0_EL1] = p->id_aa64dfr0_el1; + miscRegs[MISCREG_ID_AA64DFR1_EL1] = p->id_aa64dfr1_el1; + miscRegs[MISCREG_ID_AA64ISAR0_EL1] = p->id_aa64isar0_el1; + miscRegs[MISCREG_ID_AA64ISAR1_EL1] = p->id_aa64isar1_el1; + miscRegs[MISCREG_ID_AA64MMFR0_EL1] = p->id_aa64mmfr0_el1; + miscRegs[MISCREG_ID_AA64MMFR1_EL1] = p->id_aa64mmfr1_el1; + miscRegs[MISCREG_ID_AA64PFR0_EL1] = p->id_aa64pfr0_el1; + miscRegs[MISCREG_ID_AA64PFR1_EL1] = p->id_aa64pfr1_el1; + + // Enforce consistency with system-level settings... + + // EL3 + // (no AArch32/64 interprocessing support for now) + miscRegs[MISCREG_ID_AA64PFR0_EL1] = insertBits( + miscRegs[MISCREG_ID_AA64PFR0_EL1], 15, 12, + haveSecurity ? 0x1 : 0x0); + // EL2 + // (no AArch32/64 interprocessing support for now) + miscRegs[MISCREG_ID_AA64PFR0_EL1] = insertBits( + miscRegs[MISCREG_ID_AA64PFR0_EL1], 11, 8, + haveVirtualization ? 0x1 : 0x0); + // Large ASID support + miscRegs[MISCREG_ID_AA64MMFR0_EL1] = insertBits( + miscRegs[MISCREG_ID_AA64MMFR0_EL1], 7, 4, + haveLargeAsid64 ? 0x2 : 0x0); + // Physical address size + miscRegs[MISCREG_ID_AA64MMFR0_EL1] = insertBits( + miscRegs[MISCREG_ID_AA64MMFR0_EL1], 3, 0, + encodePhysAddrRange64(physAddrRange64)); +} + MiscReg ISA::readMiscRegNoEffect(int misc_reg) const { assert(misc_reg < NumMiscRegs); - int flat_idx; - if (misc_reg == MISCREG_SPSR) - flat_idx = flattenMiscIndex(misc_reg); - else - flat_idx = misc_reg; - MiscReg val = miscRegs[flat_idx]; + int flat_idx = flattenMiscIndex(misc_reg); // Note: indexes of AArch64 + // registers are left unchanged + MiscReg val; + + if (lookUpMiscReg[flat_idx].lower == 0 || flat_idx == MISCREG_SPSR + || flat_idx == MISCREG_SCTLR_EL1) { + if (flat_idx == MISCREG_SPSR) + flat_idx = flattenMiscIndex(MISCREG_SPSR); + if (flat_idx == MISCREG_SCTLR_EL1) + flat_idx = flattenMiscIndex(MISCREG_SCTLR); + val = miscRegs[flat_idx]; + } else + if (lookUpMiscReg[flat_idx].upper > 0) + val = ((miscRegs[lookUpMiscReg[flat_idx].lower] & mask(32)) + | (miscRegs[lookUpMiscReg[flat_idx].upper] << 32)); + else + val = miscRegs[lookUpMiscReg[flat_idx].lower]; - DPRINTF(MiscRegs, "Reading From misc reg %d (%d) : %#x\n", - misc_reg, flat_idx, val); return val; } @@ -197,33 +415,98 @@ ISA::readMiscRegNoEffect(int misc_reg) const MiscReg ISA::readMiscReg(int misc_reg, ThreadContext *tc) { - ArmSystem *arm_sys; + CPSR cpsr = 0; + PCState pc = 0; + SCR scr = 0; if (misc_reg == MISCREG_CPSR) { - CPSR cpsr = miscRegs[misc_reg]; - PCState pc = tc->pcState(); + cpsr = miscRegs[misc_reg]; + pc = tc->pcState(); cpsr.j = pc.jazelle() ? 1 : 0; cpsr.t = pc.thumb() ? 1 : 0; return cpsr; } - if (misc_reg >= MISCREG_CP15_UNIMP_START) - panic("Unimplemented CP15 register %s read.\n", - miscRegName[misc_reg]); - switch (misc_reg) { - case MISCREG_MPIDR: - arm_sys = dynamic_cast<ArmSystem*>(tc->getSystemPtr()); - assert(arm_sys); +#ifndef NDEBUG + if (!miscRegInfo[misc_reg][MISCREG_IMPLEMENTED]) { + if (miscRegInfo[misc_reg][MISCREG_WARN_NOT_FAIL]) + warn("Unimplemented system register %s read.\n", + miscRegName[misc_reg]); + else + panic("Unimplemented system register %s read.\n", + miscRegName[misc_reg]); + } +#endif - if (arm_sys->multiProc) { - return 0x80000000 | // multiprocessor extensions available - tc->cpuId(); + switch (unflattenMiscReg(misc_reg)) { + case MISCREG_HCR: + { + if (!haveVirtualization) + return 0; + else + return readMiscRegNoEffect(MISCREG_HCR); + } + case MISCREG_CPACR: + { + const uint32_t ones = (uint32_t)(-1); + CPACR cpacrMask = 0; + // Only cp10, cp11, and ase are implemented, nothing else should + // be readable? (straight copy from the write code) + cpacrMask.cp10 = ones; + cpacrMask.cp11 = ones; + cpacrMask.asedis = ones; + + // Security Extensions may limit the readability of CPACR + if (haveSecurity) { + scr = readMiscRegNoEffect(MISCREG_SCR); + cpsr = readMiscRegNoEffect(MISCREG_CPSR); + if (scr.ns && (cpsr.mode != MODE_MON)) { + NSACR nsacr = readMiscRegNoEffect(MISCREG_NSACR); + // NB: Skipping the full loop, here + if (!nsacr.cp10) cpacrMask.cp10 = 0; + if (!nsacr.cp11) cpacrMask.cp11 = 0; + } + } + MiscReg val = readMiscRegNoEffect(MISCREG_CPACR); + val &= cpacrMask; + DPRINTF(MiscRegs, "Reading misc reg %s: %#x\n", + miscRegName[misc_reg], val); + return val; + } + case MISCREG_MPIDR: + cpsr = readMiscRegNoEffect(MISCREG_CPSR); + scr = readMiscRegNoEffect(MISCREG_SCR); + if ((cpsr.mode == MODE_HYP) || inSecureState(scr, cpsr)) { + return getMPIDR(system, tc); + } else { + return readMiscReg(MISCREG_VMPIDR, tc); + } + break; + case MISCREG_MPIDR_EL1: + // @todo in the absence of v8 virtualization support just return MPIDR_EL1 + return getMPIDR(system, tc) & 0xffffffff; + case MISCREG_VMPIDR: + // top bit defined as RES1 + return readMiscRegNoEffect(misc_reg) | 0x80000000; + case MISCREG_ID_AFR0: // not implemented, so alias MIDR + case MISCREG_ID_DFR0: // not implemented, so alias MIDR + case MISCREG_REVIDR: // not implemented, so alias MIDR + case MISCREG_MIDR: + cpsr = readMiscRegNoEffect(MISCREG_CPSR); + scr = readMiscRegNoEffect(MISCREG_SCR); + if ((cpsr.mode == MODE_HYP) || inSecureState(scr, cpsr)) { + return readMiscRegNoEffect(misc_reg); } else { - return 0x80000000 | // multiprocessor extensions available - 0x40000000 | // in up system - tc->cpuId(); + return readMiscRegNoEffect(MISCREG_VPIDR); } break; + case MISCREG_JOSCR: // Jazelle trivial implementation, RAZ/WI + case MISCREG_JMCR: // Jazelle trivial implementation, RAZ/WI + case MISCREG_JIDR: // Jazelle trivial implementation, RAZ/WI + case MISCREG_AIDR: // AUX ID set to 0 + case MISCREG_TCMTR: // No TCM's + return 0; + case MISCREG_CLIDR: warn_once("The clidr register always reports 0 caches.\n"); warn_once("clidr LoUIS field of 0b001 to match current " @@ -276,6 +559,75 @@ ISA::readMiscReg(int misc_reg, ThreadContext *tc) return readMiscRegNoEffect(MISCREG_FPSCR) & ~FpscrQcMask; case MISCREG_FPSCR_EXC: return readMiscRegNoEffect(MISCREG_FPSCR) & ~FpscrExcMask; + case MISCREG_FPSR: + { + const uint32_t ones = (uint32_t)(-1); + FPSCR fpscrMask = 0; + fpscrMask.ioc = ones; + fpscrMask.dzc = ones; + fpscrMask.ofc = ones; + fpscrMask.ufc = ones; + fpscrMask.ixc = ones; + fpscrMask.idc = ones; + fpscrMask.qc = ones; + fpscrMask.v = ones; + fpscrMask.c = ones; + fpscrMask.z = ones; + fpscrMask.n = ones; + return readMiscRegNoEffect(MISCREG_FPSCR) & (uint32_t)fpscrMask; + } + case MISCREG_FPCR: + { + const uint32_t ones = (uint32_t)(-1); + FPSCR fpscrMask = 0; + fpscrMask.ioe = ones; + fpscrMask.dze = ones; + fpscrMask.ofe = ones; + fpscrMask.ufe = ones; + fpscrMask.ixe = ones; + fpscrMask.ide = ones; + fpscrMask.len = ones; + fpscrMask.stride = ones; + fpscrMask.rMode = ones; + fpscrMask.fz = ones; + fpscrMask.dn = ones; + fpscrMask.ahp = ones; + return readMiscRegNoEffect(MISCREG_FPSCR) & (uint32_t)fpscrMask; + } + case MISCREG_NZCV: + { + CPSR cpsr = 0; + cpsr.nz = tc->readIntReg(INTREG_CONDCODES_NZ); + cpsr.c = tc->readIntReg(INTREG_CONDCODES_C); + cpsr.v = tc->readIntReg(INTREG_CONDCODES_V); + return cpsr; + } + case MISCREG_DAIF: + { + CPSR cpsr = 0; + cpsr.daif = (uint8_t) ((CPSR) miscRegs[MISCREG_CPSR]).daif; + return cpsr; + } + case MISCREG_SP_EL0: + { + return tc->readIntReg(INTREG_SP0); + } + case MISCREG_SP_EL1: + { + return tc->readIntReg(INTREG_SP1); + } + case MISCREG_SP_EL2: + { + return tc->readIntReg(INTREG_SP2); + } + case MISCREG_SPSEL: + { + return miscRegs[MISCREG_CPSR] & 0x1; + } + case MISCREG_CURRENTEL: + { + return miscRegs[MISCREG_CPSR] & 0xc; + } case MISCREG_L2CTLR: { // mostly unimplemented, just set NumCPUs field from sim and return @@ -289,8 +641,120 @@ ISA::readMiscReg(int misc_reg, ThreadContext *tc) * Return 0 as we don't support debug architecture yet. */ return 0; - case MISCREG_DBGDSCR_INT: + case MISCREG_DBGDSCRint: return 0; + case MISCREG_ISR: + return tc->getCpuPtr()->getInterruptController()->getISR( + readMiscRegNoEffect(MISCREG_HCR), + readMiscRegNoEffect(MISCREG_CPSR), + readMiscRegNoEffect(MISCREG_SCR)); + case MISCREG_ISR_EL1: + return tc->getCpuPtr()->getInterruptController()->getISR( + readMiscRegNoEffect(MISCREG_HCR_EL2), + readMiscRegNoEffect(MISCREG_CPSR), + readMiscRegNoEffect(MISCREG_SCR_EL3)); + case MISCREG_DCZID_EL0: + return 0x04; // DC ZVA clear 64-byte chunks + case MISCREG_HCPTR: + { + MiscReg val = readMiscRegNoEffect(misc_reg); + // The trap bit associated with CP14 is defined as RAZ + val &= ~(1 << 14); + // If a CP bit in NSACR is 0 then the corresponding bit in + // HCPTR is RAO/WI + bool secure_lookup = haveSecurity && + inSecureState(readMiscRegNoEffect(MISCREG_SCR), + readMiscRegNoEffect(MISCREG_CPSR)); + if (!secure_lookup) { + MiscReg mask = readMiscRegNoEffect(MISCREG_NSACR); + val |= (mask ^ 0x7FFF) & 0xBFFF; + } + // Set the bits for unimplemented coprocessors to RAO/WI + val |= 0x33FF; + return (val); + } + case MISCREG_HDFAR: // alias for secure DFAR + return readMiscRegNoEffect(MISCREG_DFAR_S); + case MISCREG_HIFAR: // alias for secure IFAR + return readMiscRegNoEffect(MISCREG_IFAR_S); + case MISCREG_HVBAR: // bottom bits reserved + return readMiscRegNoEffect(MISCREG_HVBAR) & 0xFFFFFFE0; + case MISCREG_SCTLR: // Some bits hardwired + // The FI field (bit 21) is common between S/NS versions of the register + return (readMiscRegNoEffect(MISCREG_SCTLR_S) & (1 << 21)) | + (readMiscRegNoEffect(misc_reg) & 0x72DD39FF) | 0x00C00818; // V8 SCTLR + case MISCREG_SCTLR_EL1: + // The FI field (bit 21) is common between S/NS versions of the register + return (readMiscRegNoEffect(MISCREG_SCTLR_S) & (1 << 21)) | + (readMiscRegNoEffect(misc_reg) & 0x37DDDBFF) | 0x30D00800; // V8 SCTLR_EL1 + case MISCREG_SCTLR_EL3: + // The FI field (bit 21) is common between S/NS versions of the register + return (readMiscRegNoEffect(MISCREG_SCTLR_S) & (1 << 21)) | + (readMiscRegNoEffect(misc_reg) & 0x32CD183F) | 0x30C50830; // V8 SCTLR_EL3 + case MISCREG_HSCTLR: // FI comes from SCTLR + { + uint32_t mask = 1 << 27; + return (readMiscRegNoEffect(MISCREG_HSCTLR) & ~mask) | + (readMiscRegNoEffect(MISCREG_SCTLR) & mask); + } + case MISCREG_SCR: + { + CPSR cpsr = readMiscRegNoEffect(MISCREG_CPSR); + if (cpsr.width) { + return readMiscRegNoEffect(MISCREG_SCR); + } else { + return readMiscRegNoEffect(MISCREG_SCR_EL3); + } + } + // Generic Timer registers + case MISCREG_CNTFRQ: + case MISCREG_CNTFRQ_EL0: + inform_once("Read CNTFREQ_EL0 frequency\n"); + return getSystemCounter(tc)->freq(); + case MISCREG_CNTPCT: + case MISCREG_CNTPCT_EL0: + return getSystemCounter(tc)->value(); + case MISCREG_CNTVCT: + return getSystemCounter(tc)->value(); + case MISCREG_CNTVCT_EL0: + return getSystemCounter(tc)->value(); + case MISCREG_CNTP_CVAL: + case MISCREG_CNTP_CVAL_EL0: + return getArchTimer(tc, tc->cpuId())->compareValue(); + case MISCREG_CNTP_TVAL: + case MISCREG_CNTP_TVAL_EL0: + return getArchTimer(tc, tc->cpuId())->timerValue(); + case MISCREG_CNTP_CTL: + case MISCREG_CNTP_CTL_EL0: + return getArchTimer(tc, tc->cpuId())->control(); + // PL1 phys. timer, secure + // AArch64 + case MISCREG_CNTPS_CVAL_EL1: + case MISCREG_CNTPS_TVAL_EL1: + case MISCREG_CNTPS_CTL_EL1: + // PL2 phys. timer, non-secure + // AArch32 + case MISCREG_CNTHCTL: + case MISCREG_CNTHP_CVAL: + case MISCREG_CNTHP_TVAL: + case MISCREG_CNTHP_CTL: + // AArch64 + case MISCREG_CNTHCTL_EL2: + case MISCREG_CNTHP_CVAL_EL2: + case MISCREG_CNTHP_TVAL_EL2: + case MISCREG_CNTHP_CTL_EL2: + // Virtual timer + // AArch32 + case MISCREG_CNTV_CVAL: + case MISCREG_CNTV_TVAL: + case MISCREG_CNTV_CTL: + // AArch64 + // case MISCREG_CNTV_CVAL_EL2: + // case MISCREG_CNTV_TVAL_EL2: + // case MISCREG_CNTV_CTL_EL2: + panic("Generic Timer register not implemented\n"); + break; + } return readMiscRegNoEffect(misc_reg); } @@ -300,15 +764,28 @@ ISA::setMiscRegNoEffect(int misc_reg, const MiscReg &val) { assert(misc_reg < NumMiscRegs); - int flat_idx; - if (misc_reg == MISCREG_SPSR) - flat_idx = flattenMiscIndex(misc_reg); - else - flat_idx = misc_reg; - miscRegs[flat_idx] = val; + int flat_idx = flattenMiscIndex(misc_reg); // Note: indexes of AArch64 + // registers are left unchanged + + int flat_idx2 = lookUpMiscReg[flat_idx].upper; - DPRINTF(MiscRegs, "Writing to misc reg %d (%d) : %#x\n", misc_reg, - flat_idx, val); + if (flat_idx2 > 0) { + miscRegs[lookUpMiscReg[flat_idx].lower] = bits(val, 31, 0); + miscRegs[flat_idx2] = bits(val, 63, 32); + DPRINTF(MiscRegs, "Writing to misc reg %d (%d:%d) : %#x\n", + misc_reg, flat_idx, flat_idx2, val); + } else { + if (flat_idx == MISCREG_SPSR) + flat_idx = flattenMiscIndex(MISCREG_SPSR); + else if (flat_idx == MISCREG_SCTLR_EL1) + flat_idx = flattenMiscIndex(MISCREG_SCTLR); + else + flat_idx = (lookUpMiscReg[flat_idx].lower > 0) ? + lookUpMiscReg[flat_idx].lower : flat_idx; + miscRegs[flat_idx] = val; + DPRINTF(MiscRegs, "Writing to misc reg %d (%d) : %#x\n", + misc_reg, flat_idx, val); + } } void @@ -317,8 +794,13 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc) MiscReg newVal = val; int x; + bool secure_lookup; + bool hyp; System *sys; ThreadContext *oc; + uint8_t target_el; + uint16_t asid; + SCR scr; if (misc_reg == MISCREG_CPSR) { updateRegMap(val); @@ -346,12 +828,18 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc) } else { tc->pcState(pc); } - } else if (misc_reg >= MISCREG_CP15_UNIMP_START && - misc_reg < MISCREG_CP15_END) { - panic("Unimplemented CP15 register %s wrote with %#x.\n", - miscRegName[misc_reg], val); } else { - switch (misc_reg) { +#ifndef NDEBUG + if (!miscRegInfo[misc_reg][MISCREG_IMPLEMENTED]) { + if (miscRegInfo[misc_reg][MISCREG_WARN_NOT_FAIL]) + warn("Unimplemented system register %s write with %#x.\n", + miscRegName[misc_reg], val); + else + panic("Unimplemented system register %s write with %#x.\n", + miscRegName[misc_reg], val); + } +#endif + switch (unflattenMiscReg(misc_reg)) { case MISCREG_CPACR: { @@ -362,7 +850,61 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc) cpacrMask.cp10 = ones; cpacrMask.cp11 = ones; cpacrMask.asedis = ones; + + // Security Extensions may limit the writability of CPACR + if (haveSecurity) { + scr = readMiscRegNoEffect(MISCREG_SCR); + CPSR cpsr = readMiscRegNoEffect(MISCREG_CPSR); + if (scr.ns && (cpsr.mode != MODE_MON)) { + NSACR nsacr = readMiscRegNoEffect(MISCREG_NSACR); + // NB: Skipping the full loop, here + if (!nsacr.cp10) cpacrMask.cp10 = 0; + if (!nsacr.cp11) cpacrMask.cp11 = 0; + } + } + + MiscReg old_val = readMiscRegNoEffect(MISCREG_CPACR); newVal &= cpacrMask; + newVal |= old_val & ~cpacrMask; + DPRINTF(MiscRegs, "Writing misc reg %s: %#x\n", + miscRegName[misc_reg], newVal); + } + break; + case MISCREG_CPACR_EL1: + { + const uint32_t ones = (uint32_t)(-1); + CPACR cpacrMask = 0; + cpacrMask.tta = ones; + cpacrMask.fpen = ones; + newVal &= cpacrMask; + DPRINTF(MiscRegs, "Writing misc reg %s: %#x\n", + miscRegName[misc_reg], newVal); + } + break; + case MISCREG_CPTR_EL2: + { + const uint32_t ones = (uint32_t)(-1); + CPTR cptrMask = 0; + cptrMask.tcpac = ones; + cptrMask.tta = ones; + cptrMask.tfp = ones; + newVal &= cptrMask; + cptrMask = 0; + cptrMask.res1_13_12_el2 = ones; + cptrMask.res1_9_0_el2 = ones; + newVal |= cptrMask; + DPRINTF(MiscRegs, "Writing misc reg %s: %#x\n", + miscRegName[misc_reg], newVal); + } + break; + case MISCREG_CPTR_EL3: + { + const uint32_t ones = (uint32_t)(-1); + CPTR cptrMask = 0; + cptrMask.tcpac = ones; + cptrMask.tta = ones; + cptrMask.tfp = ones; + newVal &= cptrMask; DPRINTF(MiscRegs, "Writing misc reg %s: %#x\n", miscRegName[misc_reg], newVal); } @@ -370,6 +912,11 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc) case MISCREG_CSSELR: warn_once("The csselr register isn't implemented.\n"); return; + + case MISCREG_DC_ZVA_Xt: + warn("Calling DC ZVA! Not Implemeted! Expect WEIRD results\n"); + return; + case MISCREG_FPSCR: { const uint32_t ones = (uint32_t)(-1); @@ -380,6 +927,12 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc) fpscrMask.ufc = ones; fpscrMask.ixc = ones; fpscrMask.idc = ones; + fpscrMask.ioe = ones; + fpscrMask.dze = ones; + fpscrMask.ofe = ones; + fpscrMask.ufe = ones; + fpscrMask.ixe = ones; + fpscrMask.ide = ones; fpscrMask.len = ones; fpscrMask.stride = ones; fpscrMask.rMode = ones; @@ -392,26 +945,72 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc) fpscrMask.z = ones; fpscrMask.n = ones; newVal = (newVal & (uint32_t)fpscrMask) | - (miscRegs[MISCREG_FPSCR] & ~(uint32_t)fpscrMask); + (readMiscRegNoEffect(MISCREG_FPSCR) & + ~(uint32_t)fpscrMask); tc->getDecoderPtr()->setContext(newVal); } break; + case MISCREG_FPSR: + { + const uint32_t ones = (uint32_t)(-1); + FPSCR fpscrMask = 0; + fpscrMask.ioc = ones; + fpscrMask.dzc = ones; + fpscrMask.ofc = ones; + fpscrMask.ufc = ones; + fpscrMask.ixc = ones; + fpscrMask.idc = ones; + fpscrMask.qc = ones; + fpscrMask.v = ones; + fpscrMask.c = ones; + fpscrMask.z = ones; + fpscrMask.n = ones; + newVal = (newVal & (uint32_t)fpscrMask) | + (readMiscRegNoEffect(MISCREG_FPSCR) & + ~(uint32_t)fpscrMask); + misc_reg = MISCREG_FPSCR; + } + break; + case MISCREG_FPCR: + { + const uint32_t ones = (uint32_t)(-1); + FPSCR fpscrMask = 0; + fpscrMask.ioe = ones; + fpscrMask.dze = ones; + fpscrMask.ofe = ones; + fpscrMask.ufe = ones; + fpscrMask.ixe = ones; + fpscrMask.ide = ones; + fpscrMask.len = ones; + fpscrMask.stride = ones; + fpscrMask.rMode = ones; + fpscrMask.fz = ones; + fpscrMask.dn = ones; + fpscrMask.ahp = ones; + newVal = (newVal & (uint32_t)fpscrMask) | + (readMiscRegNoEffect(MISCREG_FPSCR) & + ~(uint32_t)fpscrMask); + misc_reg = MISCREG_FPSCR; + } + break; case MISCREG_CPSR_Q: { assert(!(newVal & ~CpsrMaskQ)); - newVal = miscRegs[MISCREG_CPSR] | newVal; + newVal = readMiscRegNoEffect(MISCREG_CPSR) | newVal; misc_reg = MISCREG_CPSR; } break; case MISCREG_FPSCR_QC: { - newVal = miscRegs[MISCREG_FPSCR] | (newVal & FpscrQcMask); + newVal = readMiscRegNoEffect(MISCREG_FPSCR) | + (newVal & FpscrQcMask); misc_reg = MISCREG_FPSCR; } break; case MISCREG_FPSCR_EXC: { - newVal = miscRegs[MISCREG_FPSCR] | (newVal & FpscrExcMask); + newVal = readMiscRegNoEffect(MISCREG_FPSCR) | + (newVal & FpscrExcMask); misc_reg = MISCREG_FPSCR; } break; @@ -421,16 +1020,63 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc) // bit 29 - valid only if fpexc[31] is 0 const uint32_t fpexcMask = 0x60000000; newVal = (newVal & fpexcMask) | - (miscRegs[MISCREG_FPEXC] & ~fpexcMask); + (readMiscRegNoEffect(MISCREG_FPEXC) & ~fpexcMask); + } + break; + case MISCREG_HCR: + { + if (!haveVirtualization) + return; + } + break; + case MISCREG_IFSR: + { + // ARM ARM (ARM DDI 0406C.b) B4.1.96 + const uint32_t ifsrMask = + mask(31, 13) | mask(11, 11) | mask(8, 6); + newVal = newVal & ~ifsrMask; + } + break; + case MISCREG_DFSR: + { + // ARM ARM (ARM DDI 0406C.b) B4.1.52 + const uint32_t dfsrMask = mask(31, 14) | mask(8, 8); + newVal = newVal & ~dfsrMask; + } + break; + case MISCREG_AMAIR0: + case MISCREG_AMAIR1: + { + // ARM ARM (ARM DDI 0406C.b) B4.1.5 + // Valid only with LPAE + if (!haveLPAE) + return; + DPRINTF(MiscRegs, "Writing AMAIR: %#x\n", newVal); } break; + case MISCREG_SCR: + tc->getITBPtr()->invalidateMiscReg(); + tc->getDTBPtr()->invalidateMiscReg(); + break; case MISCREG_SCTLR: { DPRINTF(MiscRegs, "Writing SCTLR: %#x\n", newVal); - SCTLR sctlr = miscRegs[MISCREG_SCTLR]; + MiscRegIndex sctlr_idx; + scr = readMiscRegNoEffect(MISCREG_SCR); + if (haveSecurity && !scr.ns) { + sctlr_idx = MISCREG_SCTLR_S; + } else { + sctlr_idx = MISCREG_SCTLR_NS; + // The FI field (bit 21) is common between S/NS versions + // of the register, we store this in the secure copy of + // the reg + miscRegs[MISCREG_SCTLR_S] &= ~(1 << 21); + miscRegs[MISCREG_SCTLR_S] |= newVal & (1 << 21); + } + SCTLR sctlr = miscRegs[sctlr_idx]; SCTLR new_sctlr = newVal; - new_sctlr.nmfi = (bool)sctlr.nmfi; - miscRegs[MISCREG_SCTLR] = (MiscReg)new_sctlr; + new_sctlr.nmfi = ((bool)sctlr.nmfi) && !haveVirtualization; + miscRegs[sctlr_idx] = (MiscReg)new_sctlr; tc->getITBPtr()->invalidateMiscReg(); tc->getDTBPtr()->invalidateMiscReg(); @@ -440,6 +1086,7 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc) sys = tc->getSystemPtr(); for (x = 0; x < sys->numContexts(); x++) { oc = sys->getThreadContext(x); + // @todo: double check this for security SCTLR other_sctlr = oc->readMiscRegNoEffect(MISCREG_SCTLR); if (!other_sctlr.c && oc->status() != ThreadContext::Halted) return; @@ -479,96 +1126,317 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc) case MISCREG_TLBTR: case MISCREG_MVFR0: case MISCREG_MVFR1: + + case MISCREG_ID_AA64AFR0_EL1: + case MISCREG_ID_AA64AFR1_EL1: + case MISCREG_ID_AA64DFR0_EL1: + case MISCREG_ID_AA64DFR1_EL1: + case MISCREG_ID_AA64ISAR0_EL1: + case MISCREG_ID_AA64ISAR1_EL1: + case MISCREG_ID_AA64MMFR0_EL1: + case MISCREG_ID_AA64MMFR1_EL1: + case MISCREG_ID_AA64PFR0_EL1: + case MISCREG_ID_AA64PFR1_EL1: // ID registers are constants. return; + // TLBI all entries, EL0&1 inner sharable (ignored) case MISCREG_TLBIALLIS: - case MISCREG_TLBIALL: + case MISCREG_TLBIALL: // TLBI all entries, EL0&1, + assert32(tc); + target_el = 1; // el 0 and 1 are handled together + scr = readMiscReg(MISCREG_SCR, tc); + secure_lookup = haveSecurity && !scr.ns; sys = tc->getSystemPtr(); for (x = 0; x < sys->numContexts(); x++) { oc = sys->getThreadContext(x); assert(oc->getITBPtr() && oc->getDTBPtr()); - oc->getITBPtr()->flushAll(); - oc->getDTBPtr()->flushAll(); + oc->getITBPtr()->flushAllSecurity(secure_lookup, target_el); + oc->getDTBPtr()->flushAllSecurity(secure_lookup, target_el); // If CheckerCPU is connected, need to notify it of a flush CheckerCPU *checker = oc->getCheckerCpuPtr(); if (checker) { - checker->getITBPtr()->flushAll(); - checker->getDTBPtr()->flushAll(); + checker->getITBPtr()->flushAllSecurity(secure_lookup, + target_el); + checker->getDTBPtr()->flushAllSecurity(secure_lookup, + target_el); } } return; + // TLBI all entries, EL0&1, instruction side case MISCREG_ITLBIALL: - tc->getITBPtr()->flushAll(); + assert32(tc); + target_el = 1; // el 0 and 1 are handled together + scr = readMiscReg(MISCREG_SCR, tc); + secure_lookup = haveSecurity && !scr.ns; + tc->getITBPtr()->flushAllSecurity(secure_lookup, target_el); return; + // TLBI all entries, EL0&1, data side case MISCREG_DTLBIALL: - tc->getDTBPtr()->flushAll(); + assert32(tc); + target_el = 1; // el 0 and 1 are handled together + scr = readMiscReg(MISCREG_SCR, tc); + secure_lookup = haveSecurity && !scr.ns; + tc->getDTBPtr()->flushAllSecurity(secure_lookup, target_el); return; + // TLBI based on VA, EL0&1 inner sharable (ignored) case MISCREG_TLBIMVAIS: case MISCREG_TLBIMVA: + assert32(tc); + target_el = 1; // el 0 and 1 are handled together + scr = readMiscReg(MISCREG_SCR, tc); + secure_lookup = haveSecurity && !scr.ns; sys = tc->getSystemPtr(); for (x = 0; x < sys->numContexts(); x++) { oc = sys->getThreadContext(x); assert(oc->getITBPtr() && oc->getDTBPtr()); oc->getITBPtr()->flushMvaAsid(mbits(newVal, 31, 12), - bits(newVal, 7,0)); + bits(newVal, 7,0), + secure_lookup, target_el); oc->getDTBPtr()->flushMvaAsid(mbits(newVal, 31, 12), - bits(newVal, 7,0)); + bits(newVal, 7,0), + secure_lookup, target_el); CheckerCPU *checker = oc->getCheckerCpuPtr(); if (checker) { checker->getITBPtr()->flushMvaAsid(mbits(newVal, 31, 12), - bits(newVal, 7,0)); + bits(newVal, 7,0), secure_lookup, target_el); checker->getDTBPtr()->flushMvaAsid(mbits(newVal, 31, 12), - bits(newVal, 7,0)); + bits(newVal, 7,0), secure_lookup, target_el); } } return; + // TLBI by ASID, EL0&1, inner sharable case MISCREG_TLBIASIDIS: case MISCREG_TLBIASID: + assert32(tc); + target_el = 1; // el 0 and 1 are handled together + scr = readMiscReg(MISCREG_SCR, tc); + secure_lookup = haveSecurity && !scr.ns; sys = tc->getSystemPtr(); for (x = 0; x < sys->numContexts(); x++) { oc = sys->getThreadContext(x); assert(oc->getITBPtr() && oc->getDTBPtr()); - oc->getITBPtr()->flushAsid(bits(newVal, 7,0)); - oc->getDTBPtr()->flushAsid(bits(newVal, 7,0)); + oc->getITBPtr()->flushAsid(bits(newVal, 7,0), + secure_lookup, target_el); + oc->getDTBPtr()->flushAsid(bits(newVal, 7,0), + secure_lookup, target_el); CheckerCPU *checker = oc->getCheckerCpuPtr(); if (checker) { - checker->getITBPtr()->flushAsid(bits(newVal, 7,0)); - checker->getDTBPtr()->flushAsid(bits(newVal, 7,0)); + checker->getITBPtr()->flushAsid(bits(newVal, 7,0), + secure_lookup, target_el); + checker->getDTBPtr()->flushAsid(bits(newVal, 7,0), + secure_lookup, target_el); } } return; + // TLBI by address, EL0&1, inner sharable (ignored) case MISCREG_TLBIMVAAIS: case MISCREG_TLBIMVAA: - sys = tc->getSystemPtr(); - for (x = 0; x < sys->numContexts(); x++) { - oc = sys->getThreadContext(x); - assert(oc->getITBPtr() && oc->getDTBPtr()); - oc->getITBPtr()->flushMva(mbits(newVal, 31,12)); - oc->getDTBPtr()->flushMva(mbits(newVal, 31,12)); - - CheckerCPU *checker = oc->getCheckerCpuPtr(); - if (checker) { - checker->getITBPtr()->flushMva(mbits(newVal, 31,12)); - checker->getDTBPtr()->flushMva(mbits(newVal, 31,12)); - } - } + assert32(tc); + target_el = 1; // el 0 and 1 are handled together + scr = readMiscReg(MISCREG_SCR, tc); + secure_lookup = haveSecurity && !scr.ns; + hyp = 0; + tlbiMVA(tc, newVal, secure_lookup, hyp, target_el); + return; + // TLBI by address, EL2, hypervisor mode + case MISCREG_TLBIMVAH: + case MISCREG_TLBIMVAHIS: + assert32(tc); + target_el = 1; // aarch32, use hyp bit + scr = readMiscReg(MISCREG_SCR, tc); + secure_lookup = haveSecurity && !scr.ns; + hyp = 1; + tlbiMVA(tc, newVal, secure_lookup, hyp, target_el); return; + // TLBI by address and asid, EL0&1, instruction side only case MISCREG_ITLBIMVA: + assert32(tc); + target_el = 1; // el 0 and 1 are handled together + scr = readMiscReg(MISCREG_SCR, tc); + secure_lookup = haveSecurity && !scr.ns; tc->getITBPtr()->flushMvaAsid(mbits(newVal, 31, 12), - bits(newVal, 7,0)); + bits(newVal, 7,0), secure_lookup, target_el); return; + // TLBI by address and asid, EL0&1, data side only case MISCREG_DTLBIMVA: + assert32(tc); + target_el = 1; // el 0 and 1 are handled together + scr = readMiscReg(MISCREG_SCR, tc); + secure_lookup = haveSecurity && !scr.ns; tc->getDTBPtr()->flushMvaAsid(mbits(newVal, 31, 12), - bits(newVal, 7,0)); + bits(newVal, 7,0), secure_lookup, target_el); return; + // TLBI by ASID, EL0&1, instrution side only case MISCREG_ITLBIASID: - tc->getITBPtr()->flushAsid(bits(newVal, 7,0)); + assert32(tc); + target_el = 1; // el 0 and 1 are handled together + scr = readMiscReg(MISCREG_SCR, tc); + secure_lookup = haveSecurity && !scr.ns; + tc->getITBPtr()->flushAsid(bits(newVal, 7,0), secure_lookup, + target_el); return; + // TLBI by ASID EL0&1 data size only case MISCREG_DTLBIASID: - tc->getDTBPtr()->flushAsid(bits(newVal, 7,0)); + assert32(tc); + target_el = 1; // el 0 and 1 are handled together + scr = readMiscReg(MISCREG_SCR, tc); + secure_lookup = haveSecurity && !scr.ns; + tc->getDTBPtr()->flushAsid(bits(newVal, 7,0), secure_lookup, + target_el); + return; + // Invalidate entire Non-secure Hyp/Non-Hyp Unified TLB + case MISCREG_TLBIALLNSNH: + case MISCREG_TLBIALLNSNHIS: + assert32(tc); + target_el = 1; // el 0 and 1 are handled together + hyp = 0; + tlbiALLN(tc, hyp, target_el); + return; + // TLBI all entries, EL2, hyp, + case MISCREG_TLBIALLH: + case MISCREG_TLBIALLHIS: + assert32(tc); + target_el = 1; // aarch32, use hyp bit + hyp = 1; + tlbiALLN(tc, hyp, target_el); + return; + // AArch64 TLBI: invalidate all entries EL3 + case MISCREG_TLBI_ALLE3IS: + case MISCREG_TLBI_ALLE3: + assert64(tc); + target_el = 3; + secure_lookup = true; + tlbiALL(tc, secure_lookup, target_el); + return; + // @todo: uncomment this to enable Virtualization + // case MISCREG_TLBI_ALLE2IS: + // case MISCREG_TLBI_ALLE2: + // TLBI all entries, EL0&1 + case MISCREG_TLBI_ALLE1IS: + case MISCREG_TLBI_ALLE1: + // AArch64 TLBI: invalidate all entries, stage 1, current VMID + case MISCREG_TLBI_VMALLE1IS: + case MISCREG_TLBI_VMALLE1: + // AArch64 TLBI: invalidate all entries, stages 1 & 2, current VMID + case MISCREG_TLBI_VMALLS12E1IS: + case MISCREG_TLBI_VMALLS12E1: + // @todo: handle VMID and stage 2 to enable Virtualization + assert64(tc); + target_el = 1; // el 0 and 1 are handled together + scr = readMiscReg(MISCREG_SCR, tc); + secure_lookup = haveSecurity && !scr.ns; + tlbiALL(tc, secure_lookup, target_el); + return; + // AArch64 TLBI: invalidate by VA and ASID, stage 1, current VMID + // VAEx(IS) and VALEx(IS) are the same because TLBs only store entries + // from the last level of translation table walks + // @todo: handle VMID to enable Virtualization + // TLBI all entries, EL0&1 + case MISCREG_TLBI_VAE3IS_Xt: + case MISCREG_TLBI_VAE3_Xt: + // TLBI by VA, EL3 regime stage 1, last level walk + case MISCREG_TLBI_VALE3IS_Xt: + case MISCREG_TLBI_VALE3_Xt: + assert64(tc); + target_el = 3; + asid = 0xbeef; // does not matter, tlbi is global + secure_lookup = true; + tlbiVA(tc, newVal, asid, secure_lookup, target_el); + return; + // TLBI by VA, EL2 + case MISCREG_TLBI_VAE2IS_Xt: + case MISCREG_TLBI_VAE2_Xt: + // TLBI by VA, EL2, stage1 last level walk + case MISCREG_TLBI_VALE2IS_Xt: + case MISCREG_TLBI_VALE2_Xt: + assert64(tc); + target_el = 2; + asid = 0xbeef; // does not matter, tlbi is global + scr = readMiscReg(MISCREG_SCR, tc); + secure_lookup = haveSecurity && !scr.ns; + tlbiVA(tc, newVal, asid, secure_lookup, target_el); + return; + // TLBI by VA EL1 & 0, stage1, ASID, current VMID + case MISCREG_TLBI_VAE1IS_Xt: + case MISCREG_TLBI_VAE1_Xt: + case MISCREG_TLBI_VALE1IS_Xt: + case MISCREG_TLBI_VALE1_Xt: + assert64(tc); + asid = bits(newVal, 63, 48); + target_el = 1; // el 0 and 1 are handled together + scr = readMiscReg(MISCREG_SCR, tc); + secure_lookup = haveSecurity && !scr.ns; + tlbiVA(tc, newVal, asid, secure_lookup, target_el); + return; + // AArch64 TLBI: invalidate by ASID, stage 1, current VMID + // @todo: handle VMID to enable Virtualization + case MISCREG_TLBI_ASIDE1IS_Xt: + case MISCREG_TLBI_ASIDE1_Xt: + assert64(tc); + target_el = 1; // el 0 and 1 are handled together + scr = readMiscReg(MISCREG_SCR, tc); + secure_lookup = haveSecurity && !scr.ns; + sys = tc->getSystemPtr(); + for (x = 0; x < sys->numContexts(); x++) { + oc = sys->getThreadContext(x); + assert(oc->getITBPtr() && oc->getDTBPtr()); + asid = bits(newVal, 63, 48); + if (haveLargeAsid64) + asid &= mask(8); + oc->getITBPtr()->flushAsid(asid, secure_lookup, target_el); + oc->getDTBPtr()->flushAsid(asid, secure_lookup, target_el); + CheckerCPU *checker = oc->getCheckerCpuPtr(); + if (checker) { + checker->getITBPtr()->flushAsid(asid, + secure_lookup, target_el); + checker->getDTBPtr()->flushAsid(asid, + secure_lookup, target_el); + } + } + return; + // AArch64 TLBI: invalidate by VA, ASID, stage 1, current VMID + // VAAE1(IS) and VAALE1(IS) are the same because TLBs only store + // entries from the last level of translation table walks + // @todo: handle VMID to enable Virtualization + case MISCREG_TLBI_VAAE1IS_Xt: + case MISCREG_TLBI_VAAE1_Xt: + case MISCREG_TLBI_VAALE1IS_Xt: + case MISCREG_TLBI_VAALE1_Xt: + assert64(tc); + target_el = 1; // el 0 and 1 are handled together + scr = readMiscReg(MISCREG_SCR, tc); + secure_lookup = haveSecurity && !scr.ns; + sys = tc->getSystemPtr(); + for (x = 0; x < sys->numContexts(); x++) { + // @todo: extra controls on TLBI broadcast? + oc = sys->getThreadContext(x); + assert(oc->getITBPtr() && oc->getDTBPtr()); + Addr va = ((Addr) bits(newVal, 43, 0)) << 12; + oc->getITBPtr()->flushMva(va, + secure_lookup, false, target_el); + oc->getDTBPtr()->flushMva(va, + secure_lookup, false, target_el); + + CheckerCPU *checker = oc->getCheckerCpuPtr(); + if (checker) { + checker->getITBPtr()->flushMva(va, + secure_lookup, false, target_el); + checker->getDTBPtr()->flushMva(va, + secure_lookup, false, target_el); + } + } + return; + // AArch64 TLBI: invalidate by IPA, stage 2, current VMID + case MISCREG_TLBI_IPAS2LE1IS_Xt: + case MISCREG_TLBI_IPAS2LE1_Xt: + case MISCREG_TLBI_IPAS2E1IS_Xt: + case MISCREG_TLBI_IPAS2E1_Xt: + assert64(tc); + // @todo: implement these as part of Virtualization + warn("Not doing anything for write of miscreg ITLB_IPAS2\n"); return; case MISCREG_ACTLR: warn("Not doing anything for write of miscreg ACTLR\n"); @@ -591,77 +1459,566 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc) warn("Not doing anything for write to miscreg %s\n", miscRegName[misc_reg]); break; - case MISCREG_V2PCWPR: - case MISCREG_V2PCWPW: - case MISCREG_V2PCWUR: - case MISCREG_V2PCWUW: - case MISCREG_V2POWPR: - case MISCREG_V2POWPW: - case MISCREG_V2POWUR: - case MISCREG_V2POWUW: + case MISCREG_HSTR: // TJDBX, now redifined to be RES0 + { + HSTR hstrMask = 0; + hstrMask.tjdbx = 1; + newVal &= ~((uint32_t) hstrMask); + break; + } + case MISCREG_HCPTR: + { + // If a CP bit in NSACR is 0 then the corresponding bit in + // HCPTR is RAO/WI. Same applies to NSASEDIS + secure_lookup = haveSecurity && + inSecureState(readMiscRegNoEffect(MISCREG_SCR), + readMiscRegNoEffect(MISCREG_CPSR)); + if (!secure_lookup) { + MiscReg oldValue = readMiscRegNoEffect(MISCREG_HCPTR); + MiscReg mask = (readMiscRegNoEffect(MISCREG_NSACR) ^ 0x7FFF) & 0xBFFF; + newVal = (newVal & ~mask) | (oldValue & mask); + } + break; + } + case MISCREG_HDFAR: // alias for secure DFAR + misc_reg = MISCREG_DFAR_S; + break; + case MISCREG_HIFAR: // alias for secure IFAR + misc_reg = MISCREG_IFAR_S; + break; + case MISCREG_ATS1CPR: + case MISCREG_ATS1CPW: + case MISCREG_ATS1CUR: + case MISCREG_ATS1CUW: + case MISCREG_ATS12NSOPR: + case MISCREG_ATS12NSOPW: + case MISCREG_ATS12NSOUR: + case MISCREG_ATS12NSOUW: + case MISCREG_ATS1HR: + case MISCREG_ATS1HW: { RequestPtr req = new Request; - unsigned flags; - BaseTLB::Mode mode; + unsigned flags = 0; + BaseTLB::Mode mode = BaseTLB::Read; + TLB::ArmTranslationType tranType = TLB::NormalTran; Fault fault; switch(misc_reg) { - case MISCREG_V2PCWPR: - flags = TLB::MustBeOne; - mode = BaseTLB::Read; - break; - case MISCREG_V2PCWPW: - flags = TLB::MustBeOne; - mode = BaseTLB::Write; - break; - case MISCREG_V2PCWUR: - flags = TLB::MustBeOne | TLB::UserMode; - mode = BaseTLB::Read; - break; - case MISCREG_V2PCWUW: - flags = TLB::MustBeOne | TLB::UserMode; - mode = BaseTLB::Write; - break; - default: - panic("Security Extensions not implemented!"); + case MISCREG_ATS1CPR: + flags = TLB::MustBeOne; + tranType = TLB::S1CTran; + mode = BaseTLB::Read; + break; + case MISCREG_ATS1CPW: + flags = TLB::MustBeOne; + tranType = TLB::S1CTran; + mode = BaseTLB::Write; + break; + case MISCREG_ATS1CUR: + flags = TLB::MustBeOne | TLB::UserMode; + tranType = TLB::S1CTran; + mode = BaseTLB::Read; + break; + case MISCREG_ATS1CUW: + flags = TLB::MustBeOne | TLB::UserMode; + tranType = TLB::S1CTran; + mode = BaseTLB::Write; + break; + case MISCREG_ATS12NSOPR: + if (!haveSecurity) + panic("Security Extensions required for ATS12NSOPR"); + flags = TLB::MustBeOne; + tranType = TLB::S1S2NsTran; + mode = BaseTLB::Read; + break; + case MISCREG_ATS12NSOPW: + if (!haveSecurity) + panic("Security Extensions required for ATS12NSOPW"); + flags = TLB::MustBeOne; + tranType = TLB::S1S2NsTran; + mode = BaseTLB::Write; + break; + case MISCREG_ATS12NSOUR: + if (!haveSecurity) + panic("Security Extensions required for ATS12NSOUR"); + flags = TLB::MustBeOne | TLB::UserMode; + tranType = TLB::S1S2NsTran; + mode = BaseTLB::Read; + break; + case MISCREG_ATS12NSOUW: + if (!haveSecurity) + panic("Security Extensions required for ATS12NSOUW"); + flags = TLB::MustBeOne | TLB::UserMode; + tranType = TLB::S1S2NsTran; + mode = BaseTLB::Write; + break; + case MISCREG_ATS1HR: // only really useful from secure mode. + flags = TLB::MustBeOne; + tranType = TLB::HypMode; + mode = BaseTLB::Read; + break; + case MISCREG_ATS1HW: + flags = TLB::MustBeOne; + tranType = TLB::HypMode; + mode = BaseTLB::Write; + break; } - warn("Translating via MISCREG in atomic mode! Fix Me!\n"); - req->setVirt(0, val, 1, flags, tc->pcState().pc(), - Request::funcMasterId); - fault = tc->getDTBPtr()->translateAtomic(req, tc, mode); + // If we're in timing mode then doing the translation in + // functional mode then we're slightly distorting performance + // results obtained from simulations. The translation should be + // done in the same mode the core is running in. NOTE: This + // can't be an atomic translation because that causes problems + // with unexpected atomic snoop requests. + warn("Translating via MISCREG(%d) in functional mode! Fix Me!\n", misc_reg); + req->setVirt(0, val, 1, flags, Request::funcMasterId, + tc->pcState().pc()); + req->setThreadContext(tc->contextId(), tc->threadId()); + fault = tc->getDTBPtr()->translateFunctional(req, tc, mode, tranType); + TTBCR ttbcr = readMiscRegNoEffect(MISCREG_TTBCR); + HCR hcr = readMiscRegNoEffect(MISCREG_HCR); + + MiscReg newVal; if (fault == NoFault) { - miscRegs[MISCREG_PAR] = - (req->getPaddr() & 0xfffff000) | - (tc->getDTBPtr()->getAttr() ); + Addr paddr = req->getPaddr(); + if (haveLPAE && (ttbcr.eae || tranType & TLB::HypMode || + ((tranType & TLB::S1S2NsTran) && hcr.vm) )) { + newVal = (paddr & mask(39, 12)) | + (tc->getDTBPtr()->getAttr()); + } else { + newVal = (paddr & 0xfffff000) | + (tc->getDTBPtr()->getAttr()); + } DPRINTF(MiscRegs, "MISCREG: Translated addr 0x%08x: PAR: 0x%08x\n", - val, miscRegs[MISCREG_PAR]); - } - else { + val, newVal); + } else { + ArmFault *armFault = reinterpret_cast<ArmFault *>(fault.get()); // Set fault bit and FSR - FSR fsr = miscRegs[MISCREG_DFSR]; - miscRegs[MISCREG_PAR] = - (fsr.ext << 6) | - (fsr.fsHigh << 5) | - (fsr.fsLow << 1) | - 0x1; // F bit + FSR fsr = armFault->getFsr(tc); + + newVal = ((fsr >> 9) & 1) << 11; + if (newVal) { + // LPAE - rearange fault status + newVal |= ((fsr >> 0) & 0x3f) << 1; + } else { + // VMSA - rearange fault status + newVal |= ((fsr >> 0) & 0xf) << 1; + newVal |= ((fsr >> 10) & 0x1) << 5; + newVal |= ((fsr >> 12) & 0x1) << 6; + } + newVal |= 0x1; // F bit + newVal |= ((armFault->iss() >> 7) & 0x1) << 8; + newVal |= armFault->isStage2() ? 0x200 : 0; + DPRINTF(MiscRegs, + "MISCREG: Translated addr 0x%08x fault fsr %#x: PAR: 0x%08x\n", + val, fsr, newVal); } + delete req; + setMiscRegNoEffect(MISCREG_PAR, newVal); return; } + case MISCREG_TTBCR: + { + TTBCR ttbcr = readMiscRegNoEffect(MISCREG_TTBCR); + const uint32_t ones = (uint32_t)(-1); + TTBCR ttbcrMask = 0; + TTBCR ttbcrNew = newVal; + + // ARM DDI 0406C.b, ARMv7-32 + ttbcrMask.n = ones; // T0SZ + if (haveSecurity) { + ttbcrMask.pd0 = ones; + ttbcrMask.pd1 = ones; + } + ttbcrMask.epd0 = ones; + ttbcrMask.irgn0 = ones; + ttbcrMask.orgn0 = ones; + ttbcrMask.sh0 = ones; + ttbcrMask.ps = ones; // T1SZ + ttbcrMask.a1 = ones; + ttbcrMask.epd1 = ones; + ttbcrMask.irgn1 = ones; + ttbcrMask.orgn1 = ones; + ttbcrMask.sh1 = ones; + if (haveLPAE) + ttbcrMask.eae = ones; + + if (haveLPAE && ttbcrNew.eae) { + newVal = newVal & ttbcrMask; + } else { + newVal = (newVal & ttbcrMask) | (ttbcr & (~ttbcrMask)); + } + } + case MISCREG_TTBR0: + case MISCREG_TTBR1: + { + TTBCR ttbcr = readMiscRegNoEffect(MISCREG_TTBCR); + if (haveLPAE) { + if (ttbcr.eae) { + // ARMv7 bit 63-56, 47-40 reserved, UNK/SBZP + // ARMv8 AArch32 bit 63-56 only + uint64_t ttbrMask = mask(63,56) | mask(47,40); + newVal = (newVal & (~ttbrMask)); + } + } + } case MISCREG_CONTEXTIDR: case MISCREG_PRRR: case MISCREG_NMRR: + case MISCREG_MAIR0: + case MISCREG_MAIR1: case MISCREG_DACR: + case MISCREG_VTTBR: + case MISCREG_SCR_EL3: + case MISCREG_SCTLR_EL1: + case MISCREG_SCTLR_EL2: + case MISCREG_SCTLR_EL3: + case MISCREG_TCR_EL1: + case MISCREG_TCR_EL2: + case MISCREG_TCR_EL3: + case MISCREG_TTBR0_EL1: + case MISCREG_TTBR1_EL1: + case MISCREG_TTBR0_EL2: + case MISCREG_TTBR0_EL3: tc->getITBPtr()->invalidateMiscReg(); tc->getDTBPtr()->invalidateMiscReg(); break; + case MISCREG_NZCV: + { + CPSR cpsr = val; + + tc->setIntReg(INTREG_CONDCODES_NZ, cpsr.nz); + tc->setIntReg(INTREG_CONDCODES_C, cpsr.c); + tc->setIntReg(INTREG_CONDCODES_V, cpsr.v); + } + break; + case MISCREG_DAIF: + { + CPSR cpsr = miscRegs[MISCREG_CPSR]; + cpsr.daif = (uint8_t) ((CPSR) newVal).daif; + newVal = cpsr; + misc_reg = MISCREG_CPSR; + } + break; + case MISCREG_SP_EL0: + tc->setIntReg(INTREG_SP0, newVal); + break; + case MISCREG_SP_EL1: + tc->setIntReg(INTREG_SP1, newVal); + break; + case MISCREG_SP_EL2: + tc->setIntReg(INTREG_SP2, newVal); + break; + case MISCREG_SPSEL: + { + CPSR cpsr = miscRegs[MISCREG_CPSR]; + cpsr.sp = (uint8_t) ((CPSR) newVal).sp; + newVal = cpsr; + misc_reg = MISCREG_CPSR; + } + break; + case MISCREG_CURRENTEL: + { + CPSR cpsr = miscRegs[MISCREG_CPSR]; + cpsr.el = (uint8_t) ((CPSR) newVal).el; + newVal = cpsr; + misc_reg = MISCREG_CPSR; + } + break; + case MISCREG_AT_S1E1R_Xt: + case MISCREG_AT_S1E1W_Xt: + case MISCREG_AT_S1E0R_Xt: + case MISCREG_AT_S1E0W_Xt: + case MISCREG_AT_S1E2R_Xt: + case MISCREG_AT_S1E2W_Xt: + case MISCREG_AT_S12E1R_Xt: + case MISCREG_AT_S12E1W_Xt: + case MISCREG_AT_S12E0R_Xt: + case MISCREG_AT_S12E0W_Xt: + case MISCREG_AT_S1E3R_Xt: + case MISCREG_AT_S1E3W_Xt: + { + RequestPtr req = new Request; + unsigned flags = 0; + BaseTLB::Mode mode = BaseTLB::Read; + TLB::ArmTranslationType tranType = TLB::NormalTran; + Fault fault; + switch(misc_reg) { + case MISCREG_AT_S1E1R_Xt: + flags = TLB::MustBeOne; + tranType = TLB::S1CTran; + mode = BaseTLB::Read; + break; + case MISCREG_AT_S1E1W_Xt: + flags = TLB::MustBeOne; + tranType = TLB::S1CTran; + mode = BaseTLB::Write; + break; + case MISCREG_AT_S1E0R_Xt: + flags = TLB::MustBeOne | TLB::UserMode; + tranType = TLB::S1CTran; + mode = BaseTLB::Read; + break; + case MISCREG_AT_S1E0W_Xt: + flags = TLB::MustBeOne | TLB::UserMode; + tranType = TLB::S1CTran; + mode = BaseTLB::Write; + break; + case MISCREG_AT_S1E2R_Xt: + flags = TLB::MustBeOne; + tranType = TLB::HypMode; + mode = BaseTLB::Read; + break; + case MISCREG_AT_S1E2W_Xt: + flags = TLB::MustBeOne; + tranType = TLB::HypMode; + mode = BaseTLB::Write; + break; + case MISCREG_AT_S12E0R_Xt: + flags = TLB::MustBeOne | TLB::UserMode; + tranType = TLB::S1S2NsTran; + mode = BaseTLB::Read; + break; + case MISCREG_AT_S12E0W_Xt: + flags = TLB::MustBeOne | TLB::UserMode; + tranType = TLB::S1S2NsTran; + mode = BaseTLB::Write; + break; + case MISCREG_AT_S12E1R_Xt: + flags = TLB::MustBeOne; + tranType = TLB::S1S2NsTran; + mode = BaseTLB::Read; + break; + case MISCREG_AT_S12E1W_Xt: + flags = TLB::MustBeOne; + tranType = TLB::S1S2NsTran; + mode = BaseTLB::Write; + break; + case MISCREG_AT_S1E3R_Xt: + flags = TLB::MustBeOne; + tranType = TLB::HypMode; // There is no TZ mode defined. + mode = BaseTLB::Read; + break; + case MISCREG_AT_S1E3W_Xt: + flags = TLB::MustBeOne; + tranType = TLB::HypMode; // There is no TZ mode defined. + mode = BaseTLB::Write; + break; + } + // If we're in timing mode then doing the translation in + // functional mode then we're slightly distorting performance + // results obtained from simulations. The translation should be + // done in the same mode the core is running in. NOTE: This + // can't be an atomic translation because that causes problems + // with unexpected atomic snoop requests. + warn("Translating via MISCREG(%d) in functional mode! Fix Me!\n", misc_reg); + req->setVirt(0, val, 1, flags, Request::funcMasterId, + tc->pcState().pc()); + req->setThreadContext(tc->contextId(), tc->threadId()); + fault = tc->getDTBPtr()->translateFunctional(req, tc, mode, + tranType); + + MiscReg newVal; + if (fault == NoFault) { + Addr paddr = req->getPaddr(); + uint64_t attr = tc->getDTBPtr()->getAttr(); + uint64_t attr1 = attr >> 56; + if (!attr1 || attr1 ==0x44) { + attr |= 0x100; + attr &= ~ uint64_t(0x80); + } + newVal = (paddr & mask(47, 12)) | attr; + DPRINTF(MiscRegs, + "MISCREG: Translated addr %#x: PAR_EL1: %#xx\n", + val, newVal); + } else { + ArmFault *armFault = reinterpret_cast<ArmFault *>(fault.get()); + // Set fault bit and FSR + FSR fsr = armFault->getFsr(tc); + + newVal = ((fsr >> 9) & 1) << 11; + // rearange fault status + newVal |= ((fsr >> 0) & 0x3f) << 1; + newVal |= 0x1; // F bit + newVal |= ((armFault->iss() >> 7) & 0x1) << 8; + newVal |= armFault->isStage2() ? 0x200 : 0; + DPRINTF(MiscRegs, + "MISCREG: Translated addr %#x fault fsr %#x: PAR: %#x\n", + val, fsr, newVal); + } + delete req; + setMiscRegNoEffect(MISCREG_PAR_EL1, newVal); + return; + } + case MISCREG_SPSR_EL3: + case MISCREG_SPSR_EL2: + case MISCREG_SPSR_EL1: + // Force bits 23:21 to 0 + newVal = val & ~(0x7 << 21); + break; case MISCREG_L2CTLR: warn("miscreg L2CTLR (%s) written with %#x. ignored...\n", miscRegName[misc_reg], uint32_t(val)); + break; + + // Generic Timer registers + case MISCREG_CNTFRQ: + case MISCREG_CNTFRQ_EL0: + getSystemCounter(tc)->setFreq(val); + break; + case MISCREG_CNTP_CVAL: + case MISCREG_CNTP_CVAL_EL0: + getArchTimer(tc, tc->cpuId())->setCompareValue(val); + break; + case MISCREG_CNTP_TVAL: + case MISCREG_CNTP_TVAL_EL0: + getArchTimer(tc, tc->cpuId())->setTimerValue(val); + break; + case MISCREG_CNTP_CTL: + case MISCREG_CNTP_CTL_EL0: + getArchTimer(tc, tc->cpuId())->setControl(val); + break; + // PL1 phys. timer, secure + // AArch64 + case MISCREG_CNTPS_CVAL_EL1: + case MISCREG_CNTPS_TVAL_EL1: + case MISCREG_CNTPS_CTL_EL1: + // PL2 phys. timer, non-secure + // AArch32 + case MISCREG_CNTHCTL: + case MISCREG_CNTHP_CVAL: + case MISCREG_CNTHP_TVAL: + case MISCREG_CNTHP_CTL: + // AArch64 + case MISCREG_CNTHCTL_EL2: + case MISCREG_CNTHP_CVAL_EL2: + case MISCREG_CNTHP_TVAL_EL2: + case MISCREG_CNTHP_CTL_EL2: + // Virtual timer + // AArch32 + case MISCREG_CNTV_CVAL: + case MISCREG_CNTV_TVAL: + case MISCREG_CNTV_CTL: + // AArch64 + // case MISCREG_CNTV_CVAL_EL2: + // case MISCREG_CNTV_TVAL_EL2: + // case MISCREG_CNTV_CTL_EL2: + panic("Generic Timer register not implemented\n"); + break; } } setMiscRegNoEffect(misc_reg, newVal); } +void +ISA::tlbiVA(ThreadContext *tc, MiscReg newVal, uint8_t asid, bool secure_lookup, + uint8_t target_el) +{ + if (haveLargeAsid64) + asid &= mask(8); + Addr va = ((Addr) bits(newVal, 43, 0)) << 12; + System *sys = tc->getSystemPtr(); + for (int x = 0; x < sys->numContexts(); x++) { + ThreadContext *oc = sys->getThreadContext(x); + assert(oc->getITBPtr() && oc->getDTBPtr()); + oc->getITBPtr()->flushMvaAsid(va, asid, + secure_lookup, target_el); + oc->getDTBPtr()->flushMvaAsid(va, asid, + secure_lookup, target_el); + + CheckerCPU *checker = oc->getCheckerCpuPtr(); + if (checker) { + checker->getITBPtr()->flushMvaAsid( + va, asid, secure_lookup, target_el); + checker->getDTBPtr()->flushMvaAsid( + va, asid, secure_lookup, target_el); + } + } +} + +void +ISA::tlbiALL(ThreadContext *tc, bool secure_lookup, uint8_t target_el) +{ + System *sys = tc->getSystemPtr(); + for (int x = 0; x < sys->numContexts(); x++) { + ThreadContext *oc = sys->getThreadContext(x); + assert(oc->getITBPtr() && oc->getDTBPtr()); + oc->getITBPtr()->flushAllSecurity(secure_lookup, target_el); + oc->getDTBPtr()->flushAllSecurity(secure_lookup, target_el); + + // If CheckerCPU is connected, need to notify it of a flush + CheckerCPU *checker = oc->getCheckerCpuPtr(); + if (checker) { + checker->getITBPtr()->flushAllSecurity(secure_lookup, + target_el); + checker->getDTBPtr()->flushAllSecurity(secure_lookup, + target_el); + } + } +} + +void +ISA::tlbiALLN(ThreadContext *tc, bool hyp, uint8_t target_el) +{ + System *sys = tc->getSystemPtr(); + for (int x = 0; x < sys->numContexts(); x++) { + ThreadContext *oc = sys->getThreadContext(x); + assert(oc->getITBPtr() && oc->getDTBPtr()); + oc->getITBPtr()->flushAllNs(hyp, target_el); + oc->getDTBPtr()->flushAllNs(hyp, target_el); + + CheckerCPU *checker = oc->getCheckerCpuPtr(); + if (checker) { + checker->getITBPtr()->flushAllNs(hyp, target_el); + checker->getDTBPtr()->flushAllNs(hyp, target_el); + } + } +} + +void +ISA::tlbiMVA(ThreadContext *tc, MiscReg newVal, bool secure_lookup, bool hyp, + uint8_t target_el) +{ + System *sys = tc->getSystemPtr(); + for (int x = 0; x < sys->numContexts(); x++) { + ThreadContext *oc = sys->getThreadContext(x); + assert(oc->getITBPtr() && oc->getDTBPtr()); + oc->getITBPtr()->flushMva(mbits(newVal, 31,12), + secure_lookup, hyp, target_el); + oc->getDTBPtr()->flushMva(mbits(newVal, 31,12), + secure_lookup, hyp, target_el); + + CheckerCPU *checker = oc->getCheckerCpuPtr(); + if (checker) { + checker->getITBPtr()->flushMva(mbits(newVal, 31,12), + secure_lookup, hyp, target_el); + checker->getDTBPtr()->flushMva(mbits(newVal, 31,12), + secure_lookup, hyp, target_el); + } + } +} + +::GenericTimer::SystemCounter * +ISA::getSystemCounter(ThreadContext *tc) +{ + ::GenericTimer::SystemCounter *cnt = ((ArmSystem *) tc->getSystemPtr())-> + getSystemCounter(); + if (cnt == NULL) { + panic("System counter not available\n"); + } + return cnt; +} + +::GenericTimer::ArchTimer * +ISA::getArchTimer(ThreadContext *tc, int cpu_id) +{ + ::GenericTimer::ArchTimer *timer = ((ArmSystem *) tc->getSystemPtr())-> + getArchTimer(cpu_id); + if (timer == NULL) { + panic("Architected timer not available\n"); + } + return timer; +} + } ArmISA::ISA * diff --git a/src/arch/arm/isa.hh b/src/arch/arm/isa.hh index c747fc770..c72d5d50f 100644 --- a/src/arch/arm/isa.hh +++ b/src/arch/arm/isa.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010, 2012-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -44,9 +44,11 @@ #define __ARCH_ARM_ISA_HH__ #include "arch/arm/registers.hh" +#include "arch/arm/system.hh" #include "arch/arm/tlb.hh" #include "arch/arm/types.hh" #include "debug/Checkpoint.hh" +#include "dev/arm/generic_timer.hh" #include "sim/sim_object.hh" struct ArmISAParams; @@ -56,45 +58,174 @@ class EventManager; namespace ArmISA { + + /** + * At the moment there are 57 registers which need to be aliased/ + * translated with other registers in the ISA. This enum helps with that + * translation. + */ + enum translateTable { + miscRegTranslateCSSELR_EL1, + miscRegTranslateSCTLR_EL1, + miscRegTranslateSCTLR_EL2, + miscRegTranslateACTLR_EL1, + miscRegTranslateACTLR_EL2, + miscRegTranslateCPACR_EL1, + miscRegTranslateCPTR_EL2, + miscRegTranslateHCR_EL2, + miscRegTranslateMDCR_EL2, + miscRegTranslateHSTR_EL2, + miscRegTranslateHACR_EL2, + miscRegTranslateTTBR0_EL1, + miscRegTranslateTTBR1_EL1, + miscRegTranslateTTBR0_EL2, + miscRegTranslateVTTBR_EL2, + miscRegTranslateTCR_EL1, + miscRegTranslateTCR_EL2, + miscRegTranslateVTCR_EL2, + miscRegTranslateAFSR0_EL1, + miscRegTranslateAFSR1_EL1, + miscRegTranslateAFSR0_EL2, + miscRegTranslateAFSR1_EL2, + miscRegTranslateESR_EL2, + miscRegTranslateFAR_EL1, + miscRegTranslateFAR_EL2, + miscRegTranslateHPFAR_EL2, + miscRegTranslatePAR_EL1, + miscRegTranslateMAIR_EL1, + miscRegTranslateMAIR_EL2, + miscRegTranslateAMAIR_EL1, + miscRegTranslateVBAR_EL1, + miscRegTranslateVBAR_EL2, + miscRegTranslateCONTEXTIDR_EL1, + miscRegTranslateTPIDR_EL0, + miscRegTranslateTPIDRRO_EL0, + miscRegTranslateTPIDR_EL1, + miscRegTranslateTPIDR_EL2, + miscRegTranslateTEECR32_EL1, + miscRegTranslateCNTFRQ_EL0, + miscRegTranslateCNTPCT_EL0, + miscRegTranslateCNTVCT_EL0, + miscRegTranslateCNTVOFF_EL2, + miscRegTranslateCNTKCTL_EL1, + miscRegTranslateCNTHCTL_EL2, + miscRegTranslateCNTP_TVAL_EL0, + miscRegTranslateCNTP_CTL_EL0, + miscRegTranslateCNTP_CVAL_EL0, + miscRegTranslateCNTV_TVAL_EL0, + miscRegTranslateCNTV_CTL_EL0, + miscRegTranslateCNTV_CVAL_EL0, + miscRegTranslateCNTHP_TVAL_EL2, + miscRegTranslateCNTHP_CTL_EL2, + miscRegTranslateCNTHP_CVAL_EL2, + miscRegTranslateDACR32_EL2, + miscRegTranslateIFSR32_EL2, + miscRegTranslateTEEHBR32_EL1, + miscRegTranslateSDER32_EL3, + miscRegTranslateMax + }; + class ISA : public SimObject { protected: + // Parent system + ArmSystem *system; + + // Cached copies of system-level properties + bool haveSecurity; + bool haveLPAE; + bool haveVirtualization; + bool haveLargeAsid64; + uint8_t physAddrRange64; + + /** Register translation entry used in lookUpMiscReg */ + struct MiscRegLUTEntry { + uint32_t lower; + uint32_t upper; + }; + + struct MiscRegInitializerEntry { + uint32_t index; + struct MiscRegLUTEntry entry; + }; + + /** Register table noting all translations */ + static const struct MiscRegInitializerEntry + MiscRegSwitch[miscRegTranslateMax]; + + /** Translation table accessible via the value of the register */ + std::vector<struct MiscRegLUTEntry> lookUpMiscReg; + MiscReg miscRegs[NumMiscRegs]; const IntRegIndex *intRegMap; void updateRegMap(CPSR cpsr) { - switch (cpsr.mode) { - case MODE_USER: - case MODE_SYSTEM: - intRegMap = IntRegUsrMap; - break; - case MODE_FIQ: - intRegMap = IntRegFiqMap; - break; - case MODE_IRQ: - intRegMap = IntRegIrqMap; - break; - case MODE_SVC: - intRegMap = IntRegSvcMap; - break; - case MODE_MON: - intRegMap = IntRegMonMap; - break; - case MODE_ABORT: - intRegMap = IntRegAbtMap; - break; - case MODE_UNDEFINED: - intRegMap = IntRegUndMap; - break; - default: - panic("Unrecognized mode setting in CPSR.\n"); + if (cpsr.width == 0) { + intRegMap = IntReg64Map; + } else { + switch (cpsr.mode) { + case MODE_USER: + case MODE_SYSTEM: + intRegMap = IntRegUsrMap; + break; + case MODE_FIQ: + intRegMap = IntRegFiqMap; + break; + case MODE_IRQ: + intRegMap = IntRegIrqMap; + break; + case MODE_SVC: + intRegMap = IntRegSvcMap; + break; + case MODE_MON: + intRegMap = IntRegMonMap; + break; + case MODE_ABORT: + intRegMap = IntRegAbtMap; + break; + case MODE_HYP: + intRegMap = IntRegHypMap; + break; + case MODE_UNDEFINED: + intRegMap = IntRegUndMap; + break; + default: + panic("Unrecognized mode setting in CPSR.\n"); + } } } + ::GenericTimer::SystemCounter * getSystemCounter(ThreadContext *tc); + ::GenericTimer::ArchTimer * getArchTimer(ThreadContext *tc, + int cpu_id); + + + private: + inline void assert32(ThreadContext *tc) { + CPSR cpsr M5_VAR_USED = readMiscReg(MISCREG_CPSR, tc); + assert(cpsr.width); + } + + inline void assert64(ThreadContext *tc) { + CPSR cpsr M5_VAR_USED = readMiscReg(MISCREG_CPSR, tc); + assert(!cpsr.width); + } + + void tlbiVA(ThreadContext *tc, MiscReg newVal, uint8_t asid, + bool secure_lookup, uint8_t target_el); + + void tlbiALL(ThreadContext *tc, bool secure_lookup, uint8_t target_el); + + void tlbiALLN(ThreadContext *tc, bool hyp, uint8_t target_el); + + void tlbiMVA(ThreadContext *tc, MiscReg newVal, bool secure_lookup, + bool hyp, uint8_t target_el); + public: void clear(); + void clear64(const ArmISAParams *p); MiscReg readMiscRegNoEffect(int misc_reg) const; MiscReg readMiscReg(int misc_reg, ThreadContext *tc); @@ -109,28 +240,28 @@ namespace ArmISA return intRegMap[reg]; } else if (reg < NUM_INTREGS) { return reg; - } else { - int mode = reg / intRegsPerMode; - reg = reg % intRegsPerMode; - switch (mode) { - case MODE_USER: - case MODE_SYSTEM: - return INTREG_USR(reg); - case MODE_FIQ: - return INTREG_FIQ(reg); - case MODE_IRQ: - return INTREG_IRQ(reg); - case MODE_SVC: - return INTREG_SVC(reg); - case MODE_MON: - return INTREG_MON(reg); - case MODE_ABORT: - return INTREG_ABT(reg); - case MODE_UNDEFINED: - return INTREG_UND(reg); + } else if (reg == INTREG_SPX) { + CPSR cpsr = miscRegs[MISCREG_CPSR]; + ExceptionLevel el = opModeToEL( + (OperatingMode) (uint8_t) cpsr.mode); + if (!cpsr.sp && el != EL0) + return INTREG_SP0; + switch (el) { + case EL3: + return INTREG_SP3; + // @todo: uncomment this to enable Virtualization + // case EL2: + // return INTREG_SP2; + case EL1: + return INTREG_SP1; + case EL0: + return INTREG_SP0; default: - panic("Flattening into an unknown mode.\n"); + panic("Invalid exception level"); + break; } + } else { + return flattenIntRegModeIndex(reg); } } @@ -150,47 +281,127 @@ namespace ArmISA int flattenMiscIndex(int reg) const { + int flat_idx = reg; + if (reg == MISCREG_SPSR) { - int spsr_idx = NUM_MISCREGS; CPSR cpsr = miscRegs[MISCREG_CPSR]; switch (cpsr.mode) { + case MODE_EL0T: + warn("User mode does not have SPSR\n"); + flat_idx = MISCREG_SPSR; + break; + case MODE_EL1T: + case MODE_EL1H: + flat_idx = MISCREG_SPSR_EL1; + break; + case MODE_EL2T: + case MODE_EL2H: + flat_idx = MISCREG_SPSR_EL2; + break; + case MODE_EL3T: + case MODE_EL3H: + flat_idx = MISCREG_SPSR_EL3; + break; case MODE_USER: warn("User mode does not have SPSR\n"); - spsr_idx = MISCREG_SPSR; + flat_idx = MISCREG_SPSR; break; case MODE_FIQ: - spsr_idx = MISCREG_SPSR_FIQ; + flat_idx = MISCREG_SPSR_FIQ; break; case MODE_IRQ: - spsr_idx = MISCREG_SPSR_IRQ; + flat_idx = MISCREG_SPSR_IRQ; break; case MODE_SVC: - spsr_idx = MISCREG_SPSR_SVC; + flat_idx = MISCREG_SPSR_SVC; break; case MODE_MON: - spsr_idx = MISCREG_SPSR_MON; + flat_idx = MISCREG_SPSR_MON; break; case MODE_ABORT: - spsr_idx = MISCREG_SPSR_ABT; + flat_idx = MISCREG_SPSR_ABT; + break; + case MODE_HYP: + flat_idx = MISCREG_SPSR_HYP; break; case MODE_UNDEFINED: - spsr_idx = MISCREG_SPSR_UND; + flat_idx = MISCREG_SPSR_UND; break; default: warn("Trying to access SPSR in an invalid mode: %d\n", cpsr.mode); - spsr_idx = MISCREG_SPSR; + flat_idx = MISCREG_SPSR; break; } - return spsr_idx; + } else if (miscRegInfo[reg][MISCREG_MUTEX]) { + // Mutually exclusive CP15 register + switch (reg) { + case MISCREG_PRRR_MAIR0: + case MISCREG_PRRR_MAIR0_NS: + case MISCREG_PRRR_MAIR0_S: + { + TTBCR ttbcr = readMiscRegNoEffect(MISCREG_TTBCR); + // If the muxed reg has been flattened, work out the + // offset and apply it to the unmuxed reg + int idxOffset = reg - MISCREG_PRRR_MAIR0; + if (ttbcr.eae) + flat_idx = flattenMiscIndex(MISCREG_MAIR0 + + idxOffset); + else + flat_idx = flattenMiscIndex(MISCREG_PRRR + + idxOffset); + } + break; + case MISCREG_NMRR_MAIR1: + case MISCREG_NMRR_MAIR1_NS: + case MISCREG_NMRR_MAIR1_S: + { + TTBCR ttbcr = readMiscRegNoEffect(MISCREG_TTBCR); + // If the muxed reg has been flattened, work out the + // offset and apply it to the unmuxed reg + int idxOffset = reg - MISCREG_NMRR_MAIR1; + if (ttbcr.eae) + flat_idx = flattenMiscIndex(MISCREG_MAIR1 + + idxOffset); + else + flat_idx = flattenMiscIndex(MISCREG_NMRR + + idxOffset); + } + break; + case MISCREG_PMXEVTYPER_PMCCFILTR: + { + PMSELR pmselr = miscRegs[MISCREG_PMSELR]; + if (pmselr.sel == 31) + flat_idx = flattenMiscIndex(MISCREG_PMCCFILTR); + else + flat_idx = flattenMiscIndex(MISCREG_PMXEVTYPER); + } + break; + default: + panic("Unrecognized misc. register.\n"); + break; + } + } else { + if (miscRegInfo[reg][MISCREG_BANKED]) { + bool secureReg = haveSecurity && + inSecureState(miscRegs[MISCREG_SCR], + miscRegs[MISCREG_CPSR]); + flat_idx += secureReg ? 2 : 1; + } } - return reg; + return flat_idx; } void serialize(std::ostream &os) { DPRINTF(Checkpoint, "Serializing Arm Misc Registers\n"); SERIALIZE_ARRAY(miscRegs, NumMiscRegs); + + SERIALIZE_SCALAR(haveSecurity); + SERIALIZE_SCALAR(haveLPAE); + SERIALIZE_SCALAR(haveVirtualization); + SERIALIZE_SCALAR(haveLargeAsid64); + SERIALIZE_SCALAR(physAddrRange64); } void unserialize(Checkpoint *cp, const std::string §ion) { @@ -198,6 +409,12 @@ namespace ArmISA UNSERIALIZE_ARRAY(miscRegs, NumMiscRegs); CPSR tmp_cpsr = miscRegs[MISCREG_CPSR]; updateRegMap(tmp_cpsr); + + UNSERIALIZE_SCALAR(haveSecurity); + UNSERIALIZE_SCALAR(haveLPAE); + UNSERIALIZE_SCALAR(haveVirtualization); + UNSERIALIZE_SCALAR(haveLargeAsid64); + UNSERIALIZE_SCALAR(physAddrRange64); } void startup(ThreadContext *tc) {} diff --git a/src/arch/arm/isa/bitfields.isa b/src/arch/arm/isa/bitfields.isa index 5a8b5db6d..6006cfb2d 100644 --- a/src/arch/arm/isa/bitfields.isa +++ b/src/arch/arm/isa/bitfields.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2010 ARM Limited +// Copyright (c) 2010, 2011 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -73,6 +73,7 @@ def bitfield SEVEN_AND_FOUR sevenAndFour; def bitfield THUMB thumb; def bitfield BIGTHUMB bigThumb; +def bitfield AARCH64 aarch64; // Other def bitfield COND_CODE condCode; diff --git a/src/arch/arm/isa/decoder/aarch64.isa b/src/arch/arm/isa/decoder/aarch64.isa new file mode 100644 index 000000000..a6c0fa2df --- /dev/null +++ b/src/arch/arm/isa/decoder/aarch64.isa @@ -0,0 +1,48 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2011 ARM Limited +// All rights reserved +// +// The license below extends only to copyright in the software and shall +// not be construed as granting a license to any other intellectual +// property including but not limited to intellectual property relating +// to a hardware implementation of the functionality of the software +// licensed hereunder. You may use the software subject to the license +// terms below provided that you ensure that this notice is replicated +// unmodified and in its entirety in all distributions of the software, +// modified or unmodified, in source code or in binary form. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Gabe Black + +//////////////////////////////////////////////////////////////////// +// +// The 64 bit ARM decoder +// -------------------------- +// + + +Aarch64::aarch64(); + diff --git a/src/arch/arm/isa/decoder/arm.isa b/src/arch/arm/isa/decoder/arm.isa index 4bd9d5cf4..f0c0dec18 100644 --- a/src/arch/arm/isa/decoder/arm.isa +++ b/src/arch/arm/isa/decoder/arm.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2010-2012 ARM Limited +// Copyright (c) 2010-2013 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -73,7 +73,11 @@ format DataOp { 0x9: ArmBlxReg::armBlxReg(); } 0x5: ArmSatAddSub::armSatAddSub(); - 0x7: Breakpoint::bkpt(); + 0x6: ArmERet::armERet(); + 0x7: decode OPCODE_22 { + 0: Breakpoint::bkpt(); + 1: ArmSmcHyp::armSmcHyp(); + } } 0x1: ArmHalfWordMultAndMultAcc::armHalfWordMultAndMultAcc(); } @@ -105,6 +109,10 @@ format DataOp { } 0x6: decode CPNUM { 0xa, 0xb: ExtensionRegLoadStore::extensionRegLoadStore(); + 0xf: decode OPCODE_20 { + 0: Mcrr15::Mcrr15(); + 1: Mrrc15::Mrrc15(); + } } 0x7: decode OPCODE_24 { 0: decode OPCODE_4 { diff --git a/src/arch/arm/isa/decoder/decoder.isa b/src/arch/arm/isa/decoder/decoder.isa index cf7d17871..94685b943 100644 --- a/src/arch/arm/isa/decoder/decoder.isa +++ b/src/arch/arm/isa/decoder/decoder.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2010 ARM Limited +// Copyright (c) 2010-2011 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -41,8 +41,12 @@ // Authors: Gabe Black decode THUMB default Unknown::unknown() { -0: -##include "arm.isa" +0: decode AARCH64 { + 0: + ##include "arm.isa" + 1: + ##include "aarch64.isa" +} 1: ##include "thumb.isa" } diff --git a/src/arch/arm/isa/decoder/thumb.isa b/src/arch/arm/isa/decoder/thumb.isa index f54cc728d..31495793e 100644 --- a/src/arch/arm/isa/decoder/thumb.isa +++ b/src/arch/arm/isa/decoder/thumb.isa @@ -95,8 +95,14 @@ decode BIGTHUMB { 0xa, 0xb: ExtensionRegLoadStore::extensionRegLoadStre(); 0xf: decode HTOPCODE_9_4 { 0x00: Unknown::undefined(); - 0x04: WarnUnimpl::mcrr(); // mcrr2 - 0x05: WarnUnimpl::mrrc(); // mrrc2 + 0x04: decode LTCOPROC { + 0xf: Mcrr15::Mcrr15(); + default: WarnUnimpl::mcrr(); // mcrr2 + } + 0x05: decode LTCOPROC { + 0xf: Mrrc15::Mrrc15(); + default: WarnUnimpl::mrrc(); // mrrc2 + } 0x02, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e: WarnUnimpl::stc(); // stc2 diff --git a/src/arch/arm/isa/formats/aarch64.isa b/src/arch/arm/isa/formats/aarch64.isa new file mode 100644 index 000000000..3ed70ce81 --- /dev/null +++ b/src/arch/arm/isa/formats/aarch64.isa @@ -0,0 +1,2035 @@ +// Copyright (c) 2011-2013 ARM Limited +// All rights reserved +// +// The license below extends only to copyright in the software and shall +// not be construed as granting a license to any other intellectual +// property including but not limited to intellectual property relating +// to a hardware implementation of the functionality of the software +// licensed hereunder. You may use the software subject to the license +// terms below provided that you ensure that this notice is replicated +// unmodified and in its entirety in all distributions of the software, +// modified or unmodified, in source code or in binary form. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Gabe Black +// Thomas Grocutt +// Mbou Eyole +// Giacomo Gabrielli + +output header {{ +namespace Aarch64 +{ + StaticInstPtr decodeDataProcImm(ExtMachInst machInst); + StaticInstPtr decodeBranchExcSys(ExtMachInst machInst); + StaticInstPtr decodeLoadsStores(ExtMachInst machInst); + StaticInstPtr decodeDataProcReg(ExtMachInst machInst); + + StaticInstPtr decodeFpAdvSIMD(ExtMachInst machInst); + StaticInstPtr decodeFp(ExtMachInst machInst); + StaticInstPtr decodeAdvSIMD(ExtMachInst machInst); + StaticInstPtr decodeAdvSIMDScalar(ExtMachInst machInst); + + StaticInstPtr decodeGem5Ops(ExtMachInst machInst); +} +}}; + +output decoder {{ +namespace Aarch64 +{ + StaticInstPtr + decodeDataProcImm(ExtMachInst machInst) + { + IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 4, 0); + IntRegIndex rdsp = makeSP(rd); + IntRegIndex rn = (IntRegIndex)(uint32_t)bits(machInst, 9, 5); + IntRegIndex rnsp = makeSP(rn); + + uint8_t opc = bits(machInst, 30, 29); + bool sf = bits(machInst, 31); + bool n = bits(machInst, 22); + uint8_t immr = bits(machInst, 21, 16); + uint8_t imms = bits(machInst, 15, 10); + switch (bits(machInst, 25, 23)) { + case 0x0: + case 0x1: + { + uint64_t immlo = bits(machInst, 30, 29); + uint64_t immhi = bits(machInst, 23, 5); + uint64_t imm = (immlo << 0) | (immhi << 2); + if (bits(machInst, 31) == 0) + return new AdrXImm(machInst, rd, INTREG_ZERO, sext<21>(imm)); + else + return new AdrpXImm(machInst, rd, INTREG_ZERO, + sext<33>(imm << 12)); + } + case 0x2: + case 0x3: + { + uint32_t imm12 = bits(machInst, 21, 10); + uint8_t shift = bits(machInst, 23, 22); + uint32_t imm; + if (shift == 0x0) + imm = imm12 << 0; + else if (shift == 0x1) + imm = imm12 << 12; + else + return new Unknown64(machInst); + switch (opc) { + case 0x0: + return new AddXImm(machInst, rdsp, rnsp, imm); + case 0x1: + return new AddXImmCc(machInst, rd, rnsp, imm); + case 0x2: + return new SubXImm(machInst, rdsp, rnsp, imm); + case 0x3: + return new SubXImmCc(machInst, rd, rnsp, imm); + } + } + case 0x4: + { + if (!sf && n) + return new Unknown64(machInst); + // len = MSB(n:NOT(imms)), len < 1 is undefined. + uint8_t len = 0; + if (n) { + len = 6; + } else if (imms == 0x3f || imms == 0x3e) { + return new Unknown64(machInst); + } else { + len = findMsbSet(imms ^ 0x3f); + } + // Generate r, s, and size. + uint64_t r = bits(immr, len - 1, 0); + uint64_t s = bits(imms, len - 1, 0); + uint8_t size = 1 << len; + if (s == size - 1) + return new Unknown64(machInst); + // Generate the pattern with s 1s, rotated by r, with size bits. + uint64_t pattern = mask(s + 1); + if (r) { + pattern = (pattern >> r) | (pattern << (size - r)); + pattern &= mask(size); + } + uint8_t width = sf ? 64 : 32; + // Replicate that to fill up the immediate. + for (unsigned i = 1; i < (width / size); i *= 2) + pattern |= (pattern << (i * size)); + uint64_t imm = pattern; + + switch (opc) { + case 0x0: + return new AndXImm(machInst, rdsp, rn, imm); + case 0x1: + return new OrrXImm(machInst, rdsp, rn, imm); + case 0x2: + return new EorXImm(machInst, rdsp, rn, imm); + case 0x3: + return new AndXImmCc(machInst, rd, rn, imm); + } + } + case 0x5: + { + IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 4, 0); + uint32_t imm16 = bits(machInst, 20, 5); + uint32_t hw = bits(machInst, 22, 21); + switch (opc) { + case 0x0: + return new Movn(machInst, rd, imm16, hw * 16); + case 0x1: + return new Unknown64(machInst); + case 0x2: + return new Movz(machInst, rd, imm16, hw * 16); + case 0x3: + return new Movk(machInst, rd, imm16, hw * 16); + } + } + case 0x6: + if ((sf != n) || (!sf && (bits(immr, 5) || bits(imms, 5)))) + return new Unknown64(machInst); + switch (opc) { + case 0x0: + return new Sbfm64(machInst, rd, rn, immr, imms); + case 0x1: + return new Bfm64(machInst, rd, rn, immr, imms); + case 0x2: + return new Ubfm64(machInst, rd, rn, immr, imms); + case 0x3: + return new Unknown64(machInst); + } + case 0x7: + { + IntRegIndex rm = (IntRegIndex)(uint8_t)bits(machInst, 20, 16); + if (opc || bits(machInst, 21)) + return new Unknown64(machInst); + else + return new Extr64(machInst, rd, rn, rm, imms); + } + } + return new FailUnimplemented("Unhandled Case8", machInst); + } +} +}}; + +output decoder {{ +namespace Aarch64 +{ + StaticInstPtr + decodeBranchExcSys(ExtMachInst machInst) + { + switch (bits(machInst, 30, 29)) { + case 0x0: + { + int64_t imm = sext<26>(bits(machInst, 25, 0)) << 2; + if (bits(machInst, 31) == 0) + return new B64(machInst, imm); + else + return new Bl64(machInst, imm); + } + case 0x1: + { + IntRegIndex rt = (IntRegIndex)(uint8_t)bits(machInst, 4, 0); + if (bits(machInst, 25) == 0) { + int64_t imm = sext<19>(bits(machInst, 23, 5)) << 2; + if (bits(machInst, 24) == 0) + return new Cbz64(machInst, imm, rt); + else + return new Cbnz64(machInst, imm, rt); + } else { + uint64_t bitmask = 0x1; + bitmask <<= bits(machInst, 23, 19); + int64_t imm = sext<14>(bits(machInst, 18, 5)) << 2; + if (bits(machInst, 31)) + bitmask <<= 32; + if (bits(machInst, 24) == 0) + return new Tbz64(machInst, bitmask, imm, rt); + else + return new Tbnz64(machInst, bitmask, imm, rt); + } + } + case 0x2: + // bit 30:26=10101 + if (bits(machInst, 31) == 0) { + if (bits(machInst, 25, 24) || bits(machInst, 4)) + return new Unknown64(machInst); + int64_t imm = sext<19>(bits(machInst, 23, 5)) << 2; + ConditionCode condCode = + (ConditionCode)(uint8_t)(bits(machInst, 3, 0)); + return new BCond64(machInst, imm, condCode); + } else if (bits(machInst, 25, 24) == 0x0) { + if (bits(machInst, 4, 2)) + return new Unknown64(machInst); + uint8_t decVal = (bits(machInst, 1, 0) << 0) | + (bits(machInst, 23, 21) << 2); + switch (decVal) { + case 0x01: + return new Svc64(machInst); + case 0x02: + return new FailUnimplemented("hvc", machInst); + case 0x03: + return new Smc64(machInst); + case 0x04: + return new FailUnimplemented("brk", machInst); + case 0x08: + return new FailUnimplemented("hlt", machInst); + case 0x15: + return new FailUnimplemented("dcps1", machInst); + case 0x16: + return new FailUnimplemented("dcps2", machInst); + case 0x17: + return new FailUnimplemented("dcps3", machInst); + default: + return new Unknown64(machInst); + } + } else if (bits(machInst, 25, 22) == 0x4) { + // bit 31:22=1101010100 + bool l = bits(machInst, 21); + uint8_t op0 = bits(machInst, 20, 19); + uint8_t op1 = bits(machInst, 18, 16); + uint8_t crn = bits(machInst, 15, 12); + uint8_t crm = bits(machInst, 11, 8); + uint8_t op2 = bits(machInst, 7, 5); + IntRegIndex rt = (IntRegIndex)(uint8_t)bits(machInst, 4, 0); + switch (op0) { + case 0x0: + if (rt != 0x1f || l) + return new Unknown64(machInst); + if (crn == 0x2 && op1 == 0x3) { + switch (op2) { + case 0x0: + return new NopInst(machInst); + case 0x1: + return new YieldInst(machInst); + case 0x2: + return new WfeInst(machInst); + case 0x3: + return new WfiInst(machInst); + case 0x4: + return new SevInst(machInst); + case 0x5: + return new SevlInst(machInst); + default: + return new Unknown64(machInst); + } + } else if (crn == 0x3 && op1 == 0x3) { + switch (op2) { + case 0x2: + return new Clrex64(machInst); + case 0x4: + return new Dsb64(machInst); + case 0x5: + return new Dmb64(machInst); + case 0x6: + return new Isb64(machInst); + default: + return new Unknown64(machInst); + } + } else if (crn == 0x4) { + // MSR immediate + switch (op1 << 3 | op2) { + case 0x5: + // SP + return new MsrSP64(machInst, + (IntRegIndex) MISCREG_SPSEL, + INTREG_ZERO, + crm & 0x1); + case 0x1e: + // DAIFSet + return new MsrDAIFSet64( + machInst, + (IntRegIndex) MISCREG_DAIF, + INTREG_ZERO, + crm); + case 0x1f: + // DAIFClr + return new MsrDAIFClr64( + machInst, + (IntRegIndex) MISCREG_DAIF, + INTREG_ZERO, + crm); + default: + return new Unknown64(machInst); + } + } else { + return new Unknown64(machInst); + } + break; + case 0x1: + case 0x2: + case 0x3: + { + // bit 31:22=1101010100, 20:19=11 + bool read = l; + MiscRegIndex miscReg = + decodeAArch64SysReg(op0, op1, crn, crm, op2); + if (read) { + if ((miscReg == MISCREG_DC_CIVAC_Xt) || + (miscReg == MISCREG_DC_CVAC_Xt) || + (miscReg == MISCREG_DC_ZVA_Xt)) { + return new Unknown64(machInst); + } + } + // Check for invalid registers + if (miscReg == MISCREG_UNKNOWN) { + return new Unknown64(machInst); + } else if (miscRegInfo[miscReg][MISCREG_IMPLEMENTED]) { + if (miscReg == MISCREG_NZCV) { + if (read) + return new MrsNZCV64(machInst, rt, (IntRegIndex) miscReg); + else + return new MsrNZCV64(machInst, (IntRegIndex) miscReg, rt); + } + uint32_t iss = msrMrs64IssBuild(read, op0, op1, crn, crm, op2, rt); + if (miscReg == MISCREG_DC_ZVA_Xt && !read) + return new Dczva(machInst, rt, (IntRegIndex) miscReg, iss); + + if (read) + return new Mrs64(machInst, rt, (IntRegIndex) miscReg, iss); + else + return new Msr64(machInst, (IntRegIndex) miscReg, rt, iss); + } else if (miscRegInfo[miscReg][MISCREG_WARN_NOT_FAIL]) { + std::string full_mnem = csprintf("%s %s", + read ? "mrs" : "msr", miscRegName[miscReg]); + return new WarnUnimplemented(read ? "mrs" : "msr", + machInst, full_mnem); + } else { + return new FailUnimplemented(csprintf("%s %s", + read ? "mrs" : "msr", miscRegName[miscReg]).c_str(), + machInst); + } + } + break; + } + } else if (bits(machInst, 25) == 0x1) { + uint8_t opc = bits(machInst, 24, 21); + uint8_t op2 = bits(machInst, 20, 16); + uint8_t op3 = bits(machInst, 15, 10); + IntRegIndex rn = (IntRegIndex)(uint8_t)bits(machInst, 9, 5); + uint8_t op4 = bits(machInst, 4, 0); + if (op2 != 0x1f || op3 != 0x0 || op4 != 0x0) + return new Unknown64(machInst); + switch (opc) { + case 0x0: + return new Br64(machInst, rn); + case 0x1: + return new Blr64(machInst, rn); + case 0x2: + return new Ret64(machInst, rn); + case 0x4: + if (rn != 0x1f) + return new Unknown64(machInst); + return new Eret64(machInst); + case 0x5: + if (rn != 0x1f) + return new Unknown64(machInst); + return new FailUnimplemented("dret", machInst); + } + } + default: + return new Unknown64(machInst); + } + return new FailUnimplemented("Unhandled Case7", machInst); + } +} +}}; + +output decoder {{ +namespace Aarch64 +{ + StaticInstPtr + decodeLoadsStores(ExtMachInst machInst) + { + // bit 27,25=10 + switch (bits(machInst, 29, 28)) { + case 0x0: + if (bits(machInst, 26) == 0) { + if (bits(machInst, 24) != 0) + return new Unknown64(machInst); + IntRegIndex rt = (IntRegIndex)(uint8_t)bits(machInst, 4, 0); + IntRegIndex rn = (IntRegIndex)(uint8_t)bits(machInst, 9, 5); + IntRegIndex rnsp = makeSP(rn); + IntRegIndex rt2 = (IntRegIndex)(uint8_t)bits(machInst, 14, 10); + IntRegIndex rs = (IntRegIndex)(uint8_t)bits(machInst, 20, 16); + uint8_t opc = (bits(machInst, 15) << 0) | + (bits(machInst, 23, 21) << 1); + uint8_t size = bits(machInst, 31, 30); + switch (opc) { + case 0x0: + switch (size) { + case 0x0: + return new STXRB64(machInst, rt, rnsp, rs); + case 0x1: + return new STXRH64(machInst, rt, rnsp, rs); + case 0x2: + return new STXRW64(machInst, rt, rnsp, rs); + case 0x3: + return new STXRX64(machInst, rt, rnsp, rs); + } + case 0x1: + switch (size) { + case 0x0: + return new STLXRB64(machInst, rt, rnsp, rs); + case 0x1: + return new STLXRH64(machInst, rt, rnsp, rs); + case 0x2: + return new STLXRW64(machInst, rt, rnsp, rs); + case 0x3: + return new STLXRX64(machInst, rt, rnsp, rs); + } + case 0x2: + switch (size) { + case 0x0: + case 0x1: + return new Unknown64(machInst); + case 0x2: + return new STXPW64(machInst, rs, rt, rt2, rnsp); + case 0x3: + return new STXPX64(machInst, rs, rt, rt2, rnsp); + } + + case 0x3: + switch (size) { + case 0x0: + case 0x1: + return new Unknown64(machInst); + case 0x2: + return new STLXPW64(machInst, rs, rt, rt2, rnsp); + case 0x3: + return new STLXPX64(machInst, rs, rt, rt2, rnsp); + } + + case 0x4: + switch (size) { + case 0x0: + return new LDXRB64(machInst, rt, rnsp, rs); + case 0x1: + return new LDXRH64(machInst, rt, rnsp, rs); + case 0x2: + return new LDXRW64(machInst, rt, rnsp, rs); + case 0x3: + return new LDXRX64(machInst, rt, rnsp, rs); + } + case 0x5: + switch (size) { + case 0x0: + return new LDAXRB64(machInst, rt, rnsp, rs); + case 0x1: + return new LDAXRH64(machInst, rt, rnsp, rs); + case 0x2: + return new LDAXRW64(machInst, rt, rnsp, rs); + case 0x3: + return new LDAXRX64(machInst, rt, rnsp, rs); + } + case 0x6: + switch (size) { + case 0x0: + case 0x1: + return new Unknown64(machInst); + case 0x2: + return new LDXPW64(machInst, rt, rt2, rnsp); + case 0x3: + return new LDXPX64(machInst, rt, rt2, rnsp); + } + + case 0x7: + switch (size) { + case 0x0: + case 0x1: + return new Unknown64(machInst); + case 0x2: + return new LDAXPW64(machInst, rt, rt2, rnsp); + case 0x3: + return new LDAXPX64(machInst, rt, rt2, rnsp); + } + + case 0x9: + switch (size) { + case 0x0: + return new STLRB64(machInst, rt, rnsp); + case 0x1: + return new STLRH64(machInst, rt, rnsp); + case 0x2: + return new STLRW64(machInst, rt, rnsp); + case 0x3: + return new STLRX64(machInst, rt, rnsp); + } + case 0xd: + switch (size) { + case 0x0: + return new LDARB64(machInst, rt, rnsp); + case 0x1: + return new LDARH64(machInst, rt, rnsp); + case 0x2: + return new LDARW64(machInst, rt, rnsp); + case 0x3: + return new LDARX64(machInst, rt, rnsp); + } + default: + return new Unknown64(machInst); + } + } else if (bits(machInst, 31)) { + return new Unknown64(machInst); + } else { + return decodeNeonMem(machInst); + } + case 0x1: + { + if (bits(machInst, 24) != 0) + return new Unknown64(machInst); + uint8_t switchVal = (bits(machInst, 26) << 0) | + (bits(machInst, 31, 30) << 1); + int64_t imm = sext<19>(bits(machInst, 23, 5)) << 2; + IntRegIndex rt = (IntRegIndex)(uint32_t)bits(machInst, 4, 0); + switch (switchVal) { + case 0x0: + return new LDRWL64_LIT(machInst, rt, imm); + case 0x1: + return new LDRSFP64_LIT(machInst, rt, imm); + case 0x2: + return new LDRXL64_LIT(machInst, rt, imm); + case 0x3: + return new LDRDFP64_LIT(machInst, rt, imm); + case 0x4: + return new LDRSWL64_LIT(machInst, rt, imm); + case 0x5: + return new BigFpMemLit("ldr", machInst, rt, imm); + case 0x6: + return new PRFM64_LIT(machInst, rt, imm); + default: + return new Unknown64(machInst); + } + } + case 0x2: + { + uint8_t opc = bits(machInst, 31, 30); + if (opc >= 3) + return new Unknown64(machInst); + uint32_t size = 0; + bool fp = bits(machInst, 26); + bool load = bits(machInst, 22); + if (fp) { + size = 4 << opc; + } else { + if ((opc == 1) && !load) + return new Unknown64(machInst); + size = (opc == 0 || opc == 1) ? 4 : 8; + } + uint8_t type = bits(machInst, 24, 23); + int64_t imm = sext<7>(bits(machInst, 21, 15)) * size; + + IntRegIndex rn = (IntRegIndex)(uint8_t)bits(machInst, 9, 5); + IntRegIndex rt = (IntRegIndex)(uint8_t)bits(machInst, 4, 0); + IntRegIndex rt2 = (IntRegIndex)(uint8_t)bits(machInst, 14, 10); + + bool noAlloc = (type == 0); + bool signExt = !noAlloc && !fp && opc == 1; + PairMemOp::AddrMode mode; + const char *mnemonic = NULL; + switch (type) { + case 0x0: + case 0x2: + mode = PairMemOp::AddrMd_Offset; + break; + case 0x1: + mode = PairMemOp::AddrMd_PostIndex; + break; + case 0x3: + mode = PairMemOp::AddrMd_PreIndex; + break; + default: + return new Unknown64(machInst); + } + if (load) { + if (noAlloc) + mnemonic = "ldnp"; + else if (signExt) + mnemonic = "ldpsw"; + else + mnemonic = "ldp"; + } else { + if (noAlloc) + mnemonic = "stnp"; + else + mnemonic = "stp"; + } + + return new LdpStp(mnemonic, machInst, size, fp, load, noAlloc, + signExt, false, false, imm, mode, rn, rt, rt2); + } + // bit 29:27=111, 25=0 + case 0x3: + { + uint8_t switchVal = (bits(machInst, 23, 22) << 0) | + (bits(machInst, 26) << 2) | + (bits(machInst, 31, 30) << 3); + if (bits(machInst, 24) == 1) { + uint64_t imm12 = bits(machInst, 21, 10); + IntRegIndex rt = (IntRegIndex)(uint32_t)bits(machInst, 4, 0); + IntRegIndex rn = (IntRegIndex)(uint32_t)bits(machInst, 9, 5); + IntRegIndex rnsp = makeSP(rn); + switch (switchVal) { + case 0x00: + return new STRB64_IMM(machInst, rt, rnsp, imm12); + case 0x01: + return new LDRB64_IMM(machInst, rt, rnsp, imm12); + case 0x02: + return new LDRSBX64_IMM(machInst, rt, rnsp, imm12); + case 0x03: + return new LDRSBW64_IMM(machInst, rt, rnsp, imm12); + case 0x04: + return new STRBFP64_IMM(machInst, rt, rnsp, imm12); + case 0x05: + return new LDRBFP64_IMM(machInst, rt, rnsp, imm12); + case 0x06: + return new BigFpMemImm("str", machInst, false, + rt, rnsp, imm12 << 4); + case 0x07: + return new BigFpMemImm("ldr", machInst, true, + rt, rnsp, imm12 << 4); + case 0x08: + return new STRH64_IMM(machInst, rt, rnsp, imm12 << 1); + case 0x09: + return new LDRH64_IMM(machInst, rt, rnsp, imm12 << 1); + case 0x0a: + return new LDRSHX64_IMM(machInst, rt, rnsp, imm12 << 1); + case 0x0b: + return new LDRSHW64_IMM(machInst, rt, rnsp, imm12 << 1); + case 0x0c: + return new STRHFP64_IMM(machInst, rt, rnsp, imm12 << 1); + case 0x0d: + return new LDRHFP64_IMM(machInst, rt, rnsp, imm12 << 1); + case 0x10: + return new STRW64_IMM(machInst, rt, rnsp, imm12 << 2); + case 0x11: + return new LDRW64_IMM(machInst, rt, rnsp, imm12 << 2); + case 0x12: + return new LDRSW64_IMM(machInst, rt, rnsp, imm12 << 2); + case 0x14: + return new STRSFP64_IMM(machInst, rt, rnsp, imm12 << 2); + case 0x15: + return new LDRSFP64_IMM(machInst, rt, rnsp, imm12 << 2); + case 0x18: + return new STRX64_IMM(machInst, rt, rnsp, imm12 << 3); + case 0x19: + return new LDRX64_IMM(machInst, rt, rnsp, imm12 << 3); + case 0x1a: + return new PRFM64_IMM(machInst, rt, rnsp, imm12 << 3); + case 0x1c: + return new STRDFP64_IMM(machInst, rt, rnsp, imm12 << 3); + case 0x1d: + return new LDRDFP64_IMM(machInst, rt, rnsp, imm12 << 3); + default: + return new Unknown64(machInst); + } + } else if (bits(machInst, 21) == 1) { + if (bits(machInst, 11, 10) != 0x2) + return new Unknown64(machInst); + if (!bits(machInst, 14)) + return new Unknown64(machInst); + IntRegIndex rt = (IntRegIndex)(uint32_t)bits(machInst, 4, 0); + IntRegIndex rn = (IntRegIndex)(uint32_t)bits(machInst, 9, 5); + IntRegIndex rnsp = makeSP(rn); + IntRegIndex rm = (IntRegIndex)(uint32_t)bits(machInst, 20, 16); + ArmExtendType type = + (ArmExtendType)(uint32_t)bits(machInst, 15, 13); + uint8_t s = bits(machInst, 12); + switch (switchVal) { + case 0x00: + return new STRB64_REG(machInst, rt, rnsp, rm, type, 0); + case 0x01: + return new LDRB64_REG(machInst, rt, rnsp, rm, type, 0); + case 0x02: + return new LDRSBX64_REG(machInst, rt, rnsp, rm, type, 0); + case 0x03: + return new LDRSBW64_REG(machInst, rt, rnsp, rm, type, 0); + case 0x04: + return new STRBFP64_REG(machInst, rt, rnsp, rm, type, 0); + case 0x05: + return new LDRBFP64_REG(machInst, rt, rnsp, rm, type, 0); + case 0x6: + return new BigFpMemReg("str", machInst, false, + rt, rnsp, rm, type, s * 4); + case 0x7: + return new BigFpMemReg("ldr", machInst, true, + rt, rnsp, rm, type, s * 4); + case 0x08: + return new STRH64_REG(machInst, rt, rnsp, rm, type, s); + case 0x09: + return new LDRH64_REG(machInst, rt, rnsp, rm, type, s); + case 0x0a: + return new LDRSHX64_REG(machInst, rt, rnsp, rm, type, s); + case 0x0b: + return new LDRSHW64_REG(machInst, rt, rnsp, rm, type, s); + case 0x0c: + return new STRHFP64_REG(machInst, rt, rnsp, rm, type, s); + case 0x0d: + return new LDRHFP64_REG(machInst, rt, rnsp, rm, type, s); + case 0x10: + return new STRW64_REG(machInst, rt, rnsp, rm, type, s * 2); + case 0x11: + return new LDRW64_REG(machInst, rt, rnsp, rm, type, s * 2); + case 0x12: + return new LDRSW64_REG(machInst, rt, rnsp, rm, type, s * 2); + case 0x14: + return new STRSFP64_REG(machInst, rt, rnsp, rm, type, s * 2); + case 0x15: + return new LDRSFP64_REG(machInst, rt, rnsp, rm, type, s * 2); + case 0x18: + return new STRX64_REG(machInst, rt, rnsp, rm, type, s * 3); + case 0x19: + return new LDRX64_REG(machInst, rt, rnsp, rm, type, s * 3); + case 0x1a: + return new PRFM64_REG(machInst, rt, rnsp, rm, type, s * 3); + case 0x1c: + return new STRDFP64_REG(machInst, rt, rnsp, rm, type, s * 3); + case 0x1d: + return new LDRDFP64_REG(machInst, rt, rnsp, rm, type, s * 3); + default: + return new Unknown64(machInst); + } + } else { + // bit 29:27=111, 25:24=00, 21=0 + switch (bits(machInst, 11, 10)) { + case 0x0: + { + IntRegIndex rt = + (IntRegIndex)(uint32_t)bits(machInst, 4, 0); + IntRegIndex rn = + (IntRegIndex)(uint32_t)bits(machInst, 9, 5); + IntRegIndex rnsp = makeSP(rn); + uint64_t imm = sext<9>(bits(machInst, 20, 12)); + switch (switchVal) { + case 0x00: + return new STURB64_IMM(machInst, rt, rnsp, imm); + case 0x01: + return new LDURB64_IMM(machInst, rt, rnsp, imm); + case 0x02: + return new LDURSBX64_IMM(machInst, rt, rnsp, imm); + case 0x03: + return new LDURSBW64_IMM(machInst, rt, rnsp, imm); + case 0x04: + return new STURBFP64_IMM(machInst, rt, rnsp, imm); + case 0x05: + return new LDURBFP64_IMM(machInst, rt, rnsp, imm); + case 0x06: + return new BigFpMemImm("stur", machInst, false, + rt, rnsp, imm); + case 0x07: + return new BigFpMemImm("ldur", machInst, true, + rt, rnsp, imm); + case 0x08: + return new STURH64_IMM(machInst, rt, rnsp, imm); + case 0x09: + return new LDURH64_IMM(machInst, rt, rnsp, imm); + case 0x0a: + return new LDURSHX64_IMM(machInst, rt, rnsp, imm); + case 0x0b: + return new LDURSHW64_IMM(machInst, rt, rnsp, imm); + case 0x0c: + return new STURHFP64_IMM(machInst, rt, rnsp, imm); + case 0x0d: + return new LDURHFP64_IMM(machInst, rt, rnsp, imm); + case 0x10: + return new STURW64_IMM(machInst, rt, rnsp, imm); + case 0x11: + return new LDURW64_IMM(machInst, rt, rnsp, imm); + case 0x12: + return new LDURSW64_IMM(machInst, rt, rnsp, imm); + case 0x14: + return new STURSFP64_IMM(machInst, rt, rnsp, imm); + case 0x15: + return new LDURSFP64_IMM(machInst, rt, rnsp, imm); + case 0x18: + return new STURX64_IMM(machInst, rt, rnsp, imm); + case 0x19: + return new LDURX64_IMM(machInst, rt, rnsp, imm); + case 0x1a: + return new PRFUM64_IMM(machInst, rt, rnsp, imm); + case 0x1c: + return new STURDFP64_IMM(machInst, rt, rnsp, imm); + case 0x1d: + return new LDURDFP64_IMM(machInst, rt, rnsp, imm); + default: + return new Unknown64(machInst); + } + } + // bit 29:27=111, 25:24=00, 21=0, 11:10=01 + case 0x1: + { + IntRegIndex rt = + (IntRegIndex)(uint32_t)bits(machInst, 4, 0); + IntRegIndex rn = + (IntRegIndex)(uint32_t)bits(machInst, 9, 5); + IntRegIndex rnsp = makeSP(rn); + uint64_t imm = sext<9>(bits(machInst, 20, 12)); + switch (switchVal) { + case 0x00: + return new STRB64_POST(machInst, rt, rnsp, imm); + case 0x01: + return new LDRB64_POST(machInst, rt, rnsp, imm); + case 0x02: + return new LDRSBX64_POST(machInst, rt, rnsp, imm); + case 0x03: + return new LDRSBW64_POST(machInst, rt, rnsp, imm); + case 0x04: + return new STRBFP64_POST(machInst, rt, rnsp, imm); + case 0x05: + return new LDRBFP64_POST(machInst, rt, rnsp, imm); + case 0x06: + return new BigFpMemPost("str", machInst, false, + rt, rnsp, imm); + case 0x07: + return new BigFpMemPost("ldr", machInst, true, + rt, rnsp, imm); + case 0x08: + return new STRH64_POST(machInst, rt, rnsp, imm); + case 0x09: + return new LDRH64_POST(machInst, rt, rnsp, imm); + case 0x0a: + return new LDRSHX64_POST(machInst, rt, rnsp, imm); + case 0x0b: + return new LDRSHW64_POST(machInst, rt, rnsp, imm); + case 0x0c: + return new STRHFP64_POST(machInst, rt, rnsp, imm); + case 0x0d: + return new LDRHFP64_POST(machInst, rt, rnsp, imm); + case 0x10: + return new STRW64_POST(machInst, rt, rnsp, imm); + case 0x11: + return new LDRW64_POST(machInst, rt, rnsp, imm); + case 0x12: + return new LDRSW64_POST(machInst, rt, rnsp, imm); + case 0x14: + return new STRSFP64_POST(machInst, rt, rnsp, imm); + case 0x15: + return new LDRSFP64_POST(machInst, rt, rnsp, imm); + case 0x18: + return new STRX64_POST(machInst, rt, rnsp, imm); + case 0x19: + return new LDRX64_POST(machInst, rt, rnsp, imm); + case 0x1c: + return new STRDFP64_POST(machInst, rt, rnsp, imm); + case 0x1d: + return new LDRDFP64_POST(machInst, rt, rnsp, imm); + default: + return new Unknown64(machInst); + } + } + case 0x2: + { + IntRegIndex rt = + (IntRegIndex)(uint32_t)bits(machInst, 4, 0); + IntRegIndex rn = + (IntRegIndex)(uint32_t)bits(machInst, 9, 5); + IntRegIndex rnsp = makeSP(rn); + uint64_t imm = sext<9>(bits(machInst, 20, 12)); + switch (switchVal) { + case 0x00: + return new STTRB64_IMM(machInst, rt, rnsp, imm); + case 0x01: + return new LDTRB64_IMM(machInst, rt, rnsp, imm); + case 0x02: + return new LDTRSBX64_IMM(machInst, rt, rnsp, imm); + case 0x03: + return new LDTRSBW64_IMM(machInst, rt, rnsp, imm); + case 0x08: + return new STTRH64_IMM(machInst, rt, rnsp, imm); + case 0x09: + return new LDTRH64_IMM(machInst, rt, rnsp, imm); + case 0x0a: + return new LDTRSHX64_IMM(machInst, rt, rnsp, imm); + case 0x0b: + return new LDTRSHW64_IMM(machInst, rt, rnsp, imm); + case 0x10: + return new STTRW64_IMM(machInst, rt, rnsp, imm); + case 0x11: + return new LDTRW64_IMM(machInst, rt, rnsp, imm); + case 0x12: + return new LDTRSW64_IMM(machInst, rt, rnsp, imm); + case 0x18: + return new STTRX64_IMM(machInst, rt, rnsp, imm); + case 0x19: + return new LDTRX64_IMM(machInst, rt, rnsp, imm); + default: + return new Unknown64(machInst); + } + } + case 0x3: + { + IntRegIndex rt = + (IntRegIndex)(uint32_t)bits(machInst, 4, 0); + IntRegIndex rn = + (IntRegIndex)(uint32_t)bits(machInst, 9, 5); + IntRegIndex rnsp = makeSP(rn); + uint64_t imm = sext<9>(bits(machInst, 20, 12)); + switch (switchVal) { + case 0x00: + return new STRB64_PRE(machInst, rt, rnsp, imm); + case 0x01: + return new LDRB64_PRE(machInst, rt, rnsp, imm); + case 0x02: + return new LDRSBX64_PRE(machInst, rt, rnsp, imm); + case 0x03: + return new LDRSBW64_PRE(machInst, rt, rnsp, imm); + case 0x04: + return new STRBFP64_PRE(machInst, rt, rnsp, imm); + case 0x05: + return new LDRBFP64_PRE(machInst, rt, rnsp, imm); + case 0x06: + return new BigFpMemPre("str", machInst, false, + rt, rnsp, imm); + case 0x07: + return new BigFpMemPre("ldr", machInst, true, + rt, rnsp, imm); + case 0x08: + return new STRH64_PRE(machInst, rt, rnsp, imm); + case 0x09: + return new LDRH64_PRE(machInst, rt, rnsp, imm); + case 0x0a: + return new LDRSHX64_PRE(machInst, rt, rnsp, imm); + case 0x0b: + return new LDRSHW64_PRE(machInst, rt, rnsp, imm); + case 0x0c: + return new STRHFP64_PRE(machInst, rt, rnsp, imm); + case 0x0d: + return new LDRHFP64_PRE(machInst, rt, rnsp, imm); + case 0x10: + return new STRW64_PRE(machInst, rt, rnsp, imm); + case 0x11: + return new LDRW64_PRE(machInst, rt, rnsp, imm); + case 0x12: + return new LDRSW64_PRE(machInst, rt, rnsp, imm); + case 0x14: + return new STRSFP64_PRE(machInst, rt, rnsp, imm); + case 0x15: + return new LDRSFP64_PRE(machInst, rt, rnsp, imm); + case 0x18: + return new STRX64_PRE(machInst, rt, rnsp, imm); + case 0x19: + return new LDRX64_PRE(machInst, rt, rnsp, imm); + case 0x1c: + return new STRDFP64_PRE(machInst, rt, rnsp, imm); + case 0x1d: + return new LDRDFP64_PRE(machInst, rt, rnsp, imm); + default: + return new Unknown64(machInst); + } + } + } + } + } + } + return new FailUnimplemented("Unhandled Case1", machInst); + } +} +}}; + +output decoder {{ +namespace Aarch64 +{ + StaticInstPtr + decodeDataProcReg(ExtMachInst machInst) + { + uint8_t switchVal = (bits(machInst, 28) << 1) | + (bits(machInst, 24) << 0); + switch (switchVal) { + case 0x0: + { + uint8_t switchVal = (bits(machInst, 21) << 0) | + (bits(machInst, 30, 29) << 1); + ArmShiftType type = (ArmShiftType)(uint8_t)bits(machInst, 23, 22); + uint8_t imm6 = bits(machInst, 15, 10); + bool sf = bits(machInst, 31); + if (!sf && (imm6 & 0x20)) + return new Unknown64(machInst); + IntRegIndex rd = (IntRegIndex)(uint8_t)bits(machInst, 4, 0); + IntRegIndex rn = (IntRegIndex)(uint8_t)bits(machInst, 9, 5); + IntRegIndex rm = (IntRegIndex)(uint8_t)bits(machInst, 20, 16); + + switch (switchVal) { + case 0x0: + return new AndXSReg(machInst, rd, rn, rm, imm6, type); + case 0x1: + return new BicXSReg(machInst, rd, rn, rm, imm6, type); + case 0x2: + return new OrrXSReg(machInst, rd, rn, rm, imm6, type); + case 0x3: + return new OrnXSReg(machInst, rd, rn, rm, imm6, type); + case 0x4: + return new EorXSReg(machInst, rd, rn, rm, imm6, type); + case 0x5: + return new EonXSReg(machInst, rd, rn, rm, imm6, type); + case 0x6: + return new AndXSRegCc(machInst, rd, rn, rm, imm6, type); + case 0x7: + return new BicXSRegCc(machInst, rd, rn, rm, imm6, type); + } + } + case 0x1: + { + uint8_t switchVal = bits(machInst, 30, 29); + if (bits(machInst, 21) == 0) { + ArmShiftType type = + (ArmShiftType)(uint8_t)bits(machInst, 23, 22); + if (type == ROR) + return new Unknown64(machInst); + uint8_t imm6 = bits(machInst, 15, 10); + if (!bits(machInst, 31) && bits(imm6, 5)) + return new Unknown64(machInst); + IntRegIndex rd = (IntRegIndex)(uint8_t)bits(machInst, 4, 0); + IntRegIndex rn = (IntRegIndex)(uint8_t)bits(machInst, 9, 5); + IntRegIndex rm = (IntRegIndex)(uint8_t)bits(machInst, 20, 16); + switch (switchVal) { + case 0x0: + return new AddXSReg(machInst, rd, rn, rm, imm6, type); + case 0x1: + return new AddXSRegCc(machInst, rd, rn, rm, imm6, type); + case 0x2: + return new SubXSReg(machInst, rd, rn, rm, imm6, type); + case 0x3: + return new SubXSRegCc(machInst, rd, rn, rm, imm6, type); + } + } else { + if (bits(machInst, 23, 22) != 0 || bits(machInst, 12, 10) > 0x4) + return new Unknown64(machInst); + ArmExtendType type = + (ArmExtendType)(uint8_t)bits(machInst, 15, 13); + uint8_t imm3 = bits(machInst, 12, 10); + IntRegIndex rd = (IntRegIndex)(uint8_t)bits(machInst, 4, 0); + IntRegIndex rdsp = makeSP(rd); + IntRegIndex rn = (IntRegIndex)(uint8_t)bits(machInst, 9, 5); + IntRegIndex rnsp = makeSP(rn); + IntRegIndex rm = (IntRegIndex)(uint8_t)bits(machInst, 20, 16); + + switch (switchVal) { + case 0x0: + return new AddXEReg(machInst, rdsp, rnsp, rm, type, imm3); + case 0x1: + return new AddXERegCc(machInst, rd, rnsp, rm, type, imm3); + case 0x2: + return new SubXEReg(machInst, rdsp, rnsp, rm, type, imm3); + case 0x3: + return new SubXERegCc(machInst, rd, rnsp, rm, type, imm3); + } + } + } + case 0x2: + { + if (bits(machInst, 21) == 1) + return new Unknown64(machInst); + IntRegIndex rd = (IntRegIndex)(uint8_t)bits(machInst, 4, 0); + IntRegIndex rn = (IntRegIndex)(uint8_t)bits(machInst, 9, 5); + IntRegIndex rm = (IntRegIndex)(uint8_t)bits(machInst, 20, 16); + switch (bits(machInst, 23, 22)) { + case 0x0: + { + if (bits(machInst, 15, 10)) + return new Unknown64(machInst); + uint8_t switchVal = bits(machInst, 30, 29); + switch (switchVal) { + case 0x0: + return new AdcXSReg(machInst, rd, rn, rm, 0, LSL); + case 0x1: + return new AdcXSRegCc(machInst, rd, rn, rm, 0, LSL); + case 0x2: + return new SbcXSReg(machInst, rd, rn, rm, 0, LSL); + case 0x3: + return new SbcXSRegCc(machInst, rd, rn, rm, 0, LSL); + } + } + case 0x1: + { + if ((bits(machInst, 4) == 1) || + (bits(machInst, 10) == 1) || + (bits(machInst, 29) == 0)) { + return new Unknown64(machInst); + } + ConditionCode cond = + (ConditionCode)(uint8_t)bits(machInst, 15, 12); + uint8_t flags = bits(machInst, 3, 0); + IntRegIndex rn = (IntRegIndex)(uint8_t)bits(machInst, 9, 5); + if (bits(machInst, 11) == 0) { + IntRegIndex rm = + (IntRegIndex)(uint8_t)bits(machInst, 20, 16); + if (bits(machInst, 30) == 0) { + return new CcmnReg64(machInst, rn, rm, cond, flags); + } else { + return new CcmpReg64(machInst, rn, rm, cond, flags); + } + } else { + uint8_t imm5 = bits(machInst, 20, 16); + if (bits(machInst, 30) == 0) { + return new CcmnImm64(machInst, rn, imm5, cond, flags); + } else { + return new CcmpImm64(machInst, rn, imm5, cond, flags); + } + } + } + case 0x2: + { + if (bits(machInst, 29) == 1 || + bits(machInst, 11) == 1) { + return new Unknown64(machInst); + } + uint8_t switchVal = (bits(machInst, 10) << 0) | + (bits(machInst, 30) << 1); + IntRegIndex rd = (IntRegIndex)(uint8_t)bits(machInst, 4, 0); + IntRegIndex rn = (IntRegIndex)(uint8_t)bits(machInst, 9, 5); + IntRegIndex rm = (IntRegIndex)(uint8_t)bits(machInst, 20, 16); + ConditionCode cond = + (ConditionCode)(uint8_t)bits(machInst, 15, 12); + switch (switchVal) { + case 0x0: + return new Csel64(machInst, rd, rn, rm, cond); + case 0x1: + return new Csinc64(machInst, rd, rn, rm, cond); + case 0x2: + return new Csinv64(machInst, rd, rn, rm, cond); + case 0x3: + return new Csneg64(machInst, rd, rn, rm, cond); + } + } + case 0x3: + if (bits(machInst, 30) == 0) { + if (bits(machInst, 29) != 0) + return new Unknown64(machInst); + uint8_t switchVal = bits(machInst, 15, 10); + switch (switchVal) { + case 0x2: + return new Udiv64(machInst, rd, rn, rm); + case 0x3: + return new Sdiv64(machInst, rd, rn, rm); + case 0x8: + return new Lslv64(machInst, rd, rn, rm); + case 0x9: + return new Lsrv64(machInst, rd, rn, rm); + case 0xa: + return new Asrv64(machInst, rd, rn, rm); + case 0xb: + return new Rorv64(machInst, rd, rn, rm); + default: + return new Unknown64(machInst); + } + } else { + if (bits(machInst, 20, 16) != 0 || + bits(machInst, 29) != 0) { + return new Unknown64(machInst); + } + uint8_t switchVal = bits(machInst, 15, 10); + switch (switchVal) { + case 0x0: + return new Rbit64(machInst, rd, rn); + case 0x1: + return new Rev1664(machInst, rd, rn); + case 0x2: + if (bits(machInst, 31) == 0) + return new Rev64(machInst, rd, rn); + else + return new Rev3264(machInst, rd, rn); + case 0x3: + if (bits(machInst, 31) != 1) + return new Unknown64(machInst); + return new Rev64(machInst, rd, rn); + case 0x4: + return new Clz64(machInst, rd, rn); + case 0x5: + return new Cls64(machInst, rd, rn); + } + } + } + } + case 0x3: + { + if (bits(machInst, 30, 29) != 0x0 || + (bits(machInst, 23, 21) != 0 && bits(machInst, 31) == 0)) + return new Unknown64(machInst); + IntRegIndex rd = (IntRegIndex)(uint8_t)bits(machInst, 4, 0); + IntRegIndex rn = (IntRegIndex)(uint8_t)bits(machInst, 9, 5); + IntRegIndex ra = (IntRegIndex)(uint8_t)bits(machInst, 14, 10); + IntRegIndex rm = (IntRegIndex)(uint8_t)bits(machInst, 20, 16); + switch (bits(machInst, 23, 21)) { + case 0x0: + if (bits(machInst, 15) == 0) + return new Madd64(machInst, rd, ra, rn, rm); + else + return new Msub64(machInst, rd, ra, rn, rm); + case 0x1: + if (bits(machInst, 15) == 0) + return new Smaddl64(machInst, rd, ra, rn, rm); + else + return new Smsubl64(machInst, rd, ra, rn, rm); + case 0x2: + if (bits(machInst, 15) != 0) + return new Unknown64(machInst); + return new Smulh64(machInst, rd, rn, rm); + case 0x5: + if (bits(machInst, 15) == 0) + return new Umaddl64(machInst, rd, ra, rn, rm); + else + return new Umsubl64(machInst, rd, ra, rn, rm); + case 0x6: + if (bits(machInst, 15) != 0) + return new Unknown64(machInst); + return new Umulh64(machInst, rd, rn, rm); + default: + return new Unknown64(machInst); + } + } + } + return new FailUnimplemented("Unhandled Case2", machInst); + } +} +}}; + +output decoder {{ +namespace Aarch64 +{ + StaticInstPtr + decodeAdvSIMD(ExtMachInst machInst) + { + if (bits(machInst, 24) == 1) { + if (bits(machInst, 10) == 0) { + return decodeNeonIndexedElem(machInst); + } else if (bits(machInst, 23) == 1) { + return new Unknown64(machInst); + } else { + if (bits(machInst, 22, 19)) { + return decodeNeonShiftByImm(machInst); + } else { + return decodeNeonModImm(machInst); + } + } + } else if (bits(machInst, 21) == 1) { + if (bits(machInst, 10) == 1) { + return decodeNeon3Same(machInst); + } else if (bits(machInst, 11) == 0) { + return decodeNeon3Diff(machInst); + } else if (bits(machInst, 20, 17) == 0x0) { + return decodeNeon2RegMisc(machInst); + } else if (bits(machInst, 20, 17) == 0x8) { + return decodeNeonAcrossLanes(machInst); + } else { + return new Unknown64(machInst); + } + } else if (bits(machInst, 24) || + bits(machInst, 21) || + bits(machInst, 15)) { + return new Unknown64(machInst); + } else if (bits(machInst, 10) == 1) { + if (bits(machInst, 23, 22)) + return new Unknown64(machInst); + return decodeNeonCopy(machInst); + } else if (bits(machInst, 29) == 1) { + return decodeNeonExt(machInst); + } else if (bits(machInst, 11) == 1) { + return decodeNeonZipUzpTrn(machInst); + } else if (bits(machInst, 23, 22) == 0x0) { + return decodeNeonTblTbx(machInst); + } else { + return new Unknown64(machInst); + } + return new FailUnimplemented("Unhandled Case3", machInst); + } +} +}}; + + +output decoder {{ +namespace Aarch64 +{ + StaticInstPtr + // bit 30=0, 28:25=1111 + decodeFp(ExtMachInst machInst) + { + if (bits(machInst, 24) == 1) { + if (bits(machInst, 31) || bits(machInst, 29)) + return new Unknown64(machInst); + IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 4, 0); + IntRegIndex rn = (IntRegIndex)(uint32_t)bits(machInst, 9, 5); + IntRegIndex rm = (IntRegIndex)(uint32_t)bits(machInst, 20, 16); + IntRegIndex ra = (IntRegIndex)(uint32_t)bits(machInst, 14, 10); + uint8_t switchVal = (bits(machInst, 23, 21) << 1) | + (bits(machInst, 15) << 0); + switch (switchVal) { + case 0x0: // FMADD Sd = Sa + Sn*Sm + return new FMAddS(machInst, rd, rn, rm, ra); + case 0x1: // FMSUB Sd = Sa + (-Sn)*Sm + return new FMSubS(machInst, rd, rn, rm, ra); + case 0x2: // FNMADD Sd = (-Sa) + (-Sn)*Sm + return new FNMAddS(machInst, rd, rn, rm, ra); + case 0x3: // FNMSUB Sd = (-Sa) + Sn*Sm + return new FNMSubS(machInst, rd, rn, rm, ra); + case 0x4: // FMADD Dd = Da + Dn*Dm + return new FMAddD(machInst, rd, rn, rm, ra); + case 0x5: // FMSUB Dd = Da + (-Dn)*Dm + return new FMSubD(machInst, rd, rn, rm, ra); + case 0x6: // FNMADD Dd = (-Da) + (-Dn)*Dm + return new FNMAddD(machInst, rd, rn, rm, ra); + case 0x7: // FNMSUB Dd = (-Da) + Dn*Dm + return new FNMSubD(machInst, rd, rn, rm, ra); + default: + return new Unknown64(machInst); + } + } else if (bits(machInst, 21) == 0) { + bool s = bits(machInst, 29); + if (s) + return new Unknown64(machInst); + uint8_t switchVal = bits(machInst, 20, 16); + uint8_t type = bits(machInst, 23, 22); + uint8_t scale = bits(machInst, 15, 10); + IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 4, 0); + IntRegIndex rn = (IntRegIndex)(uint32_t)bits(machInst, 9, 5); + if (bits(machInst, 18, 17) == 3 && scale != 0) + return new Unknown64(machInst); + // 30:24=0011110, 21=0 + switch (switchVal) { + case 0x00: + return new FailUnimplemented("fcvtns", machInst); + case 0x01: + return new FailUnimplemented("fcvtnu", machInst); + case 0x02: + switch ( (bits(machInst, 31) << 2) | type ) { + case 0: // SCVTF Sd = convertFromInt(Wn/(2^fbits)) + return new FcvtSFixedFpSW(machInst, rd, rn, scale); + case 1: // SCVTF Dd = convertFromInt(Wn/(2^fbits)) + return new FcvtSFixedFpDW(machInst, rd, rn, scale); + case 4: // SCVTF Sd = convertFromInt(Xn/(2^fbits)) + return new FcvtSFixedFpSX(machInst, rd, rn, scale); + case 5: // SCVTF Dd = convertFromInt(Xn/(2^fbits)) + return new FcvtSFixedFpDX(machInst, rd, rn, scale); + default: + return new Unknown64(machInst); + } + case 0x03: + switch ( (bits(machInst, 31) << 2) | type ) { + case 0: // UCVTF Sd = convertFromInt(Wn/(2^fbits)) + return new FcvtUFixedFpSW(machInst, rd, rn, scale); + case 1: // UCVTF Dd = convertFromInt(Wn/(2^fbits)) + return new FcvtUFixedFpDW(machInst, rd, rn, scale); + case 4: // UCVTF Sd = convertFromInt(Xn/(2^fbits)) + return new FcvtUFixedFpSX(machInst, rd, rn, scale); + case 5: // UCVTF Dd = convertFromInt(Xn/(2^fbits)) + return new FcvtUFixedFpDX(machInst, rd, rn, scale); + default: + return new Unknown64(machInst); + } + case 0x04: + return new FailUnimplemented("fcvtas", machInst); + case 0x05: + return new FailUnimplemented("fcvtau", machInst); + case 0x08: + return new FailUnimplemented("fcvtps", machInst); + case 0x09: + return new FailUnimplemented("fcvtpu", machInst); + case 0x0e: + return new FailUnimplemented("fmov elem. to 64", machInst); + case 0x0f: + return new FailUnimplemented("fmov 64 bit", machInst); + case 0x10: + return new FailUnimplemented("fcvtms", machInst); + case 0x11: + return new FailUnimplemented("fcvtmu", machInst); + case 0x18: + switch ( (bits(machInst, 31) << 2) | type ) { + case 0: // FCVTZS Wd = convertToIntExactTowardZero(Sn*(2^fbits)) + return new FcvtFpSFixedSW(machInst, rd, rn, scale); + case 1: // FCVTZS Wd = convertToIntExactTowardZero(Dn*(2^fbits)) + return new FcvtFpSFixedDW(machInst, rd, rn, scale); + case 4: // FCVTZS Xd = convertToIntExactTowardZero(Sn*(2^fbits)) + return new FcvtFpSFixedSX(machInst, rd, rn, scale); + case 5: // FCVTZS Xd = convertToIntExactTowardZero(Dn*(2^fbits)) + return new FcvtFpSFixedDX(machInst, rd, rn, scale); + default: + return new Unknown64(machInst); + } + case 0x19: + switch ( (bits(machInst, 31) << 2) | type ) { + case 0: // FCVTZU Wd = convertToIntExactTowardZero(Sn*(2^fbits)) + return new FcvtFpUFixedSW(machInst, rd, rn, scale); + case 1: // FCVTZU Wd = convertToIntExactTowardZero(Dn*(2^fbits)) + return new FcvtFpUFixedDW(machInst, rd, rn, scale); + case 4: // FCVTZU Xd = convertToIntExactTowardZero(Sn*(2^fbits)) + return new FcvtFpUFixedSX(machInst, rd, rn, scale); + case 5: // FCVTZU Xd = convertToIntExactTowardZero(Dn*(2^fbits)) + return new FcvtFpUFixedDX(machInst, rd, rn, scale); + default: + return new Unknown64(machInst); + } + } + } else { + // 30=0, 28:24=11110, 21=1 + uint8_t type = bits(machInst, 23, 22); + uint8_t imm8 = bits(machInst, 20, 13); + IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 4, 0); + IntRegIndex rn = (IntRegIndex)(uint32_t)bits(machInst, 9, 5); + switch (bits(machInst, 11, 10)) { + case 0x0: + if (bits(machInst, 12) == 1) { + if (bits(machInst, 31) || + bits(machInst, 29) || + bits(machInst, 9, 5)) { + return new Unknown64(machInst); + } + // 31:29=000, 28:24=11110, 21=1, 12:10=100 + if (type == 0) { + // FMOV S[d] = imm8<7>:NOT(imm8<6>):Replicate(imm8<6>,5) + // :imm8<5:0>:Zeros(19) + uint32_t imm = vfp_modified_imm(imm8, false); + return new FmovImmS(machInst, rd, imm); + } else if (type == 1) { + // FMOV D[d] = imm8<7>:NOT(imm8<6>):Replicate(imm8<6>,8) + // :imm8<5:0>:Zeros(48) + uint64_t imm = vfp_modified_imm(imm8, true); + return new FmovImmD(machInst, rd, imm); + } else { + return new Unknown64(machInst); + } + } else if (bits(machInst, 13) == 1) { + if (bits(machInst, 31) || + bits(machInst, 29) || + bits(machInst, 15, 14) || + bits(machInst, 23) || + bits(machInst, 2, 0)) { + return new Unknown64(machInst); + } + uint8_t switchVal = (bits(machInst, 4, 3) << 0) | + (bits(machInst, 22) << 2); + IntRegIndex rm = (IntRegIndex)(uint32_t) + bits(machInst, 20, 16); + // 28:23=000111100, 21=1, 15:10=001000, 2:0=000 + switch (switchVal) { + case 0x0: + // FCMP flags = compareQuiet(Sn,Sm) + return new FCmpRegS(machInst, rn, rm); + case 0x1: + // FCMP flags = compareQuiet(Sn,0.0) + return new FCmpImmS(machInst, rn, 0); + case 0x2: + // FCMPE flags = compareSignaling(Sn,Sm) + return new FCmpERegS(machInst, rn, rm); + case 0x3: + // FCMPE flags = compareSignaling(Sn,0.0) + return new FCmpEImmS(machInst, rn, 0); + case 0x4: + // FCMP flags = compareQuiet(Dn,Dm) + return new FCmpRegD(machInst, rn, rm); + case 0x5: + // FCMP flags = compareQuiet(Dn,0.0) + return new FCmpImmD(machInst, rn, 0); + case 0x6: + // FCMPE flags = compareSignaling(Dn,Dm) + return new FCmpERegD(machInst, rn, rm); + case 0x7: + // FCMPE flags = compareSignaling(Dn,0.0) + return new FCmpEImmD(machInst, rn, 0); + default: + return new Unknown64(machInst); + } + } else if (bits(machInst, 14) == 1) { + if (bits(machInst, 31) || bits(machInst, 29)) + return new Unknown64(machInst); + uint8_t opcode = bits(machInst, 20, 15); + // Bits 31:24=00011110, 21=1, 14:10=10000 + switch (opcode) { + case 0x0: + if (type == 0) + // FMOV Sd = Sn + return new FmovRegS(machInst, rd, rn); + else if (type == 1) + // FMOV Dd = Dn + return new FmovRegD(machInst, rd, rn); + break; + case 0x1: + if (type == 0) + // FABS Sd = abs(Sn) + return new FAbsS(machInst, rd, rn); + else if (type == 1) + // FABS Dd = abs(Dn) + return new FAbsD(machInst, rd, rn); + break; + case 0x2: + if (type == 0) + // FNEG Sd = -Sn + return new FNegS(machInst, rd, rn); + else if (type == 1) + // FNEG Dd = -Dn + return new FNegD(machInst, rd, rn); + break; + case 0x3: + if (type == 0) + // FSQRT Sd = sqrt(Sn) + return new FSqrtS(machInst, rd, rn); + else if (type == 1) + // FSQRT Dd = sqrt(Dn) + return new FSqrtD(machInst, rd, rn); + break; + case 0x4: + if (type == 1) + // FCVT Sd = convertFormat(Dn) + return new FcvtFpDFpS(machInst, rd, rn); + else if (type == 3) + // FCVT Sd = convertFormat(Hn) + return new FcvtFpHFpS(machInst, rd, rn); + break; + case 0x5: + if (type == 0) + // FCVT Dd = convertFormat(Sn) + return new FCvtFpSFpD(machInst, rd, rn); + else if (type == 3) + // FCVT Dd = convertFormat(Hn) + return new FcvtFpHFpD(machInst, rd, rn); + break; + case 0x7: + if (type == 0) + // FCVT Hd = convertFormat(Sn) + return new FcvtFpSFpH(machInst, rd, rn); + else if (type == 1) + // FCVT Hd = convertFormat(Dn) + return new FcvtFpDFpH(machInst, rd, rn); + break; + case 0x8: + if (type == 0) // FRINTN Sd = roundToIntegralTiesToEven(Sn) + return new FRIntNS(machInst, rd, rn); + else if (type == 1) // FRINTN Dd = roundToIntegralTiesToEven(Dn) + return new FRIntND(machInst, rd, rn); + break; + case 0x9: + if (type == 0) // FRINTP Sd = roundToIntegralTowardPlusInf(Sn) + return new FRIntPS(machInst, rd, rn); + else if (type == 1) // FRINTP Dd = roundToIntegralTowardPlusInf(Dn) + return new FRIntPD(machInst, rd, rn); + break; + case 0xa: + if (type == 0) // FRINTM Sd = roundToIntegralTowardMinusInf(Sn) + return new FRIntMS(machInst, rd, rn); + else if (type == 1) // FRINTM Dd = roundToIntegralTowardMinusInf(Dn) + return new FRIntMD(machInst, rd, rn); + break; + case 0xb: + if (type == 0) // FRINTZ Sd = roundToIntegralTowardZero(Sn) + return new FRIntZS(machInst, rd, rn); + else if (type == 1) // FRINTZ Dd = roundToIntegralTowardZero(Dn) + return new FRIntZD(machInst, rd, rn); + break; + case 0xc: + if (type == 0) // FRINTA Sd = roundToIntegralTiesToAway(Sn) + return new FRIntAS(machInst, rd, rn); + else if (type == 1) // FRINTA Dd = roundToIntegralTiesToAway(Dn) + return new FRIntAD(machInst, rd, rn); + break; + case 0xe: + if (type == 0) // FRINTX Sd = roundToIntegralExact(Sn) + return new FRIntXS(machInst, rd, rn); + else if (type == 1) // FRINTX Dd = roundToIntegralExact(Dn) + return new FRIntXD(machInst, rd, rn); + break; + case 0xf: + if (type == 0) // FRINTI Sd = roundToIntegral(Sn) + return new FRIntIS(machInst, rd, rn); + else if (type == 1) // FRINTI Dd = roundToIntegral(Dn) + return new FRIntID(machInst, rd, rn); + break; + default: + return new Unknown64(machInst); + } + return new Unknown64(machInst); + } else if (bits(machInst, 15) == 1) { + return new Unknown64(machInst); + } else { + if (bits(machInst, 29)) + return new Unknown64(machInst); + uint8_t rmode = bits(machInst, 20, 19); + uint8_t switchVal1 = bits(machInst, 18, 16); + uint8_t switchVal2 = (type << 1) | bits(machInst, 31); + // 30:24=0011110, 21=1, 15:10=000000 + switch (switchVal1) { + case 0x0: + switch ((switchVal2 << 2) | rmode) { + case 0x0: //FCVTNS Wd = convertToIntExactTiesToEven(Sn) + return new FcvtFpSIntWSN(machInst, rd, rn); + case 0x1: //FCVTPS Wd = convertToIntExactTowardPlusInf(Sn) + return new FcvtFpSIntWSP(machInst, rd, rn); + case 0x2: //FCVTMS Wd = convertToIntExactTowardMinusInf(Sn) + return new FcvtFpSIntWSM(machInst, rd, rn); + case 0x3: //FCVTZS Wd = convertToIntExactTowardZero(Sn) + return new FcvtFpSIntWSZ(machInst, rd, rn); + case 0x4: //FCVTNS Xd = convertToIntExactTiesToEven(Sn) + return new FcvtFpSIntXSN(machInst, rd, rn); + case 0x5: //FCVTPS Xd = convertToIntExactTowardPlusInf(Sn) + return new FcvtFpSIntXSP(machInst, rd, rn); + case 0x6: //FCVTMS Xd = convertToIntExactTowardMinusInf(Sn) + return new FcvtFpSIntXSM(machInst, rd, rn); + case 0x7: //FCVTZS Xd = convertToIntExactTowardZero(Sn) + return new FcvtFpSIntXSZ(machInst, rd, rn); + case 0x8: //FCVTNS Wd = convertToIntExactTiesToEven(Dn) + return new FcvtFpSIntWDN(machInst, rd, rn); + case 0x9: //FCVTPS Wd = convertToIntExactTowardPlusInf(Dn) + return new FcvtFpSIntWDP(machInst, rd, rn); + case 0xA: //FCVTMS Wd = convertToIntExactTowardMinusInf(Dn) + return new FcvtFpSIntWDM(machInst, rd, rn); + case 0xB: //FCVTZS Wd = convertToIntExactTowardZero(Dn) + return new FcvtFpSIntWDZ(machInst, rd, rn); + case 0xC: //FCVTNS Xd = convertToIntExactTiesToEven(Dn) + return new FcvtFpSIntXDN(machInst, rd, rn); + case 0xD: //FCVTPS Xd = convertToIntExactTowardPlusInf(Dn) + return new FcvtFpSIntXDP(machInst, rd, rn); + case 0xE: //FCVTMS Xd = convertToIntExactTowardMinusInf(Dn) + return new FcvtFpSIntXDM(machInst, rd, rn); + case 0xF: //FCVTZS Xd = convertToIntExactTowardZero(Dn) + return new FcvtFpSIntXDZ(machInst, rd, rn); + default: + return new Unknown64(machInst); + } + case 0x1: + switch ((switchVal2 << 2) | rmode) { + case 0x0: //FCVTNU Wd = convertToIntExactTiesToEven(Sn) + return new FcvtFpUIntWSN(machInst, rd, rn); + case 0x1: //FCVTPU Wd = convertToIntExactTowardPlusInf(Sn) + return new FcvtFpUIntWSP(machInst, rd, rn); + case 0x2: //FCVTMU Wd = convertToIntExactTowardMinusInf(Sn) + return new FcvtFpUIntWSM(machInst, rd, rn); + case 0x3: //FCVTZU Wd = convertToIntExactTowardZero(Sn) + return new FcvtFpUIntWSZ(machInst, rd, rn); + case 0x4: //FCVTNU Xd = convertToIntExactTiesToEven(Sn) + return new FcvtFpUIntXSN(machInst, rd, rn); + case 0x5: //FCVTPU Xd = convertToIntExactTowardPlusInf(Sn) + return new FcvtFpUIntXSP(machInst, rd, rn); + case 0x6: //FCVTMU Xd = convertToIntExactTowardMinusInf(Sn) + return new FcvtFpUIntXSM(machInst, rd, rn); + case 0x7: //FCVTZU Xd = convertToIntExactTowardZero(Sn) + return new FcvtFpUIntXSZ(machInst, rd, rn); + case 0x8: //FCVTNU Wd = convertToIntExactTiesToEven(Dn) + return new FcvtFpUIntWDN(machInst, rd, rn); + case 0x9: //FCVTPU Wd = convertToIntExactTowardPlusInf(Dn) + return new FcvtFpUIntWDP(machInst, rd, rn); + case 0xA: //FCVTMU Wd = convertToIntExactTowardMinusInf(Dn) + return new FcvtFpUIntWDM(machInst, rd, rn); + case 0xB: //FCVTZU Wd = convertToIntExactTowardZero(Dn) + return new FcvtFpUIntWDZ(machInst, rd, rn); + case 0xC: //FCVTNU Xd = convertToIntExactTiesToEven(Dn) + return new FcvtFpUIntXDN(machInst, rd, rn); + case 0xD: //FCVTPU Xd = convertToIntExactTowardPlusInf(Dn) + return new FcvtFpUIntXDP(machInst, rd, rn); + case 0xE: //FCVTMU Xd = convertToIntExactTowardMinusInf(Dn) + return new FcvtFpUIntXDM(machInst, rd, rn); + case 0xF: //FCVTZU Xd = convertToIntExactTowardZero(Dn) + return new FcvtFpUIntXDZ(machInst, rd, rn); + default: + return new Unknown64(machInst); + } + case 0x2: + if (rmode != 0) + return new Unknown64(machInst); + switch (switchVal2) { + case 0: // SCVTF Sd = convertFromInt(Wn) + return new FcvtWSIntFpS(machInst, rd, rn); + case 1: // SCVTF Sd = convertFromInt(Xn) + return new FcvtXSIntFpS(machInst, rd, rn); + case 2: // SCVTF Dd = convertFromInt(Wn) + return new FcvtWSIntFpD(machInst, rd, rn); + case 3: // SCVTF Dd = convertFromInt(Xn) + return new FcvtXSIntFpD(machInst, rd, rn); + default: + return new Unknown64(machInst); + } + case 0x3: + switch (switchVal2) { + case 0: // UCVTF Sd = convertFromInt(Wn) + return new FcvtWUIntFpS(machInst, rd, rn); + case 1: // UCVTF Sd = convertFromInt(Xn) + return new FcvtXUIntFpS(machInst, rd, rn); + case 2: // UCVTF Dd = convertFromInt(Wn) + return new FcvtWUIntFpD(machInst, rd, rn); + case 3: // UCVTF Dd = convertFromInt(Xn) + return new FcvtXUIntFpD(machInst, rd, rn); + default: + return new Unknown64(machInst); + } + case 0x4: + if (rmode != 0) + return new Unknown64(machInst); + switch (switchVal2) { + case 0: // FCVTAS Wd = convertToIntExactTiesToAway(Sn) + return new FcvtFpSIntWSA(machInst, rd, rn); + case 1: // FCVTAS Xd = convertToIntExactTiesToAway(Sn) + return new FcvtFpSIntXSA(machInst, rd, rn); + case 2: // FCVTAS Wd = convertToIntExactTiesToAway(Dn) + return new FcvtFpSIntWDA(machInst, rd, rn); + case 3: // FCVTAS Wd = convertToIntExactTiesToAway(Dn) + return new FcvtFpSIntXDA(machInst, rd, rn); + default: + return new Unknown64(machInst); + } + case 0x5: + switch (switchVal2) { + case 0: // FCVTAU Wd = convertToIntExactTiesToAway(Sn) + return new FcvtFpUIntWSA(machInst, rd, rn); + case 1: // FCVTAU Xd = convertToIntExactTiesToAway(Sn) + return new FcvtFpUIntXSA(machInst, rd, rn); + case 2: // FCVTAU Wd = convertToIntExactTiesToAway(Dn) + return new FcvtFpUIntWDA(machInst, rd, rn); + case 3: // FCVTAU Xd = convertToIntExactTiesToAway(Dn) + return new FcvtFpUIntXDA(machInst, rd, rn); + default: + return new Unknown64(machInst); + } + case 0x06: + switch (switchVal2) { + case 0: // FMOV Wd = Sn + if (rmode != 0) + return new Unknown64(machInst); + return new FmovRegCoreW(machInst, rd, rn); + case 3: // FMOV Xd = Dn + if (rmode != 0) + return new Unknown64(machInst); + return new FmovRegCoreX(machInst, rd, rn); + case 5: // FMOV Xd = Vn<127:64> + if (rmode != 1) + return new Unknown64(machInst); + return new FmovURegCoreX(machInst, rd, rn); + default: + return new Unknown64(machInst); + } + break; + case 0x07: + switch (switchVal2) { + case 0: // FMOV Sd = Wn + if (rmode != 0) + return new Unknown64(machInst); + return new FmovCoreRegW(machInst, rd, rn); + case 3: // FMOV Xd = Dn + if (rmode != 0) + return new Unknown64(machInst); + return new FmovCoreRegX(machInst, rd, rn); + case 5: // FMOV Xd = Vn<127:64> + if (rmode != 1) + return new Unknown64(machInst); + return new FmovUCoreRegX(machInst, rd, rn); + default: + return new Unknown64(machInst); + } + break; + default: // Warning! missing cases in switch statement above, that still need to be added + return new Unknown64(machInst); + } + } + case 0x1: + { + if (bits(machInst, 31) || + bits(machInst, 29) || + bits(machInst, 23)) { + return new Unknown64(machInst); + } + IntRegIndex rm = (IntRegIndex)(uint32_t) bits(machInst, 20, 16); + IntRegIndex rn = (IntRegIndex)(uint32_t) bits(machInst, 9, 5); + uint8_t imm = (IntRegIndex)(uint32_t) bits(machInst, 3, 0); + ConditionCode cond = + (ConditionCode)(uint8_t)(bits(machInst, 15, 12)); + uint8_t switchVal = (bits(machInst, 4) << 0) | + (bits(machInst, 22) << 1); + // 31:23=000111100, 21=1, 11:10=01 + switch (switchVal) { + case 0x0: + // FCCMP flags = if cond the compareQuiet(Sn,Sm) else #nzcv + return new FCCmpRegS(machInst, rn, rm, cond, imm); + case 0x1: + // FCCMP flags = if cond then compareSignaling(Sn,Sm) + // else #nzcv + return new FCCmpERegS(machInst, rn, rm, cond, imm); + case 0x2: + // FCCMP flags = if cond then compareQuiet(Dn,Dm) else #nzcv + return new FCCmpRegD(machInst, rn, rm, cond, imm); + case 0x3: + // FCCMP flags = if cond then compareSignaling(Dn,Dm) + // else #nzcv + return new FCCmpERegD(machInst, rn, rm, cond, imm); + default: + return new Unknown64(machInst); + } + } + case 0x2: + { + if (bits(machInst, 31) || + bits(machInst, 29) || + bits(machInst, 23)) { + return new Unknown64(machInst); + } + IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 4, 0); + IntRegIndex rn = (IntRegIndex)(uint32_t)bits(machInst, 9, 5); + IntRegIndex rm = (IntRegIndex)(uint32_t)bits(machInst, 20, 16); + uint8_t switchVal = (bits(machInst, 15, 12) << 0) | + (bits(machInst, 22) << 4); + switch (switchVal) { + case 0x00: // FMUL Sd = Sn * Sm + return new FMulS(machInst, rd, rn, rm); + case 0x10: // FMUL Dd = Dn * Dm + return new FMulD(machInst, rd, rn, rm); + case 0x01: // FDIV Sd = Sn / Sm + return new FDivS(machInst, rd, rn, rm); + case 0x11: // FDIV Dd = Dn / Dm + return new FDivD(machInst, rd, rn, rm); + case 0x02: // FADD Sd = Sn + Sm + return new FAddS(machInst, rd, rn, rm); + case 0x12: // FADD Dd = Dn + Dm + return new FAddD(machInst, rd, rn, rm); + case 0x03: // FSUB Sd = Sn - Sm + return new FSubS(machInst, rd, rn, rm); + case 0x13: // FSUB Dd = Dn - Dm + return new FSubD(machInst, rd, rn, rm); + case 0x04: // FMAX Sd = max(Sn, Sm) + return new FMaxS(machInst, rd, rn, rm); + case 0x14: // FMAX Dd = max(Dn, Dm) + return new FMaxD(machInst, rd, rn, rm); + case 0x05: // FMIN Sd = min(Sn, Sm) + return new FMinS(machInst, rd, rn, rm); + case 0x15: // FMIN Dd = min(Dn, Dm) + return new FMinD(machInst, rd, rn, rm); + case 0x06: // FMAXNM Sd = maxNum(Sn, Sm) + return new FMaxNMS(machInst, rd, rn, rm); + case 0x16: // FMAXNM Dd = maxNum(Dn, Dm) + return new FMaxNMD(machInst, rd, rn, rm); + case 0x07: // FMINNM Sd = minNum(Sn, Sm) + return new FMinNMS(machInst, rd, rn, rm); + case 0x17: // FMINNM Dd = minNum(Dn, Dm) + return new FMinNMD(machInst, rd, rn, rm); + case 0x08: // FNMUL Sd = -(Sn * Sm) + return new FNMulS(machInst, rd, rn, rm); + case 0x18: // FNMUL Dd = -(Dn * Dm) + return new FNMulD(machInst, rd, rn, rm); + default: + return new Unknown64(machInst); + } + } + case 0x3: + { + if (bits(machInst, 31) || bits(machInst, 29)) + return new Unknown64(machInst); + uint8_t type = bits(machInst, 23, 22); + IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 4, 0); + IntRegIndex rn = (IntRegIndex)(uint32_t)bits(machInst, 9, 5); + IntRegIndex rm = (IntRegIndex)(uint32_t)bits(machInst, 20, 16); + ConditionCode cond = + (ConditionCode)(uint8_t)(bits(machInst, 15, 12)); + if (type == 0) // FCSEL Sd = if cond then Sn else Sm + return new FCSelS(machInst, rd, rn, rm, cond); + else if (type == 1) // FCSEL Dd = if cond then Dn else Dm + return new FCSelD(machInst, rd, rn, rm, cond); + else + return new Unknown64(machInst); + } + } + } + return new FailUnimplemented("Unhandled Case4", machInst); + } +} +}}; + +output decoder {{ +namespace Aarch64 +{ + StaticInstPtr + decodeAdvSIMDScalar(ExtMachInst machInst) + { + if (bits(machInst, 24) == 1) { + if (bits(machInst, 10) == 0) { + return decodeNeonScIndexedElem(machInst); + } else if (bits(machInst, 23) == 0) { + return decodeNeonScShiftByImm(machInst); + } + } else if (bits(machInst, 21) == 1) { + if (bits(machInst, 10) == 1) { + return decodeNeonSc3Same(machInst); + } else if (bits(machInst, 11) == 0) { + return decodeNeonSc3Diff(machInst); + } else if (bits(machInst, 20, 17) == 0x0) { + return decodeNeonSc2RegMisc(machInst); + } else if (bits(machInst, 20, 17) == 0x8) { + return decodeNeonScPwise(machInst); + } else { + return new Unknown64(machInst); + } + } else if (bits(machInst, 23, 22) == 0 && + bits(machInst, 15) == 0 && + bits(machInst, 10) == 1) { + return decodeNeonScCopy(machInst); + } else { + return new Unknown64(machInst); + } + return new FailUnimplemented("Unhandled Case6", machInst); + } +} +}}; + +output decoder {{ +namespace Aarch64 +{ + StaticInstPtr + decodeFpAdvSIMD(ExtMachInst machInst) + { + + if (bits(machInst, 28) == 0) { + if (bits(machInst, 31) == 0) { + return decodeAdvSIMD(machInst); + } else { + return new Unknown64(machInst); + } + } else if (bits(machInst, 30) == 0) { + return decodeFp(machInst); + } else if (bits(machInst, 31) == 0) { + return decodeAdvSIMDScalar(machInst); + } else { + return new Unknown64(machInst); + } + } +} +}}; + +output decoder {{ +namespace Aarch64 +{ + StaticInstPtr + decodeGem5Ops(ExtMachInst machInst) + { + const uint32_t m5func = bits(machInst, 23, 16); + switch (m5func) { + case 0x00: return new Arm(machInst); + case 0x01: return new Quiesce(machInst); + case 0x02: return new QuiesceNs64(machInst); + case 0x03: return new QuiesceCycles64(machInst); + case 0x04: return new QuiesceTime64(machInst); + case 0x07: return new Rpns64(machInst); + case 0x09: return new WakeCPU64(machInst); + case 0x10: return new Deprecated_ivlb(machInst); + case 0x11: return new Deprecated_ivle(machInst); + case 0x20: return new Deprecated_exit (machInst); + case 0x21: return new M5exit64(machInst); + case 0x31: return new Loadsymbol(machInst); + case 0x30: return new Initparam64(machInst); + case 0x40: return new Resetstats64(machInst); + case 0x41: return new Dumpstats64(machInst); + case 0x42: return new Dumpresetstats64(machInst); + case 0x43: return new M5checkpoint64(machInst); + case 0x4F: return new M5writefile64(machInst); + case 0x50: return new M5readfile64(machInst); + case 0x51: return new M5break(machInst); + case 0x52: return new M5switchcpu(machInst); + case 0x53: return new M5addsymbol64(machInst); + case 0x54: return new M5panic(machInst); + case 0x5a: return new M5workbegin64(machInst); + case 0x5b: return new M5workend64(machInst); + default: return new Unknown64(machInst); + } + } +} +}}; + +def format Aarch64() {{ + decode_block = ''' + { + using namespace Aarch64; + if (bits(machInst, 27) == 0x0) { + if (bits(machInst, 28) == 0x0) + return new Unknown64(machInst); + else if (bits(machInst, 26) == 0) + // bit 28:26=100 + return decodeDataProcImm(machInst); + else + // bit 28:26=101 + return decodeBranchExcSys(machInst); + } else if (bits(machInst, 25) == 0) { + // bit 27=1, 25=0 + return decodeLoadsStores(machInst); + } else if (bits(machInst, 26) == 0) { + // bit 27:25=101 + return decodeDataProcReg(machInst); + } else if (bits(machInst, 24) == 1 && + bits(machInst, 31, 28) == 0xF) { + return decodeGem5Ops(machInst); + } else { + // bit 27:25=111 + return decodeFpAdvSIMD(machInst); + } + } + ''' +}}; diff --git a/src/arch/arm/isa/formats/branch.isa b/src/arch/arm/isa/formats/branch.isa index f1b17ec90..513506d31 100644 --- a/src/arch/arm/isa/formats/branch.isa +++ b/src/arch/arm/isa/formats/branch.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2010 ARM Limited +// Copyright (c) 2010, 2012-2013 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -101,7 +101,7 @@ def format Thumb16CondBranchAndSvc() {{ return new B(machInst, sext<9>(bits(machInst, 7, 0) << 1), (ConditionCode)(uint32_t)bits(machInst, 11, 8)); } else if (bits(machInst, 8)) { - return new Svc(machInst); + return new Svc(machInst, bits(machInst, 7, 0)); } else { // This space will not be allocated in the future. return new Unknown(machInst); @@ -127,7 +127,7 @@ def format Thumb32BranchesAndMiscCtrl() {{ // Permanently undefined. return new Unknown(machInst); } else { - return new WarnUnimplemented("smc", machInst); + return new Smc(machInst); } } else if ((op & 0x38) != 0x38) { const uint32_t s = bits(machInst, 26); @@ -141,20 +141,26 @@ def format Thumb32BranchesAndMiscCtrl() {{ return new B(machInst, imm, (ConditionCode)(uint32_t)bits(machInst, 25, 22)); } else { + // HIGH: 12-11=10, LOW: 15-14=00, 12=0 switch (op) { case 0x38: - { - const IntRegIndex rn = - (IntRegIndex)(uint32_t)bits(machInst, 19, 16); - const uint8_t byteMask = bits(machInst, 11, 8); - return new MsrCpsrReg(machInst, rn, byteMask); - } case 0x39: { const IntRegIndex rn = (IntRegIndex)(uint32_t)bits(machInst, 19, 16); const uint8_t byteMask = bits(machInst, 11, 8); - return new MsrSpsrReg(machInst, rn, byteMask); + const bool r = bits(machInst, 20); + if (bits(machInst, 5)) { + const uint8_t sysM = (bits(machInst, 4) << 4) | + byteMask; + return new MsrBankedReg(machInst, rn, sysM, r); + } else { + if (r) { + return new MsrSpsrReg(machInst, rn, byteMask); + } else { + return new MsrCpsrReg(machInst, rn, byteMask); + } + } } case 0x3a: { @@ -196,11 +202,11 @@ def format Thumb32BranchesAndMiscCtrl() {{ case 0x2: return new Clrex(machInst); case 0x4: - return new Dsb(machInst); + return new Dsb(machInst, 0); case 0x5: - return new Dmb(machInst); + return new Dmb(machInst, 0); case 0x6: - return new Isb(machInst); + return new Isb(machInst, 0); default: break; } @@ -208,28 +214,44 @@ def format Thumb32BranchesAndMiscCtrl() {{ } case 0x3c: { - // On systems that don't support bxj, bxj == bx - return new BxReg(machInst, + return new BxjReg(machInst, (IntRegIndex)(uint32_t)bits(machInst, 19, 16), COND_UC); } case 0x3d: { const uint32_t imm32 = bits(machInst, 7, 0); - return new SubsImmPclr(machInst, INTREG_PC, INTREG_LR, - imm32, false); + if (imm32 == 0) { + return new Eret(machInst); + } else { + return new SubsImmPclr(machInst, INTREG_PC, + INTREG_LR, imm32, false); + } } case 0x3e: + case 0x3f: { + const IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 11, 8); - return new MrsCpsr(machInst, rd); + const bool r = bits(machInst, 20); + if (bits(machInst, 5)) { + const uint8_t sysM = (bits(machInst, 4) << 4) | + bits(machInst, 11, 8); + return new MrsBankedReg(machInst, rd, sysM, r); + } else { + if (r) { + return new MrsSpsr(machInst, rd); + } else { + return new MrsCpsr(machInst, rd); + } + } } - case 0x3f: + case 0xfe: { - const IntRegIndex rd = - (IntRegIndex)(uint32_t)bits(machInst, 11, 8); - return new MrsSpsr(machInst, rd); + uint32_t imm16 = (bits(machInst, 19, 16) << 12) | + (bits(machInst, 11, 0) << 0); + return new Hvc(machInst, imm16); } } break; diff --git a/src/arch/arm/isa/formats/formats.isa b/src/arch/arm/isa/formats/formats.isa index 90144c101..44e9c5b5e 100644 --- a/src/arch/arm/isa/formats/formats.isa +++ b/src/arch/arm/isa/formats/formats.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2010 ARM Limited +// Copyright (c) 2010-2011 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -44,6 +44,12 @@ //Include the basic format ##include "basic.isa" +//Include support for decoding AArch64 instructions +##include "aarch64.isa" + +//Include support for decoding AArch64 NEON instructions +##include "neon64.isa" + //Include support for predicated instructions ##include "pred.isa" diff --git a/src/arch/arm/isa/formats/fp.isa b/src/arch/arm/isa/formats/fp.isa index 6d779e541..ccd4589a3 100644 --- a/src/arch/arm/isa/formats/fp.isa +++ b/src/arch/arm/isa/formats/fp.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2010 ARM Limited +// Copyright (c) 2010-2011 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -151,8 +151,7 @@ let {{ if (singleAll) { size = bits(machInst, 7, 6); bool t = bits(machInst, 5); - unsigned eBytes = (1 << size); - align = (eBytes - 1) | TLB::AllowUnaligned; + align = size | TLB::AllowUnaligned; if (width == 1) { regs = t ? 2 : 1; inc = 1; @@ -164,7 +163,7 @@ let {{ case 1: case 2: if (bits(machInst, 4)) - align = width * eBytes - 1; + align = size + width - 1; break; case 3: break; @@ -173,20 +172,19 @@ let {{ if (bits(machInst, 4) == 0) return new Unknown(machInst); size = 2; - align = 0xf; + align = 0x4; } else if (size == 2) { if (bits(machInst, 4)) - align = 7; + align = 0x3; } else { if (bits(machInst, 4)) - align = 4 * eBytes - 1; + align = size + 2; } break; } } else { size = bits(machInst, 11, 10); - unsigned eBytes = (1 << size); - align = (eBytes - 1) | TLB::AllowUnaligned; + align = size | TLB::AllowUnaligned; regs = width; unsigned indexAlign = bits(machInst, 7, 4); // If width is 1, inc is always 1. That's overridden later. @@ -219,13 +217,13 @@ let {{ break; case 2: if (bits(indexAlign, 1, 0)) - align = 3; + align = 2; break; } break; case 2: if (bits(indexAlign, 0)) - align = (2 * eBytes) - 1; + align = size + 1; break; case 3: break; @@ -234,11 +232,11 @@ let {{ case 0: case 1: if (bits(indexAlign, 0)) - align = (4 * eBytes) - 1; + align = size + 2; break; case 2: if (bits(indexAlign, 0)) - align = (4 << bits(indexAlign, 1, 0)) - 1; + align = bits(indexAlign, 1, 0) + 2; break; } break; @@ -252,9 +250,9 @@ let {{ align = bits(machInst, 5, 4); if (align == 0) { // @align wasn't specified, so alignment can be turned off. - align = ((1 << size) - 1) | TLB::AllowUnaligned; + align = size | TLB::AllowUnaligned; } else { - align = ((4 << align) - 1); + align = align + 2; } switch (width) { case 1: @@ -588,6 +586,23 @@ let {{ } } case 0xc: + if (b) { + if (!u) { + if (bits(c, 1) == 0) { + if (q) { + return new NVfmaQFp<float>(machInst, vd, vn, vm); + } else { + return new NVfmaDFp<float>(machInst, vd, vn, vm); + } + } else { + if (q) { + return new NVfmsQFp<float>(machInst, vd, vn, vm); + } else { + return new NVfmsDFp<float>(machInst, vd, vn, vm); + } + } + } + } return new Unknown(machInst); case 0xd: if (b) { @@ -1827,7 +1842,7 @@ let {{ break; case 0x1: { - if (offset == 0 || vd + offset/2 > NumFloatArchRegs) { + if (offset == 0 || vd + offset/2 > NumFloatV7ArchRegs) { break; } switch (bits(opcode, 1, 0)) { @@ -1951,8 +1966,9 @@ let {{ } else if (a == 0x7) { const IntRegIndex rt = (IntRegIndex)(uint32_t)bits(machInst, 15, 12); - uint32_t specReg = bits(machInst, 19, 16); - switch (specReg) { + uint32_t reg = bits(machInst, 19, 16); + uint32_t specReg; + switch (reg) { case 0: specReg = MISCREG_FPSID; break; @@ -1974,7 +1990,9 @@ let {{ if (specReg == MISCREG_FPSCR) { return new VmsrFpscr(machInst, (IntRegIndex)specReg, rt); } else { - return new Vmsr(machInst, (IntRegIndex)specReg, rt); + uint32_t iss = mcrMrcIssBuild(0, bits(machInst, 3, 0), rt, + reg, a, bits(machInst, 7, 5)); + return new Vmsr(machInst, (IntRegIndex)specReg, rt, iss); } } } else if (l == 0 && c == 1) { @@ -2041,8 +2059,9 @@ let {{ } else if (a == 7) { const IntRegIndex rt = (IntRegIndex)(uint32_t)bits(machInst, 15, 12); - uint32_t specReg = bits(machInst, 19, 16); - switch (specReg) { + uint32_t reg = bits(machInst, 19, 16); + uint32_t specReg; + switch (reg) { case 0: specReg = MISCREG_FPSID; break; @@ -2070,7 +2089,9 @@ let {{ } else if (specReg == MISCREG_FPSCR) { return new VmrsFpscr(machInst, rt, (IntRegIndex)specReg); } else { - return new Vmrs(machInst, rt, (IntRegIndex)specReg); + uint32_t iss = mcrMrcIssBuild(l, bits(machInst, 3, 0), rt, + reg, a, bits(machInst, 7, 5)); + return new Vmrs(machInst, rt, (IntRegIndex)specReg, iss); } } } else { @@ -2235,6 +2256,44 @@ let {{ } } break; + case 0x9: + if ((opc3 & 0x1) == 0) { + if (single) { + return decodeVfpRegRegRegOp<VfnmaS>( + machInst, vd, vn, vm, false); + } else { + return decodeVfpRegRegRegOp<VfnmaD>( + machInst, vd, vn, vm, true); + } + } else { + if (single) { + return decodeVfpRegRegRegOp<VfnmsS>( + machInst, vd, vn, vm, false); + } else { + return decodeVfpRegRegRegOp<VfnmsD>( + machInst, vd, vn, vm, true); + } + } + break; + case 0xa: + if ((opc3 & 0x1) == 0) { + if (single) { + return decodeVfpRegRegRegOp<VfmaS>( + machInst, vd, vn, vm, false); + } else { + return decodeVfpRegRegRegOp<VfmaD>( + machInst, vd, vn, vm, true); + } + } else { + if (single) { + return decodeVfpRegRegRegOp<VfmsS>( + machInst, vd, vn, vm, false); + } else { + return decodeVfpRegRegRegOp<VfmsD>( + machInst, vd, vn, vm, true); + } + } + break; case 0xb: if ((opc3 & 0x1) == 0) { const uint32_t baseImm = diff --git a/src/arch/arm/isa/formats/mem.isa b/src/arch/arm/isa/formats/mem.isa index f7830eff3..abac27021 100644 --- a/src/arch/arm/isa/formats/mem.isa +++ b/src/arch/arm/isa/formats/mem.isa @@ -282,7 +282,7 @@ def format Thumb32SrsRfe() {{ } } else { const uint32_t mode = bits(machInst, 4, 0); - if (badMode((OperatingMode)mode)) + if (badMode32((OperatingMode)mode)) return new Unknown(machInst); if (!add && !wb) { return new %(srs)s(machInst, mode, diff --git a/src/arch/arm/isa/formats/misc.isa b/src/arch/arm/isa/formats/misc.isa index 00a37d17b..647f9846d 100644 --- a/src/arch/arm/isa/formats/misc.isa +++ b/src/arch/arm/isa/formats/misc.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2010-2012 ARM Limited +// Copyright (c) 2010-2013 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -36,19 +36,42 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: Gabe Black +// Giacomo Gabrielli + +def format ArmERet() {{ + decode_block = "return new Eret(machInst);" +}}; def format Svc() {{ - decode_block = "return new Svc(machInst);" + decode_block = "return new Svc(machInst, bits(machInst, 23, 0));" +}}; + +def format ArmSmcHyp() {{ + decode_block = ''' + { + if (bits(machInst, 21)) + { + return new Smc(machInst); + } else { + uint32_t imm16 = (bits(machInst, 19, 8) << 4) | + (bits(machInst, 3, 0) << 0); + return new Hvc(machInst, imm16); + } + } + ''' }}; def format ArmMsrMrs() {{ decode_block = ''' { const uint8_t byteMask = bits(machInst, 19, 16); + const uint8_t sysM = byteMask | (bits(machInst, 8) << 4); const IntRegIndex rn = (IntRegIndex)(uint32_t)bits(machInst, 3, 0); const IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 15, 12); const uint32_t opcode = bits(machInst, 24, 21); const bool useImm = bits(machInst, 25); + const bool r = bits(machInst, 22); + const bool isBanked = bits(machInst, 9); const uint32_t unrotated = bits(machInst, 7, 0); const uint32_t rotation = (bits(machInst, 11, 8) << 1); @@ -56,20 +79,36 @@ def format ArmMsrMrs() {{ switch (opcode) { case 0x8: - return new MrsCpsr(machInst, rd); + if (isBanked) { + return new MrsBankedReg(machInst, rd, sysM, r!=0); + } else { + return new MrsCpsr(machInst, rd); + } case 0x9: if (useImm) { return new MsrCpsrImm(machInst, imm, byteMask); } else { - return new MsrCpsrReg(machInst, rn, byteMask); + if (isBanked) { + return new MsrBankedReg(machInst, rn, sysM, r!=0); + } else { + return new MsrCpsrReg(machInst, rn, byteMask); + } } case 0xa: - return new MrsSpsr(machInst, rd); + if (isBanked) { + return new MrsBankedReg(machInst, rd, sysM, r!=0); + } else { + return new MrsSpsr(machInst, rd); + } case 0xb: if (useImm) { return new MsrSpsrImm(machInst, imm, byteMask); } else { - return new MsrSpsrReg(machInst, rn, byteMask); + if (isBanked) { + return new MsrBankedReg(machInst, rn, sysM, r!=0); + } else { + return new MsrSpsrReg(machInst, rn, byteMask); + } } default: return new Unknown(machInst); @@ -99,16 +138,17 @@ let {{ switch (miscReg) { case MISCREG_NOP: return new NopInst(machInst); - case NUM_MISCREGS: + case MISCREG_CP14_UNIMPL: return new FailUnimplemented( csprintf("miscreg crn:%d opc1:%d crm:%d opc2:%d %s unknown", crn, opc1, crm, opc2, isRead ? "read" : "write").c_str(), machInst); default: + uint32_t iss = mcrMrcIssBuild(isRead, crm, rt, crn, opc1, opc2); if (isRead) { - return new Mrc14(machInst, rt, (IntRegIndex)miscReg); + return new Mrc14(machInst, rt, (IntRegIndex)miscReg, iss); } else { - return new Mcr14(machInst, (IntRegIndex)miscReg, rt); + return new Mcr14(machInst, (IntRegIndex)miscReg, rt, iss); } } } @@ -123,8 +163,8 @@ def format McrMrc14() {{ let {{ header_output = ''' - StaticInstPtr - decodeMcrMrc15(ExtMachInst machInst); + StaticInstPtr decodeMcrMrc14(ExtMachInst machInst); + StaticInstPtr decodeMcrMrc15(ExtMachInst machInst); ''' decoder_output = ''' StaticInstPtr @@ -136,107 +176,50 @@ let {{ const uint32_t crm = bits(machInst, 3, 0); const MiscRegIndex miscReg = decodeCP15Reg(crn, opc1, crm, opc2); const IntRegIndex rt = (IntRegIndex)(uint32_t)bits(machInst, 15, 12); - const bool isRead = bits(machInst, 20); + uint32_t iss = mcrMrcIssBuild(isRead, crm, rt, crn, opc1, opc2); switch (miscReg) { case MISCREG_NOP: return new NopInst(machInst); - case NUM_MISCREGS: + case MISCREG_CP15_UNIMPL: return new FailUnimplemented( csprintf("miscreg crn:%d opc1:%d crm:%d opc2:%d %s unknown", crn, opc1, crm, opc2, isRead ? "read" : "write").c_str(), machInst); - case MISCREG_DCCISW: - return new WarnUnimplemented( - isRead ? "mrc dccisw" : "mcr dcisw", machInst); - case MISCREG_DCCIMVAC: - return new WarnUnimplemented( - isRead ? "mrc dccimvac" : "mcr dccimvac", machInst); - case MISCREG_DCIMVAC: - return new WarnUnimplemented( - isRead ? "mrc dcimvac" : "mcr dcimvac", machInst); case MISCREG_DCCMVAC: return new FlushPipeInst( isRead ? "mrc dccmvac" : "mcr dccmvac", machInst); - case MISCREG_DCCMVAU: - return new WarnUnimplemented( - isRead ? "mrc dccmvau" : "mcr dccmvau", machInst); case MISCREG_CP15ISB: - return new Isb(machInst); + return new Isb(machInst, iss); case MISCREG_CP15DSB: - return new Dsb(machInst); + return new Dsb(machInst, iss); case MISCREG_CP15DMB: - return new Dmb(machInst); - case MISCREG_ICIALLUIS: - return new WarnUnimplemented( - isRead ? "mrc icialluis" : "mcr icialluis", machInst); - case MISCREG_ICIMVAU: - return new WarnUnimplemented( - isRead ? "mrc icimvau" : "mcr icimvau", machInst); - case MISCREG_BPIMVA: - return new WarnUnimplemented( - isRead ? "mrc bpimva" : "mcr bpimva", machInst); - case MISCREG_BPIALLIS: - return new WarnUnimplemented( - isRead ? "mrc bpiallis" : "mcr bpiallis", machInst); - case MISCREG_BPIALL: - return new WarnUnimplemented( - isRead ? "mrc bpiall" : "mcr bpiall", machInst); - case MISCREG_L2LATENCY: - return new WarnUnimplemented( - isRead ? "mrc l2latency" : "mcr l2latency", machInst); - case MISCREG_CRN15: - return new WarnUnimplemented( - isRead ? "mrc crn15" : "mcr crn15", machInst); - - // Write only. - case MISCREG_TLBIALLIS: - case MISCREG_TLBIMVAIS: - case MISCREG_TLBIASIDIS: - case MISCREG_TLBIMVAAIS: - case MISCREG_ITLBIALL: - case MISCREG_ITLBIMVA: - case MISCREG_ITLBIASID: - case MISCREG_DTLBIALL: - case MISCREG_DTLBIMVA: - case MISCREG_DTLBIASID: - case MISCREG_TLBIALL: - case MISCREG_TLBIMVA: - case MISCREG_TLBIASID: - case MISCREG_TLBIMVAA: - if (isRead) { - return new Unknown(machInst); - } else { - return new Mcr15(machInst, (IntRegIndex)miscReg, rt); - } + return new Dmb(machInst, iss); + default: + if (miscRegInfo[miscReg][MISCREG_WARN_NOT_FAIL]) { + std::string full_mnem = csprintf("%s %s", + isRead ? "mrc" : "mcr", miscRegName[miscReg]); + warn("\\tinstruction '%s' unimplemented\\n", full_mnem); - // Read only in user mode. - case MISCREG_TPIDRURO: - if (isRead) { - return new Mrc15User(machInst, rt, (IntRegIndex)miscReg); - } else { - return new Mcr15(machInst, (IntRegIndex)miscReg, rt); + // Remove the warn flag and set the implemented flag. This + // prevents the instruction warning a second time, it also + // means the instruction is actually generated. Actually + // creating the instruction to access an register that isn't + // implemented sounds a bit silly, but its required to get + // the correct behaviour for hyp traps and undef exceptions. + miscRegInfo[miscReg][MISCREG_IMPLEMENTED] = true; + miscRegInfo[miscReg][MISCREG_WARN_NOT_FAIL] = false; } - // Read/write in user mode. - case MISCREG_TPIDRURW: - if (isRead) { - return new Mrc15User(machInst, rt, (IntRegIndex)miscReg); + if (miscRegInfo[miscReg][MISCREG_IMPLEMENTED]) { + if (isRead) + return new Mrc15(machInst, rt, (IntRegIndex)miscReg, iss); + return new Mcr15(machInst, (IntRegIndex)miscReg, rt, iss); } else { - return new Mcr15User(machInst, (IntRegIndex)miscReg, rt); - } - - // Read/write, priveleged only. - default: - if (miscReg >= MISCREG_CP15_UNIMP_START) return new FailUnimplemented(csprintf("%s %s", isRead ? "mrc" : "mcr", miscRegName[miscReg]).c_str(), machInst); - if (isRead) { - return new Mrc15(machInst, rt, (IntRegIndex)miscReg); - } else { - return new Mcr15(machInst, (IntRegIndex)miscReg, rt); } } } @@ -248,3 +231,70 @@ def format McrMrc15() {{ return decodeMcrMrc15(machInst); ''' }}; + +let {{ + header_output = ''' + StaticInstPtr + decodeMcrrMrrc15(ExtMachInst machInst); + ''' + decoder_output = ''' + StaticInstPtr + decodeMcrrMrrc15(ExtMachInst machInst) + { + const uint32_t crm = bits(machInst, 3, 0); + const uint32_t opc1 = bits(machInst, 7, 4); + const MiscRegIndex miscReg = decodeCP15Reg64(crm, opc1); + const IntRegIndex rt = (IntRegIndex) (uint32_t) bits(machInst, 15, 12); + const IntRegIndex rt2 = (IntRegIndex) (uint32_t) bits(machInst, 19, 16); + + const bool isRead = bits(machInst, 20); + + switch (miscReg) { + case MISCREG_CP15_UNIMPL: + return new FailUnimplemented( + csprintf("miscreg crm:%d opc1:%d 64-bit %s unknown", + crm, opc1, isRead ? "read" : "write").c_str(), + machInst); + default: + if (miscRegInfo[miscReg][MISCREG_WARN_NOT_FAIL]) { + std::string full_mnem = csprintf("%s %s", + isRead ? "mrrc" : "mcrr", miscRegName[miscReg]); + warn("\\tinstruction '%s' unimplemented\\n", full_mnem); + + // Remove the warn flag and set the implemented flag. This + // prevents the instruction warning a second time, it also + // means the instruction is actually generated. Actually + // creating the instruction to access an register that isn't + // implemented sounds a bit silly, but its required to get + // the correct behaviour for hyp traps and undef exceptions. + miscRegInfo[miscReg][MISCREG_IMPLEMENTED] = true; + miscRegInfo[miscReg][MISCREG_WARN_NOT_FAIL] = false; + } + + if (miscRegInfo[miscReg][MISCREG_IMPLEMENTED]) { + uint32_t iss = mcrrMrrcIssBuild(isRead, crm, rt, rt2, opc1); + + if (isRead) + return new Mrrc15(machInst, (IntRegIndex) miscReg, rt2, rt, iss); + return new Mcrr15(machInst, rt2, rt, (IntRegIndex) miscReg, iss); + } else { + return new FailUnimplemented(csprintf("%s %s", + isRead ? "mrrc" : "mcrr", miscRegName[miscReg]).c_str(), + machInst); + } + } + } + ''' +}}; + +def format Mcrr15() {{ + decode_block = ''' + return decodeMcrrMrrc15(machInst); + ''' +}}; + +def format Mrrc15() {{ + decode_block = ''' + return decodeMcrrMrrc15(machInst); + ''' +}}; diff --git a/src/arch/arm/isa/formats/neon64.isa b/src/arch/arm/isa/formats/neon64.isa new file mode 100644 index 000000000..72bbd0c60 --- /dev/null +++ b/src/arch/arm/isa/formats/neon64.isa @@ -0,0 +1,2626 @@ +// Copyright (c) 2012-2013 ARM Limited +// All rights reserved +// +// The license below extends only to copyright in the software and shall +// not be construed as granting a license to any other intellectual +// property including but not limited to intellectual property relating +// to a hardware implementation of the functionality of the software +// licensed hereunder. You may use the software subject to the license +// terms below provided that you ensure that this notice is replicated +// unmodified and in its entirety in all distributions of the software, +// modified or unmodified, in source code or in binary form. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Giacomo Gabrielli +// Mbou Eyole + +output header {{ +namespace Aarch64 +{ + // AdvSIMD three same + StaticInstPtr decodeNeon3Same(ExtMachInst machInst); + // AdvSIMD three different + StaticInstPtr decodeNeon3Diff(ExtMachInst machInst); + // AdvSIMD two-reg misc + StaticInstPtr decodeNeon2RegMisc(ExtMachInst machInst); + // AdvSIMD across lanes + StaticInstPtr decodeNeonAcrossLanes(ExtMachInst machInst); + // AdvSIMD copy + StaticInstPtr decodeNeonCopy(ExtMachInst machInst); + // AdvSIMD vector x indexed element + StaticInstPtr decodeNeonIndexedElem(ExtMachInst machInst); + // AdvSIMD modified immediate + StaticInstPtr decodeNeonModImm(ExtMachInst machInst); + // AdvSIMD shift by immediate + StaticInstPtr decodeNeonShiftByImm(ExtMachInst machInst); + // AdvSIMD TBL/TBX + StaticInstPtr decodeNeonTblTbx(ExtMachInst machInst); + // AdvSIMD ZIP/UZP/TRN + StaticInstPtr decodeNeonZipUzpTrn(ExtMachInst machInst); + // AdvSIMD EXT + StaticInstPtr decodeNeonExt(ExtMachInst machInst); + + // AdvSIMD scalar three same + StaticInstPtr decodeNeonSc3Same(ExtMachInst machInst); + // AdvSIMD scalar three different + StaticInstPtr decodeNeonSc3Diff(ExtMachInst machInst); + // AdvSIMD scalar two-reg misc + StaticInstPtr decodeNeonSc2RegMisc(ExtMachInst machInst); + // AdvSIMD scalar pairwise + StaticInstPtr decodeNeonScPwise(ExtMachInst machInst); + // AdvSIMD scalar copy + StaticInstPtr decodeNeonScCopy(ExtMachInst machInst); + // AdvSIMD scalar x indexed element + StaticInstPtr decodeNeonScIndexedElem(ExtMachInst machInst); + // AdvSIMD scalar shift by immediate + StaticInstPtr decodeNeonScShiftByImm(ExtMachInst machInst); + + // AdvSIMD load/store + StaticInstPtr decodeNeonMem(ExtMachInst machInst); +} +}}; + +output decoder {{ +namespace Aarch64 +{ + StaticInstPtr + decodeNeon3Same(ExtMachInst machInst) + { + uint8_t q = bits(machInst, 30); + uint8_t u = bits(machInst, 29); + uint8_t size = bits(machInst, 23, 22); + uint8_t opcode = bits(machInst, 15, 11); + + IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); + IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); + IntRegIndex vm = (IntRegIndex) (uint8_t) bits(machInst, 20, 16); + + uint8_t size_q = (size << 1) | q; + uint8_t sz_q = size_q & 0x3; + + switch (opcode) { + case 0x00: + if (size == 0x3) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeSReg<UhaddDX, UhaddQX>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonSThreeSReg<ShaddDX, ShaddQX>( + q, size, machInst, vd, vn, vm); + case 0x01: + if (size_q == 0x6) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeXReg<UqaddDX, UqaddQX>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonSThreeXReg<SqaddDX, SqaddQX>( + q, size, machInst, vd, vn, vm); + case 0x02: + if (size == 0x3) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeSReg<UrhaddDX, UrhaddQX>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonSThreeSReg<SrhaddDX, SrhaddQX>( + q, size, machInst, vd, vn, vm); + case 0x03: + switch (size) { + case 0x0: + if (u) { + if (q) + return new EorQX<uint64_t>(machInst, vd, vn, vm); + else + return new EorDX<uint64_t>(machInst, vd, vn, vm); + } else { + if (q) + return new AndQX<uint64_t>(machInst, vd, vn, vm); + else + return new AndDX<uint64_t>(machInst, vd, vn, vm); + } + case 0x1: + if (u) { + if (q) + return new BslQX<uint64_t>(machInst, vd, vn, vm); + else + return new BslDX<uint64_t>(machInst, vd, vn, vm); + } else { + if (q) + return new BicQX<uint64_t>(machInst, vd, vn, vm); + else + return new BicDX<uint64_t>(machInst, vd, vn, vm); + } + case 0x2: + if (u) { + if (q) + return new BitQX<uint64_t>(machInst, vd, vn, vm); + else + return new BitDX<uint64_t>(machInst, vd, vn, vm); + } else { + if (q) + return new OrrQX<uint64_t>(machInst, vd, vn, vm); + else + return new OrrDX<uint64_t>(machInst, vd, vn, vm); + } + case 0x3: + if (u) { + if (q) + return new BifQX<uint64_t>(machInst, vd, vn, vm); + else + return new BifDX<uint64_t>(machInst, vd, vn, vm); + } else { + if (q) + return new OrnQX<uint64_t>(machInst, vd, vn, vm); + else + return new OrnDX<uint64_t>(machInst, vd, vn, vm); + } + } + case 0x04: + if (size == 0x3) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeSReg<UhsubDX, UhsubQX>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonSThreeSReg<ShsubDX, ShsubQX>( + q, size, machInst, vd, vn, vm); + case 0x05: + if (size_q == 0x6) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeXReg<UqsubDX, UqsubQX>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonSThreeXReg<SqsubDX, SqsubQX>( + q, size, machInst, vd, vn, vm); + case 0x06: + if (size_q == 0x6) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeXReg<CmhiDX, CmhiQX>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonSThreeXReg<CmgtDX, CmgtQX>( + q, size, machInst, vd, vn, vm); + case 0x07: + if (size_q == 0x6) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeXReg<CmhsDX, CmhsQX>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonSThreeXReg<CmgeDX, CmgeQX>( + q, size, machInst, vd, vn, vm); + case 0x08: + if (size_q == 0x6) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeXReg<UshlDX, UshlQX>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonSThreeXReg<SshlDX, SshlQX>( + q, size, machInst, vd, vn, vm); + case 0x09: + if (size_q == 0x6) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeXReg<UqshlDX, UqshlQX>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonSThreeXReg<SqshlDX, SqshlQX>( + q, size, machInst, vd, vn, vm); + case 0x0a: + if (size_q == 0x6) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeXReg<UrshlDX, UrshlQX>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonSThreeXReg<SrshlDX, SrshlQX>( + q, size, machInst, vd, vn, vm); + case 0x0b: + if (size_q == 0x6) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeXReg<UqrshlDX, UqrshlQX>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonSThreeXReg<SqrshlDX, SqrshlQX>( + q, size, machInst, vd, vn, vm); + case 0x0c: + if (size == 0x3) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeSReg<UmaxDX, UmaxQX>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonSThreeSReg<SmaxDX, SmaxQX>( + q, size, machInst, vd, vn, vm); + case 0x0d: + if (size == 0x3) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeSReg<UminDX, UminQX>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonSThreeSReg<SminDX, SminQX>( + q, size, machInst, vd, vn, vm); + case 0x0e: + if (size == 0x3) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeSReg<UabdDX, UabdQX>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonSThreeSReg<SabdDX, SabdQX>( + q, size, machInst, vd, vn, vm); + case 0x0f: + if (size == 0x3) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeSReg<UabaDX, UabaQX>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonSThreeSReg<SabaDX, SabaQX>( + q, size, machInst, vd, vn, vm); + case 0x10: + if (size_q == 0x6) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeXReg<SubDX, SubQX>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonUThreeXReg<AddDX, AddQX>( + q, size, machInst, vd, vn, vm); + case 0x11: + if (size_q == 0x6) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeXReg<CmeqDX, CmeqQX>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonUThreeXReg<CmtstDX, CmtstQX>( + q, size, machInst, vd, vn, vm); + case 0x12: + if (size == 0x3) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeSReg<MlsDX, MlsQX>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonUThreeSReg<MlaDX, MlaQX>( + q, size, machInst, vd, vn, vm); + case 0x13: + if (size == 0x3 || (size != 0x0 && bits(machInst, 29))) + return new Unknown64(machInst); + if (u) { + if (q) + return new PmulQX<uint8_t>(machInst, vd, vn, vm); + else + return new PmulDX<uint8_t>(machInst, vd, vn, vm); + } else { + return decodeNeonUThreeSReg<MulDX, MulQX>( + q, size, machInst, vd, vn, vm); + } + case 0x14: + if (size == 0x3) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeSReg<UmaxpDX, UmaxpQX>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonSThreeSReg<SmaxpDX, SmaxpQX>( + q, size, machInst, vd, vn, vm); + case 0x15: + if (size == 0x3) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeSReg<UminpDX, UminpQX>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonSThreeSReg<SminpDX, SminpQX>( + q, size, machInst, vd, vn, vm); + case 0x16: + if (size == 0x3 || size == 0x0) + return new Unknown64(machInst); + if (u) { + if (q) + return decodeNeonSThreeHAndWReg<SqrdmulhQX>( + size, machInst, vd, vn, vm); + else + return decodeNeonSThreeHAndWReg<SqrdmulhDX>( + size, machInst, vd, vn, vm); + } else { + if (q) + return decodeNeonSThreeHAndWReg<SqdmulhQX>( + size, machInst, vd, vn, vm); + else + return decodeNeonSThreeHAndWReg<SqdmulhDX>( + size, machInst, vd, vn, vm); + } + case 0x17: + if (u || size_q == 0x6) + return new Unknown64(machInst); + else + return decodeNeonUThreeXReg<AddpDX, AddpQX>( + q, size, machInst, vd, vn, vm); + case 0x18: + if (sz_q == 0x2) + return new Unknown64(machInst); + if (size < 0x2) { + if (u) + return decodeNeonUThreeFpReg<FmaxnmpDX, FmaxnmpQX>( + q, size & 0x1, machInst, vd, vn, vm); + else + return decodeNeonUThreeFpReg<FmaxnmDX, FmaxnmQX>( + q, size & 0x1, machInst, vd, vn, vm); + } else { + if (u) + return decodeNeonUThreeFpReg<FminnmpDX, FminnmpQX>( + q, size & 0x1, machInst, vd, vn, vm); + else + return decodeNeonUThreeFpReg<FminnmDX, FminnmQX>( + q, size & 0x1, machInst, vd, vn, vm); + } + case 0x19: + if (size < 0x2) { + if (u || sz_q == 0x2) + return new Unknown64(machInst); + else + return decodeNeonUThreeFpReg<FmlaDX, FmlaQX>( + q, size & 0x1, machInst, vd, vn, vm); + } else { + if (u || sz_q == 0x2) + return new Unknown64(machInst); + else + return decodeNeonUThreeFpReg<FmlsDX, FmlsQX>( + q, size & 0x1, machInst, vd, vn, vm); + } + case 0x1a: + if (sz_q == 0x2) + return new Unknown64(machInst); + if (size < 0x2) { + if (u) + return decodeNeonUThreeFpReg<FaddpDX, FaddpQX>( + q, size & 0x1, machInst, vd, vn, vm); + else + return decodeNeonUThreeFpReg<FaddDX, FaddQX>( + q, size & 0x1, machInst, vd, vn, vm); + } else { + if (u) + return decodeNeonUThreeFpReg<FabdDX, FabdQX>( + q, size & 0x1, machInst, vd, vn, vm); + else + return decodeNeonUThreeFpReg<FsubDX, FsubQX>( + q, size & 0x1, machInst, vd, vn, vm); + } + case 0x1b: + if (size < 0x2 && sz_q != 0x2) { + if (u) + return decodeNeonUThreeFpReg<FmulDX, FmulQX>( + q, size & 0x1, machInst, vd, vn, vm); + else + return decodeNeonUThreeFpReg<FmulxDX, FmulxQX>( + q, size & 0x1, machInst, vd, vn, vm); + } else { + return new Unknown64(machInst); + } + case 0x1c: + if (size < 0x2) { + if (u) + return decodeNeonUThreeFpReg<FcmgeDX, FcmgeQX>( + q, size & 0x1, machInst, vd, vn, vm); + else + return decodeNeonUThreeFpReg<FcmeqDX, FcmeqQX>( + q, size & 0x1, machInst, vd, vn, vm); + } else { + if (u) + return decodeNeonUThreeFpReg<FcmgtDX, FcmgtQX>( + q, size & 0x1, machInst, vd, vn, vm); + else + return new Unknown64(machInst); + } + case 0x1d: + if (size < 0x2) { + if (u) + return decodeNeonUThreeFpReg<FacgeDX, FacgeQX>( + q, size & 0x1, machInst, vd, vn, vm); + else + return new Unknown64(machInst); + } else { + if (u) + return decodeNeonUThreeFpReg<FacgtDX, FacgtQX>( + q, size & 0x1, machInst, vd, vn, vm); + else + return new Unknown64(machInst); + } + case 0x1e: + if (sz_q == 0x2) + return new Unknown64(machInst); + if (size < 0x2) { + if (u) + return decodeNeonUThreeFpReg<FmaxpDX, FmaxpQX>( + q, size & 0x1, machInst, vd, vn, vm); + else + return decodeNeonUThreeFpReg<FmaxDX, FmaxQX>( + q, size & 0x1, machInst, vd, vn, vm); + } else { + if (u) + return decodeNeonUThreeFpReg<FminpDX, FminpQX>( + q, size & 0x1, machInst, vd, vn, vm); + else + return decodeNeonUThreeFpReg<FminDX, FminQX>( + q, size & 0x1, machInst, vd, vn, vm); + } + case 0x1f: + if (sz_q == 0x2) + return new Unknown64(machInst); + if (size < 0x2) { + if (u) + return decodeNeonUThreeFpReg<FdivDX, FdivQX>( + q, size & 0x1, machInst, vd, vn, vm); + else + return decodeNeonUThreeFpReg<FrecpsDX, FrecpsQX>( + q, size & 0x1, machInst, vd, vn, vm); + } else { + if (u) + return new Unknown64(machInst); + else + return decodeNeonUThreeFpReg<FrsqrtsDX, FrsqrtsQX>( + q, size & 0x1, machInst, vd, vn, vm); + } + default: + return new Unknown64(machInst); + } + } + + StaticInstPtr + decodeNeon3Diff(ExtMachInst machInst) + { + uint8_t q = bits(machInst, 30); + uint8_t u = bits(machInst, 29); + uint8_t size = bits(machInst, 23, 22); + uint8_t opcode = bits(machInst, 15, 12); + + IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); + IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); + IntRegIndex vm = (IntRegIndex) (uint8_t) bits(machInst, 20, 16); + + switch (opcode) { + case 0x0: + if (size == 0x3) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeSReg<UaddlX, Uaddl2X>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonSThreeSReg<SaddlX, Saddl2X>( + q, size, machInst, vd, vn, vm); + case 0x1: + if (size == 0x3) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeSReg<UaddwX, Uaddw2X>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonSThreeSReg<SaddwX, Saddw2X>( + q, size, machInst, vd, vn, vm); + case 0x2: + if (size == 0x3) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeSReg<UsublX, Usubl2X>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonSThreeSReg<SsublX, Ssubl2X>( + q, size, machInst, vd, vn, vm); + case 0x3: + if (size == 0x3) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeSReg<UsubwX, Usubw2X>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonSThreeSReg<SsubwX, Ssubw2X>( + q, size, machInst, vd, vn, vm); + case 0x4: + if (size == 0x3) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeSReg<RaddhnX, Raddhn2X>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonUThreeSReg<AddhnX, Addhn2X>( + q, size, machInst, vd, vn, vm); + case 0x5: + if (size == 0x3) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeSReg<UabalX, Uabal2X>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonSThreeSReg<SabalX, Sabal2X>( + q, size, machInst, vd, vn, vm); + case 0x6: + if (size == 0x3) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeSReg<RsubhnX, Rsubhn2X>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonUThreeSReg<SubhnX, Subhn2X>( + q, size, machInst, vd, vn, vm); + case 0x7: + if (size == 0x3) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeSReg<UabdlX, Uabdl2X>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonSThreeSReg<SabdlX, Sabdl2X>( + q, size, machInst, vd, vn, vm); + case 0x8: + if (size == 0x3) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeSReg<UmlalX, Umlal2X>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonSThreeSReg<SmlalX, Smlal2X>( + q, size, machInst, vd, vn, vm); + case 0x9: + if (u || (size == 0x0 || size == 0x3)) { + return new Unknown64(machInst); + } else { + if (q) { + return decodeNeonSThreeHAndWReg<Sqdmlal2X>( + size, machInst, vd, vn, vm); + } else { + return decodeNeonSThreeHAndWReg<SqdmlalX>( + size, machInst, vd, vn, vm); + } + } + case 0xa: + if (size == 0x3) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeSReg<UmlslX, Umlsl2X>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonSThreeSReg<SmlslX, Smlsl2X>( + q, size, machInst, vd, vn, vm); + case 0xb: + if (u || (size == 0x0 || size == 0x3)) { + return new Unknown64(machInst); + } else { + if (q) { + return decodeNeonSThreeHAndWReg<Sqdmlsl2X>( + size, machInst, vd, vn, vm); + } else { + return decodeNeonSThreeHAndWReg<SqdmlslX>( + size, machInst, vd, vn, vm); + } + } + case 0xc: + if (size == 0x3) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeSReg<UmullX, Umull2X>( + q, size, machInst, vd, vn, vm); + else + return decodeNeonSThreeSReg<SmullX, Smull2X>( + q, size, machInst, vd, vn, vm); + case 0xd: + if (u || (size == 0x0 || size == 0x3)) { + return new Unknown64(machInst); + } else { + if (q) { + return decodeNeonSThreeHAndWReg<Sqdmull2X>( + size, machInst, vd, vn, vm); + } else { + return decodeNeonSThreeHAndWReg<SqdmullX>( + size, machInst, vd, vn, vm); + } + } + case 0xe: + if (u || size != 0) { + return new Unknown64(machInst); + } else { + if (q) + return new Pmull2X<uint8_t>(machInst, vd, vn, vm); + else + return new PmullX<uint8_t>(machInst, vd, vn, vm); + } + default: + return new Unknown64(machInst); + } + } + + StaticInstPtr + decodeNeon2RegMisc(ExtMachInst machInst) + { + uint8_t q = bits(machInst, 30); + uint8_t u = bits(machInst, 29); + uint8_t size = bits(machInst, 23, 22); + uint8_t opcode = bits(machInst, 16, 12); + + IntRegIndex vd = (IntRegIndex)(uint8_t)bits(machInst, 4, 0); + IntRegIndex vn = (IntRegIndex)(uint8_t)bits(machInst, 9, 5); + + uint8_t size_q = (size << 1) | q; + uint8_t sz_q = size_q & 0x3; + uint8_t op = (uint8_t)((bits(machInst, 12) << 1) | + bits(machInst, 29)); + uint8_t switchVal = opcode | ((u ? 1 : 0) << 5); + + switch (switchVal) { + case 0x00: + if (op + size >= 3) + return new Unknown64(machInst); + return decodeNeonUTwoMiscSReg<Rev64DX, Rev64QX>( + q, size, machInst, vd, vn); + case 0x01: + if (op + size >= 3) + return new Unknown64(machInst); + if (q) + return new Rev16QX<uint8_t>(machInst, vd, vn); + else + return new Rev16DX<uint8_t>(machInst, vd, vn); + case 0x02: + if (size == 0x3) + return new Unknown64(machInst); + return decodeNeonSTwoMiscSReg<SaddlpDX, SaddlpQX>( + q, size, machInst, vd, vn); + case 0x03: + if (size_q == 0x6) + return new Unknown64(machInst); + return decodeNeonUTwoMiscXReg<SuqaddDX, SuqaddQX>( + q, size, machInst, vd, vn); + case 0x04: + if (size == 0x3) + return new Unknown64(machInst); + return decodeNeonSTwoMiscSReg<ClsDX, ClsQX>( + q, size, machInst, vd, vn); + case 0x05: + if (size != 0x0) + return new Unknown64(machInst); + if (q) + return new CntQX<uint8_t>(machInst, vd, vn); + else + return new CntDX<uint8_t>(machInst, vd, vn); + case 0x06: + if (size == 0x3) + return new Unknown64(machInst); + return decodeNeonSTwoMiscSReg<SadalpDX, SadalpQX>( + q, size, machInst, vd, vn); + case 0x07: + if (size_q == 0x6) + return new Unknown64(machInst); + return decodeNeonSTwoMiscXReg<SqabsDX, SqabsQX>( + q, size, machInst, vd, vn); + case 0x08: + if (size_q == 0x6) + return new Unknown64(machInst); + return decodeNeonSTwoMiscXReg<CmgtZeroDX, CmgtZeroQX>( + q, size, machInst, vd, vn); + case 0x09: + if (size_q == 0x6) + return new Unknown64(machInst); + return decodeNeonSTwoMiscXReg<CmeqZeroDX, CmeqZeroQX>( + q, size, machInst, vd, vn); + case 0x0a: + if (size_q == 0x6) + return new Unknown64(machInst); + return decodeNeonSTwoMiscXReg<CmltZeroDX, CmltZeroQX>( + q, size, machInst, vd, vn); + case 0x0b: + if (size_q == 0x6) + return new Unknown64(machInst); + return decodeNeonSTwoMiscXReg<AbsDX, AbsQX>( + q, size, machInst, vd, vn); + case 0x0c: + if (size < 0x2 || sz_q == 0x2) + return new Unknown64(machInst); + return decodeNeonUTwoMiscFpReg<FcmgtZeroDX, FcmgtZeroQX>( + q, size & 0x1, machInst, vd, vn); + case 0x0d: + if (size < 0x2 || sz_q == 0x2) + return new Unknown64(machInst); + return decodeNeonUTwoMiscFpReg<FcmeqZeroDX, FcmeqZeroQX>( + q, size & 0x1, machInst, vd, vn); + case 0x0e: + if (size < 0x2 || sz_q == 0x2) + return new Unknown64(machInst); + return decodeNeonUTwoMiscFpReg<FcmltZeroDX, FcmltZeroQX>( + q, size & 0x1, machInst, vd, vn); + case 0x0f: + if (size < 0x2 || sz_q == 0x2) + return new Unknown64(machInst); + return decodeNeonUTwoMiscFpReg<FabsDX, FabsQX>( + q, size & 0x1, machInst, vd, vn); + case 0x12: + if (size == 0x3) + return new Unknown64(machInst); + return decodeNeonUTwoMiscSReg<XtnX, Xtn2X>( + q, size, machInst, vd, vn); + case 0x14: + if (size == 0x3) + return new Unknown64(machInst); + return decodeNeonSTwoMiscSReg<SqxtnX, Sqxtn2X>( + q, size, machInst, vd, vn); + case 0x16: + if (size > 0x1) + return new Unknown64(machInst); + if (q) { + if (size) + return new Fcvtn2X<uint32_t>(machInst, vd, vn); + else + return new Fcvtn2X<uint16_t>(machInst, vd, vn); + } else { + if (size) + return new FcvtnX<uint32_t>(machInst, vd, vn); + else + return new FcvtnX<uint16_t>(machInst, vd, vn); + } + case 0x17: + if (size > 0x1) + return new Unknown64(machInst); + if (q) { + if (size) + return new Fcvtl2X<uint32_t>(machInst, vd, vn); + else + return new Fcvtl2X<uint16_t>(machInst, vd, vn); + } else { + if (size) + return new FcvtlX<uint32_t>(machInst, vd, vn); + else + return new FcvtlX<uint16_t>(machInst, vd, vn); + } + case 0x18: + if (sz_q == 0x2) + return new Unknown64(machInst); + if (size < 0x2) + return decodeNeonUTwoMiscFpReg<FrintnDX, FrintnQX>( + q, size & 0x1, machInst, vd, vn); + else + return decodeNeonUTwoMiscFpReg<FrintpDX, FrintpQX>( + q, size & 0x1, machInst, vd, vn); + case 0x19: + if (sz_q == 0x2) + return new Unknown64(machInst); + if (size < 0x2) + return decodeNeonUTwoMiscFpReg<FrintmDX, FrintmQX>( + q, size & 0x1, machInst, vd, vn); + else + return decodeNeonUTwoMiscFpReg<FrintzDX, FrintzQX>( + q, size & 0x1, machInst, vd, vn); + case 0x1a: + if (sz_q == 0x2) + return new Unknown64(machInst); + if (size < 0x2) + return decodeNeonUTwoMiscFpReg<FcvtnsDX, FcvtnsQX>( + q, size & 0x1, machInst, vd, vn); + else + return decodeNeonUTwoMiscFpReg<FcvtpsDX, FcvtpsQX>( + q, size & 0x1, machInst, vd, vn); + case 0x1b: + if (sz_q == 0x2) + return new Unknown64(machInst); + if (size < 0x2) + return decodeNeonUTwoMiscFpReg<FcvtmsDX, FcvtmsQX>( + q, size & 0x1, machInst, vd, vn); + else + return decodeNeonUTwoMiscFpReg<FcvtzsIntDX, FcvtzsIntQX>( + q, size & 0x1, machInst, vd, vn); + case 0x1c: + if (size < 0x2) { + if (sz_q == 0x2) + return new Unknown64(machInst); + return decodeNeonUTwoMiscFpReg<FcvtasDX, FcvtasQX>( + q, size & 0x1, machInst, vd, vn); + } else { + if (size & 0x1) + return new Unknown64(machInst); + if (q) + return new UrecpeQX<uint32_t>(machInst, vd, vn); + else + return new UrecpeDX<uint32_t>(machInst, vd, vn); + } + case 0x1d: + if (sz_q == 0x2) + return new Unknown64(machInst); + if (size < 0x2) { + if (q) { + if (size & 0x1) + return new ScvtfIntDQX<uint64_t>(machInst, vd, vn); + else + return new ScvtfIntSQX<uint32_t>(machInst, vd, vn); + } else { + if (size & 0x1) + return new Unknown(machInst); + else + return new ScvtfIntDX<uint32_t>(machInst, vd, vn); + } + } else { + return decodeNeonUTwoMiscFpReg<FrecpeDX, FrecpeQX>( + q, size & 0x1, machInst, vd, vn); + } + case 0x20: + if (op + size >= 3) + return new Unknown64(machInst); + if (q) { + if (size & 0x1) + return new Rev32QX<uint16_t>(machInst, vd, vn); + else + return new Rev32QX<uint8_t>(machInst, vd, vn); + } else { + if (size & 0x1) + return new Rev32DX<uint16_t>(machInst, vd, vn); + else + return new Rev32DX<uint8_t>(machInst, vd, vn); + } + case 0x22: + if (size == 0x3) + return new Unknown64(machInst); + return decodeNeonUTwoMiscSReg<UaddlpDX, UaddlpQX>( + q, size, machInst, vd, vn); + case 0x23: + if (size_q == 0x6) + return new Unknown64(machInst); + return decodeNeonUTwoMiscXReg<UsqaddDX, UsqaddQX>( + q, size, machInst, vd, vn); + return new Unknown64(machInst); + case 0x24: + if (size == 0x3) + return new Unknown64(machInst); + return decodeNeonSTwoMiscSReg<ClzDX, ClzQX>( + q, size, machInst, vd, vn); + case 0x25: + if (size == 0x0) { + if (q) + return new MvnQX<uint64_t>(machInst, vd, vn); + else + return new MvnDX<uint64_t>(machInst, vd, vn); + } else if (size == 0x1) { + if (q) + return new RbitQX<uint8_t>(machInst, vd, vn); + else + return new RbitDX<uint8_t>(machInst, vd, vn); + } else { + return new Unknown64(machInst); + } + case 0x26: + if (size == 0x3) + return new Unknown64(machInst); + return decodeNeonUTwoMiscSReg<UadalpDX, UadalpQX>( + q, size, machInst, vd, vn); + case 0x27: + if (size_q == 0x6) + return new Unknown64(machInst); + return decodeNeonSTwoMiscXReg<SqnegDX, SqnegQX>( + q, size, machInst, vd, vn); + case 0x28: + if (size_q == 0x6) + return new Unknown64(machInst); + return decodeNeonSTwoMiscXReg<CmgeZeroDX, CmgeZeroQX>( + q, size, machInst, vd, vn); + case 0x29: + if (size_q == 0x6) + return new Unknown64(machInst); + return decodeNeonSTwoMiscXReg<CmleZeroDX, CmleZeroQX>( + q, size, machInst, vd, vn); + case 0x2b: + if (size_q == 0x6) + return new Unknown64(machInst); + return decodeNeonSTwoMiscXReg<NegDX, NegQX>( + q, size, machInst, vd, vn); + case 0x2c: + if (size < 0x2 || sz_q == 0x2) + return new Unknown64(machInst); + return decodeNeonUTwoMiscFpReg<FcmgeZeroDX, FcmgeZeroQX>( + q, size & 0x1, machInst, vd, vn); + case 0x2d: + if (size < 0x2 || sz_q == 0x2) + return new Unknown64(machInst); + return decodeNeonUTwoMiscFpReg<FcmleZeroDX, FcmleZeroQX>( + q, size & 0x1, machInst, vd, vn); + case 0x2f: + if (size < 0x2 || size_q == 0x6) + return new Unknown64(machInst); + return decodeNeonUTwoMiscFpReg<FnegDX, FnegQX>( + q, size & 0x1, machInst, vd, vn); + case 0x32: + if (size == 0x3) + return new Unknown64(machInst); + return decodeNeonSTwoMiscSReg<SqxtunX, Sqxtun2X>( + q, size, machInst, vd, vn); + case 0x33: + if (size == 0x3) + return new Unknown64(machInst); + return decodeNeonUTwoMiscSReg<ShllX, Shll2X>( + q, size, machInst, vd, vn); + case 0x34: + if (size == 0x3) + return new Unknown64(machInst); + return decodeNeonUTwoMiscSReg<UqxtnX, Uqxtn2X>( + q, size, machInst, vd, vn); + case 0x36: + if (size != 0x1) + return new Unknown64(machInst); + if (q) + return new Fcvtxn2X<uint32_t>(machInst, vd, vn); + else + return new FcvtxnX<uint32_t>(machInst, vd, vn); + case 0x38: + if (size > 0x1 || sz_q == 0x2) + return new Unknown64(machInst); + return decodeNeonUTwoMiscFpReg<FrintaDX, FrintaQX>( + q, size & 0x1, machInst, vd, vn); + case 0x39: + if (sz_q == 0x2) + return new Unknown64(machInst); + if (size < 0x2) + return decodeNeonUTwoMiscFpReg<FrintxDX, FrintxQX>( + q, size & 0x1, machInst, vd, vn); + else + return decodeNeonUTwoMiscFpReg<FrintiDX, FrintiQX>( + q, size & 0x1, machInst, vd, vn); + case 0x3a: + if (sz_q == 0x2) + return new Unknown64(machInst); + if (size < 0x2) + return decodeNeonUTwoMiscFpReg<FcvtnuDX, FcvtnuQX>( + q, size & 0x1, machInst, vd, vn); + else + return decodeNeonUTwoMiscFpReg<FcvtpuDX, FcvtpuQX>( + q, size & 0x1, machInst, vd, vn); + case 0x3b: + if (sz_q == 0x2) + return new Unknown64(machInst); + if (size < 0x2) + return decodeNeonUTwoMiscFpReg<FcvtmuDX, FcvtmuQX>( + q, size & 0x1, machInst, vd, vn); + else + return decodeNeonUTwoMiscFpReg<FcvtzuIntDX, FcvtzuIntQX>( + q, size & 0x1, machInst, vd, vn); + case 0x3c: + if (size < 0x2) { + return decodeNeonUTwoMiscFpReg<FcvtauDX, FcvtauQX>( + q, size & 0x1, machInst, vd, vn); + } else if (size == 0x2) { + if (q) + return new UrsqrteQX<uint32_t>(machInst, vd, vn); + else + return new UrsqrteDX<uint32_t>(machInst, vd, vn); + } else { + return new Unknown64(machInst); + } + case 0x3d: + if (sz_q == 0x2) + return new Unknown64(machInst); + if (size < 0x2) + return decodeNeonUTwoMiscFpReg<UcvtfIntDX, UcvtfIntQX>( + q, size & 0x1, machInst, vd, vn); + else + return decodeNeonUTwoMiscFpReg<FrsqrteDX, FrsqrteQX>( + q, size & 0x1, machInst, vd, vn); + case 0x3f: + if (size < 0x2 || sz_q == 0x2) + return new Unknown64(machInst); + return decodeNeonUTwoMiscFpReg<FsqrtDX, FsqrtQX>( + q, size & 0x1, machInst, vd, vn); + default: + return new Unknown64(machInst); + } + } + + StaticInstPtr + decodeNeonAcrossLanes(ExtMachInst machInst) + { + uint8_t q = bits(machInst, 30); + uint8_t u = bits(machInst, 29); + uint8_t size = bits(machInst, 23, 22); + uint8_t opcode = bits(machInst, 16, 12); + + IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); + IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); + + uint8_t size_q = (size << 1) | q; + uint8_t sz_q = size_q & 0x3; + uint8_t switchVal = opcode | ((u ? 1 : 0) << 5); + + switch (switchVal) { + case 0x03: + if (size_q == 0x4 || size == 0x3) + return new Unknown64(machInst); + return decodeNeonSAcrossLanesLongReg<SaddlvDX, SaddlvQX, + SaddlvBQX>( + q, size, machInst, vd, vn); + case 0x0a: + if (size_q == 0x4 || size == 0x3) + return new Unknown64(machInst); + return decodeNeonSAcrossLanesReg<SmaxvDX, SmaxvQX>( + q, size, machInst, vd, vn); + case 0x1a: + if (size_q == 0x4 || size == 0x3) + return new Unknown64(machInst); + return decodeNeonSAcrossLanesReg<SminvDX, SminvQX>( + q, size, machInst, vd, vn); + case 0x1b: + if (size_q == 0x4 || size == 0x3) + return new Unknown64(machInst); + return decodeNeonUAcrossLanesReg<AddvDX, AddvQX>( + q, size, machInst, vd, vn); + case 0x23: + if (size_q == 0x4 || size == 0x3) + return new Unknown64(machInst); + return decodeNeonUAcrossLanesLongReg<UaddlvDX, UaddlvQX, + UaddlvBQX>( + q, size, machInst, vd, vn); + case 0x2a: + if (size_q == 0x4 || size == 0x3) + return new Unknown64(machInst); + return decodeNeonUAcrossLanesReg<UmaxvDX, UmaxvQX>( + q, size, machInst, vd, vn); + case 0x2c: + if (sz_q != 0x1) + return new Unknown64(machInst); + if (size < 0x2) { + if (q) + return new FmaxnmvQX<uint32_t>(machInst, vd, vn); + else + return new Unknown64(machInst); + } else { + if (q) + return new FminnmvQX<uint32_t>(machInst, vd, vn); + else + return new Unknown64(machInst); + } + case 0x2f: + if (sz_q != 0x1) + return new Unknown64(machInst); + if (size < 0x2) { + if (q) + return new FmaxvQX<uint32_t>(machInst, vd, vn); + else + return new Unknown64(machInst); + } else { + if (q) + return new FminvQX<uint32_t>(machInst, vd, vn); + else + return new Unknown64(machInst); + } + case 0x3a: + if (size_q == 0x4 || size == 0x3) + return new Unknown64(machInst); + return decodeNeonUAcrossLanesReg<UminvDX, UminvQX>( + q, size, machInst, vd, vn); + default: + return new Unknown64(machInst); + } + } + + StaticInstPtr + decodeNeonCopy(ExtMachInst machInst) + { + uint8_t q = bits(machInst, 30); + uint8_t op = bits(machInst, 29); + uint8_t imm5 = bits(machInst, 20, 16); + uint8_t imm4 = bits(machInst, 14, 11); + + IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); + IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); + + uint8_t imm5_pos = findLsbSet(imm5); + uint8_t index1 = 0, index2 = 0; + + if (op) { + if (!q || (imm4 & mask(imm5_pos))) + return new Unknown64(machInst); + + index1 = bits(imm5, 4, imm5_pos + 1); // dst + index2 = bits(imm4, 3, imm5_pos); // src + + switch (imm5_pos) { + case 0: + return new InsElemX<uint8_t>(machInst, vd, vn, index1, index2); + case 1: + return new InsElemX<uint16_t>(machInst, vd, vn, index1, index2); + case 2: + return new InsElemX<uint32_t>(machInst, vd, vn, index1, index2); + case 3: + return new InsElemX<uint64_t>(machInst, vd, vn, index1, index2); + default: + return new Unknown64(machInst); + } + } + + switch (imm4) { + case 0x0: + index1 = bits(imm5, 4, imm5_pos + 1); + switch (imm5_pos) { + case 0: + if (q) + return new DupElemQX<uint8_t>(machInst, vd, vn, index1); + else + return new DupElemDX<uint8_t>(machInst, vd, vn, index1); + case 1: + if (q) + return new DupElemQX<uint16_t>(machInst, vd, vn, index1); + else + return new DupElemDX<uint16_t>(machInst, vd, vn, index1); + case 2: + if (q) + return new DupElemQX<uint32_t>(machInst, vd, vn, index1); + else + return new DupElemDX<uint32_t>(machInst, vd, vn, index1); + case 3: + if (q) + return new DupElemQX<uint64_t>(machInst, vd, vn, index1); + else + return new Unknown64(machInst); + default: + return new Unknown64(machInst); + } + case 0x1: + switch (imm5) { + case 0x1: + if (q) + return new DupGprWQX<uint8_t>(machInst, vd, vn); + else + return new DupGprWDX<uint8_t>(machInst, vd, vn); + case 0x2: + if (q) + return new DupGprWQX<uint16_t>(machInst, vd, vn); + else + return new DupGprWDX<uint16_t>(machInst, vd, vn); + case 0x4: + if (q) + return new DupGprWQX<uint32_t>(machInst, vd, vn); + else + return new DupGprWDX<uint32_t>(machInst, vd, vn); + case 0x8: + if (q) + return new DupGprXQX<uint64_t>(machInst, vd, vn); + else + return new Unknown64(machInst); + } + case 0x3: + index1 = imm5 >> (imm5_pos + 1); + switch (imm5_pos) { + case 0: + return new InsGprWX<uint8_t>(machInst, vd, vn, index1); + case 1: + return new InsGprWX<uint16_t>(machInst, vd, vn, index1); + case 2: + return new InsGprWX<uint32_t>(machInst, vd, vn, index1); + case 3: + return new InsGprXX<uint64_t>(machInst, vd, vn, index1); + default: + return new Unknown64(machInst); + } + case 0x5: + index1 = bits(imm5, 4, imm5_pos + 1); + switch (imm5_pos) { + case 0: + if (q) + return new SmovXX<int8_t>(machInst, vd, vn, index1); + else + return new SmovWX<int8_t>(machInst, vd, vn, index1); + case 1: + if (q) + return new SmovXX<int16_t>(machInst, vd, vn, index1); + else + return new SmovWX<int16_t>(machInst, vd, vn, index1); + case 2: + if (q) + return new SmovXX<int32_t>(machInst, vd, vn, index1); + else + return new Unknown64(machInst); + default: + return new Unknown64(machInst); + } + case 0x7: + index1 = imm5 >> (imm5_pos + 1); + + if ((q && imm5_pos != 3) || (!q && imm5_pos >= 3)) + return new Unknown64(machInst); + + switch (imm5_pos) { + case 0: + return new UmovWX<uint8_t>(machInst, vd, vn, index1); + case 1: + return new UmovWX<uint16_t>(machInst, vd, vn, index1); + case 2: + return new UmovWX<uint32_t>(machInst, vd, vn, index1); + case 3: + return new UmovXX<uint64_t>(machInst, vd, vn, index1); + default: + return new Unknown64(machInst); + } + default: + return new Unknown64(machInst); + } + } + + StaticInstPtr + decodeNeonIndexedElem(ExtMachInst machInst) + { + uint8_t q = bits(machInst, 30); + uint8_t u = bits(machInst, 29); + uint8_t size = bits(machInst, 23, 22); + uint8_t L = bits(machInst, 21); + uint8_t M = bits(machInst, 20); + uint8_t opcode = bits(machInst, 15, 12); + uint8_t H = bits(machInst, 11); + + IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); + IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); + IntRegIndex vm_bf = (IntRegIndex) (uint8_t) bits(machInst, 19, 16); + + uint8_t index = 0; + uint8_t index_fp = 0; + uint8_t vmh = 0; + uint8_t sz = size & 0x1; + uint8_t sz_q = (sz << 1) | bits(machInst, 30); + uint8_t sz_L = (sz << 1) | L; + + // Index and 2nd register operand for integer instructions + if (size == 0x1) { + index = (H << 2) | (L << 1) | M; + // vmh = 0; + } else if (size == 0x2) { + index = (H << 1) | L; + vmh = M; + } + IntRegIndex vm = (IntRegIndex) (uint8_t) (vmh << 4 | vm_bf); + + // Index and 2nd register operand for FP instructions + vmh = M; + if ((size & 0x1) == 0) { + index_fp = (H << 1) | L; + } else if (L == 0) { + index_fp = H; + } + IntRegIndex vm_fp = (IntRegIndex) (uint8_t) (vmh << 4 | vm_bf); + + switch (opcode) { + case 0x0: + if (!u || (size == 0x0 || size == 0x3)) + return new Unknown64(machInst); + else + return decodeNeonUThreeImmHAndWReg<MlaElemDX, MlaElemQX>( + q, size, machInst, vd, vn, vm, index); + case 0x1: + if (!u && size >= 2 && sz_q != 0x2 && sz_L != 0x3) + return decodeNeonUThreeImmFpReg<FmlaElemDX, FmlaElemQX>( + q, sz, machInst, vd, vn, vm_fp, index_fp); + else + return new Unknown64(machInst); + case 0x2: + if (size == 0x0 || size == 0x3) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeImmHAndWReg<UmlalElemX, UmlalElem2X>( + q, size, machInst, vd, vn, vm, index); + else + return decodeNeonSThreeImmHAndWReg<SmlalElemX, SmlalElem2X>( + q, size, machInst, vd, vn, vm, index); + case 0x3: + if (u || (size == 0x0 || size == 0x3)) + return new Unknown64(machInst); + else + return decodeNeonSThreeImmHAndWReg<SqdmlalElemX, + SqdmlalElem2X>( + q, size, machInst, vd, vn, vm, index); + case 0x4: + if (u && !(size == 0x0 || size == 0x3)) + return decodeNeonUThreeImmHAndWReg<MlsElemDX, MlsElemQX>( + q, size, machInst, vd, vn, vm, index); + else + return new Unknown64(machInst); + case 0x5: + if (!u && size >= 0x2 && sz_L != 0x3 && sz_q != 0x2) + return decodeNeonUThreeImmFpReg<FmlsElemDX, FmlsElemQX>( + q, sz, machInst, vd, vn, vm_fp, index_fp); + else + return new Unknown64(machInst); + case 0x6: + if (size == 0x0 || size == 0x3) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeImmHAndWReg<UmlslElemX, UmlslElem2X>( + q, size, machInst, vd, vn, vm, index); + else + return decodeNeonSThreeImmHAndWReg<SmlslElemX, SmlslElem2X>( + q, size, machInst, vd, vn, vm, index); + case 0x7: + if (u || (size == 0x0 || size == 0x3)) + return new Unknown64(machInst); + else + return decodeNeonSThreeImmHAndWReg<SqdmlslElemX, + SqdmlslElem2X>( + q, size, machInst, vd, vn, vm, index); + case 0x8: + if (u || (size == 0x0 || size == 0x3)) + return new Unknown64(machInst); + else + return decodeNeonUThreeImmHAndWReg<MulElemDX, MulElemQX>( + q, size, machInst, vd, vn, vm, index); + case 0x9: + if (size >= 2 && sz_q != 0x2 && sz_L != 0x3) { + if (u) + return decodeNeonUThreeImmFpReg<FmulxElemDX, FmulxElemQX>( + q, sz, machInst, vd, vn, vm_fp, index_fp); + else + return decodeNeonUThreeImmFpReg<FmulElemDX, FmulElemQX>( + q, sz, machInst, vd, vn, vm_fp, index_fp); + } else { + return new Unknown64(machInst); + } + case 0xa: + if (size == 0x0 || size == 0x3) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeImmHAndWReg<UmullElemX, UmullElem2X>( + q, size, machInst, vd, vn, vm, index); + else + return decodeNeonSThreeImmHAndWReg<SmullElemX, SmullElem2X>( + q, size, machInst, vd, vn, vm, index); + case 0xb: + if (u || (size == 0x0 || size == 0x3)) + return new Unknown64(machInst); + else + return decodeNeonSThreeImmHAndWReg<SqdmullElemX, SqdmullElem2X>( + q, size, machInst, vd, vn, vm, index); + case 0xc: + if (u || (size == 0x0 || size == 0x3)) + return new Unknown64(machInst); + else + return decodeNeonSThreeImmHAndWReg<SqdmulhElemDX, SqdmulhElemQX>( + q, size, machInst, vd, vn, vm, index); + case 0xd: + if (u || (size == 0x0 || size == 0x3)) + return new Unknown64(machInst); + else + return decodeNeonSThreeImmHAndWReg<SqrdmulhElemDX, SqrdmulhElemQX>( + q, size, machInst, vd, vn, vm, index); + default: + return new Unknown64(machInst); + } + } + + StaticInstPtr + decodeNeonModImm(ExtMachInst machInst) + { + uint8_t q = bits(machInst, 30); + uint8_t op = bits(machInst, 29); + uint8_t abcdefgh = (bits(machInst, 18, 16) << 5) | + bits(machInst, 9, 5); + uint8_t cmode = bits(machInst, 15, 12); + uint8_t o2 = bits(machInst, 11); + + IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); + + if (o2 == 0x1 || (op == 0x1 && cmode == 0xf && !q)) + return new Unknown64(machInst); + + bool immValid = true; + const uint64_t bigImm = simd_modified_imm(op, cmode, abcdefgh, + immValid, + true /* isAarch64 */); + if (!immValid) { + return new Unknown(machInst); + } + + if (op) { + if (bits(cmode, 3) == 0) { + if (bits(cmode, 0) == 0) { + if (q) + return new MvniQX<uint64_t>(machInst, vd, bigImm); + else + return new MvniDX<uint64_t>(machInst, vd, bigImm); + } else { + if (q) + return new BicImmQX<uint64_t>(machInst, vd, bigImm); + else + return new BicImmDX<uint64_t>(machInst, vd, bigImm); + } + } else { + if (bits(cmode, 2) == 1) { + switch (bits(cmode, 1, 0)) { + case 0: + case 1: + if (q) + return new MvniQX<uint64_t>(machInst, vd, bigImm); + else + return new MvniDX<uint64_t>(machInst, vd, bigImm); + case 2: + if (q) + return new MoviQX<uint64_t>(machInst, vd, bigImm); + else + return new MoviDX<uint64_t>(machInst, vd, bigImm); + case 3: + if (q) + return new FmovQX<uint64_t>(machInst, vd, bigImm); + else + return new MoviDX<uint64_t>(machInst, vd, bigImm); + } + } else { + if (bits(cmode, 0) == 0) { + if (q) + return new MvniQX<uint64_t>(machInst, vd, bigImm); + else + return new MvniDX<uint64_t>(machInst, vd, bigImm); + } else { + if (q) + return new BicImmQX<uint64_t>(machInst, vd, + bigImm); + else + return new BicImmDX<uint64_t>(machInst, vd, + bigImm); + } + } + } + } else { + if (bits(cmode, 3) == 0) { + if (bits(cmode, 0) == 0) { + if (q) + return new MoviQX<uint64_t>(machInst, vd, bigImm); + else + return new MoviDX<uint64_t>(machInst, vd, bigImm); + } else { + if (q) + return new OrrImmQX<uint64_t>(machInst, vd, bigImm); + else + return new OrrImmDX<uint64_t>(machInst, vd, bigImm); + } + } else { + if (bits(cmode, 2) == 1) { + if (bits(cmode, 1, 0) == 0x3) { + if (q) + return new FmovQX<uint32_t>(machInst, vd, bigImm); + else + return new FmovDX<uint32_t>(machInst, vd, bigImm); + } else { + if (q) + return new MoviQX<uint64_t>(machInst, vd, bigImm); + else + return new MoviDX<uint64_t>(machInst, vd, bigImm); + } + } else { + if (bits(cmode, 0) == 0) { + if (q) + return new MoviQX<uint64_t>(machInst, vd, bigImm); + else + return new MoviDX<uint64_t>(machInst, vd, bigImm); + } else { + if (q) + return new OrrImmQX<uint64_t>(machInst, vd, + bigImm); + else + return new OrrImmDX<uint64_t>(machInst, vd, bigImm); + } + } + } + } + return new Unknown(machInst); + } + + StaticInstPtr + decodeNeonShiftByImm(ExtMachInst machInst) + { + uint8_t q = bits(machInst, 30); + uint8_t u = bits(machInst, 29); + uint8_t immh = bits(machInst, 22, 19); + uint8_t immb = bits(machInst, 18, 16); + uint8_t opcode = bits(machInst, 15, 11); + + IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); + IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); + + uint8_t immh3 = bits(machInst, 22); + uint8_t immh3_q = (immh3 << 1) | q; + uint8_t op_u = (bits(machInst, 12) << 1) | u; + uint8_t size = findMsbSet(immh); + int shiftAmt = 0; + + switch (opcode) { + case 0x00: + if (immh3_q == 0x2) + return new Unknown64(machInst); + shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); + if (u) + return decodeNeonUTwoShiftXReg<UshrDX, UshrQX>( + q, size, machInst, vd, vn, shiftAmt); + else + return decodeNeonSTwoShiftXReg<SshrDX, SshrQX>( + q, size, machInst, vd, vn, shiftAmt); + case 0x02: + if (immh3_q == 0x2) + return new Unknown64(machInst); + shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); + if (u) + return decodeNeonUTwoShiftXReg<UsraDX, UsraQX>( + q, size, machInst, vd, vn, shiftAmt); + else + return decodeNeonSTwoShiftXReg<SsraDX, SsraQX>( + q, size, machInst, vd, vn, shiftAmt); + case 0x04: + if (immh3_q == 0x2) + return new Unknown64(machInst); + shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); + if (u) + return decodeNeonUTwoShiftXReg<UrshrDX, UrshrQX>( + q, size, machInst, vd, vn, shiftAmt); + else + return decodeNeonSTwoShiftXReg<SrshrDX, SrshrQX>( + q, size, machInst, vd, vn, shiftAmt); + case 0x06: + if (immh3_q == 0x2) + return new Unknown64(machInst); + shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); + if (u) + return decodeNeonUTwoShiftXReg<UrsraDX, UrsraQX>( + q, size, machInst, vd, vn, shiftAmt); + else + return decodeNeonSTwoShiftXReg<SrsraDX, SrsraQX>( + q, size, machInst, vd, vn, shiftAmt); + case 0x08: + if (u && !(immh3_q == 0x2)) { + shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); + return decodeNeonUTwoShiftXReg<SriDX, SriQX>( + q, size, machInst, vd, vn, shiftAmt); + } else { + return new Unknown64(machInst); + } + case 0x0a: + if (immh3_q == 0x2) + return new Unknown64(machInst); + shiftAmt = ((immh << 3) | immb) - (8 << size); + if (u) + return decodeNeonUTwoShiftXReg<SliDX, SliQX>( + q, size, machInst, vd, vn, shiftAmt); + else + return decodeNeonUTwoShiftXReg<ShlDX, ShlQX>( + q, size, machInst, vd, vn, shiftAmt); + case 0x0c: + if (u && !(immh3_q == 0x2 || op_u == 0x0)) { + shiftAmt = ((immh << 3) | immb) - (8 << size); + return decodeNeonSTwoShiftXReg<SqshluDX, SqshluQX>( + q, size, machInst, vd, vn, shiftAmt); + } else { + return new Unknown64(machInst); + } + case 0x0e: + if (immh3_q == 0x2 || op_u == 0x0) + return new Unknown64(machInst); + shiftAmt = ((immh << 3) | immb) - (8 << size); + if (u) + return decodeNeonUTwoShiftXReg<UqshlImmDX, UqshlImmQX>( + q, size, machInst, vd, vn, shiftAmt); + else + return decodeNeonSTwoShiftXReg<SqshlImmDX, SqshlImmQX>( + q, size, machInst, vd, vn, shiftAmt); + case 0x10: + if (immh3) + return new Unknown64(machInst); + shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); + if (u) + return decodeNeonSTwoShiftSReg<SqshrunX, Sqshrun2X>( + q, size, machInst, vd, vn, shiftAmt); + else + return decodeNeonUTwoShiftSReg<ShrnX, Shrn2X>( + q, size, machInst, vd, vn, shiftAmt); + case 0x11: + if (immh3) + return new Unknown64(machInst); + shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); + if (u) + return decodeNeonSTwoShiftSReg<SqrshrunX, Sqrshrun2X>( + q, size, machInst, vd, vn, shiftAmt); + else + return decodeNeonUTwoShiftSReg<RshrnX, Rshrn2X>( + q, size, machInst, vd, vn, shiftAmt); + case 0x12: + if (immh3) + return new Unknown64(machInst); + shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); + if (u) + return decodeNeonUTwoShiftSReg<UqshrnX, Uqshrn2X>( + q, size, machInst, vd, vn, shiftAmt); + else + return decodeNeonSTwoShiftSReg<SqshrnX, Sqshrn2X>( + q, size, machInst, vd, vn, shiftAmt); + case 0x13: + if (immh3) + return new Unknown64(machInst); + shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); + if (u) + return decodeNeonUTwoShiftSReg<UqrshrnX, Uqrshrn2X>( + q, size, machInst, vd, vn, shiftAmt); + else + return decodeNeonSTwoShiftSReg<SqrshrnX, Sqrshrn2X>( + q, size, machInst, vd, vn, shiftAmt); + case 0x14: + if (immh3) + return new Unknown64(machInst); + shiftAmt = ((immh << 3) | immb) - (8 << size); + if (u) + return decodeNeonUTwoShiftSReg<UshllX, Ushll2X>( + q, size, machInst, vd, vn, shiftAmt); + else + return decodeNeonSTwoShiftSReg<SshllX, Sshll2X>( + q, size, machInst, vd, vn, shiftAmt); + case 0x1c: + if (immh < 0x4 || immh3_q == 0x2) + return new Unknown64(machInst); + shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); + if (u) { + return decodeNeonUTwoShiftFpReg<UcvtfFixedDX, UcvtfFixedQX>( + q, size & 0x1, machInst, vd, vn, shiftAmt); + } else { + if (q) { + if (size & 0x1) + return new ScvtfFixedDQX<uint64_t>(machInst, vd, vn, + shiftAmt); + else + return new ScvtfFixedSQX<uint32_t>(machInst, vd, vn, + shiftAmt); + } else { + if (size & 0x1) + return new Unknown(machInst); + else + return new ScvtfFixedDX<uint32_t>(machInst, vd, vn, + shiftAmt); + } + } + case 0x1f: + if (immh < 0x4 || immh3_q == 0x2) + return new Unknown64(machInst); + shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); + if (u) + return decodeNeonUTwoShiftFpReg<FcvtzuFixedDX, FcvtzuFixedQX>( + q, size & 0x1, machInst, vd, vn, shiftAmt); + else + return decodeNeonUTwoShiftFpReg<FcvtzsFixedDX, FcvtzsFixedQX>( + q, size & 0x1, machInst, vd, vn, shiftAmt); + default: + return new Unknown64(machInst); + } + } + + StaticInstPtr + decodeNeonTblTbx(ExtMachInst machInst) + { + uint8_t q = bits(machInst, 30); + + IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); + IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); + IntRegIndex vm = (IntRegIndex) (uint8_t) bits(machInst, 20, 16); + + uint8_t switchVal = bits(machInst, 14, 12); + + switch (switchVal) { + case 0x0: + if (q) + return new Tbl1QX<uint8_t>(machInst, vd, vn, vm); + else + return new Tbl1DX<uint8_t>(machInst, vd, vn, vm); + case 0x1: + if (q) + return new Tbx1QX<uint8_t>(machInst, vd, vn, vm); + else + return new Tbx1DX<uint8_t>(machInst, vd, vn, vm); + case 0x2: + if (q) + return new Tbl2QX<uint8_t>(machInst, vd, vn, vm); + else + return new Tbl2DX<uint8_t>(machInst, vd, vn, vm); + case 0x3: + if (q) + return new Tbx2QX<uint8_t>(machInst, vd, vn, vm); + else + return new Tbx2DX<uint8_t>(machInst, vd, vn, vm); + case 0x4: + if (q) + return new Tbl3QX<uint8_t>(machInst, vd, vn, vm); + else + return new Tbl3DX<uint8_t>(machInst, vd, vn, vm); + case 0x5: + if (q) + return new Tbx3QX<uint8_t>(machInst, vd, vn, vm); + else + return new Tbx3DX<uint8_t>(machInst, vd, vn, vm); + case 0x6: + if (q) + return new Tbl4QX<uint8_t>(machInst, vd, vn, vm); + else + return new Tbl4DX<uint8_t>(machInst, vd, vn, vm); + case 0x7: + if (q) + return new Tbx4QX<uint8_t>(machInst, vd, vn, vm); + else + return new Tbx4DX<uint8_t>(machInst, vd, vn, vm); + default: + return new Unknown64(machInst); + } + + return new Unknown64(machInst); + } + + StaticInstPtr + decodeNeonZipUzpTrn(ExtMachInst machInst) + { + uint8_t q = bits(machInst, 30); + uint8_t size = bits(machInst, 23, 22); + uint8_t opcode = bits(machInst, 14, 12); + + IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); + IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); + IntRegIndex vm = (IntRegIndex) (uint8_t) bits(machInst, 20, 16); + + switch (opcode) { + case 0x1: + return decodeNeonUThreeXReg<Uzp1DX, Uzp1QX>( + q, size, machInst, vd, vn, vm); + case 0x2: + return decodeNeonUThreeXReg<Trn1DX, Trn1QX>( + q, size, machInst, vd, vn, vm); + case 0x3: + return decodeNeonUThreeXReg<Zip1DX, Zip1QX>( + q, size, machInst, vd, vn, vm); + case 0x5: + return decodeNeonUThreeXReg<Uzp2DX, Uzp2QX>( + q, size, machInst, vd, vn, vm); + case 0x6: + return decodeNeonUThreeXReg<Trn2DX, Trn2QX>( + q, size, machInst, vd, vn, vm); + case 0x7: + return decodeNeonUThreeXReg<Zip2DX, Zip2QX>( + q, size, machInst, vd, vn, vm); + default: + return new Unknown64(machInst); + } + return new Unknown64(machInst); + } + + StaticInstPtr + decodeNeonExt(ExtMachInst machInst) + { + uint8_t q = bits(machInst, 30); + uint8_t op2 = bits(machInst, 23, 22); + uint8_t imm4 = bits(machInst, 14, 11); + + IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); + IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); + IntRegIndex vm = (IntRegIndex) (uint8_t) bits(machInst, 20, 16); + + if (op2 != 0 || (q == 0x0 && bits(imm4, 3) == 0x1)) + return new Unknown64(machInst); + + uint8_t index = q ? imm4 : imm4 & 0x7; + + if (q) { + return new ExtQX<uint8_t>(machInst, vd, vn, vm, index); + } else { + return new ExtDX<uint8_t>(machInst, vd, vn, vm, index); + } + } + + StaticInstPtr + decodeNeonSc3Same(ExtMachInst machInst) + { + uint8_t u = bits(machInst, 29); + uint8_t size = bits(machInst, 23, 22); + uint8_t opcode = bits(machInst, 15, 11); + uint8_t s = bits(machInst, 11); + + IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); + IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); + IntRegIndex vm = (IntRegIndex) (uint8_t) bits(machInst, 20, 16); + + switch (opcode) { + case 0x01: + if (u) + return decodeNeonUThreeUReg<UqaddScX>( + size, machInst, vd, vn, vm); + else + return decodeNeonSThreeUReg<SqaddScX>( + size, machInst, vd, vn, vm); + case 0x05: + if (u) + return decodeNeonUThreeUReg<UqsubScX>( + size, machInst, vd, vn, vm); + else + return decodeNeonSThreeUReg<SqsubScX>( + size, machInst, vd, vn, vm); + case 0x06: + if (size != 0x3) + return new Unknown64(machInst); + if (u) + return new CmhiDX<uint64_t>(machInst, vd, vn, vm); + else + return new CmgtDX<int64_t>(machInst, vd, vn, vm); + case 0x07: + if (size != 0x3) + return new Unknown64(machInst); + if (u) + return new CmhsDX<uint64_t>(machInst, vd, vn, vm); + else + return new CmgeDX<int64_t>(machInst, vd, vn, vm); + case 0x08: + if (!s && size != 0x3) + return new Unknown64(machInst); + if (u) + return new UshlDX<uint64_t>(machInst, vd, vn, vm); + else + return new SshlDX<int64_t>(machInst, vd, vn, vm); + case 0x09: + if (!s && size != 0x3) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeUReg<UqshlScX>( + size, machInst, vd, vn, vm); + else + return decodeNeonSThreeUReg<SqshlScX>( + size, machInst, vd, vn, vm); + case 0x0a: + if (!s && size != 0x3) + return new Unknown64(machInst); + if (u) + return new UrshlDX<uint64_t>(machInst, vd, vn, vm); + else + return new SrshlDX<int64_t>(machInst, vd, vn, vm); + case 0x0b: + if (!s && size != 0x3) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeUReg<UqrshlScX>( + size, machInst, vd, vn, vm); + else + return decodeNeonSThreeUReg<SqrshlScX>( + size, machInst, vd, vn, vm); + case 0x10: + if (size != 0x3) + return new Unknown64(machInst); + if (u) + return new SubDX<uint64_t>(machInst, vd, vn, vm); + else + return new AddDX<uint64_t>(machInst, vd, vn, vm); + case 0x11: + if (size != 0x3) + return new Unknown64(machInst); + if (u) + return new CmeqDX<uint64_t>(machInst, vd, vn, vm); + else + return new CmtstDX<uint64_t>(machInst, vd, vn, vm); + case 0x16: + if (size == 0x3 || size == 0x0) + return new Unknown64(machInst); + if (u) + return decodeNeonSThreeHAndWReg<SqrdmulhScX>( + size, machInst, vd, vn, vm); + else + return decodeNeonSThreeHAndWReg<SqdmulhScX>( + size, machInst, vd, vn, vm); + case 0x1a: + if (!u || size < 0x2) + return new Unknown64(machInst); + else + return decodeNeonUThreeScFpReg<FabdScX>( + size & 0x1, machInst, vd, vn, vm); + case 0x1b: + if (u || size > 0x1) + return new Unknown64(machInst); + else + return decodeNeonUThreeScFpReg<FmulxScX>( + size & 0x1, machInst, vd, vn, vm); + case 0x1c: + if (size < 0x2) { + if (u) + return decodeNeonUThreeScFpReg<FcmgeScX>( + size & 0x1, machInst, vd, vn, vm); + else + return decodeNeonUThreeScFpReg<FcmeqScX>( + size & 0x1, machInst, vd, vn, vm); + } else { + if (u) + return decodeNeonUThreeScFpReg<FcmgtScX>( + size & 0x1, machInst, vd, vn, vm); + else + return new Unknown64(machInst); + } + case 0x1d: + if (!u) + return new Unknown64(machInst); + if (size < 0x2) + return decodeNeonUThreeScFpReg<FacgeScX>( + size & 0x1, machInst, vd, vn, vm); + else + return decodeNeonUThreeScFpReg<FacgtScX>( + size & 0x1, machInst, vd, vn, vm); + case 0x1f: + if (u) + return new Unknown64(machInst); + if (size < 0x2) + return decodeNeonUThreeScFpReg<FrecpsScX>( + size & 0x1, machInst, vd, vn, vm); + else + return decodeNeonUThreeScFpReg<FrsqrtsScX>( + size & 0x1, machInst, vd, vn, vm); + default: + return new Unknown64(machInst); + } + } + + StaticInstPtr + decodeNeonSc3Diff(ExtMachInst machInst) + { + if (bits(machInst, 29)) + return new Unknown64(machInst); + + uint8_t size = bits(machInst, 23, 22); + if (size == 0x0 || size == 0x3) + return new Unknown64(machInst); + + uint8_t opcode = bits(machInst, 15, 12); + + IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); + IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); + IntRegIndex vm = (IntRegIndex) (uint8_t) bits(machInst, 20, 16); + + switch (opcode) { + case 0x9: + return decodeNeonSThreeHAndWReg<SqdmlalScX>(size, machInst, vd, vn, vm); + case 0xb: + return decodeNeonSThreeHAndWReg<SqdmlslScX>(size, machInst, vd, vn, vm); + case 0xd: + return decodeNeonSThreeHAndWReg<SqdmullScX>(size, machInst, vd, vn, vm); + default: + return new Unknown64(machInst); + } + } + + StaticInstPtr + decodeNeonSc2RegMisc(ExtMachInst machInst) + { + uint8_t u = bits(machInst, 29); + uint8_t size = bits(machInst, 23, 22); + uint8_t opcode = bits(machInst, 16, 12); + + IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); + IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); + + uint8_t switchVal = opcode | ((u ? 1 : 0) << 5); + switch (switchVal) { + case 0x03: + return decodeNeonUTwoMiscUReg<SuqaddScX>(size, machInst, vd, vn); + case 0x07: + return decodeNeonSTwoMiscUReg<SqabsScX>(size, machInst, vd, vn); + case 0x08: + if (size != 0x3) + return new Unknown64(machInst); + else + return new CmgtZeroDX<int64_t>(machInst, vd, vn); + case 0x09: + if (size != 0x3) + return new Unknown64(machInst); + else + return new CmeqZeroDX<int64_t>(machInst, vd, vn); + case 0x0a: + if (size != 0x3) + return new Unknown64(machInst); + else + return new CmltZeroDX<int64_t>(machInst, vd, vn); + case 0x0b: + if (size != 0x3) + return new Unknown64(machInst); + else + return new AbsDX<int64_t>(machInst, vd, vn); + case 0x0c: + if (size < 0x2) + return new Unknown64(machInst); + else + return decodeNeonUTwoMiscScFpReg<FcmgtZeroScX>( + size & 0x1, machInst, vd, vn); + case 0x0d: + if (size < 0x2) + return new Unknown64(machInst); + else + return decodeNeonUTwoMiscScFpReg<FcmeqZeroScX>( + size & 0x1, machInst, vd, vn); + case 0x0e: + if (size < 0x2) + return new Unknown64(machInst); + else + return decodeNeonUTwoMiscScFpReg<FcmltZeroScX>( + size & 0x1, machInst, vd, vn); + case 0x14: + if (size == 0x3) { + return new Unknown64(machInst); + } else { + switch (size) { + case 0x0: + return new SqxtnScX<int8_t>(machInst, vd, vn); + case 0x1: + return new SqxtnScX<int16_t>(machInst, vd, vn); + case 0x2: + return new SqxtnScX<int32_t>(machInst, vd, vn); + } + } + case 0x1a: + if (size < 0x2) + return decodeNeonUTwoMiscScFpReg<FcvtnsScX>( + size & 0x1, machInst, vd, vn); + else + return decodeNeonUTwoMiscScFpReg<FcvtpsScX>( + size & 0x1, machInst, vd, vn); + case 0x1b: + if (size < 0x2) + return decodeNeonUTwoMiscScFpReg<FcvtmsScX>( + size & 0x1, machInst, vd, vn); + else + return decodeNeonUTwoMiscScFpReg<FcvtzsIntScX>( + size & 0x1, machInst, vd, vn); + case 0x1c: + if (size < 0x2) + return decodeNeonUTwoMiscScFpReg<FcvtasScX>( + size & 0x1, machInst, vd, vn); + else + return new Unknown64(machInst); + case 0x1d: + if (size < 0x2) { + if (size & 0x1) + return new ScvtfIntScDX<uint64_t>(machInst, vd, vn); + else + return new ScvtfIntScSX<uint32_t>(machInst, vd, vn); + } else { + return decodeNeonUTwoMiscScFpReg<FrecpeScX>( + size & 0x1, machInst, vd, vn); + } + case 0x1f: + if (size < 0x2) + return new Unknown64(machInst); + else + return decodeNeonUTwoMiscScFpReg<FrecpxX>( + size & 0x1, machInst, vd, vn); + case 0x23: + return decodeNeonUTwoMiscUReg<UsqaddScX>(size, machInst, vd, vn); + case 0x27: + return decodeNeonSTwoMiscUReg<SqnegScX>(size, machInst, vd, vn); + case 0x28: + if (size != 0x3) + return new Unknown64(machInst); + else + return new CmgeZeroDX<int64_t>(machInst, vd, vn); + case 0x29: + if (size != 0x3) + return new Unknown64(machInst); + else + return new CmleZeroDX<int64_t>(machInst, vd, vn); + case 0x2b: + if (size != 0x3) + return new Unknown64(machInst); + else + return new NegDX<int64_t>(machInst, vd, vn); + case 0x2c: + if (size < 0x2) + return new Unknown64(machInst); + else + return decodeNeonUTwoMiscScFpReg<FcmgeZeroScX>( + size & 0x1, machInst, vd, vn); + case 0x2d: + if (size < 0x2) + return new Unknown64(machInst); + else + return decodeNeonUTwoMiscScFpReg<FcmleZeroScX>( + size & 0x1, machInst, vd, vn); + case 0x32: + if (size == 0x3) { + return new Unknown64(machInst); + } else { + switch (size) { + case 0x0: + return new SqxtunScX<int8_t>(machInst, vd, vn); + case 0x1: + return new SqxtunScX<int16_t>(machInst, vd, vn); + case 0x2: + return new SqxtunScX<int32_t>(machInst, vd, vn); + } + } + case 0x34: + if (size == 0x3) { + return new Unknown64(machInst); + } else { + switch (size) { + case 0x0: + return new UqxtnScX<uint8_t>(machInst, vd, vn); + case 0x1: + return new UqxtnScX<uint16_t>(machInst, vd, vn); + case 0x2: + return new UqxtnScX<uint32_t>(machInst, vd, vn); + } + } + case 0x36: + if (size != 0x1) { + return new Unknown64(machInst); + } else { + return new FcvtxnScX<uint32_t>(machInst, vd, vn); + } + case 0x3a: + if (size < 0x2) + return decodeNeonUTwoMiscScFpReg<FcvtnuScX>( + size & 0x1, machInst, vd, vn); + else + return decodeNeonUTwoMiscScFpReg<FcvtpuScX>( + size & 0x1, machInst, vd, vn); + case 0x3b: + if (size < 0x2) + return decodeNeonUTwoMiscScFpReg<FcvtmuScX>( + size & 0x1, machInst, vd, vn); + else + return decodeNeonUTwoMiscScFpReg<FcvtzuIntScX>( + size & 0x1, machInst, vd, vn); + case 0x3c: + if (size < 0x2) + return decodeNeonUTwoMiscScFpReg<FcvtauScX>( + size & 0x1, machInst, vd, vn); + else + return new Unknown64(machInst); + case 0x3d: + if (size < 0x2) + return decodeNeonUTwoMiscScFpReg<UcvtfIntScX>( + size & 0x1, machInst, vd, vn); + else + return decodeNeonUTwoMiscScFpReg<FrsqrteScX>( + size & 0x1, machInst, vd, vn); + default: + return new Unknown64(machInst); + } + } + + StaticInstPtr + decodeNeonScPwise(ExtMachInst machInst) + { + uint8_t u = bits(machInst, 29); + uint8_t size = bits(machInst, 23, 22); + uint8_t opcode = bits(machInst, 16, 12); + + IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); + IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); + + if (!u) { + if (opcode == 0x1b && size == 0x3) + return new AddpScQX<uint64_t>(machInst, vd, vn); + else + return new Unknown64(machInst); + } + + uint8_t switchVal = (opcode << 0) | (size << 5); + switch (switchVal) { + case 0x0c: + case 0x2c: + return decodeNeonUTwoMiscPwiseScFpReg<FmaxnmpScDX, FmaxnmpScQX>( + size & 0x1, machInst, vd, vn); + case 0x0d: + case 0x2d: + return decodeNeonUTwoMiscPwiseScFpReg<FaddpScDX, FaddpScQX>( + size & 0x1, machInst, vd, vn); + case 0x0f: + case 0x2f: + return decodeNeonUTwoMiscPwiseScFpReg<FmaxpScDX, FmaxpScQX>( + size & 0x1, machInst, vd, vn); + case 0x4c: + case 0x6c: + return decodeNeonUTwoMiscPwiseScFpReg<FminnmpScDX, FminnmpScQX>( + size & 0x1, machInst, vd, vn); + case 0x4f: + case 0x6f: + return decodeNeonUTwoMiscPwiseScFpReg<FminpScDX, FminpScQX>( + size & 0x1, machInst, vd, vn); + default: + return new Unknown64(machInst); + } + } + + StaticInstPtr + decodeNeonScCopy(ExtMachInst machInst) + { + if (bits(machInst, 14, 11) != 0 || bits(machInst, 29)) + return new Unknown64(machInst); + + uint8_t imm5 = bits(machInst, 20, 16); + + IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); + IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); + + uint8_t size = findLsbSet(imm5); + uint8_t index = bits(imm5, 4, size + 1); + + return decodeNeonUTwoShiftUReg<DupElemScX>( + size, machInst, vd, vn, index); + } + + StaticInstPtr + decodeNeonScIndexedElem(ExtMachInst machInst) + { + uint8_t u = bits(machInst, 29); + uint8_t size = bits(machInst, 23, 22); + uint8_t L = bits(machInst, 21); + uint8_t M = bits(machInst, 20); + uint8_t opcode = bits(machInst, 15, 12); + uint8_t H = bits(machInst, 11); + + IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); + IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); + IntRegIndex vm_bf = (IntRegIndex) (uint8_t) bits(machInst, 19, 16); + + uint8_t index = 0; + uint8_t index_fp = 0; + uint8_t vmh = 0; + uint8_t sz_L = bits(machInst, 22, 21); + + // Index and 2nd register operand for integer instructions + if (size == 0x1) { + index = (H << 2) | (L << 1) | M; + // vmh = 0; + } else if (size == 0x2) { + index = (H << 1) | L; + vmh = M; + } else if (size == 0x3) { + index = H; + vmh = M; + } + IntRegIndex vm = (IntRegIndex) (uint8_t) (vmh << 4 | vm_bf); + + // Index and 2nd register operand for FP instructions + vmh = M; + if ((size & 0x1) == 0) { + index_fp = (H << 1) | L; + } else if (L == 0) { + index_fp = H; + } + IntRegIndex vm_fp = (IntRegIndex) (uint8_t) (vmh << 4 | vm_bf); + + if (u && opcode != 9) + return new Unknown64(machInst); + + switch (opcode) { + case 0x1: + if (size < 2 || sz_L == 0x3) + return new Unknown64(machInst); + else + return decodeNeonUThreeImmScFpReg<FmlaElemScX>( + size & 0x1, machInst, vd, vn, vm_fp, index_fp); + case 0x3: + if (size == 0x0 || size == 0x3) + return new Unknown64(machInst); + else + return decodeNeonSThreeImmHAndWReg<SqdmlalElemScX>( + size, machInst, vd, vn, vm, index); + case 0x5: + if (size < 2 || sz_L == 0x3) + return new Unknown64(machInst); + else + return decodeNeonUThreeImmScFpReg<FmlsElemScX>( + size & 0x1, machInst, vd, vn, vm_fp, index_fp); + case 0x7: + if (size == 0x0 || size == 0x3) + return new Unknown64(machInst); + else + return decodeNeonSThreeImmHAndWReg<SqdmlslElemScX>( + size, machInst, vd, vn, vm, index); + case 0x9: + if (size < 2 || sz_L == 0x3) + return new Unknown64(machInst); + if (u) + return decodeNeonUThreeImmScFpReg<FmulxElemScX>( + size & 0x1, machInst, vd, vn, vm_fp, index_fp); + else + return decodeNeonUThreeImmScFpReg<FmulElemScX>( + size & 0x1, machInst, vd, vn, vm_fp, index_fp); + case 0xb: + if (size == 0x0 || size == 0x3) + return new Unknown64(machInst); + else + return decodeNeonSThreeImmHAndWReg<SqdmullElemScX>( + size, machInst, vd, vn, vm, index); + case 0xc: + if (size == 0x0 || size == 0x3) + return new Unknown64(machInst); + else + return decodeNeonSThreeImmHAndWReg<SqdmulhElemScX>( + size, machInst, vd, vn, vm, index); + case 0xd: + if (size == 0x0 || size == 0x3) + return new Unknown64(machInst); + else + return decodeNeonSThreeImmHAndWReg<SqrdmulhElemScX>( + size, machInst, vd, vn, vm, index); + default: + return new Unknown64(machInst); + } + } + + StaticInstPtr + decodeNeonScShiftByImm(ExtMachInst machInst) + { + bool u = bits(machInst, 29); + uint8_t immh = bits(machInst, 22, 19); + uint8_t immb = bits(machInst, 18, 16); + uint8_t opcode = bits(machInst, 15, 11); + + IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); + IntRegIndex vn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); + + uint8_t immh3 = bits(machInst, 22); + uint8_t size = findMsbSet(immh); + int shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); + + if (immh == 0x0) + return new Unknown64(machInst); + + switch (opcode) { + case 0x00: + if (!immh3) + return new Unknown64(machInst); + shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); + if (u) + return new UshrDX<uint64_t>(machInst, vd, vn, shiftAmt); + else + return new SshrDX<int64_t>(machInst, vd, vn, shiftAmt); + case 0x02: + if (!immh3) + return new Unknown64(machInst); + shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); + if (u) + return new UsraDX<uint64_t>(machInst, vd, vn, shiftAmt); + else + return new SsraDX<int64_t>(machInst, vd, vn, shiftAmt); + case 0x04: + if (!immh3) + return new Unknown64(machInst); + shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); + if (u) + return new UrshrDX<uint64_t>(machInst, vd, vn, shiftAmt); + else + return new SrshrDX<int64_t>(machInst, vd, vn, shiftAmt); + case 0x06: + if (!immh3) + return new Unknown64(machInst); + shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); + if (u) + return new UrsraDX<uint64_t>(machInst, vd, vn, shiftAmt); + else + return new SrsraDX<int64_t>(machInst, vd, vn, shiftAmt); + case 0x08: + if (!immh3) + return new Unknown64(machInst); + shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); + if (u) + return new SriDX<uint64_t>(machInst, vd, vn, shiftAmt); + else + return new Unknown64(machInst); + case 0x0a: + if (!immh3) + return new Unknown64(machInst); + shiftAmt = ((immh << 3) | immb) - (8 << size); + if (u) + return new SliDX<uint64_t>(machInst, vd, vn, shiftAmt); + else + return new ShlDX<uint64_t>(machInst, vd, vn, shiftAmt); + case 0x0c: + if (u) { + shiftAmt = ((immh << 3) | immb) - (8 << size); + return decodeNeonSTwoShiftUReg<SqshluScX>( + size, machInst, vd, vn, shiftAmt); + } else { + return new Unknown64(machInst); + } + case 0x0e: + shiftAmt = ((immh << 3) | immb) - (8 << size); + if (u) + return decodeNeonUTwoShiftUReg<UqshlImmScX>( + size, machInst, vd, vn, shiftAmt); + else + return decodeNeonSTwoShiftUReg<SqshlImmScX>( + size, machInst, vd, vn, shiftAmt); + case 0x10: + if (!u || immh3) + return new Unknown64(machInst); + shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); + return decodeNeonSTwoShiftUSReg<SqshrunScX>( + size, machInst, vd, vn, shiftAmt); + case 0x11: + if (!u || immh3) + return new Unknown64(machInst); + shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); + return decodeNeonSTwoShiftUSReg<SqrshrunScX>( + size, machInst, vd, vn, shiftAmt); + case 0x12: + if (immh3) + return new Unknown64(machInst); + shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); + if (u) + return decodeNeonUTwoShiftUSReg<UqshrnScX>( + size, machInst, vd, vn, shiftAmt); + else + return decodeNeonSTwoShiftUSReg<SqshrnScX>( + size, machInst, vd, vn, shiftAmt); + case 0x13: + if (immh3) + return new Unknown64(machInst); + shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); + if (u) + return decodeNeonUTwoShiftUSReg<UqrshrnScX>( + size, machInst, vd, vn, shiftAmt); + else + return decodeNeonSTwoShiftUSReg<SqrshrnScX>( + size, machInst, vd, vn, shiftAmt); + case 0x1c: + if (immh < 0x4) + return new Unknown64(machInst); + shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); + if (u) { + return decodeNeonUTwoShiftUFpReg<UcvtfFixedScX>( + size & 0x1, machInst, vd, vn, shiftAmt); + } else { + if (size & 0x1) + return new ScvtfFixedScDX<uint64_t>(machInst, vd, vn, + shiftAmt); + else + return new ScvtfFixedScSX<uint32_t>(machInst, vd, vn, + shiftAmt); + } + case 0x1f: + if (immh < 0x4) + return new Unknown64(machInst); + shiftAmt = (8 << (size + 1)) - ((immh << 3) | immb); + if (u) + return decodeNeonUTwoShiftUFpReg<FcvtzuFixedScX>( + size & 0x1, machInst, vd, vn, shiftAmt); + else + return decodeNeonUTwoShiftUFpReg<FcvtzsFixedScX>( + size & 0x1, machInst, vd, vn, shiftAmt); + default: + return new Unknown64(machInst); + } + } + + StaticInstPtr + decodeNeonMem(ExtMachInst machInst) + { + uint8_t dataSize = bits(machInst, 30) ? 128 : 64; + bool multiple = bits(machInst, 24, 23) < 0x2; + bool load = bits(machInst, 22); + + uint8_t numStructElems = 0; + uint8_t numRegs = 0; + + if (multiple) { // AdvSIMD load/store multiple structures + uint8_t opcode = bits(machInst, 15, 12); + uint8_t eSize = bits(machInst, 11, 10); + bool wb = !(bits(machInst, 20, 16) == 0x0 && !bits(machInst, 23)); + + switch (opcode) { + case 0x0: // LD/ST4 (4 regs) + numStructElems = 4; + numRegs = 4; + break; + case 0x2: // LD/ST1 (4 regs) + numStructElems = 1; + numRegs = 4; + break; + case 0x4: // LD/ST3 (3 regs) + numStructElems = 3; + numRegs = 3; + break; + case 0x6: // LD/ST1 (3 regs) + numStructElems = 1; + numRegs = 3; + break; + case 0x7: // LD/ST1 (1 reg) + numStructElems = 1; + numRegs = 1; + break; + case 0x8: // LD/ST2 (2 regs) + numStructElems = 2; + numRegs = 2; + break; + case 0xa: // LD/ST1 (2 regs) + numStructElems = 1; + numRegs = 2; + break; + default: + return new Unknown64(machInst); + } + + IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); + IntRegIndex rn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); + IntRegIndex rm = (IntRegIndex) (uint8_t) bits(machInst, 20, 16); + + if (load) { + return new VldMult64(machInst, rn, vd, rm, eSize, dataSize, + numStructElems, numRegs, wb); + } else { + return new VstMult64(machInst, rn, vd, rm, eSize, dataSize, + numStructElems, numRegs, wb); + } + } else { // AdvSIMD load/store single structure + uint8_t scale = bits(machInst, 15, 14); + uint8_t numStructElems = (((uint8_t) bits(machInst, 13) << 1) | + (uint8_t) bits(machInst, 21)) + 1; + uint8_t index = 0; + bool wb = !(bits(machInst, 20, 16) == 0x0 && !bits(machInst, 23)); + bool replicate = false; + + switch (scale) { + case 0x0: + index = ((uint8_t) bits(machInst, 30) << 3) | + ((uint8_t) bits(machInst, 12) << 2) | + (uint8_t) bits(machInst, 11, 10); + break; + case 0x1: + index = ((uint8_t) bits(machInst, 30) << 2) | + ((uint8_t) bits(machInst, 12) << 1) | + (uint8_t) bits(machInst, 11); + break; + case 0x2: + if (bits(machInst, 10) == 0x0) { + index = ((uint8_t) bits(machInst, 30) << 1) | + bits(machInst, 12); + } else { + index = (uint8_t) bits(machInst, 30); + scale = 0x3; + } + break; + case 0x3: + scale = bits(machInst, 11, 10); + replicate = true; + break; + default: + return new Unknown64(machInst); + } + + uint8_t eSize = scale; + + IntRegIndex vd = (IntRegIndex) (uint8_t) bits(machInst, 4, 0); + IntRegIndex rn = (IntRegIndex) (uint8_t) bits(machInst, 9, 5); + IntRegIndex rm = (IntRegIndex) (uint8_t) bits(machInst, 20, 16); + + if (load) { + return new VldSingle64(machInst, rn, vd, rm, eSize, dataSize, + numStructElems, index, wb, replicate); + } else { + return new VstSingle64(machInst, rn, vd, rm, eSize, dataSize, + numStructElems, index, wb, replicate); + } + } + } +} +}}; diff --git a/src/arch/arm/isa/formats/uncond.isa b/src/arch/arm/isa/formats/uncond.isa index 4a18a55bb..c376cd9ce 100644 --- a/src/arch/arm/isa/formats/uncond.isa +++ b/src/arch/arm/isa/formats/uncond.isa @@ -99,11 +99,11 @@ def format ArmUnconditional() {{ case 0x1: return new Clrex(machInst); case 0x4: - return new Dsb(machInst); + return new Dsb(machInst, 0); case 0x5: - return new Dmb(machInst); + return new Dmb(machInst, 0); case 0x6: - return new Isb(machInst); + return new Isb(machInst, 0); } } } else if (bits(op2, 0) == 0) { @@ -166,7 +166,7 @@ def format ArmUnconditional() {{ const uint32_t val = ((machInst >> 20) & 0x5); if (val == 0x4) { const uint32_t mode = bits(machInst, 4, 0); - if (badMode((OperatingMode)mode)) + if (badMode32((OperatingMode)mode)) return new Unknown(machInst); switch (bits(machInst, 24, 21)) { case 0x2: @@ -250,17 +250,10 @@ def format ArmUnconditional() {{ "ldc, ldc2 (immediate)", machInst); } } - if (op1 == 0xC5) { - return new WarnUnimplemented( - "mrrc, mrrc2", machInst); - } } else { if (bits(op1, 4, 3) != 0 || bits(op1, 1) == 1) { return new WarnUnimplemented( "stc, stc2", machInst); - } else if (op1 == 0xC4) { - return new WarnUnimplemented( - "mcrr, mcrrc", machInst); } } } diff --git a/src/arch/arm/isa/formats/unimp.isa b/src/arch/arm/isa/formats/unimp.isa index 1c9a4b402..8e346112c 100644 --- a/src/arch/arm/isa/formats/unimp.isa +++ b/src/arch/arm/isa/formats/unimp.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2010 ARM Limited +// Copyright (c) 2010, 2012 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -85,6 +85,9 @@ output header {{ private: /// Have we warned on this instruction yet? mutable bool warned; + /// Full mnemonic for MRC and MCR instructions including the + /// coproc. register name + std::string fullMnemonic; public: /// Constructor @@ -96,6 +99,16 @@ output header {{ flags[IsNonSpeculative] = true; } + WarnUnimplemented(const char *_mnemonic, ExtMachInst _machInst, + const std::string& _fullMnemonic) + : ArmStaticInst(_mnemonic, _machInst, No_OpClass), warned(false), + fullMnemonic(_fullMnemonic) + { + // don't call execute() (which panics) if we're on a + // speculative path + flags[IsNonSpeculative] = true; + } + %(BasicExecDeclare)s std::string @@ -147,10 +160,7 @@ output exec {{ FailUnimplemented::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const { - if (FullSystem) - return new UndefinedInstruction; - else - return new UndefinedInstruction(machInst, false, mnemonic); + return new UndefinedInstruction(machInst, false, mnemonic); } Fault @@ -158,7 +168,8 @@ output exec {{ Trace::InstRecord *traceData) const { if (!warned) { - warn("\tinstruction '%s' unimplemented\n", mnemonic); + warn("\tinstruction '%s' unimplemented\n", + fullMnemonic.size() ? fullMnemonic.c_str() : mnemonic); warned = true; } diff --git a/src/arch/arm/isa/includes.isa b/src/arch/arm/isa/includes.isa index 5dd13d623..a2ce84345 100644 --- a/src/arch/arm/isa/includes.isa +++ b/src/arch/arm/isa/includes.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2010 ARM Limited +// Copyright (c) 2010, 2012 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -50,10 +50,16 @@ output header {{ #include <sstream> #include "arch/arm/insts/branch.hh" +#include "arch/arm/insts/branch64.hh" +#include "arch/arm/insts/data64.hh" +#include "arch/arm/insts/fplib.hh" #include "arch/arm/insts/macromem.hh" #include "arch/arm/insts/mem.hh" +#include "arch/arm/insts/mem64.hh" #include "arch/arm/insts/misc.hh" +#include "arch/arm/insts/misc64.hh" #include "arch/arm/insts/mult.hh" +#include "arch/arm/insts/neon64_mem.hh" #include "arch/arm/insts/pred_inst.hh" #include "arch/arm/insts/static_inst.hh" #include "arch/arm/insts/vfp.hh" @@ -63,6 +69,7 @@ output header {{ }}; output decoder {{ +#include <string> #include "arch/arm/decoder.hh" #include "arch/arm/faults.hh" #include "arch/arm/intregs.hh" diff --git a/src/arch/arm/isa/insts/aarch64.isa b/src/arch/arm/isa/insts/aarch64.isa new file mode 100644 index 000000000..6fcf9b5d2 --- /dev/null +++ b/src/arch/arm/isa/insts/aarch64.isa @@ -0,0 +1,58 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2011 ARM Limited +// All rights reserved +// +// The license below extends only to copyright in the software and shall +// not be construed as granting a license to any other intellectual +// property including but not limited to intellectual property relating +// to a hardware implementation of the functionality of the software +// licensed hereunder. You may use the software subject to the license +// terms below provided that you ensure that this notice is replicated +// unmodified and in its entirety in all distributions of the software, +// modified or unmodified, in source code or in binary form. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Gabe Black + +let {{ + movzCode = 'Dest64 = ((uint64_t)imm1) << imm2;' + movzIop = InstObjParams("movz", "Movz", "RegImmImmOp", movzCode, []) + header_output += RegImmImmOpDeclare.subst(movzIop) + decoder_output += RegImmImmOpConstructor.subst(movzIop) + exec_output += BasicExecute.subst(movzIop) + + movkCode = 'Dest64 = insertBits(Dest64, imm2 + 15, imm2, imm1);' + movkIop = InstObjParams("movk", "Movk", "RegImmImmOp", movkCode, []) + header_output += RegImmImmOpDeclare.subst(movkIop) + decoder_output += RegImmImmOpConstructor.subst(movkIop) + exec_output += BasicExecute.subst(movkIop) + + movnCode = 'Dest64 = ~(((uint64_t)imm1) << imm2);' + movnIop = InstObjParams("movn", "Movn", "RegImmImmOp", movnCode, []) + header_output += RegImmImmOpDeclare.subst(movnIop) + decoder_output += RegImmImmOpConstructor.subst(movnIop) + exec_output += BasicExecute.subst(movnIop) +}}; diff --git a/src/arch/arm/isa/insts/branch.isa b/src/arch/arm/isa/insts/branch.isa index e360f4581..3ee9d88e4 100644 --- a/src/arch/arm/isa/insts/branch.isa +++ b/src/arch/arm/isa/insts/branch.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2010 ARM Limited +// Copyright (c) 2010-2012 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -48,7 +48,7 @@ let {{ bCode = ''' NPC = (uint32_t)(PC + imm); ''' - br_tgt_code = '''pcs.instNPC(branchPC.instPC() + imm);''' + br_tgt_code = '''pcs.instNPC((uint32_t)(branchPC.instPC() + imm));''' instFlags = ["IsDirectControl"] if (link): bCode += ''' @@ -86,9 +86,9 @@ let {{ Name += "Imm" # Since we're switching ISAs, the target ISA will be the opposite # of the current ISA. Thumb is whether the target is ARM. - newPC = '(Thumb ? (roundDown(PC, 4) + imm) : (PC + imm))' + newPC = '(uint32_t)(Thumb ? (roundDown(PC, 4) + imm) : (PC + imm))' br_tgt_code = ''' - pcs.instNPC((branchPC.thumb() ? (roundDown(branchPC.instPC(),4) + imm) : + pcs.instNPC((uint32_t)(branchPC.thumb() ? (roundDown(branchPC.instPC(),4) + imm) : (branchPC.instPC() + imm))); ''' base = "BranchImmCond" @@ -150,7 +150,26 @@ let {{ if imm: decoder_output += BranchTarget.subst(blxIop) - #Ignore BXJ for now + bxjcode = ''' + HSTR hstr = Hstr; + CPSR cpsr = Cpsr; + SCR scr = Scr; + + if (ArmSystem::haveVirtualization(xc->tcBase()) && hstr.tjdbx && + !inSecureState(scr, cpsr) && (cpsr.mode != MODE_HYP)) { + fault = new HypervisorTrap(machInst, op1, EC_TRAPPED_BXJ); + } + IWNPC = Op1; + ''' + + bxjIop = InstObjParams("bxj", "BxjReg", "BranchRegCond", + {"code": bxjcode, + "predicate_test": predicateTest, + "is_ras_pop": "op1 == INTREG_LR" }, + ["IsIndirectControl"]) + header_output += BranchRegCondDeclare.subst(bxjIop) + decoder_output += BranchRegCondConstructor.subst(bxjIop) + exec_output += PredOpExecute.subst(bxjIop) #CBNZ, CBZ. These are always unconditional as far as predicates for (mnem, test) in (("cbz", "=="), ("cbnz", "!=")): diff --git a/src/arch/arm/isa/insts/branch64.isa b/src/arch/arm/isa/insts/branch64.isa new file mode 100644 index 000000000..89cee6c22 --- /dev/null +++ b/src/arch/arm/isa/insts/branch64.isa @@ -0,0 +1,248 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2011-2013 ARM Limited +// All rights reserved +// +// The license below extends only to copyright in the software and shall +// not be construed as granting a license to any other intellectual +// property including but not limited to intellectual property relating +// to a hardware implementation of the functionality of the software +// licensed hereunder. You may use the software subject to the license +// terms below provided that you ensure that this notice is replicated +// unmodified and in its entirety in all distributions of the software, +// modified or unmodified, in source code or in binary form. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Gabe Black +// Giacomo Gabrielli + +let {{ + + header_output = "" + decoder_output = "" + exec_output = "" + + # B, BL + for (mnem, link) in (("b", False), ("bl", True)): + bCode = ('NPC = purifyTaggedAddr(RawPC + imm, xc->tcBase(), ' + 'currEL(xc->tcBase()));\n') + instFlags = ['IsDirectControl', 'IsUncondControl'] + if (link): + bCode += 'XLR = RawPC + 4;\n' + instFlags += ['IsCall'] + + bIop = InstObjParams(mnem, mnem.capitalize() + "64", + "BranchImm64", bCode, instFlags) + header_output += BranchImm64Declare.subst(bIop) + decoder_output += BranchImm64Constructor.subst(bIop) + exec_output += BasicExecute.subst(bIop) + + # BR, BLR + for (mnem, link) in (("br", False), ("blr", True)): + bCode = ('NPC = purifyTaggedAddr(XOp1, xc->tcBase(), ' + 'currEL(xc->tcBase()));\n') + instFlags = ['IsIndirectControl', 'IsUncondControl'] + if (link): + bCode += 'XLR = RawPC + 4;\n' + instFlags += ['IsCall'] + + bIop = InstObjParams(mnem, mnem.capitalize() + "64", + "BranchReg64", bCode, instFlags) + header_output += BranchReg64Declare.subst(bIop) + decoder_output += BranchReg64Constructor.subst(bIop) + exec_output += BasicExecute.subst(bIop) + + # B conditional + bCode = ''' + if (testPredicate(CondCodesNZ, CondCodesC, CondCodesV, condCode)) + NPC = purifyTaggedAddr(RawPC + imm, xc->tcBase(), + currEL(xc->tcBase())); + else + NPC = NPC; + ''' + bIop = InstObjParams("b", "BCond64", "BranchImmCond64", bCode, + ['IsCondControl', 'IsDirectControl']) + header_output += BranchImmCond64Declare.subst(bIop) + decoder_output += BranchImmCond64Constructor.subst(bIop) + exec_output += BasicExecute.subst(bIop) + + # RET + bCode = ('NPC = purifyTaggedAddr(XOp1, xc->tcBase(), ' + 'currEL(xc->tcBase()));\n') + instFlags = ['IsIndirectControl', 'IsUncondControl', 'IsReturn'] + + bIop = InstObjParams('ret', 'Ret64', "BranchRet64", bCode, instFlags) + header_output += BranchReg64Declare.subst(bIop) + decoder_output += BranchReg64Constructor.subst(bIop) + exec_output += BasicExecute.subst(bIop) + + # ERET + bCode = '''Addr newPc; + CPSR cpsr = Cpsr; + CPSR spsr = Spsr; + + ExceptionLevel curr_el = opModeToEL((OperatingMode) (uint8_t) cpsr.mode); + switch (curr_el) { + case EL3: + newPc = xc->tcBase()->readMiscReg(MISCREG_ELR_EL3); + break; + case EL2: + newPc = xc->tcBase()->readMiscReg(MISCREG_ELR_EL2); + break; + case EL1: + newPc = xc->tcBase()->readMiscReg(MISCREG_ELR_EL1); + break; + default: + return new UndefinedInstruction(machInst, false, mnemonic); + break; + } + if (spsr.width && (newPc & mask(2))) { + // To avoid PC Alignment fault when returning to AArch32 + if (spsr.t) + newPc = newPc & ~mask(1); + else + newPc = newPc & ~mask(2); + } + spsr.q = 0; + spsr.it1 = 0; + spsr.j = 0; + spsr.res0_23_22 = 0; + spsr.ge = 0; + spsr.it2 = 0; + spsr.t = 0; + + OperatingMode mode = (OperatingMode) (uint8_t) spsr.mode; + bool illegal = false; + ExceptionLevel target_el; + if (badMode(mode)) { + illegal = true; + } else { + target_el = opModeToEL(mode); + if (((target_el == EL2) && + !ArmSystem::haveVirtualization(xc->tcBase())) || + (target_el > curr_el) || + (spsr.width == 1)) { + illegal = true; + } else { + bool known = true; + bool from32 = (spsr.width == 1); + bool to32 = false; + if (false) { // TODO: !haveAArch32EL + to32 = false; + } else if (!ArmSystem::highestELIs64(xc->tcBase())) { + to32 = true; + } else { + bool scr_rw, hcr_rw; + if (ArmSystem::haveSecurity(xc->tcBase())) { + SCR scr = xc->tcBase()->readMiscReg(MISCREG_SCR_EL3); + scr_rw = scr.rw; + } else { + scr_rw = true; + } + + if (ArmSystem::haveVirtualization(xc->tcBase())) { + HCR hcr = xc->tcBase()->readMiscReg(MISCREG_HCR_EL2); + hcr_rw = hcr.rw; + } else { + hcr_rw = scr_rw; + } + + switch (target_el) { + case EL3: + to32 = false; + break; + case EL2: + to32 = !scr_rw; + break; + case EL1: + to32 = !scr_rw || !hcr_rw; + break; + case EL0: + if (curr_el == EL0) { + to32 = cpsr.width; + } else if (!scr_rw || !hcr_rw) { + // EL0 using AArch32 if EL1 using AArch32 + to32 = true; + } else { + known = false; + to32 = false; + } + } + } + if (known) + illegal = (from32 != to32); + } + } + + if (illegal) { + uint8_t old_mode = cpsr.mode; + spsr.mode = old_mode; // Preserve old mode when invalid + spsr.il = 1; + } else { + if (cpsr.width != spsr.width) + panic("AArch32/AArch64 interprocessing not supported yet"); + } + Cpsr = spsr; + + CondCodesNZ = spsr.nz; + CondCodesC = spsr.c; + CondCodesV = spsr.v; + NPC = purifyTaggedAddr(newPc, xc->tcBase(), + opModeToEL((OperatingMode) (uint8_t) spsr.mode)); + LLSCLock = 0; // Clear exclusive monitor + SevMailbox = 1; //Set Event Register + ''' + instFlags = ['IsSerializeAfter', 'IsNonSpeculative', 'IsSquashAfter'] + bIop = InstObjParams('eret', 'Eret64', "BranchEret64", bCode, instFlags) + header_output += BasicDeclare.subst(bIop) + decoder_output += BasicConstructor64.subst(bIop) + exec_output += BasicExecute.subst(bIop) + + # CBNZ, CBZ + for (mnem, test) in (("cbz", "=="), ("cbnz", "!=")): + code = ('NPC = (Op164 %(test)s 0) ? ' + 'purifyTaggedAddr(RawPC + imm, xc->tcBase(), ' + 'currEL(xc->tcBase())) : NPC;\n') + code = code % {"test": test} + iop = InstObjParams(mnem, mnem.capitalize() + "64", + "BranchImmReg64", code, + ['IsCondControl', 'IsDirectControl']) + header_output += BranchImmReg64Declare.subst(iop) + decoder_output += BranchImmReg64Constructor.subst(iop) + exec_output += BasicExecute.subst(iop) + + # TBNZ, TBZ + for (mnem, test) in (("tbz", "=="), ("tbnz", "!=")): + code = ('NPC = ((Op164 & imm1) %(test)s 0) ? ' + 'purifyTaggedAddr(RawPC + imm2, xc->tcBase(), ' + 'currEL(xc->tcBase())) : NPC;\n') + code = code % {"test": test} + iop = InstObjParams(mnem, mnem.capitalize() + "64", + "BranchImmImmReg64", code, + ['IsCondControl', 'IsDirectControl']) + header_output += BranchImmImmReg64Declare.subst(iop) + decoder_output += BranchImmImmReg64Constructor.subst(iop) + exec_output += BasicExecute.subst(iop) +}}; diff --git a/src/arch/arm/isa/insts/data.isa b/src/arch/arm/isa/insts/data.isa index be56554b0..881676496 100644 --- a/src/arch/arm/isa/insts/data.isa +++ b/src/arch/arm/isa/insts/data.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2010 ARM Limited +// Copyright (c) 2010, 2013 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -257,7 +257,8 @@ let {{ CPSR old_cpsr = Cpsr; CPSR new_cpsr = - cpsrWriteByInstr(old_cpsr, Spsr, 0xF, true, sctlr.nmfi); + cpsrWriteByInstr(old_cpsr, Spsr, Scr, Nsacr, 0xF, true, + sctlr.nmfi, xc->tcBase()); Cpsr = ~CondCodesMask & new_cpsr; CondCodesNZ = new_cpsr.nz; CondCodesC = new_cpsr.c; diff --git a/src/arch/arm/isa/insts/data64.isa b/src/arch/arm/isa/insts/data64.isa new file mode 100644 index 000000000..77d7541ca --- /dev/null +++ b/src/arch/arm/isa/insts/data64.isa @@ -0,0 +1,465 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2011-2013 ARM Limited +// All rights reserved +// +// The license below extends only to copyright in the software and shall +// not be construed as granting a license to any other intellectual +// property including but not limited to intellectual property relating +// to a hardware implementation of the functionality of the software +// licensed hereunder. You may use the software subject to the license +// terms below provided that you ensure that this notice is replicated +// unmodified and in its entirety in all distributions of the software, +// modified or unmodified, in source code or in binary form. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Gabe Black + +let {{ + + header_output = "" + decoder_output = "" + exec_output = "" + + def createCcCode64(carry, overflow): + code = "" + code += ''' + uint16_t _iz, _in; + _in = bits(resTemp, intWidth - 1); + _iz = ((resTemp & mask(intWidth)) == 0); + CondCodesNZ = (_in << 1) | _iz; + DPRINTF(Arm, "(in, iz) = (%%d, %%d)\\n", _in, _iz); + ''' + if overflow and overflow != "none": + code += ''' + uint16_t _iv; + _iv = %s & 1; + CondCodesV = _iv; + DPRINTF(Arm, "(iv) = (%%d)\\n", _iv); + ''' % overflow + if carry and carry != "none": + code += ''' + uint16_t _ic; + _ic = %s & 1; + CondCodesC = _ic; + DPRINTF(Arm, "(ic) = (%%d)\\n", _ic); + ''' % carry + return code + + oldC = 'CondCodesC' + oldV = 'CondCodesV' + # Dicts of ways to set the carry flag. + carryCode64 = { + "none": "none", + "add": 'findCarry(intWidth, resTemp, Op164, secOp)', + "sub": 'findCarry(intWidth, resTemp, Op164, ~secOp)', + "logic": '0' + } + # Dict of ways to set the overflow flag. + overflowCode64 = { + "none": "none", + "add": 'findOverflow(intWidth, resTemp, Op164, secOp)', + "sub": 'findOverflow(intWidth, resTemp, Op164, ~secOp)', + "logic": '0' + } + + immOp2 = "uint64_t secOp M5_VAR_USED = imm;" + sRegOp2 = "uint64_t secOp M5_VAR_USED = " + \ + "shiftReg64(Op264, shiftAmt, shiftType, intWidth);" + eRegOp2 = "uint64_t secOp M5_VAR_USED = " + \ + "extendReg64(Op264, extendType, shiftAmt, intWidth);" + + def buildDataWork(mnem, code, flagType, suffix, buildCc, buildNonCc, + base, templateBase): + code = ''' + uint64_t resTemp M5_VAR_USED = 0; + ''' + code + ccCode = createCcCode64(carryCode64[flagType], overflowCode64[flagType]) + Name = mnem.capitalize() + suffix + iop = InstObjParams(mnem, Name, base, code) + iopCc = InstObjParams(mnem + "s", Name + "Cc", base, code + ccCode) + + def subst(iop): + global header_output, decoder_output, exec_output + header_output += eval(templateBase + "Declare").subst(iop) + decoder_output += eval(templateBase + "Constructor").subst(iop) + exec_output += BasicExecute.subst(iop) + + if buildNonCc: + subst(iop) + if buildCc: + subst(iopCc) + + def buildXImmDataInst(mnem, code, flagType = "logic", \ + buildCc = True, buildNonCc = True, \ + suffix = "XImm"): + buildDataWork(mnem, immOp2 + code, flagType, suffix, + buildCc, buildNonCc, "DataXImmOp", "DataXImm") + + def buildXSRegDataInst(mnem, code, flagType = "logic", \ + buildCc = True, buildNonCc = True, \ + suffix = "XSReg"): + buildDataWork(mnem, sRegOp2 + code, flagType, suffix, + buildCc, buildNonCc, "DataXSRegOp", "DataXSReg") + + def buildXERegDataInst(mnem, code, flagType = "logic", \ + buildCc = True, buildNonCc = True, \ + suffix = "XEReg"): + buildDataWork(mnem, eRegOp2 + code, flagType, suffix, + buildCc, buildNonCc, "DataXERegOp", "DataXEReg") + + def buildDataInst(mnem, code, flagType = "logic", + buildCc = True, buildNonCc = True): + buildXImmDataInst(mnem, code, flagType, buildCc, buildNonCc) + buildXSRegDataInst(mnem, code, flagType, buildCc, buildNonCc) + buildXERegDataInst(mnem, code, flagType, buildCc, buildNonCc) + + buildXImmDataInst("adr", "Dest64 = RawPC + imm", buildCc = False); + buildXImmDataInst("adrp", "Dest64 = (RawPC & ~mask(12)) + imm", + buildCc = False); + buildDataInst("and", "Dest64 = resTemp = Op164 & secOp;") + buildDataInst("eor", "Dest64 = Op164 ^ secOp;", buildCc = False) + buildXSRegDataInst("eon", "Dest64 = Op164 ^ ~secOp;", buildCc = False) + buildDataInst("sub", "Dest64 = resTemp = Op164 - secOp;", "sub") + buildDataInst("add", "Dest64 = resTemp = Op164 + secOp;", "add") + buildXSRegDataInst("adc", + "Dest64 = resTemp = Op164 + secOp + %s;" % oldC, "add") + buildXSRegDataInst("sbc", + "Dest64 = resTemp = Op164 - secOp - !%s;" % oldC, "sub") + buildDataInst("orr", "Dest64 = Op164 | secOp;", buildCc = False) + buildXSRegDataInst("orn", "Dest64 = Op164 | ~secOp;", buildCc = False) + buildXSRegDataInst("bic", "Dest64 = resTemp = Op164 & ~secOp;") + + def buildDataXImmInst(mnem, code, optArgs = []): + global header_output, decoder_output, exec_output + classNamePrefix = mnem[0].upper() + mnem[1:] + templateBase = "DataXImm" + iop = InstObjParams(mnem, classNamePrefix + "64", + templateBase + "Op", code, optArgs) + header_output += eval(templateBase + "Declare").subst(iop) + decoder_output += eval(templateBase + "Constructor").subst(iop) + exec_output += BasicExecute.subst(iop) + + def buildDataXRegInst(mnem, regOps, code, optArgs = [], + overrideOpClass=None): + global header_output, decoder_output, exec_output + templateBase = "DataX%dReg" % regOps + classNamePrefix = mnem[0].upper() + mnem[1:] + if overrideOpClass: + iop = InstObjParams(mnem, classNamePrefix + "64", + templateBase + "Op", + { 'code': code, 'op_class': overrideOpClass}, + optArgs) + else: + iop = InstObjParams(mnem, classNamePrefix + "64", + templateBase + "Op", code, optArgs) + header_output += eval(templateBase + "Declare").subst(iop) + decoder_output += eval(templateBase + "Constructor").subst(iop) + exec_output += BasicExecute.subst(iop) + + buildDataXRegInst("madd", 3, "Dest64 = Op164 + Op264 * Op364", + overrideOpClass="IntMultOp") + buildDataXRegInst("msub", 3, "Dest64 = Op164 - Op264 * Op364", + overrideOpClass="IntMultOp") + buildDataXRegInst("smaddl", 3, + "XDest = XOp1 + sext<32>(WOp2) * sext<32>(WOp3)", + overrideOpClass="IntMultOp") + buildDataXRegInst("smsubl", 3, + "XDest = XOp1 - sext<32>(WOp2) * sext<32>(WOp3)", + overrideOpClass="IntMultOp") + buildDataXRegInst("smulh", 2, ''' + uint64_t op1H = (int32_t)(XOp1 >> 32); + uint64_t op1L = (uint32_t)XOp1; + uint64_t op2H = (int32_t)(XOp2 >> 32); + uint64_t op2L = (uint32_t)XOp2; + uint64_t mid1 = ((op1L * op2L) >> 32) + op1H * op2L; + uint64_t mid2 = op1L * op2H; + uint64_t result = ((uint64_t)(uint32_t)mid1 + (uint32_t)mid2) >> 32; + result += shiftReg64(mid1, 32, ASR, intWidth); + result += shiftReg64(mid2, 32, ASR, intWidth); + XDest = result + op1H * op2H; + ''', overrideOpClass="IntMultOp") + buildDataXRegInst("umaddl", 3, "XDest = XOp1 + WOp2 * WOp3", + overrideOpClass="IntMultOp") + buildDataXRegInst("umsubl", 3, "XDest = XOp1 - WOp2 * WOp3", + overrideOpClass="IntMultOp") + buildDataXRegInst("umulh", 2, ''' + uint64_t op1H = (uint32_t)(XOp1 >> 32); + uint64_t op1L = (uint32_t)XOp1; + uint64_t op2H = (uint32_t)(XOp2 >> 32); + uint64_t op2L = (uint32_t)XOp2; + uint64_t mid1 = ((op1L * op2L) >> 32) + op1H * op2L; + uint64_t mid2 = op1L * op2H; + uint64_t result = ((uint64_t)(uint32_t)mid1 + (uint32_t)mid2) >> 32; + result += mid1 >> 32; + result += mid2 >> 32; + XDest = result + op1H * op2H; + ''', overrideOpClass="IntMultOp") + + buildDataXRegInst("asrv", 2, + "Dest64 = shiftReg64(Op164, Op264, ASR, intWidth)") + buildDataXRegInst("lslv", 2, + "Dest64 = shiftReg64(Op164, Op264, LSL, intWidth)") + buildDataXRegInst("lsrv", 2, + "Dest64 = shiftReg64(Op164, Op264, LSR, intWidth)") + buildDataXRegInst("rorv", 2, + "Dest64 = shiftReg64(Op164, Op264, ROR, intWidth)") + buildDataXRegInst("sdiv", 2, ''' + int64_t op1 = Op164; + int64_t op2 = Op264; + if (intWidth == 32) { + op1 = sext<32>(op1); + op2 = sext<32>(op2); + } + Dest64 = op2 == -1 ? -op1 : op2 ? op1 / op2 : 0; + ''', overrideOpClass="IntDivOp") + buildDataXRegInst("udiv", 2, "Dest64 = Op264 ? Op164 / Op264 : 0", + overrideOpClass="IntDivOp") + + buildDataXRegInst("cls", 1, ''' + uint64_t op1 = Op164; + if (bits(op1, intWidth - 1)) + op1 ^= mask(intWidth); + Dest64 = (op1 == 0) ? intWidth - 1 : (intWidth - 2 - findMsbSet(op1)); + ''') + buildDataXRegInst("clz", 1, ''' + Dest64 = (Op164 == 0) ? intWidth : (intWidth - 1 - findMsbSet(Op164)); + ''') + buildDataXRegInst("rbit", 1, ''' + uint64_t result = Op164; + uint64_t lBit = 1ULL << (intWidth - 1); + uint64_t rBit = 1ULL; + while (lBit > rBit) { + uint64_t maskBits = lBit | rBit; + uint64_t testBits = result & maskBits; + // If these bits are different, swap them by toggling them. + if (testBits && testBits != maskBits) + result ^= maskBits; + lBit >>= 1; rBit <<= 1; + } + Dest64 = result; + ''') + buildDataXRegInst("rev", 1, ''' + if (intWidth == 32) + Dest64 = betole<uint32_t>(Op164); + else + Dest64 = betole<uint64_t>(Op164); + ''') + buildDataXRegInst("rev16", 1, ''' + int count = intWidth / 16; + uint64_t result = 0; + for (unsigned i = 0; i < count; i++) { + uint16_t hw = Op164 >> (i * 16); + result |= (uint64_t)betole<uint16_t>(hw) << (i * 16); + } + Dest64 = result; + ''') + buildDataXRegInst("rev32", 1, ''' + int count = intWidth / 32; + uint64_t result = 0; + for (unsigned i = 0; i < count; i++) { + uint32_t hw = Op164 >> (i * 32); + result |= (uint64_t)betole<uint32_t>(hw) << (i * 32); + } + Dest64 = result; + ''') + + msrMrs64EnabledCheckCode = ''' + // Check for read/write access right + if (!can%sAArch64SysReg(flat_idx, Scr64, cpsr, xc->tcBase())) { + if (flat_idx == MISCREG_DAIF || + flat_idx == MISCREG_DC_ZVA_Xt || + flat_idx == MISCREG_DC_CVAC_Xt || + flat_idx == MISCREG_DC_CIVAC_Xt + ) + return new UndefinedInstruction(machInst, 0, EC_TRAPPED_MSR_MRS_64); + return new UndefinedInstruction(machInst, false, mnemonic); + } + + // Check for traps to supervisor (FP/SIMD regs) + if (el <= EL1 && msrMrs64TrapToSup(flat_idx, el, Cpacr64)) + return new SupervisorTrap(machInst, 0x1E00000, EC_TRAPPED_SIMD_FP); + + bool is_vfp_neon = false; + + // Check for traps to hypervisor + if ((ArmSystem::haveVirtualization(xc->tcBase()) && el <= EL2) && + msrMrs64TrapToHyp(flat_idx, %s, CptrEl264, Hcr64, &is_vfp_neon)) { + return new HypervisorTrap(machInst, is_vfp_neon ? 0x1E00000 : imm, + is_vfp_neon ? EC_TRAPPED_SIMD_FP : EC_TRAPPED_MSR_MRS_64); + } + + // Check for traps to secure monitor + if ((ArmSystem::haveSecurity(xc->tcBase()) && el <= EL3) && + msrMrs64TrapToMon(flat_idx, CptrEl364, el, &is_vfp_neon)) { + return new SecureMonitorTrap(machInst, + is_vfp_neon ? 0x1E00000 : imm, + is_vfp_neon ? EC_TRAPPED_SIMD_FP : EC_TRAPPED_MSR_MRS_64); + } + ''' + + buildDataXImmInst("mrs", ''' + MiscRegIndex flat_idx = (MiscRegIndex) xc->tcBase()-> + flattenMiscIndex(op1); + CPSR cpsr = Cpsr; + ExceptionLevel el = (ExceptionLevel) (uint8_t) cpsr.el; + %s + XDest = MiscOp1_ud; + ''' % (msrMrs64EnabledCheckCode % ('Read', 'true'),), + ["IsSerializeBefore"]) + + buildDataXRegInst("mrsNZCV", 1, ''' + CPSR cpsr = 0; + cpsr.nz = CondCodesNZ; + cpsr.c = CondCodesC; + cpsr.v = CondCodesV; + XDest = cpsr; + ''') + + buildDataXImmInst("msr", ''' + MiscRegIndex flat_idx = (MiscRegIndex) xc->tcBase()-> + flattenMiscIndex(dest); + CPSR cpsr = Cpsr; + ExceptionLevel el = (ExceptionLevel) (uint8_t) cpsr.el; + %s + MiscDest_ud = XOp1; + ''' % (msrMrs64EnabledCheckCode % ('Write', 'false'),), + ["IsSerializeAfter", "IsNonSpeculative"]) + + buildDataXRegInst("msrNZCV", 1, ''' + CPSR cpsr = XOp1; + CondCodesNZ = cpsr.nz; + CondCodesC = cpsr.c; + CondCodesV = cpsr.v; + ''') + + msrdczva_ea_code = ''' + MiscRegIndex flat_idx = (MiscRegIndex) xc->tcBase()->flattenMiscIndex(dest); + CPSR cpsr = Cpsr; + ExceptionLevel el = (ExceptionLevel) (uint8_t) cpsr.el; + ''' + + msrdczva_ea_code += msrMrs64EnabledCheckCode % ('Write', 'false') + msrdczva_ea_code += ''' + Request::Flags memAccessFlags = Request::CACHE_BLOCK_ZERO|ArmISA::TLB::MustBeOne; + EA = XBase; + assert(!(Dczid & 0x10)); + uint64_t op_size = power(2, Dczid + 2); + EA &= ~(op_size - 1); + + ''' + + msrDCZVAIop = InstObjParams("dczva", "Dczva", "SysDC64", + { "ea_code" : msrdczva_ea_code, + "memacc_code" : ";", "use_uops" : 0, + "op_wb" : ";", "fa_code" : ";"}, ['IsStore', 'IsMemRef']); + header_output += DCStore64Declare.subst(msrDCZVAIop); + decoder_output += DCStore64Constructor.subst(msrDCZVAIop); + exec_output += DCStore64Execute.subst(msrDCZVAIop); + exec_output += DCStore64InitiateAcc.subst(msrDCZVAIop); + exec_output += Store64CompleteAcc.subst(msrDCZVAIop); + + + + buildDataXImmInst("msrSP", ''' + if (!canWriteAArch64SysReg( + (MiscRegIndex) xc->tcBase()->flattenMiscIndex(dest), + Scr64, Cpsr, xc->tcBase())) { + return new UndefinedInstruction(machInst, false, mnemonic); + } + MiscDest_ud = imm; + ''', optArgs = ["IsSerializeAfter", "IsNonSpeculative"]) + + buildDataXImmInst("msrDAIFSet", ''' + if (!canWriteAArch64SysReg( + (MiscRegIndex) xc->tcBase()->flattenMiscIndex(dest), + Scr64, Cpsr, xc->tcBase())) { + return new UndefinedInstruction(machInst, 0, EC_TRAPPED_MSR_MRS_64); + } + CPSR cpsr = Cpsr; + cpsr.daif = cpsr.daif | imm; + Cpsr = cpsr; + ''', optArgs = ["IsSerializeAfter", "IsNonSpeculative"]) + + buildDataXImmInst("msrDAIFClr", ''' + if (!canWriteAArch64SysReg( + (MiscRegIndex) xc->tcBase()->flattenMiscIndex(dest), + Scr64, Cpsr, xc->tcBase())) { + return new UndefinedInstruction(machInst, 0, EC_TRAPPED_MSR_MRS_64); + } + CPSR cpsr = Cpsr; + cpsr.daif = cpsr.daif & ~imm; + Cpsr = cpsr; + ''', optArgs = ["IsSerializeAfter", "IsNonSpeculative"]) + + def buildDataXCompInst(mnem, instType, suffix, code): + global header_output, decoder_output, exec_output + templateBase = "DataXCond%s" % instType + iop = InstObjParams(mnem, mnem.capitalize() + suffix + "64", + templateBase + "Op", code) + header_output += eval(templateBase + "Declare").subst(iop) + decoder_output += eval(templateBase + "Constructor").subst(iop) + exec_output += BasicExecute.subst(iop) + + def buildDataXCondImmInst(mnem, code): + buildDataXCompInst(mnem, "CompImm", "Imm", code) + def buildDataXCondRegInst(mnem, code): + buildDataXCompInst(mnem, "CompReg", "Reg", code) + def buildDataXCondSelInst(mnem, code): + buildDataXCompInst(mnem, "Sel", "", code) + + def condCompCode(flagType, op, imm): + ccCode = createCcCode64(carryCode64[flagType], overflowCode64[flagType]) + opDecl = "uint64_t secOp M5_VAR_USED = imm;" + if not imm: + opDecl = "uint64_t secOp M5_VAR_USED = Op264;" + return opDecl + ''' + if (testPredicate(CondCodesNZ, CondCodesC, CondCodesV, condCode)) { + uint64_t resTemp = Op164 ''' + op + ''' secOp; + ''' + ccCode + ''' + } else { + CondCodesNZ = (defCc >> 2) & 0x3; + CondCodesC = (defCc >> 1) & 0x1; + CondCodesV = defCc & 0x1; + } + ''' + + buildDataXCondImmInst("ccmn", condCompCode("add", "+", True)) + buildDataXCondImmInst("ccmp", condCompCode("sub", "-", True)) + buildDataXCondRegInst("ccmn", condCompCode("add", "+", False)) + buildDataXCondRegInst("ccmp", condCompCode("sub", "-", False)) + + condSelCode = ''' + if (testPredicate(CondCodesNZ, CondCodesC, CondCodesV, condCode)) { + Dest64 = Op164; + } else { + Dest64 = %(altVal)s; + } + ''' + buildDataXCondSelInst("csel", condSelCode % {"altVal" : "Op264"}) + buildDataXCondSelInst("csinc", condSelCode % {"altVal" : "Op264 + 1"}) + buildDataXCondSelInst("csinv", condSelCode % {"altVal" : "~Op264"}) + buildDataXCondSelInst("csneg", condSelCode % {"altVal" : "-Op264"}) +}}; diff --git a/src/arch/arm/isa/insts/div.isa b/src/arch/arm/isa/insts/div.isa index 1ff6ef9e4..0896ea94f 100644 --- a/src/arch/arm/isa/insts/div.isa +++ b/src/arch/arm/isa/insts/div.isa @@ -40,12 +40,6 @@ let {{ sdivCode = ''' if (Op2_sw == 0) { - if (((SCTLR)Sctlr).dz) { - if (FullSystem) - return new UndefinedInstruction; - else - return new UndefinedInstruction(false, mnemonic); - } Dest_sw = 0; } else if (Op1_sw == INT_MIN && Op2_sw == -1) { Dest_sw = INT_MIN; @@ -63,12 +57,6 @@ let {{ udivCode = ''' if (Op2_uw == 0) { - if (((SCTLR)Sctlr).dz) { - if (FullSystem) - return new UndefinedInstruction; - else - return new UndefinedInstruction(false, mnemonic); - } Dest_uw = 0; } else { Dest_uw = Op1_uw / Op2_uw; diff --git a/src/arch/arm/isa/insts/fp.isa b/src/arch/arm/isa/insts/fp.isa index b701995f4..60f030c3d 100644 --- a/src/arch/arm/isa/insts/fp.isa +++ b/src/arch/arm/isa/insts/fp.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2010 ARM Limited +// Copyright (c) 2010-2013 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -191,14 +191,17 @@ let {{ decoder_output = "" exec_output = "" - vmsrIop = InstObjParams("vmsr", "Vmsr", "FpRegRegOp", - { "code": vmsrEnabledCheckCode + \ - "MiscDest = Op1;", + vmsrCode = vmsrEnabledCheckCode + ''' + MiscDest = Op1; + ''' + + vmsrIop = InstObjParams("vmsr", "Vmsr", "FpRegRegImmOp", + { "code": vmsrCode, "predicate_test": predicateTest, "op_class": "SimdFloatMiscOp" }, ["IsSerializeAfter","IsNonSpeculative"]) - header_output += FpRegRegOpDeclare.subst(vmsrIop); - decoder_output += FpRegRegOpConstructor.subst(vmsrIop); + header_output += FpRegRegImmOpDeclare.subst(vmsrIop); + decoder_output += FpRegRegImmOpConstructor.subst(vmsrIop); exec_output += PredOpExecute.subst(vmsrIop); vmsrFpscrCode = vmsrEnabledCheckCode + ''' @@ -215,14 +218,36 @@ let {{ decoder_output += FpRegRegOpConstructor.subst(vmsrFpscrIop); exec_output += PredOpExecute.subst(vmsrFpscrIop); - vmrsIop = InstObjParams("vmrs", "Vmrs", "FpRegRegOp", - { "code": vmrsEnabledCheckCode + \ - "Dest = MiscOp1;", + vmrsCode = vmrsEnabledCheckCode + ''' + CPSR cpsr = Cpsr; + SCR scr = Scr; + if (!inSecureState(scr, cpsr) && (cpsr.mode != MODE_HYP)) { + HCR hcr = Hcr; + bool hypTrap = false; + switch(xc->tcBase()->flattenMiscIndex(op1)) { + case MISCREG_FPSID: + hypTrap = hcr.tid0; + break; + case MISCREG_MVFR0: + case MISCREG_MVFR1: + hypTrap = hcr.tid3; + break; + } + if (hypTrap) { + return new HypervisorTrap(machInst, imm, + EC_TRAPPED_CP10_MRC_VMRS); + } + } + Dest = MiscOp1; + ''' + + vmrsIop = InstObjParams("vmrs", "Vmrs", "FpRegRegImmOp", + { "code": vmrsCode, "predicate_test": predicateTest, "op_class": "SimdFloatMiscOp" }, ["IsSerializeBefore"]) - header_output += FpRegRegOpDeclare.subst(vmrsIop); - decoder_output += FpRegRegOpConstructor.subst(vmrsIop); + header_output += FpRegRegImmOpDeclare.subst(vmrsIop); + decoder_output += FpRegRegImmOpConstructor.subst(vmrsIop); exec_output += PredOpExecute.subst(vmrsIop); vmrsFpscrIop = InstObjParams("vmrs", "VmrsFpscr", "FpRegRegOp", @@ -323,7 +348,7 @@ let {{ decoder_output += FpRegRegOpConstructor.subst(vmovRegQIop); exec_output += PredOpExecute.subst(vmovRegQIop); - vmovCoreRegBCode = vfpEnabledCheckCode + ''' + vmovCoreRegBCode = simdEnabledCheckCode + ''' FpDest_uw = insertBits(FpDest_uw, imm * 8 + 7, imm * 8, Op1_ub); ''' vmovCoreRegBIop = InstObjParams("vmov", "VmovCoreRegB", "FpRegRegImmOp", @@ -334,7 +359,7 @@ let {{ decoder_output += FpRegRegImmOpConstructor.subst(vmovCoreRegBIop); exec_output += PredOpExecute.subst(vmovCoreRegBIop); - vmovCoreRegHCode = vfpEnabledCheckCode + ''' + vmovCoreRegHCode = simdEnabledCheckCode + ''' FpDest_uw = insertBits(FpDest_uw, imm * 16 + 15, imm * 16, Op1_uh); ''' vmovCoreRegHIop = InstObjParams("vmov", "VmovCoreRegH", "FpRegRegImmOp", @@ -453,6 +478,17 @@ let {{ singleCode = singleSimpleCode + ''' FpscrExc = fpscr; ''' + singleTernOp = vfpEnabledCheckCode + ''' + FPSCR fpscr = (FPSCR) FpscrExc; + VfpSavedState state = prepFpState(fpscr.rMode); + float cOp1 = FpOp1; + float cOp2 = FpOp2; + float cOp3 = FpDestP0; + FpDestP0 = ternaryOp(fpscr, %(palam)s, %(op)s, + fpscr.fz, fpscr.dn, fpscr.rMode); + finishVfp(fpscr, state, fpscr.fz); + FpscrExc = fpscr; + ''' singleBinOp = "binaryOp(fpscr, FpOp1, FpOp2," + \ "%(func)s, fpscr.fz, fpscr.dn, fpscr.rMode)" singleUnaryOp = "unaryOp(fpscr, FpOp1, %(func)s, fpscr.fz, fpscr.rMode)" @@ -463,6 +499,19 @@ let {{ FpDestP1_uw = dblHi(dest); FpscrExc = fpscr; ''' + doubleTernOp = vfpEnabledCheckCode + ''' + FPSCR fpscr = (FPSCR) FpscrExc; + VfpSavedState state = prepFpState(fpscr.rMode); + double cOp1 = dbl(FpOp1P0_uw, FpOp1P1_uw); + double cOp2 = dbl(FpOp2P0_uw, FpOp2P1_uw); + double cOp3 = dbl(FpDestP0_uw, FpDestP1_uw); + double cDest = ternaryOp(fpscr, %(palam)s, %(op)s, + fpscr.fz, fpscr.dn, fpscr.rMode); + FpDestP0_uw = dblLow(cDest); + FpDestP1_uw = dblHi(cDest); + finishVfp(fpscr, state, fpscr.fz); + FpscrExc = fpscr; + ''' doubleBinOp = ''' binaryOp(fpscr, dbl(FpOp1P0_uw, FpOp1P1_uw), dbl(FpOp2P0_uw, FpOp2P1_uw), @@ -473,6 +522,37 @@ let {{ fpscr.fz, fpscr.rMode) ''' + def buildTernaryFpOp(Name, base, opClass, singleOp, doubleOp, paramStr): + global header_output, decoder_output, exec_output + + code = singleTernOp % { "op": singleOp, "palam": paramStr } + sIop = InstObjParams(Name.lower() + "s", Name + "S", base, + { "code": code, + "predicate_test": predicateTest, + "op_class": opClass }, []) + code = doubleTernOp % { "op": doubleOp, "palam": paramStr } + dIop = InstObjParams(Name.lower() + "d", Name + "D", base, + { "code": code, + "predicate_test": predicateTest, + "op_class": opClass }, []) + + declareTempl = eval(base + "Declare"); + constructorTempl = eval(base + "Constructor"); + + for iop in sIop, dIop: + header_output += declareTempl.subst(iop) + decoder_output += constructorTempl.subst(iop) + exec_output += PredOpExecute.subst(iop) + + buildTernaryFpOp("Vfma", "FpRegRegRegOp", "SimdFloatMultAccOp", + "fpMulAdd<float>", "fpMulAdd<double>", " cOp1, cOp2, cOp3" ) + buildTernaryFpOp("Vfms", "FpRegRegRegOp", "SimdFloatMultAccOp", + "fpMulAdd<float>", "fpMulAdd<double>", "-cOp1, cOp2, cOp3" ) + buildTernaryFpOp("Vfnma", "FpRegRegRegOp", "SimdFloatMultAccOp", + "fpMulAdd<float>", "fpMulAdd<double>", "-cOp1, cOp2, -cOp3" ) + buildTernaryFpOp("Vfnms", "FpRegRegRegOp", "SimdFloatMultAccOp", + "fpMulAdd<float>", "fpMulAdd<double>", " cOp1, cOp2, -cOp3" ) + def buildBinFpOp(name, Name, base, opClass, singleOp, doubleOp): global header_output, decoder_output, exec_output @@ -830,7 +910,7 @@ let {{ VfpSavedState state = prepFpState(fpscr.rMode); vfpFlushToZero(fpscr, FpOp1); __asm__ __volatile__("" : "=m" (FpOp1) : "m" (FpOp1)); - FpDest_uw = vfpFpSToFixed(FpOp1, false, false, 0, false); + FpDest_uw = vfpFpToFixed<float>(FpOp1, false, 32, 0, false); __asm__ __volatile__("" :: "m" (FpDest_uw)); finishVfp(fpscr, state, fpscr.fz); FpscrExc = fpscr; @@ -849,7 +929,7 @@ let {{ vfpFlushToZero(fpscr, cOp1); VfpSavedState state = prepFpState(fpscr.rMode); __asm__ __volatile__("" : "=m" (cOp1) : "m" (cOp1)); - uint64_t result = vfpFpDToFixed(cOp1, false, false, 0, false); + uint64_t result = vfpFpToFixed<double>(cOp1, false, 32, 0, false); __asm__ __volatile__("" :: "m" (result)); finishVfp(fpscr, state, fpscr.fz); FpDestP0_uw = result; @@ -868,7 +948,7 @@ let {{ VfpSavedState state = prepFpState(fpscr.rMode); vfpFlushToZero(fpscr, FpOp1); __asm__ __volatile__("" : "=m" (FpOp1) : "m" (FpOp1)); - FpDest_sw = vfpFpSToFixed(FpOp1, true, false, 0, false); + FpDest_sw = vfpFpToFixed<float>(FpOp1, true, 32, 0, false); __asm__ __volatile__("" :: "m" (FpDest_sw)); finishVfp(fpscr, state, fpscr.fz); FpscrExc = fpscr; @@ -887,7 +967,7 @@ let {{ vfpFlushToZero(fpscr, cOp1); VfpSavedState state = prepFpState(fpscr.rMode); __asm__ __volatile__("" : "=m" (cOp1) : "m" (cOp1)); - int64_t result = vfpFpDToFixed(cOp1, true, false, 0, false); + int64_t result = vfpFpToFixed<double>(cOp1, true, 32, 0, false); __asm__ __volatile__("" :: "m" (result)); finishVfp(fpscr, state, fpscr.fz); FpDestP0_uw = result; @@ -907,7 +987,7 @@ let {{ VfpSavedState state = prepFpState(fpscr.rMode); fesetround(FeRoundZero); __asm__ __volatile__("" : "=m" (FpOp1) : "m" (FpOp1)); - FpDest_uw = vfpFpSToFixed(FpOp1, false, false, 0); + FpDest_uw = vfpFpToFixed<float>(FpOp1, false, 32, 0); __asm__ __volatile__("" :: "m" (FpDest_uw)); finishVfp(fpscr, state, fpscr.fz); FpscrExc = fpscr; @@ -927,7 +1007,7 @@ let {{ VfpSavedState state = prepFpState(fpscr.rMode); fesetround(FeRoundZero); __asm__ __volatile__("" : "=m" (cOp1) : "m" (cOp1)); - uint64_t result = vfpFpDToFixed(cOp1, false, false, 0); + uint64_t result = vfpFpToFixed<double>(cOp1, false, 32, 0); __asm__ __volatile__("" :: "m" (result)); finishVfp(fpscr, state, fpscr.fz); FpDestP0_uw = result; @@ -947,7 +1027,7 @@ let {{ VfpSavedState state = prepFpState(fpscr.rMode); fesetround(FeRoundZero); __asm__ __volatile__("" : "=m" (FpOp1) : "m" (FpOp1)); - FpDest_sw = vfpFpSToFixed(FpOp1, true, false, 0); + FpDest_sw = vfpFpToFixed<float>(FpOp1, true, 32, 0); __asm__ __volatile__("" :: "m" (FpDest_sw)); finishVfp(fpscr, state, fpscr.fz); FpscrExc = fpscr; @@ -967,7 +1047,7 @@ let {{ VfpSavedState state = prepFpState(fpscr.rMode); fesetround(FeRoundZero); __asm__ __volatile__("" : "=m" (cOp1) : "m" (cOp1)); - int64_t result = vfpFpDToFixed(cOp1, true, false, 0); + int64_t result = vfpFpToFixed<double>(cOp1, true, 32, 0); __asm__ __volatile__("" :: "m" (result)); finishVfp(fpscr, state, fpscr.fz); FpDestP0_uw = result; @@ -1333,7 +1413,7 @@ let {{ vfpFlushToZero(fpscr, FpOp1); VfpSavedState state = prepFpState(fpscr.rMode); __asm__ __volatile__("" : "=m" (FpOp1) : "m" (FpOp1)); - FpDest_sw = vfpFpSToFixed(FpOp1, true, false, imm); + FpDest_sw = vfpFpToFixed<float>(FpOp1, true, 32, imm); __asm__ __volatile__("" :: "m" (FpDest_sw)); finishVfp(fpscr, state, fpscr.fz); FpscrExc = fpscr; @@ -1352,7 +1432,7 @@ let {{ vfpFlushToZero(fpscr, cOp1); VfpSavedState state = prepFpState(fpscr.rMode); __asm__ __volatile__("" : "=m" (cOp1) : "m" (cOp1)); - uint64_t mid = vfpFpDToFixed(cOp1, true, false, imm); + uint64_t mid = vfpFpToFixed<double>(cOp1, true, 32, imm); __asm__ __volatile__("" :: "m" (mid)); finishVfp(fpscr, state, fpscr.fz); FpDestP0_uw = mid; @@ -1372,7 +1452,7 @@ let {{ vfpFlushToZero(fpscr, FpOp1); VfpSavedState state = prepFpState(fpscr.rMode); __asm__ __volatile__("" : "=m" (FpOp1) : "m" (FpOp1)); - FpDest_uw = vfpFpSToFixed(FpOp1, false, false, imm); + FpDest_uw = vfpFpToFixed<float>(FpOp1, false, 32, imm); __asm__ __volatile__("" :: "m" (FpDest_uw)); finishVfp(fpscr, state, fpscr.fz); FpscrExc = fpscr; @@ -1391,7 +1471,7 @@ let {{ vfpFlushToZero(fpscr, cOp1); VfpSavedState state = prepFpState(fpscr.rMode); __asm__ __volatile__("" : "=m" (cOp1) : "m" (cOp1)); - uint64_t mid = vfpFpDToFixed(cOp1, false, false, imm); + uint64_t mid = vfpFpToFixed<double>(cOp1, false, 32, imm); __asm__ __volatile__("" :: "m" (mid)); finishVfp(fpscr, state, fpscr.fz); FpDestP0_uw = mid; @@ -1410,7 +1490,7 @@ let {{ FPSCR fpscr = (FPSCR) FpscrExc; VfpSavedState state = prepFpState(fpscr.rMode); __asm__ __volatile__("" : "=m" (FpOp1_sw) : "m" (FpOp1_sw)); - FpDest = vfpSFixedToFpS(fpscr.fz, fpscr.dn, FpOp1_sw, false, imm); + FpDest = vfpSFixedToFpS(fpscr.fz, fpscr.dn, FpOp1_sw, 32, imm); __asm__ __volatile__("" :: "m" (FpDest)); finishVfp(fpscr, state, fpscr.fz); FpscrExc = fpscr; @@ -1428,7 +1508,7 @@ let {{ uint64_t mid = ((uint64_t)FpOp1P0_uw | ((uint64_t)FpOp1P1_uw << 32)); VfpSavedState state = prepFpState(fpscr.rMode); __asm__ __volatile__("" : "=m" (mid) : "m" (mid)); - double cDest = vfpSFixedToFpD(fpscr.fz, fpscr.dn, mid, false, imm); + double cDest = vfpSFixedToFpD(fpscr.fz, fpscr.dn, mid, 32, imm); __asm__ __volatile__("" :: "m" (cDest)); finishVfp(fpscr, state, fpscr.fz); FpDestP0_uw = dblLow(cDest); @@ -1447,7 +1527,7 @@ let {{ FPSCR fpscr = (FPSCR) FpscrExc; VfpSavedState state = prepFpState(fpscr.rMode); __asm__ __volatile__("" : "=m" (FpOp1_uw) : "m" (FpOp1_uw)); - FpDest = vfpUFixedToFpS(fpscr.fz, fpscr.dn, FpOp1_uw, false, imm); + FpDest = vfpUFixedToFpS(fpscr.fz, fpscr.dn, FpOp1_uw, 32, imm); __asm__ __volatile__("" :: "m" (FpDest)); finishVfp(fpscr, state, fpscr.fz); FpscrExc = fpscr; @@ -1465,7 +1545,7 @@ let {{ uint64_t mid = ((uint64_t)FpOp1P0_uw | ((uint64_t)FpOp1P1_uw << 32)); VfpSavedState state = prepFpState(fpscr.rMode); __asm__ __volatile__("" : "=m" (mid) : "m" (mid)); - double cDest = vfpUFixedToFpD(fpscr.fz, fpscr.dn, mid, false, imm); + double cDest = vfpUFixedToFpD(fpscr.fz, fpscr.dn, mid, 32, imm); __asm__ __volatile__("" :: "m" (cDest)); finishVfp(fpscr, state, fpscr.fz); FpDestP0_uw = dblLow(cDest); @@ -1485,7 +1565,7 @@ let {{ vfpFlushToZero(fpscr, FpOp1); VfpSavedState state = prepFpState(fpscr.rMode); __asm__ __volatile__("" : "=m" (FpOp1) : "m" (FpOp1)); - FpDest_sh = vfpFpSToFixed(FpOp1, true, true, imm); + FpDest_sh = vfpFpToFixed<float>(FpOp1, true, 16, imm); __asm__ __volatile__("" :: "m" (FpDest_sh)); finishVfp(fpscr, state, fpscr.fz); FpscrExc = fpscr; @@ -1505,7 +1585,7 @@ let {{ vfpFlushToZero(fpscr, cOp1); VfpSavedState state = prepFpState(fpscr.rMode); __asm__ __volatile__("" : "=m" (cOp1) : "m" (cOp1)); - uint64_t result = vfpFpDToFixed(cOp1, true, true, imm); + uint64_t result = vfpFpToFixed<double>(cOp1, true, 16, imm); __asm__ __volatile__("" :: "m" (result)); finishVfp(fpscr, state, fpscr.fz); FpDestP0_uw = result; @@ -1526,7 +1606,7 @@ let {{ vfpFlushToZero(fpscr, FpOp1); VfpSavedState state = prepFpState(fpscr.rMode); __asm__ __volatile__("" : "=m" (FpOp1) : "m" (FpOp1)); - FpDest_uh = vfpFpSToFixed(FpOp1, false, true, imm); + FpDest_uh = vfpFpToFixed<float>(FpOp1, false, 16, imm); __asm__ __volatile__("" :: "m" (FpDest_uh)); finishVfp(fpscr, state, fpscr.fz); FpscrExc = fpscr; @@ -1546,7 +1626,7 @@ let {{ vfpFlushToZero(fpscr, cOp1); VfpSavedState state = prepFpState(fpscr.rMode); __asm__ __volatile__("" : "=m" (cOp1) : "m" (cOp1)); - uint64_t mid = vfpFpDToFixed(cOp1, false, true, imm); + uint64_t mid = vfpFpToFixed<double>(cOp1, false, 16, imm); __asm__ __volatile__("" :: "m" (mid)); finishVfp(fpscr, state, fpscr.fz); FpDestP0_uw = mid; @@ -1566,7 +1646,7 @@ let {{ FPSCR fpscr = (FPSCR) FpscrExc; VfpSavedState state = prepFpState(fpscr.rMode); __asm__ __volatile__("" : "=m" (FpOp1_sh) : "m" (FpOp1_sh)); - FpDest = vfpSFixedToFpS(fpscr.fz, fpscr.dn, FpOp1_sh, true, imm); + FpDest = vfpSFixedToFpS(fpscr.fz, fpscr.dn, FpOp1_sh, 16, imm); __asm__ __volatile__("" :: "m" (FpDest)); finishVfp(fpscr, state, fpscr.fz); FpscrExc = fpscr; @@ -1585,7 +1665,7 @@ let {{ uint64_t mid = ((uint64_t)FpOp1P0_uw | ((uint64_t)FpOp1P1_uw << 32)); VfpSavedState state = prepFpState(fpscr.rMode); __asm__ __volatile__("" : "=m" (mid) : "m" (mid)); - double cDest = vfpSFixedToFpD(fpscr.fz, fpscr.dn, mid, true, imm); + double cDest = vfpSFixedToFpD(fpscr.fz, fpscr.dn, mid, 16, imm); __asm__ __volatile__("" :: "m" (cDest)); finishVfp(fpscr, state, fpscr.fz); FpDestP0_uw = dblLow(cDest); @@ -1605,7 +1685,7 @@ let {{ FPSCR fpscr = (FPSCR) FpscrExc; VfpSavedState state = prepFpState(fpscr.rMode); __asm__ __volatile__("" : "=m" (FpOp1_uh) : "m" (FpOp1_uh)); - FpDest = vfpUFixedToFpS(fpscr.fz, fpscr.dn, FpOp1_uh, true, imm); + FpDest = vfpUFixedToFpS(fpscr.fz, fpscr.dn, FpOp1_uh, 16, imm); __asm__ __volatile__("" :: "m" (FpDest)); finishVfp(fpscr, state, fpscr.fz); FpscrExc = fpscr; @@ -1624,7 +1704,7 @@ let {{ uint64_t mid = ((uint64_t)FpOp1P0_uw | ((uint64_t)FpOp1P1_uw << 32)); VfpSavedState state = prepFpState(fpscr.rMode); __asm__ __volatile__("" : "=m" (mid) : "m" (mid)); - double cDest = vfpUFixedToFpD(fpscr.fz, fpscr.dn, mid, true, imm); + double cDest = vfpUFixedToFpD(fpscr.fz, fpscr.dn, mid, 16, imm); __asm__ __volatile__("" :: "m" (cDest)); finishVfp(fpscr, state, fpscr.fz); FpDestP0_uw = dblLow(cDest); diff --git a/src/arch/arm/isa/insts/fp64.isa b/src/arch/arm/isa/insts/fp64.isa new file mode 100644 index 000000000..95dec5062 --- /dev/null +++ b/src/arch/arm/isa/insts/fp64.isa @@ -0,0 +1,811 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2012-2013 ARM Limited +// All rights reserved +// +// The license below extends only to copyright in the software and shall +// not be construed as granting a license to any other intellectual +// property including but not limited to intellectual property relating +// to a hardware implementation of the functionality of the software +// licensed hereunder. You may use the software subject to the license +// terms below provided that you ensure that this notice is replicated +// unmodified and in its entirety in all distributions of the software, +// modified or unmodified, in source code or in binary form. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Thomas Grocutt +// Edmund Grimley Evans + +let {{ + + header_output = "" + decoder_output = "" + exec_output = "" + + fmovImmSCode = vfp64EnabledCheckCode + ''' + AA64FpDestP0_uw = bits(imm, 31, 0); + AA64FpDestP1_uw = 0; + AA64FpDestP2_uw = 0; + AA64FpDestP3_uw = 0; + ''' + fmovImmSIop = InstObjParams("fmov", "FmovImmS", "FpRegImmOp", + { "code": fmovImmSCode, + "op_class": "SimdFloatMiscOp" }, []) + header_output += FpRegImmOpDeclare.subst(fmovImmSIop); + decoder_output += FpRegImmOpConstructor.subst(fmovImmSIop); + exec_output += BasicExecute.subst(fmovImmSIop); + + fmovImmDCode = vfp64EnabledCheckCode + ''' + AA64FpDestP0_uw = bits(imm, 31, 0); + AA64FpDestP1_uw = bits(imm, 63, 32); + AA64FpDestP2_uw = 0; + AA64FpDestP3_uw = 0; + ''' + fmovImmDIop = InstObjParams("fmov", "FmovImmD", "FpRegImmOp", + { "code": fmovImmDCode, + "op_class": "SimdFloatMiscOp" }, []) + header_output += FpRegImmOpDeclare.subst(fmovImmDIop); + decoder_output += AA64FpRegImmOpConstructor.subst(fmovImmDIop); + exec_output += BasicExecute.subst(fmovImmDIop); + + fmovRegSCode = vfp64EnabledCheckCode + ''' + AA64FpDestP0_uw = AA64FpOp1P0_uw; + AA64FpDestP1_uw = 0; + AA64FpDestP2_uw = 0; + AA64FpDestP3_uw = 0; + ''' + fmovRegSIop = InstObjParams("fmov", "FmovRegS", "FpRegRegOp", + { "code": fmovRegSCode, + "op_class": "SimdFloatMiscOp" }, []) + header_output += FpRegRegOpDeclare.subst(fmovRegSIop); + decoder_output += AA64FpRegRegOpConstructor.subst(fmovRegSIop); + exec_output += BasicExecute.subst(fmovRegSIop); + + fmovRegDCode = vfp64EnabledCheckCode + ''' + AA64FpDestP0_uw = AA64FpOp1P0_uw; + AA64FpDestP1_uw = AA64FpOp1P1_uw; + AA64FpDestP2_uw = 0; + AA64FpDestP3_uw = 0; + ''' + fmovRegDIop = InstObjParams("fmov", "FmovRegD", "FpRegRegOp", + { "code": fmovRegDCode, + "op_class": "SimdFloatMiscOp" }, []) + header_output += FpRegRegOpDeclare.subst(fmovRegDIop); + decoder_output += AA64FpRegRegOpConstructor.subst(fmovRegDIop); + exec_output += BasicExecute.subst(fmovRegDIop); + + fmovCoreRegWCode = vfp64EnabledCheckCode + ''' + AA64FpDestP0_uw = WOp1_uw; + AA64FpDestP1_uw = 0; + AA64FpDestP2_uw = 0; + AA64FpDestP3_uw = 0; + ''' + fmovCoreRegWIop = InstObjParams("fmov", "FmovCoreRegW", "FpRegRegOp", + { "code": fmovCoreRegWCode, + "op_class": "SimdFloatMiscOp" }, []) + header_output += FpRegRegOpDeclare.subst(fmovCoreRegWIop); + decoder_output += AA64FpRegRegOpConstructor.subst(fmovCoreRegWIop); + exec_output += BasicExecute.subst(fmovCoreRegWIop); + + fmovCoreRegXCode = vfp64EnabledCheckCode + ''' + AA64FpDestP0_uw = XOp1_ud; + AA64FpDestP1_uw = XOp1_ud >> 32; + AA64FpDestP2_uw = 0; + AA64FpDestP3_uw = 0; + ''' + fmovCoreRegXIop = InstObjParams("fmov", "FmovCoreRegX", "FpRegRegOp", + { "code": fmovCoreRegXCode, + "op_class": "SimdFloatMiscOp" }, []) + header_output += FpRegRegOpDeclare.subst(fmovCoreRegXIop); + decoder_output += AA64FpRegRegOpConstructor.subst(fmovCoreRegXIop); + exec_output += BasicExecute.subst(fmovCoreRegXIop); + + fmovUCoreRegXCode = vfp64EnabledCheckCode + ''' + AA64FpDestP2_uw = XOp1_ud; + AA64FpDestP3_uw = XOp1_ud >> 32; + ''' + fmovUCoreRegXIop = InstObjParams("fmov", "FmovUCoreRegX", "FpRegRegOp", + { "code": fmovUCoreRegXCode, + "op_class": "SimdFloatMiscOp" }, []) + header_output += FpRegRegOpDeclare.subst(fmovUCoreRegXIop); + decoder_output += AA64FpRegRegOpConstructor.subst(fmovUCoreRegXIop); + exec_output += BasicExecute.subst(fmovUCoreRegXIop); + + fmovRegCoreWCode = vfp64EnabledCheckCode + ''' + WDest = AA64FpOp1P0_uw; + ''' + fmovRegCoreWIop = InstObjParams("fmov", "FmovRegCoreW", "FpRegRegOp", + { "code": fmovRegCoreWCode, + "op_class": "SimdFloatMiscOp" }, []) + header_output += FpRegRegOpDeclare.subst(fmovRegCoreWIop); + decoder_output += AA64FpRegRegOpConstructor.subst(fmovRegCoreWIop); + exec_output += BasicExecute.subst(fmovRegCoreWIop); + + fmovRegCoreXCode = vfp64EnabledCheckCode + ''' + XDest = ( ((uint64_t) AA64FpOp1P1_uw) << 32) | AA64FpOp1P0_uw; + ''' + fmovRegCoreXIop = InstObjParams("fmov", "FmovRegCoreX", "FpRegRegOp", + { "code": fmovRegCoreXCode, + "op_class": "SimdFloatMiscOp" }, []) + header_output += FpRegRegOpDeclare.subst(fmovRegCoreXIop); + decoder_output += AA64FpRegRegOpConstructor.subst(fmovRegCoreXIop); + exec_output += BasicExecute.subst(fmovRegCoreXIop); + + fmovURegCoreXCode = vfp64EnabledCheckCode + ''' + XDest = ( ((uint64_t) AA64FpOp1P3_uw) << 32) | AA64FpOp1P2_uw; + ''' + fmovURegCoreXIop = InstObjParams("fmov", "FmovURegCoreX", "FpRegRegOp", + { "code": fmovURegCoreXCode, + "op_class": "SimdFloatMiscOp" }, []) + header_output += FpRegRegOpDeclare.subst(fmovURegCoreXIop); + decoder_output += AA64FpRegRegOpConstructor.subst(fmovURegCoreXIop); + exec_output += BasicExecute.subst(fmovURegCoreXIop); +}}; + +let {{ + + header_output = "" + decoder_output = "" + exec_output = "" + + singleIntConvCode = vfp64EnabledCheckCode + ''' + FPSCR fpscr = (FPSCR) FpscrExc; + uint32_t cOp1 = AA64FpOp1P0_uw; + uint32_t cDest = %(op)s; + AA64FpDestP0_uw = cDest; + AA64FpDestP1_uw = 0; + AA64FpDestP2_uw = 0; + AA64FpDestP3_uw = 0; + FpscrExc = fpscr; + ''' + + singleIntConvCode2 = vfp64EnabledCheckCode + ''' + FPSCR fpscr = (FPSCR) FpscrExc; + uint32_t cOp1 = AA64FpOp1P0_uw; + uint32_t cOp2 = AA64FpOp2P0_uw; + uint32_t cDest = %(op)s; + AA64FpDestP0_uw = cDest; + AA64FpDestP1_uw = 0; + AA64FpDestP2_uw = 0; + AA64FpDestP3_uw = 0; + FpscrExc = fpscr; + ''' + + singleBinOp = "binaryOp(fpscr, AA64FpOp1P0, AA64FpOp2P0," + \ + "%(func)s, fpscr.fz, fpscr.dn, fpscr.rMode)" + singleUnaryOp = "unaryOp(fpscr, AA64FpOp1P0, %(func)s, fpscr.fz, fpscr.rMode)" + + doubleIntConvCode = vfp64EnabledCheckCode + ''' + FPSCR fpscr = (FPSCR) FpscrExc; + uint64_t cOp1 = ((uint64_t) AA64FpOp1P1_uw) << 32 | AA64FpOp1P0_uw; + uint64_t cDest = %(op)s; + AA64FpDestP0_uw = cDest & 0xFFFFFFFF; + AA64FpDestP1_uw = cDest >> 32; + AA64FpDestP2_uw = 0; + AA64FpDestP3_uw = 0; + FpscrExc = fpscr; + ''' + + doubleIntConvCode2 = vfp64EnabledCheckCode + ''' + FPSCR fpscr = (FPSCR) FpscrExc; + uint64_t cOp1 = ((uint64_t) AA64FpOp1P1_uw) << 32 | AA64FpOp1P0_uw; + uint64_t cOp2 = ((uint64_t) AA64FpOp2P1_uw) << 32 | AA64FpOp2P0_uw; + uint64_t cDest = %(op)s; + AA64FpDestP0_uw = cDest & 0xFFFFFFFF; + AA64FpDestP1_uw = cDest >> 32; + AA64FpDestP2_uw = 0; + AA64FpDestP3_uw = 0; + FpscrExc = fpscr; + ''' + + doubleBinOp = ''' + binaryOp(fpscr, dbl(AA64FpOp1P0_uw, AA64FpOp1P1_uw), + dbl(AA64FpOp2P0_uw, AA64FpOp2P1_uw), + %(func)s, fpscr.fz, fpscr.dn, fpscr.rMode); + ''' + doubleUnaryOp = ''' + unaryOp(fpscr, dbl(AA64FpOp1P0_uw, AA64FpOp1P1_uw), %(func)s, + fpscr.fz, fpscr.rMode) + ''' + + def buildTernaryFpOp(name, opClass, sOp, dOp): + global header_output, decoder_output, exec_output + for isDouble in True, False: + code = vfp64EnabledCheckCode + ''' + FPSCR fpscr = (FPSCR) FpscrExc; + ''' + if isDouble: + code += ''' + uint64_t cOp1 = AA64FpOp1P0_uw | (uint64_t)AA64FpOp1P1_uw << 32; + uint64_t cOp2 = AA64FpOp2P0_uw | (uint64_t)AA64FpOp2P1_uw << 32; + uint64_t cOp3 = AA64FpOp3P0_uw | (uint64_t)AA64FpOp3P1_uw << 32; + uint64_t cDest; + ''' "cDest = " + dOp + ";" + ''' + AA64FpDestP0_uw = cDest; + AA64FpDestP1_uw = cDest >> 32; + ''' + else: + code += ''' + uint32_t cOp1 = AA64FpOp1P0_uw; + uint32_t cOp2 = AA64FpOp2P0_uw; + uint32_t cOp3 = AA64FpOp3P0_uw; + uint32_t cDest; + ''' "cDest = " + sOp + ";" + ''' + AA64FpDestP0_uw = cDest; + AA64FpDestP1_uw = 0; + ''' + code += ''' + AA64FpDestP2_uw = 0; + AA64FpDestP3_uw = 0; + FpscrExc = fpscr; + ''' + + iop = InstObjParams(name.lower(), name + ("D" if isDouble else "S"), + "FpRegRegRegRegOp", + { "code": code, "op_class": opClass }, []) + + header_output += AA64FpRegRegRegRegOpDeclare.subst(iop) + decoder_output += AA64FpRegRegRegRegOpConstructor.subst(iop) + exec_output += BasicExecute.subst(iop) + + buildTernaryFpOp("FMAdd", "SimdFloatMultAccOp", + "fplibMulAdd<uint32_t>(cOp3, cOp1, cOp2, fpscr)", + "fplibMulAdd<uint64_t>(cOp3, cOp1, cOp2, fpscr)" ) + buildTernaryFpOp("FMSub", "SimdFloatMultAccOp", + "fplibMulAdd<uint32_t>(cOp3, fplibNeg<uint32_t>(cOp1), cOp2, fpscr)", + "fplibMulAdd<uint64_t>(cOp3, fplibNeg<uint64_t>(cOp1), cOp2, fpscr)" ) + buildTernaryFpOp("FNMAdd", "SimdFloatMultAccOp", + "fplibMulAdd<uint32_t>(fplibNeg<uint32_t>(cOp3), fplibNeg<uint32_t>(cOp1), cOp2, fpscr)", + "fplibMulAdd<uint64_t>(fplibNeg<uint64_t>(cOp3), fplibNeg<uint64_t>(cOp1), cOp2, fpscr)" ) + buildTernaryFpOp("FNMSub", "SimdFloatMultAccOp", + "fplibMulAdd<uint32_t>(fplibNeg<uint32_t>(cOp3), cOp1, cOp2, fpscr)", + "fplibMulAdd<uint64_t>(fplibNeg<uint64_t>(cOp3), cOp1, cOp2, fpscr)" ) + + def buildBinFpOp(name, Name, base, opClass, singleOp, doubleOp): + global header_output, decoder_output, exec_output + + code = singleIntConvCode2 % { "op": singleOp } + sIop = InstObjParams(name, Name + "S", base, + { "code": code, + "op_class": opClass }, []) + + code = doubleIntConvCode2 % { "op": doubleOp } + dIop = InstObjParams(name, Name + "D", base, + { "code": code, + "op_class": opClass }, []) + + declareTempl = eval( base + "Declare"); + constructorTempl = eval("AA64" + base + "Constructor"); + + for iop in sIop, dIop: + header_output += declareTempl.subst(iop) + decoder_output += constructorTempl.subst(iop) + exec_output += BasicExecute.subst(iop) + + buildBinFpOp("fadd", "FAdd", "FpRegRegRegOp", "SimdFloatAddOp", + "fplibAdd<uint32_t>(cOp1, cOp2, fpscr)", + "fplibAdd<uint64_t>(cOp1, cOp2, fpscr)") + buildBinFpOp("fsub", "FSub", "FpRegRegRegOp", "SimdFloatAddOp", + "fplibSub<uint32_t>(cOp1, cOp2, fpscr)", + "fplibSub<uint64_t>(cOp1, cOp2, fpscr)") + buildBinFpOp("fdiv", "FDiv", "FpRegRegRegOp", "SimdFloatDivOp", + "fplibDiv<uint32_t>(cOp1, cOp2, fpscr)", + "fplibDiv<uint64_t>(cOp1, cOp2, fpscr)") + buildBinFpOp("fmul", "FMul", "FpRegRegRegOp", "SimdFloatMultOp", + "fplibMul<uint32_t>(cOp1, cOp2, fpscr)", + "fplibMul<uint64_t>(cOp1, cOp2, fpscr)") + buildBinFpOp("fnmul", "FNMul", "FpRegRegRegOp", "SimdFloatMultOp", + "fplibNeg<uint32_t>(fplibMul<uint32_t>(cOp1, cOp2, fpscr))", + "fplibNeg<uint64_t>(fplibMul<uint64_t>(cOp1, cOp2, fpscr))") + buildBinFpOp("fmin", "FMin", "FpRegRegRegOp", "SimdFloatCmpOp", + "fplibMin<uint32_t>(cOp1, cOp2, fpscr)", + "fplibMin<uint64_t>(cOp1, cOp2, fpscr)") + buildBinFpOp("fmax", "FMax", "FpRegRegRegOp", "SimdFloatCmpOp", + "fplibMax<uint32_t>(cOp1, cOp2, fpscr)", + "fplibMax<uint64_t>(cOp1, cOp2, fpscr)") + buildBinFpOp("fminnm", "FMinNM", "FpRegRegRegOp", "SimdFloatCmpOp", + "fplibMinNum<uint32_t>(cOp1, cOp2, fpscr)", + "fplibMinNum<uint64_t>(cOp1, cOp2, fpscr)") + buildBinFpOp("fmaxnm", "FMaxNM", "FpRegRegRegOp", "SimdFloatCmpOp", + "fplibMaxNum<uint32_t>(cOp1, cOp2, fpscr)", + "fplibMaxNum<uint64_t>(cOp1, cOp2, fpscr)") + + def buildUnaryFpOp(name, Name, base, opClass, singleOp, doubleOp = None): + if doubleOp is None: + doubleOp = singleOp + global header_output, decoder_output, exec_output + + code = singleIntConvCode % { "op": singleOp } + sIop = InstObjParams(name, Name + "S", base, + { "code": code, + "op_class": opClass }, []) + code = doubleIntConvCode % { "op": doubleOp } + dIop = InstObjParams(name, Name + "D", base, + { "code": code, + "op_class": opClass }, []) + + declareTempl = eval( base + "Declare"); + constructorTempl = eval("AA64" + base + "Constructor"); + + for iop in sIop, dIop: + header_output += declareTempl.subst(iop) + decoder_output += constructorTempl.subst(iop) + exec_output += BasicExecute.subst(iop) + + buildUnaryFpOp("fsqrt", "FSqrt", "FpRegRegOp", "SimdFloatSqrtOp", + "fplibSqrt<uint32_t>(cOp1, fpscr)", "fplibSqrt<uint64_t>(cOp1, fpscr)") + + def buildSimpleUnaryFpOp(name, Name, base, opClass, singleOp, + doubleOp = None, isIntConv = True): + if doubleOp is None: + doubleOp = singleOp + global header_output, decoder_output, exec_output + + if isIntConv: + sCode = singleIntConvCode + dCode = doubleIntConvCode + else: + sCode = singleCode + dCode = doubleCode + + for code, op, suffix in [[sCode, singleOp, "S"], + [dCode, doubleOp, "D"]]: + iop = InstObjParams(name, Name + suffix, base, + { "code": code % { "op": op }, + "op_class": opClass }, []) + + declareTempl = eval( base + "Declare"); + constructorTempl = eval("AA64" + base + "Constructor"); + + header_output += declareTempl.subst(iop) + decoder_output += constructorTempl.subst(iop) + exec_output += BasicExecute.subst(iop) + + buildSimpleUnaryFpOp("fneg", "FNeg", "FpRegRegOp", "SimdFloatMiscOp", + "fplibNeg<uint32_t>(cOp1)", "fplibNeg<uint64_t>(cOp1)") + buildSimpleUnaryFpOp("fabs", "FAbs", "FpRegRegOp", "SimdFloatMiscOp", + "fplibAbs<uint32_t>(cOp1)", "fplibAbs<uint64_t>(cOp1)") + buildSimpleUnaryFpOp("frintn", "FRIntN", "FpRegRegOp", "SimdFloatMiscOp", + "fplibRoundInt<uint32_t>(cOp1, FPRounding_TIEEVEN, false, fpscr)", + "fplibRoundInt<uint64_t>(cOp1, FPRounding_TIEEVEN, false, fpscr)") + buildSimpleUnaryFpOp("frintp", "FRIntP", "FpRegRegOp", "SimdFloatMiscOp", + "fplibRoundInt<uint32_t>(cOp1, FPRounding_POSINF, false, fpscr)", + "fplibRoundInt<uint64_t>(cOp1, FPRounding_POSINF, false, fpscr)") + buildSimpleUnaryFpOp("frintm", "FRIntM", "FpRegRegOp", "SimdFloatMiscOp", + "fplibRoundInt<uint32_t>(cOp1, FPRounding_NEGINF, false, fpscr)", + "fplibRoundInt<uint64_t>(cOp1, FPRounding_NEGINF, false, fpscr)") + buildSimpleUnaryFpOp("frintz", "FRIntZ", "FpRegRegOp", "SimdFloatMiscOp", + "fplibRoundInt<uint32_t>(cOp1, FPRounding_ZERO, false, fpscr)", + "fplibRoundInt<uint64_t>(cOp1, FPRounding_ZERO, false, fpscr)") + buildSimpleUnaryFpOp("frinta", "FRIntA", "FpRegRegOp", "SimdFloatMiscOp", + "fplibRoundInt<uint32_t>(cOp1, FPRounding_TIEAWAY, false, fpscr)", + "fplibRoundInt<uint64_t>(cOp1, FPRounding_TIEAWAY, false, fpscr)") + buildSimpleUnaryFpOp("frinti", "FRIntI", "FpRegRegOp", "SimdFloatMiscOp", + "fplibRoundInt<uint32_t>(cOp1, FPCRRounding(fpscr), false, fpscr)", + "fplibRoundInt<uint64_t>(cOp1, FPCRRounding(fpscr), false, fpscr)") + buildSimpleUnaryFpOp("frintx", "FRIntX", "FpRegRegOp", "SimdFloatMiscOp", + "fplibRoundInt<uint32_t>(cOp1, FPCRRounding(fpscr), true, fpscr)", + "fplibRoundInt<uint64_t>(cOp1, FPCRRounding(fpscr), true, fpscr)") +}}; + +let {{ + + header_output = "" + decoder_output = "" + exec_output = "" + + # Creates the integer to floating point instructions, including variants for + # signed/unsigned, float/double, etc + for regL, regOpL, width in [["W", "w", 32], + ["X", "d", 64]]: + for isDouble in True, False: + for us, usCode in [["U", "uint%d_t cSrc = %sOp1_u%s;" %(width, regL, regOpL)], + ["S", "int%d_t cSrc = %sOp1_u%s;" %(width, regL, regOpL)]]: + fcvtIntFpDCode = vfp64EnabledCheckCode + ''' + FPSCR fpscr = (FPSCR) FpscrExc; + %s + ''' %(usCode) + + if isDouble: + fcvtIntFpDCode += ''' + uint64_t cDest = fplibFixedToFP<uint64_t>(cSrc, 0, + %s, FPCRRounding(fpscr), fpscr); + AA64FpDestP0_uw = cDest; + AA64FpDestP1_uw = cDest >> 32; + ''' % ("true" if us == "U" else "false") + else: + fcvtIntFpDCode += ''' + uint32_t cDest = fplibFixedToFP<uint32_t>(cSrc, 0, + %s, FPCRRounding(fpscr), fpscr); + AA64FpDestP0_uw = cDest; + AA64FpDestP1_uw = 0; + ''' % ("true" if us == "U" else "false") + fcvtIntFpDCode += ''' + AA64FpDestP2_uw = 0; + AA64FpDestP3_uw = 0; + FpscrExc = fpscr; + ''' + + instName = "Fcvt%s%sIntFp%s" %(regL, us, "D" if isDouble else "S") + mnem = "%scvtf" %(us.lower()) + fcvtIntFpDIop = InstObjParams(mnem, instName, "FpRegRegOp", + { "code": fcvtIntFpDCode, + "op_class": "SimdFloatCvtOp" }, []) + header_output += FpRegRegOpDeclare.subst(fcvtIntFpDIop); + decoder_output += AA64FpRegRegOpConstructor.subst(fcvtIntFpDIop); + exec_output += BasicExecute.subst(fcvtIntFpDIop); + + # Generates the floating point to integer conversion instructions in various + # variants, eg signed/unsigned + def buildFpCvtIntOp(isDouble, isSigned, isXReg): + global header_output, decoder_output, exec_output + + for rmode, roundingMode in [["N", "FPRounding_TIEEVEN"], + ["P", "FPRounding_POSINF"], + ["M", "FPRounding_NEGINF"], + ["Z", "FPRounding_ZERO"], + ["A", "FPRounding_TIEAWAY"]]: + fcvtFpIntCode = vfp64EnabledCheckCode + ''' + FPSCR fpscr = (FPSCR) FpscrExc;''' + if isDouble: + fcvtFpIntCode += ''' + uint64_t cOp1 = AA64FpOp1P0_uw | (uint64_t)AA64FpOp1P1_uw << 32; + ''' + else: + fcvtFpIntCode += "uint32_t cOp1 = AA64FpOp1P0_uw;" + + fcvtFpIntCode += ''' + %sDest = fplibFPToFixed<uint%s_t, uint%s_t>(cOp1, 0, %s, %s, fpscr); + FpscrExc = fpscr; + ''' %("X" if isXReg else "W", + "64" if isDouble else "32", + "64" if isXReg else "32", + "false" if isSigned else "true", + roundingMode) + + instName = "FcvtFp%sInt%s%s%s" %("S" if isSigned else "U", + "X" if isXReg else "W", + "D" if isDouble else "S", rmode) + mnem = "fcvt%s%s" %(rmode, "s" if isSigned else "u") + fcvtFpIntIop = InstObjParams(mnem, instName, "FpRegRegOp", + { "code": fcvtFpIntCode, + "op_class": "SimdFloatCvtOp" }, []) + header_output += FpRegRegOpDeclare.subst(fcvtFpIntIop); + decoder_output += FpRegRegOpConstructor.subst(fcvtFpIntIop); + exec_output += BasicExecute.subst(fcvtFpIntIop); + + # Now actually do the building with the different variants + for isDouble in True, False: + for isSigned in True, False: + for isXReg in True, False: + buildFpCvtIntOp(isDouble, isSigned, isXReg) + + fcvtFpSFpDCode = vfp64EnabledCheckCode + ''' + FPSCR fpscr = (FPSCR) FpscrExc; + uint64_t cDest = fplibConvert<uint32_t, uint64_t>(AA64FpOp1P0_uw, + FPCRRounding(fpscr), fpscr); + AA64FpDestP0_uw = cDest; + AA64FpDestP1_uw = cDest >> 32; + AA64FpDestP2_uw = 0; + AA64FpDestP3_uw = 0; + FpscrExc = fpscr; + ''' + fcvtFpSFpDIop = InstObjParams("fcvt", "FCvtFpSFpD", "FpRegRegOp", + { "code": fcvtFpSFpDCode, + "op_class": "SimdFloatCvtOp" }, []) + header_output += FpRegRegOpDeclare.subst(fcvtFpSFpDIop); + decoder_output += AA64FpRegRegOpConstructor.subst(fcvtFpSFpDIop); + exec_output += BasicExecute.subst(fcvtFpSFpDIop); + + fcvtFpDFpSCode = vfp64EnabledCheckCode + ''' + FPSCR fpscr = (FPSCR) FpscrExc; + uint64_t cOp1 = AA64FpOp1P0_uw | (uint64_t)AA64FpOp1P1_uw << 32; + AA64FpDestP0_uw = fplibConvert<uint64_t, uint32_t>(cOp1, + FPCRRounding(fpscr), fpscr); + AA64FpDestP1_uw = 0; + AA64FpDestP2_uw = 0; + AA64FpDestP3_uw = 0; + FpscrExc = fpscr; + ''' + fcvtFpDFpSIop = InstObjParams("fcvt", "FcvtFpDFpS", "FpRegRegOp", + {"code": fcvtFpDFpSCode, + "op_class": "SimdFloatCvtOp" }, []) + header_output += FpRegRegOpDeclare.subst(fcvtFpDFpSIop); + decoder_output += AA64FpRegRegOpConstructor.subst(fcvtFpDFpSIop); + exec_output += BasicExecute.subst(fcvtFpDFpSIop); + + # Half precision to single or double precision conversion + for isDouble in True, False: + code = vfp64EnabledCheckCode + ''' + FPSCR fpscr = (FPSCR) FpscrExc; + %s cDest = fplibConvert<uint16_t, uint%s_t>(AA64FpOp1P0_uw, + FPCRRounding(fpscr), fpscr); + ''' % ("uint64_t" if isDouble else "uint32_t", + "64" if isDouble else "32") + if isDouble: + code += ''' + AA64FpDestP0_uw = cDest; + AA64FpDestP1_uw = cDest >> 32; + ''' + else: + code += ''' + AA64FpDestP0_uw = cDest; + AA64FpDestP1_uw = 0; + ''' + code += ''' + AA64FpDestP2_uw = 0; + AA64FpDestP3_uw = 0; + FpscrExc = fpscr; + ''' + + instName = "FcvtFpHFp%s" %("D" if isDouble else "S") + fcvtFpHFpIop = InstObjParams("fcvt", instName, "FpRegRegOp", + { "code": code, + "op_class": "SimdFloatCvtOp" }, []) + header_output += FpRegRegOpDeclare.subst(fcvtFpHFpIop); + decoder_output += AA64FpRegRegOpConstructor.subst(fcvtFpHFpIop); + exec_output += BasicExecute.subst(fcvtFpHFpIop); + + # single or double precision to Half precision conversion + for isDouble in True, False: + code = vfp64EnabledCheckCode + ''' + FPSCR fpscr = (FPSCR) FpscrExc; + %s; + AA64FpDestP0_uw = fplibConvert<uint%s_t, uint16_t>(cOp1, + FPCRRounding(fpscr), fpscr); + AA64FpDestP1_uw = 0; + AA64FpDestP2_uw = 0; + AA64FpDestP3_uw = 0; + FpscrExc = fpscr; + ''' % ("uint64_t cOp1 = AA64FpOp1P0_uw | (uint64_t)AA64FpOp1P1_uw << 32" + if isDouble else "uint32_t cOp1 = AA64FpOp1P0_uw", + "64" if isDouble else "32") + + instName = "FcvtFp%sFpH" %("D" if isDouble else "S") + fcvtFpFpHIop = InstObjParams("fcvt", instName, "FpRegRegOp", + { "code": code, + "op_class": "SimdFloatCvtOp" }, []) + header_output += FpRegRegOpDeclare.subst(fcvtFpFpHIop); + decoder_output += AA64FpRegRegOpConstructor.subst(fcvtFpFpHIop); + exec_output += BasicExecute.subst(fcvtFpFpHIop); + + # Build the various versions of the floating point compare instructions + def buildFCmpOp(isQuiet, isDouble, isImm): + global header_output, decoder_output, exec_output + + fcmpCode = vfp64EnabledCheckCode + ''' + FPSCR fpscr = (FPSCR) FpscrExc; + %s cOp1 = %s; + ''' % ("uint64_t" if isDouble else "uint32_t", + "AA64FpDestP0_uw | (uint64_t)AA64FpDestP1_uw << 32" + if isDouble else "AA64FpDestP0_uw") + if isImm: + fcmpCode += ''' + %s cOp2 = imm; + ''' % ("uint64_t" if isDouble else "uint32_t") + else: + fcmpCode += ''' + %s cOp2 = %s; + ''' % ("uint64_t" if isDouble else "uint32_t", + "AA64FpOp1P0_uw | (uint64_t)AA64FpOp1P1_uw << 32" + if isDouble else "AA64FpOp1P0_uw") + fcmpCode += ''' + int cc = fplibCompare<uint%s_t>(cOp1, cOp2, %s, fpscr); + CondCodesNZ = cc >> 2 & 3; + CondCodesC = cc >> 1 & 1; + CondCodesV = cc & 1; + FpCondCodes = fpscr & FpCondCodesMask; + FpscrExc = fpscr; + ''' % ("64" if isDouble else "32", "false" if isQuiet else "true") + + typeName = "Imm" if isImm else "Reg" + instName = "FCmp%s%s%s" %("" if isQuiet else "E", typeName, + "D" if isDouble else "S") + fcmpIop = InstObjParams("fcmp%s" %("" if isQuiet else "e"), instName, + "FpReg%sOp" %(typeName), + {"code": fcmpCode, + "op_class": "SimdFloatCmpOp"}, []) + + declareTemp = eval("FpReg%sOpDeclare" %(typeName)); + constructorTemp = eval("AA64FpReg%sOpConstructor" %(typeName)); + header_output += declareTemp.subst(fcmpIop); + decoder_output += constructorTemp.subst(fcmpIop); + exec_output += BasicExecute.subst(fcmpIop); + + for isQuiet in True, False: + for isDouble in True, False: + for isImm in True, False: + buildFCmpOp(isQuiet, isDouble, isImm) + + # Build the various versions of the conditional floating point compare + # instructions + def buildFCCmpOp(isQuiet, isDouble): + global header_output, decoder_output, exec_output + + fccmpCode = vfp64EnabledCheckCode + ''' + FPSCR fpscr = (FPSCR) FpscrExc; + if (testPredicate(CondCodesNZ, CondCodesC, CondCodesV, condCode)) { + %s cOp1 = %s; + %s cOp2 = %s; + int cc = fplibCompare<uint%s_t>(cOp1, cOp2, %s, fpscr); + CondCodesNZ = cc >> 2 & 3; + CondCodesC = cc >> 1 & 1; + CondCodesV = cc & 1; + } else { + CondCodesNZ = (defCc >> 2) & 0x3; + CondCodesC = (defCc >> 1) & 0x1; + CondCodesV = defCc & 0x1; + } + FpCondCodes = fpscr & FpCondCodesMask; + FpscrExc = fpscr; + ''' % ("uint64_t" if isDouble else "uint32_t", + "AA64FpOp1P0_uw | (uint64_t)AA64FpOp1P1_uw << 32" + if isDouble else "AA64FpOp1P0_uw", + "uint64_t" if isDouble else "uint32_t", + "AA64FpOp2P0_uw | (uint64_t)AA64FpOp2P1_uw << 32" + if isDouble else "AA64FpOp2P0_uw", + "64" if isDouble else "32", "false" if isQuiet else "true") + + instName = "FCCmp%sReg%s" %("" if isQuiet else "E", + "D" if isDouble else "S") + fccmpIop = InstObjParams("fccmp%s" %("" if isQuiet else "e"), + instName, "FpCondCompRegOp", + {"code": fccmpCode, + "op_class": "SimdFloatCmpOp"}, []) + header_output += DataXCondCompRegDeclare.subst(fccmpIop); + decoder_output += DataXCondCompRegConstructor.subst(fccmpIop); + exec_output += BasicExecute.subst(fccmpIop); + + for isQuiet in True, False: + for isDouble in True, False: + buildFCCmpOp(isQuiet, isDouble) + +}}; + +let {{ + + header_output = "" + decoder_output = "" + exec_output = "" + + # Generates the variants of the floating to fixed point instructions + def buildFpCvtFixedOp(isSigned, isDouble, isXReg): + global header_output, decoder_output, exec_output + + fcvtFpFixedCode = vfp64EnabledCheckCode + ''' + FPSCR fpscr = (FPSCR) FpscrExc; + ''' + if isDouble: + fcvtFpFixedCode += ''' + uint64_t cOp1 = AA64FpOp1P0_uw | (uint64_t)AA64FpOp1P1_uw << 32; + ''' + else: + fcvtFpFixedCode += "uint32_t cOp1 = AA64FpOp1P0_uw;" + fcvtFpFixedCode += ''' + %sDest = fplibFPToFixed<uint%s_t, uint%s_t>(cOp1, 64 - imm, %s, + FPRounding_ZERO, fpscr); + FpscrExc = fpscr; + ''' %("X" if isXReg else "W", + "64" if isDouble else "32", + "64" if isXReg else "32", + "false" if isSigned else "true") + + instName = "FcvtFp%sFixed%s%s" %("S" if isSigned else "U", + "D" if isDouble else "S", + "X" if isXReg else "W") + mnem = "fcvtz%s" %("s" if isSigned else "u") + fcvtFpFixedIop = InstObjParams(mnem, instName, "FpRegRegImmOp", + { "code": fcvtFpFixedCode, + "op_class": "SimdFloatCvtOp" }, []) + header_output += FpRegRegImmOpDeclare.subst(fcvtFpFixedIop); + decoder_output += AA64FpRegRegImmOpConstructor.subst(fcvtFpFixedIop); + exec_output += BasicExecute.subst(fcvtFpFixedIop); + + # Generates the variants of the fixed to floating point instructions + def buildFixedCvtFpOp(isSigned, isDouble, isXReg): + global header_output, decoder_output, exec_output + + srcRegType = "X" if isXReg else "W" + fcvtFixedFpCode = vfp64EnabledCheckCode + ''' + FPSCR fpscr = (FPSCR) FpscrExc; + %s result = fplibFixedToFP<uint%s_t>((%s%s_t)%sOp1, 64 - imm, + %s, FPCRRounding(fpscr), fpscr); + ''' %("uint64_t" if isDouble else "uint32_t", + "64" if isDouble else "32", + "int" if isSigned else "uint", "64" if isXReg else "32", + srcRegType, + "false" if isSigned else "true") + if isDouble: + fcvtFixedFpCode += ''' + AA64FpDestP0_uw = result; + AA64FpDestP1_uw = result >> 32; + ''' + else: + fcvtFixedFpCode += ''' + AA64FpDestP0_uw = result; + AA64FpDestP1_uw = 0; + ''' + fcvtFixedFpCode += ''' + AA64FpDestP2_uw = 0; + AA64FpDestP3_uw = 0; + FpscrExc = fpscr; + ''' + + instName = "Fcvt%sFixedFp%s%s" %("S" if isSigned else "U", + "D" if isDouble else "S", + srcRegType) + mnem = "%scvtf" %("s" if isSigned else "u") + fcvtFixedFpIop = InstObjParams(mnem, instName, "FpRegRegImmOp", + { "code": fcvtFixedFpCode, + "op_class": "SimdFloatCvtOp" }, []) + header_output += FpRegRegImmOpDeclare.subst(fcvtFixedFpIop); + decoder_output += FpRegRegImmOpConstructor.subst(fcvtFixedFpIop); + exec_output += BasicExecute.subst(fcvtFixedFpIop); + + # loop over the variants building the instructions for each + for isXReg in True, False: + for isDouble in True, False: + for isSigned in True, False: + buildFpCvtFixedOp(isSigned, isDouble, isXReg) + buildFixedCvtFpOp(isSigned, isDouble, isXReg) +}}; + +let {{ + + header_output = "" + decoder_output = "" + exec_output = "" + + for isDouble in True, False: + code = ''' + if (testPredicate(CondCodesNZ, CondCodesC, CondCodesV, condCode)) { + AA64FpDestP0_uw = AA64FpOp1P0_uw; + ''' + if isDouble: + code += ''' + AA64FpDestP1_uw = AA64FpOp1P1_uw; + } else { + AA64FpDestP0_uw = AA64FpOp2P0_uw; + AA64FpDestP1_uw = AA64FpOp2P1_uw; + } + ''' + else: + code += ''' + } else { + AA64FpDestP0_uw = AA64FpOp2P0_uw; + } + AA64FpDestP1_uw = 0; + ''' + code += ''' + AA64FpDestP2_uw = 0; + AA64FpDestP3_uw = 0; + ''' + + iop = InstObjParams("fcsel", "FCSel%s" %("D" if isDouble else "S"), + "FpCondSelOp", code) + header_output += DataXCondSelDeclare.subst(iop) + decoder_output += DataXCondSelConstructor.subst(iop) + exec_output += BasicExecute.subst(iop) +}}; diff --git a/src/arch/arm/isa/insts/insts.isa b/src/arch/arm/isa/insts/insts.isa index c01e87df8..9d90f7779 100644 --- a/src/arch/arm/isa/insts/insts.isa +++ b/src/arch/arm/isa/insts/insts.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2010 ARM Limited +// Copyright (c) 2010-2012 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -37,6 +37,9 @@ // // Authors: Gabe Black +//AArch64 instructions +##include "aarch64.isa" + //Basic forms of various templates ##include "basic.isa" @@ -46,8 +49,15 @@ //Loads of a single item ##include "ldr.isa" +//Loads of a single item, AArch64 +##include "ldr64.isa" + //Miscellaneous instructions that don't fit elsewhere ##include "misc.isa" +##include "misc64.isa" + +//Stores of a single item, AArch64 +##include "str64.isa" //Stores of a single item ##include "str.isa" @@ -61,8 +71,12 @@ //Data processing instructions ##include "data.isa" +//AArch64 data processing instructions +##include "data64.isa" + //Branches ##include "branch.isa" +##include "branch64.isa" //Multiply ##include "mult.isa" @@ -72,9 +86,14 @@ //VFP ##include "fp.isa" +##include "fp64.isa" //Neon ##include "neon.isa" +//AArch64 Neon +##include "neon64.isa" +##include "neon64_mem.isa" + //m5 Psuedo-ops ##include "m5ops.isa" diff --git a/src/arch/arm/isa/insts/ldr.isa b/src/arch/arm/isa/insts/ldr.isa index f599fa4b9..6bfe40118 100644 --- a/src/arch/arm/isa/insts/ldr.isa +++ b/src/arch/arm/isa/insts/ldr.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2010 ARM Limited +// Copyright (c) 2010-2011 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -38,6 +38,7 @@ // Authors: Gabe Black let {{ + import math header_output = "" decoder_output = "" @@ -78,7 +79,8 @@ let {{ newDecoder, newExec) = self.fillTemplates(self.name, self.Name, codeBlobs, self.memFlags, instFlags, base, - wbDecl, pcDecl, self.rasPop) + wbDecl, pcDecl, self.rasPop, + self.size, self.sign) header_output += newHeader decoder_output += newDecoder @@ -160,7 +162,7 @@ let {{ self.size, self.sign, self.user) # Add memory request flags where necessary - self.memFlags.append("%d" % (self.size - 1)) + self.memFlags.append("%d" % int(math.log(self.size, 2))) if self.user: self.memFlags.append("ArmISA::TLB::UserMode") diff --git a/src/arch/arm/isa/insts/ldr64.isa b/src/arch/arm/isa/insts/ldr64.isa new file mode 100644 index 000000000..78460f661 --- /dev/null +++ b/src/arch/arm/isa/insts/ldr64.isa @@ -0,0 +1,446 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2011-2013 ARM Limited +// All rights reserved +// +// The license below extends only to copyright in the software and shall +// not be construed as granting a license to any other intellectual +// property including but not limited to intellectual property relating +// to a hardware implementation of the functionality of the software +// licensed hereunder. You may use the software subject to the license +// terms below provided that you ensure that this notice is replicated +// unmodified and in its entirety in all distributions of the software, +// modified or unmodified, in source code or in binary form. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Gabe Black + +let {{ + + header_output = "" + decoder_output = "" + exec_output = "" + + class LoadInst64(LoadStoreInst): + execBase = 'Load64' + micro = False + + def __init__(self, mnem, Name, size=4, sign=False, user=False, + literal=False, flavor="normal", top=False): + super(LoadInst64, self).__init__() + + self.name = mnem + self.Name = Name + self.size = size + self.sign = sign + self.user = user + self.literal = literal + self.flavor = flavor + self.top = top + + self.memFlags = ["ArmISA::TLB::MustBeOne"] + self.instFlags = [] + self.codeBlobs = {"postacc_code" : ""} + + # Add memory request flags where necessary + if self.user: + self.memFlags.append("ArmISA::TLB::UserMode") + + if self.flavor == "dprefetch": + self.memFlags.append("Request::PREFETCH") + self.instFlags = ['IsDataPrefetch'] + elif self.flavor == "iprefetch": + self.memFlags.append("Request::PREFETCH") + self.instFlags = ['IsInstPrefetch'] + if self.micro: + self.instFlags.append("IsMicroop") + + if self.flavor in ("acexp", "exp"): + # For exclusive pair ops alignment check is based on total size + self.memFlags.append("%d" % int(math.log(self.size, 2) + 1)) + elif not (self.size == 16 and self.top): + # Only the first microop should perform alignment checking. + self.memFlags.append("%d" % int(math.log(self.size, 2))) + + if self.flavor not in ("acquire", "acex", "exclusive", + "acexp", "exp"): + self.memFlags.append("ArmISA::TLB::AllowUnaligned") + + if self.flavor in ("acquire", "acex", "acexp"): + self.instFlags.extend(["IsMemBarrier", + "IsWriteBarrier", + "IsReadBarrier"]) + if self.flavor in ("acex", "exclusive", "exp", "acexp"): + self.memFlags.append("Request::LLSC") + + def buildEACode(self): + # Address computation code + eaCode = "" + if self.flavor == "fp": + eaCode += vfp64EnabledCheckCode + + if self.literal: + eaCode += "EA = RawPC" + else: + eaCode += SPAlignmentCheckCode + "EA = XBase" + + if self.size == 16: + if self.top: + eaCode += " + (isBigEndian64(xc->tcBase()) ? 0 : 8)" + else: + eaCode += " + (isBigEndian64(xc->tcBase()) ? 8 : 0)" + if not self.post: + eaCode += self.offset + eaCode += ";" + + self.codeBlobs["ea_code"] = eaCode + + def emitHelper(self, base='Memory64', wbDecl=None): + global header_output, decoder_output, exec_output + + # If this is a microop itself, don't allow anything that would + # require further microcoding. + if self.micro: + assert not wbDecl + + fa_code = None + if not self.micro and self.flavor in ("normal", "widen", "acquire"): + fa_code = ''' + fault->annotate(ArmFault::SAS, %s); + fault->annotate(ArmFault::SSE, %s); + fault->annotate(ArmFault::SRT, dest); + fault->annotate(ArmFault::SF, %s); + fault->annotate(ArmFault::AR, %s); + ''' % ("0" if self.size == 1 else + "1" if self.size == 2 else + "2" if self.size == 4 else "3", + "true" if self.sign else "false", + "true" if (self.size == 8 or + self.flavor == "widen") else "false", + "true" if self.flavor == "acquire" else "false") + + (newHeader, newDecoder, newExec) = \ + self.fillTemplates(self.name, self.Name, self.codeBlobs, + self.memFlags, self.instFlags, + base, wbDecl, faCode=fa_code) + + header_output += newHeader + decoder_output += newDecoder + exec_output += newExec + + class LoadImmInst64(LoadInst64): + def __init__(self, *args, **kargs): + super(LoadImmInst64, self).__init__(*args, **kargs) + self.offset = " + imm" + + self.wbDecl = "MicroAddXiUop(machInst, base, base, imm);" + + class LoadRegInst64(LoadInst64): + def __init__(self, *args, **kargs): + super(LoadRegInst64, self).__init__(*args, **kargs) + self.offset = " + extendReg64(XOffset, type, shiftAmt, 64)" + + self.wbDecl = \ + "MicroAddXERegUop(machInst, base, base, " + \ + " offset, type, shiftAmt);" + + class LoadRawRegInst64(LoadInst64): + def __init__(self, *args, **kargs): + super(LoadRawRegInst64, self).__init__(*args, **kargs) + self.offset = "" + + class LoadSingle64(LoadInst64): + def emit(self): + self.buildEACode() + + # Code that actually handles the access + if self.flavor in ("dprefetch", "iprefetch"): + accCode = 'uint64_t temp M5_VAR_USED = Mem%s;' + elif self.flavor == "fp": + if self.size in (1, 2, 4): + accCode = ''' + AA64FpDestP0_uw = cSwap(Mem%s, + isBigEndian64(xc->tcBase())); + AA64FpDestP1_uw = 0; + AA64FpDestP2_uw = 0; + AA64FpDestP3_uw = 0; + ''' + elif self.size == 8 or (self.size == 16 and not self.top): + accCode = ''' + uint64_t data = cSwap(Mem%s, + isBigEndian64(xc->tcBase())); + AA64FpDestP0_uw = (uint32_t)data; + AA64FpDestP1_uw = (data >> 32); + ''' + # Only zero out the other half if this isn't part of a + # pair of 8 byte loads implementing a 16 byte load. + if self.size == 8: + accCode += ''' + AA64FpDestP2_uw = 0; + AA64FpDestP3_uw = 0; + ''' + elif self.size == 16 and self.top: + accCode = ''' + uint64_t data = cSwap(Mem%s, + isBigEndian64(xc->tcBase())); + AA64FpDestP2_uw = (uint32_t)data; + AA64FpDestP3_uw = (data >> 32); + ''' + elif self.flavor == "widen" or self.size == 8: + accCode = "XDest = cSwap(Mem%s, isBigEndian64(xc->tcBase()));" + else: + accCode = "WDest = cSwap(Mem%s, isBigEndian64(xc->tcBase()));" + if self.size == 16: + accCode = accCode % buildMemSuffix(self.sign, 8) + else: + accCode = accCode % buildMemSuffix(self.sign, self.size) + + self.codeBlobs["memacc_code"] = accCode + + # Push it out to the output files + wbDecl = None + if self.writeback and not self.micro: + wbDecl = self.wbDecl + self.emitHelper(self.base, wbDecl) + + class LoadDouble64(LoadInst64): + def emit(self): + self.buildEACode() + + # Code that actually handles the access + if self.flavor == "fp": + accCode = ''' + uint64_t data = cSwap(Mem_ud, isBigEndian64(xc->tcBase())); + AA64FpDestP0_uw = (uint32_t)data; + AA64FpDestP1_uw = 0; + AA64FpDestP2_uw = 0; + AA64FpDestP3_uw = 0; + AA64FpDest2P0_uw = (data >> 32); + AA64FpDest2P1_uw = 0; + AA64FpDest2P2_uw = 0; + AA64FpDest2P3_uw = 0; + ''' + else: + if self.sign: + if self.size == 4: + accCode = ''' + uint64_t data = cSwap(Mem_ud, + isBigEndian64(xc->tcBase())); + XDest = sext<32>((uint32_t)data); + XDest2 = sext<32>(data >> 32); + ''' + elif self.size == 8: + accCode = ''' + XDest = sext<64>(Mem_tud.a); + XDest2 = sext<64>(Mem_tud.b); + ''' + else: + if self.size == 4: + accCode = ''' + uint64_t data = cSwap(Mem_ud, + isBigEndian64(xc->tcBase())); + XDest = (uint32_t)data; + XDest2 = data >> 32; + ''' + elif self.size == 8: + accCode = ''' + XDest = Mem_tud.a; + XDest2 = Mem_tud.b; + ''' + self.codeBlobs["memacc_code"] = accCode + + # Push it out to the output files + wbDecl = None + if self.writeback and not self.micro: + wbDecl = self.wbDecl + self.emitHelper(self.base, wbDecl) + + class LoadImm64(LoadImmInst64, LoadSingle64): + decConstBase = 'LoadStoreImm64' + base = 'ArmISA::MemoryImm64' + writeback = False + post = False + + class LoadPre64(LoadImmInst64, LoadSingle64): + decConstBase = 'LoadStoreImm64' + base = 'ArmISA::MemoryPreIndex64' + writeback = True + post = False + + class LoadPost64(LoadImmInst64, LoadSingle64): + decConstBase = 'LoadStoreImm64' + base = 'ArmISA::MemoryPostIndex64' + writeback = True + post = True + + class LoadReg64(LoadRegInst64, LoadSingle64): + decConstBase = 'LoadStoreReg64' + base = 'ArmISA::MemoryReg64' + writeback = False + post = False + + class LoadRaw64(LoadRawRegInst64, LoadSingle64): + decConstBase = 'LoadStoreRaw64' + base = 'ArmISA::MemoryRaw64' + writeback = False + post = False + + class LoadEx64(LoadRawRegInst64, LoadSingle64): + decConstBase = 'LoadStoreEx64' + base = 'ArmISA::MemoryEx64' + writeback = False + post = False + + class LoadLit64(LoadImmInst64, LoadSingle64): + decConstBase = 'LoadStoreLit64' + base = 'ArmISA::MemoryLiteral64' + writeback = False + post = False + + def buildLoads64(mnem, NameBase, size, sign, flavor="normal"): + LoadImm64(mnem, NameBase + "_IMM", size, sign, flavor=flavor).emit() + LoadPre64(mnem, NameBase + "_PRE", size, sign, flavor=flavor).emit() + LoadPost64(mnem, NameBase + "_POST", size, sign, flavor=flavor).emit() + LoadReg64(mnem, NameBase + "_REG", size, sign, flavor=flavor).emit() + + buildLoads64("ldrb", "LDRB64", 1, False) + buildLoads64("ldrsb", "LDRSBW64", 1, True) + buildLoads64("ldrsb", "LDRSBX64", 1, True, flavor="widen") + buildLoads64("ldrh", "LDRH64", 2, False) + buildLoads64("ldrsh", "LDRSHW64", 2, True) + buildLoads64("ldrsh", "LDRSHX64", 2, True, flavor="widen") + buildLoads64("ldrsw", "LDRSW64", 4, True, flavor="widen") + buildLoads64("ldr", "LDRW64", 4, False) + buildLoads64("ldr", "LDRX64", 8, False) + buildLoads64("ldr", "LDRBFP64", 1, False, flavor="fp") + buildLoads64("ldr", "LDRHFP64", 2, False, flavor="fp") + buildLoads64("ldr", "LDRSFP64", 4, False, flavor="fp") + buildLoads64("ldr", "LDRDFP64", 8, False, flavor="fp") + + LoadImm64("prfm", "PRFM64_IMM", 8, flavor="dprefetch").emit() + LoadReg64("prfm", "PRFM64_REG", 8, flavor="dprefetch").emit() + LoadLit64("prfm", "PRFM64_LIT", 8, literal=True, flavor="dprefetch").emit() + LoadImm64("prfum", "PRFUM64_IMM", 8, flavor="dprefetch").emit() + + LoadImm64("ldurb", "LDURB64_IMM", 1, False).emit() + LoadImm64("ldursb", "LDURSBW64_IMM", 1, True).emit() + LoadImm64("ldursb", "LDURSBX64_IMM", 1, True, flavor="widen").emit() + LoadImm64("ldurh", "LDURH64_IMM", 2, False).emit() + LoadImm64("ldursh", "LDURSHW64_IMM", 2, True).emit() + LoadImm64("ldursh", "LDURSHX64_IMM", 2, True, flavor="widen").emit() + LoadImm64("ldursw", "LDURSW64_IMM", 4, True, flavor="widen").emit() + LoadImm64("ldur", "LDURW64_IMM", 4, False).emit() + LoadImm64("ldur", "LDURX64_IMM", 8, False).emit() + LoadImm64("ldur", "LDURBFP64_IMM", 1, flavor="fp").emit() + LoadImm64("ldur", "LDURHFP64_IMM", 2, flavor="fp").emit() + LoadImm64("ldur", "LDURSFP64_IMM", 4, flavor="fp").emit() + LoadImm64("ldur", "LDURDFP64_IMM", 8, flavor="fp").emit() + + LoadImm64("ldtrb", "LDTRB64_IMM", 1, False, True).emit() + LoadImm64("ldtrsb", "LDTRSBW64_IMM", 1, True, True).emit() + LoadImm64("ldtrsb", "LDTRSBX64_IMM", 1, True, True, flavor="widen").emit() + LoadImm64("ldtrh", "LDTRH64_IMM", 2, False, True).emit() + LoadImm64("ldtrsh", "LDTRSHW64_IMM", 2, True, True).emit() + LoadImm64("ldtrsh", "LDTRSHX64_IMM", 2, True, True, flavor="widen").emit() + LoadImm64("ldtrsw", "LDTRSW64_IMM", 4, True, flavor="widen").emit() + LoadImm64("ldtr", "LDTRW64_IMM", 4, False, True).emit() + LoadImm64("ldtr", "LDTRX64_IMM", 8, False, True).emit() + + LoadLit64("ldrsw", "LDRSWL64_LIT", 4, True, \ + literal=True, flavor="widen").emit() + LoadLit64("ldr", "LDRWL64_LIT", 4, False, literal=True).emit() + LoadLit64("ldr", "LDRXL64_LIT", 8, False, literal=True).emit() + LoadLit64("ldr", "LDRSFP64_LIT", 4, literal=True, flavor="fp").emit() + LoadLit64("ldr", "LDRDFP64_LIT", 8, literal=True, flavor="fp").emit() + + LoadRaw64("ldar", "LDARX64", 8, flavor="acquire").emit() + LoadRaw64("ldar", "LDARW64", 4, flavor="acquire").emit() + LoadRaw64("ldarh", "LDARH64", 2, flavor="acquire").emit() + LoadRaw64("ldarb", "LDARB64", 1, flavor="acquire").emit() + + LoadEx64("ldaxr", "LDAXRX64", 8, flavor="acex").emit() + LoadEx64("ldaxr", "LDAXRW64", 4, flavor="acex").emit() + LoadEx64("ldaxrh", "LDAXRH64", 2, flavor="acex").emit() + LoadEx64("ldaxrb", "LDAXRB64", 1, flavor="acex").emit() + + LoadEx64("ldxr", "LDXRX64", 8, flavor="exclusive").emit() + LoadEx64("ldxr", "LDXRW64", 4, flavor="exclusive").emit() + LoadEx64("ldxrh", "LDXRH64", 2, flavor="exclusive").emit() + LoadEx64("ldxrb", "LDXRB64", 1, flavor="exclusive").emit() + + class LoadImmU64(LoadImm64): + decConstBase = 'LoadStoreImmU64' + micro = True + + class LoadImmDU64(LoadImmInst64, LoadDouble64): + decConstBase = 'LoadStoreImmDU64' + base = 'ArmISA::MemoryDImm64' + micro = True + post = False + writeback = False + + class LoadImmDouble64(LoadImmInst64, LoadDouble64): + decConstBase = 'LoadStoreImmDU64' + base = 'ArmISA::MemoryDImm64' + micro = False + post = False + writeback = False + + class LoadRegU64(LoadReg64): + decConstBase = 'LoadStoreRegU64' + micro = True + + class LoadLitU64(LoadLit64): + decConstBase = 'LoadStoreLitU64' + micro = True + + LoadImmDouble64("ldaxp", "LDAXPW64", 4, flavor="acexp").emit() + LoadImmDouble64("ldaxp", "LDAXPX64", 8, flavor="acexp").emit() + LoadImmDouble64("ldxp", "LDXPW64", 4, flavor="exp").emit() + LoadImmDouble64("ldxp", "LDXPX64", 8, flavor="exp").emit() + + LoadImmU64("ldrxi_uop", "MicroLdrXImmUop", 8).emit() + LoadRegU64("ldrxr_uop", "MicroLdrXRegUop", 8).emit() + LoadLitU64("ldrxl_uop", "MicroLdrXLitUop", 8, literal=True).emit() + LoadImmU64("ldrfpxi_uop", "MicroLdrFpXImmUop", 8, flavor="fp").emit() + LoadRegU64("ldrfpxr_uop", "MicroLdrFpXRegUop", 8, flavor="fp").emit() + LoadLitU64("ldrfpxl_uop", "MicroLdrFpXLitUop", 8, literal=True, + flavor="fp").emit() + LoadImmU64("ldrqbfpxi_uop", "MicroLdrQBFpXImmUop", + 16, flavor="fp", top = False).emit() + LoadRegU64("ldrqbfpxr_uop", "MicroLdrQBFpXRegUop", + 16, flavor="fp", top = False).emit() + LoadLitU64("ldrqbfpxl_uop", "MicroLdrQBFpXLitUop", + 16, literal=True, flavor="fp", top = False).emit() + LoadImmU64("ldrqtfpxi_uop", "MicroLdrQTFpXImmUop", + 16, flavor="fp", top = True).emit() + LoadRegU64("ldrqtfpxr_uop", "MicroLdrQTFpXRegUop", + 16, flavor="fp", top = True).emit() + LoadLitU64("ldrqtfpxl_uop", "MicroLdrQTFpXLitUop", + 16, literal=True, flavor="fp", top = True).emit() + LoadImmDU64("ldrduxi_uop", "MicroLdrDUXImmUop", 4, sign=False).emit() + LoadImmDU64("ldrdsxi_uop", "MicroLdrDSXImmUop", 4, sign=True).emit() + LoadImmDU64("ldrdfpxi_uop", "MicroLdrDFpXImmUop", 4, flavor="fp").emit() +}}; diff --git a/src/arch/arm/isa/insts/m5ops.isa b/src/arch/arm/isa/insts/m5ops.isa index 06ed34af8..928d1be0d 100644 --- a/src/arch/arm/isa/insts/m5ops.isa +++ b/src/arch/arm/isa/insts/m5ops.isa @@ -1,5 +1,5 @@ // -// Copyright (c) 2010 ARM Limited +// Copyright (c) 2010, 2012-2013 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -58,6 +58,7 @@ let {{ armCode = ''' PseudoInst::arm(xc->tcBase()); ''' + armIop = InstObjParams("arm", "Arm", "PredOp", { "code": armCode, "predicate_test": predicateTest }, @@ -69,6 +70,7 @@ let {{ quiesceCode = ''' PseudoInst::quiesce(xc->tcBase()); ''' + quiesceIop = InstObjParams("quiesce", "Quiesce", "PredOp", { "code": quiesceCode, "predicate_test": predicateTest }, @@ -81,6 +83,10 @@ let {{ PseudoInst::quiesceNs(xc->tcBase(), join32to64(R1, R0)); ''' + quiesceNsCode64 = ''' + PseudoInst::quiesceNs(xc->tcBase(), X0); + ''' + quiesceNsIop = InstObjParams("quiesceNs", "QuiesceNs", "PredOp", { "code": quiesceNsCode, "predicate_test": predicateTest }, @@ -89,10 +95,22 @@ let {{ decoder_output += BasicConstructor.subst(quiesceNsIop) exec_output += QuiescePredOpExecute.subst(quiesceNsIop) + quiesceNsIop = InstObjParams("quiesceNs", "QuiesceNs64", "PredOp", + { "code": quiesceNsCode64, + "predicate_test": predicateTest }, + ["IsNonSpeculative", "IsQuiesce"]) + header_output += BasicDeclare.subst(quiesceNsIop) + decoder_output += BasicConstructor.subst(quiesceNsIop) + exec_output += QuiescePredOpExecute.subst(quiesceNsIop) + quiesceCyclesCode = ''' PseudoInst::quiesceCycles(xc->tcBase(), join32to64(R1, R0)); ''' + quiesceCyclesCode64 = ''' + PseudoInst::quiesceCycles(xc->tcBase(), X0); + ''' + quiesceCyclesIop = InstObjParams("quiesceCycles", "QuiesceCycles", "PredOp", { "code": quiesceCyclesCode, "predicate_test": predicateTest }, @@ -101,12 +119,23 @@ let {{ decoder_output += BasicConstructor.subst(quiesceCyclesIop) exec_output += QuiescePredOpExecute.subst(quiesceCyclesIop) + quiesceCyclesIop = InstObjParams("quiesceCycles", "QuiesceCycles64", "PredOp", + { "code": quiesceCyclesCode64, + "predicate_test": predicateTest }, + ["IsNonSpeculative", "IsQuiesce", "IsUnverifiable"]) + header_output += BasicDeclare.subst(quiesceCyclesIop) + decoder_output += BasicConstructor.subst(quiesceCyclesIop) + exec_output += QuiescePredOpExecute.subst(quiesceCyclesIop) + quiesceTimeCode = ''' uint64_t qt_val = PseudoInst::quiesceTime(xc->tcBase()); R0 = bits(qt_val, 31, 0); R1 = bits(qt_val, 63, 32); ''' + quiesceTimeCode64 = ''' + X0 = PseudoInst::quiesceTime(xc->tcBase()); + ''' quiesceTimeIop = InstObjParams("quiesceTime", "QuiesceTime", "PredOp", { "code": quiesceTimeCode, "predicate_test": predicateTest }, @@ -115,12 +144,23 @@ let {{ decoder_output += BasicConstructor.subst(quiesceTimeIop) exec_output += PredOpExecute.subst(quiesceTimeIop) + quiesceTimeIop = InstObjParams("quiesceTime", "QuiesceTime64", "PredOp", + { "code": quiesceTimeCode64, + "predicate_test": predicateTest }, + ["IsNonSpeculative", "IsUnverifiable"]) + header_output += BasicDeclare.subst(quiesceTimeIop) + decoder_output += BasicConstructor.subst(quiesceTimeIop) + exec_output += PredOpExecute.subst(quiesceTimeIop) + rpnsCode = ''' uint64_t rpns_val = PseudoInst::rpns(xc->tcBase()); R0 = bits(rpns_val, 31, 0); R1 = bits(rpns_val, 63, 32); ''' + rpnsCode64 = ''' + X0 = PseudoInst::rpns(xc->tcBase()); + ''' rpnsIop = InstObjParams("rpns", "Rpns", "PredOp", { "code": rpnsCode, "predicate_test": predicateTest }, @@ -129,10 +169,22 @@ let {{ decoder_output += BasicConstructor.subst(rpnsIop) exec_output += PredOpExecute.subst(rpnsIop) + rpnsIop = InstObjParams("rpns", "Rpns64", "PredOp", + { "code": rpnsCode64, + "predicate_test": predicateTest }, + ["IsNonSpeculative", "IsUnverifiable"]) + header_output += BasicDeclare.subst(rpnsIop) + decoder_output += BasicConstructor.subst(rpnsIop) + exec_output += PredOpExecute.subst(rpnsIop) + wakeCpuCode = ''' PseudoInst::wakeCPU(xc->tcBase(), join32to64(R1,R0)); ''' + wakeCpuCode64 = ''' + PseudoInst::wakeCPU(xc->tcBase(), X0); + ''' + wakeCPUIop = InstObjParams("wakeCPU", "WakeCPU", "PredOp", { "code": wakeCpuCode, "predicate_test": predicateTest }, @@ -141,6 +193,14 @@ let {{ decoder_output += BasicConstructor.subst(wakeCPUIop) exec_output += PredOpExecute.subst(wakeCPUIop) + wakeCPUIop = InstObjParams("wakeCPU", "WakeCPU64", "PredOp", + { "code": wakeCpuCode64, + "predicate_test": predicateTest }, + ["IsNonSpeculative", "IsUnverifiable"]) + header_output += BasicDeclare.subst(wakeCPUIop) + decoder_output += BasicConstructor.subst(wakeCPUIop) + exec_output += PredOpExecute.subst(wakeCPUIop) + deprecated_ivlbIop = InstObjParams("deprecated_ivlb", "Deprecated_ivlb", "PredOp", { "code": '''warn_once("Obsolete M5 ivlb instruction encountered.\\n");''', "predicate_test": predicateTest }) @@ -171,6 +231,11 @@ let {{ m5exit_code = ''' PseudoInst::m5exit(xc->tcBase(), join32to64(R1, R0)); ''' + + m5exit_code64 = ''' + PseudoInst::m5exit(xc->tcBase(), X0); + ''' + m5exitIop = InstObjParams("m5exit", "M5exit", "PredOp", { "code": m5exit_code, "predicate_test": predicateTest }, @@ -190,6 +255,14 @@ let {{ decoder_output += BasicConstructor.subst(m5failIop) exec_output += PredOpExecute.subst(m5failIop) + m5exitIop = InstObjParams("m5exit", "M5exit64", "PredOp", + { "code": m5exit_code64, + "predicate_test": predicateTest }, + ["No_OpClass", "IsNonSpeculative"]) + header_output += BasicDeclare.subst(m5exitIop) + decoder_output += BasicConstructor.subst(m5exitIop) + exec_output += PredOpExecute.subst(m5exitIop) + loadsymbolCode = ''' PseudoInst::loadsymbol(xc->tcBase()); ''' @@ -208,6 +281,10 @@ let {{ R1 = bits(ip_val, 63, 32); ''' + initparamCode64 = ''' + X0 = PseudoInst::initParam(xc->tcBase()); + ''' + initparamIop = InstObjParams("initparam", "Initparam", "PredOp", { "code": initparamCode, "predicate_test": predicateTest }, @@ -216,10 +293,21 @@ let {{ decoder_output += BasicConstructor.subst(initparamIop) exec_output += PredOpExecute.subst(initparamIop) + initparamIop = InstObjParams("initparam", "Initparam64", "PredOp", + { "code": initparamCode64, + "predicate_test": predicateTest }, + ["IsNonSpeculative"]) + header_output += BasicDeclare.subst(initparamIop) + decoder_output += BasicConstructor.subst(initparamIop) + exec_output += PredOpExecute.subst(initparamIop) + resetstats_code = ''' PseudoInst::resetstats(xc->tcBase(), join32to64(R1, R0), join32to64(R3, R2)); ''' + resetstats_code64 = ''' + PseudoInst::resetstats(xc->tcBase(), X0, X1); + ''' resetstatsIop = InstObjParams("resetstats", "Resetstats", "PredOp", { "code": resetstats_code, "predicate_test": predicateTest }, @@ -228,9 +316,22 @@ let {{ decoder_output += BasicConstructor.subst(resetstatsIop) exec_output += PredOpExecute.subst(resetstatsIop) + resetstatsIop = InstObjParams("resetstats", "Resetstats64", "PredOp", + { "code": resetstats_code64, + "predicate_test": predicateTest }, + ["IsNonSpeculative"]) + header_output += BasicDeclare.subst(resetstatsIop) + decoder_output += BasicConstructor.subst(resetstatsIop) + exec_output += PredOpExecute.subst(resetstatsIop) + dumpstats_code = ''' PseudoInst::dumpstats(xc->tcBase(), join32to64(R1, R0), join32to64(R3, R2)); ''' + + dumpstats_code64 = ''' + PseudoInst::dumpstats(xc->tcBase(), X0, X1); + ''' + dumpstatsIop = InstObjParams("dumpstats", "Dumpstats", "PredOp", { "code": dumpstats_code, "predicate_test": predicateTest }, @@ -239,9 +340,22 @@ let {{ decoder_output += BasicConstructor.subst(dumpstatsIop) exec_output += PredOpExecute.subst(dumpstatsIop) + dumpstatsIop = InstObjParams("dumpstats", "Dumpstats64", "PredOp", + { "code": dumpstats_code64, + "predicate_test": predicateTest }, + ["IsNonSpeculative"]) + header_output += BasicDeclare.subst(dumpstatsIop) + decoder_output += BasicConstructor.subst(dumpstatsIop) + exec_output += PredOpExecute.subst(dumpstatsIop) + dumpresetstats_code = ''' PseudoInst::dumpresetstats(xc->tcBase(), join32to64(R1, R0), join32to64(R3, R2)); ''' + + dumpresetstats_code64 = ''' + PseudoInst::dumpresetstats(xc->tcBase(), X0, X1); + ''' + dumpresetstatsIop = InstObjParams("dumpresetstats", "Dumpresetstats", "PredOp", { "code": dumpresetstats_code, "predicate_test": predicateTest }, @@ -250,9 +364,22 @@ let {{ decoder_output += BasicConstructor.subst(dumpresetstatsIop) exec_output += PredOpExecute.subst(dumpresetstatsIop) + dumpresetstatsIop = InstObjParams("dumpresetstats", "Dumpresetstats64", "PredOp", + { "code": dumpresetstats_code64, + "predicate_test": predicateTest }, + ["IsNonSpeculative"]) + header_output += BasicDeclare.subst(dumpresetstatsIop) + decoder_output += BasicConstructor.subst(dumpresetstatsIop) + exec_output += PredOpExecute.subst(dumpresetstatsIop) + m5checkpoint_code = ''' PseudoInst::m5checkpoint(xc->tcBase(), join32to64(R1, R0), join32to64(R3, R2)); ''' + + m5checkpoint_code64 = ''' + PseudoInst::m5checkpoint(xc->tcBase(), X0, X1); + ''' + m5checkpointIop = InstObjParams("m5checkpoint", "M5checkpoint", "PredOp", { "code": m5checkpoint_code, "predicate_test": predicateTest }, @@ -261,11 +388,27 @@ let {{ decoder_output += BasicConstructor.subst(m5checkpointIop) exec_output += PredOpExecute.subst(m5checkpointIop) + m5checkpointIop = InstObjParams("m5checkpoint", "M5checkpoint64", "PredOp", + { "code": m5checkpoint_code64, + "predicate_test": predicateTest }, + ["IsNonSpeculative", "IsUnverifiable"]) + header_output += BasicDeclare.subst(m5checkpointIop) + decoder_output += BasicConstructor.subst(m5checkpointIop) + exec_output += PredOpExecute.subst(m5checkpointIop) + m5readfileCode = ''' int n = 4; uint64_t offset = getArgument(xc->tcBase(), n, sizeof(uint64_t), false); R0 = PseudoInst::readfile(xc->tcBase(), R0, join32to64(R3,R2), offset); ''' + + m5readfileCode64 = ''' + int n = 4; + uint64_t offset = getArgument(xc->tcBase(), n, sizeof(uint64_t), false); + n = 6; + X0 = PseudoInst::readfile(xc->tcBase(), (uint32_t)X0, X1, offset); + ''' + m5readfileIop = InstObjParams("m5readfile", "M5readfile", "PredOp", { "code": m5readfileCode, "predicate_test": predicateTest }, @@ -274,6 +417,14 @@ let {{ decoder_output += BasicConstructor.subst(m5readfileIop) exec_output += PredOpExecute.subst(m5readfileIop) + m5readfileIop = InstObjParams("m5readfile", "M5readfile64", "PredOp", + { "code": m5readfileCode64, + "predicate_test": predicateTest }, + ["IsNonSpeculative", "IsUnverifiable"]) + header_output += BasicDeclare.subst(m5readfileIop) + decoder_output += BasicConstructor.subst(m5readfileIop) + exec_output += PredOpExecute.subst(m5readfileIop) + m5writefileCode = ''' int n = 4; uint64_t offset = getArgument(xc->tcBase(), n, sizeof(uint64_t), false); @@ -282,6 +433,16 @@ let {{ R0 = PseudoInst::writefile(xc->tcBase(), R0, join32to64(R3,R2), offset, filenameAddr); ''' + + m5writefileCode64 = ''' + int n = 4; + uint64_t offset = getArgument(xc->tcBase(), n, sizeof(uint64_t), false); + n = 6; + Addr filenameAddr = getArgument(xc->tcBase(), n, sizeof(Addr), false); + X0 = PseudoInst::writefile(xc->tcBase(), (uint32_t)X0, X1, offset, + filenameAddr); + ''' + m5writefileIop = InstObjParams("m5writefile", "M5writefile", "PredOp", { "code": m5writefileCode, "predicate_test": predicateTest }, @@ -290,6 +451,14 @@ let {{ decoder_output += BasicConstructor.subst(m5writefileIop) exec_output += PredOpExecute.subst(m5writefileIop) + m5writefileIop = InstObjParams("m5writefile", "M5writefile64", "PredOp", + { "code": m5writefileCode64, + "predicate_test": predicateTest }, + ["IsNonSpeculative"]) + header_output += BasicDeclare.subst(m5writefileIop) + decoder_output += BasicConstructor.subst(m5writefileIop) + exec_output += PredOpExecute.subst(m5writefileIop) + m5breakIop = InstObjParams("m5break", "M5break", "PredOp", { "code": "PseudoInst::debugbreak(xc->tcBase());", "predicate_test": predicateTest }, @@ -309,6 +478,9 @@ let {{ m5addsymbolCode = ''' PseudoInst::addsymbol(xc->tcBase(), join32to64(R1, R0), R2); ''' + m5addsymbolCode64 = ''' + PseudoInst::addsymbol(xc->tcBase(), X0, (uint32_t)X1); + ''' m5addsymbolIop = InstObjParams("m5addsymbol", "M5addsymbol", "PredOp", { "code": m5addsymbolCode, "predicate_test": predicateTest }, @@ -317,8 +489,17 @@ let {{ decoder_output += BasicConstructor.subst(m5addsymbolIop) exec_output += PredOpExecute.subst(m5addsymbolIop) + m5addsymbolIop = InstObjParams("m5addsymbol", "M5addsymbol64", "PredOp", + { "code": m5addsymbolCode64, + "predicate_test": predicateTest }, + ["IsNonSpeculative"]) + header_output += BasicDeclare.subst(m5addsymbolIop) + decoder_output += BasicConstructor.subst(m5addsymbolIop) + exec_output += PredOpExecute.subst(m5addsymbolIop) + m5panicCode = '''panic("M5 panic instruction called at pc=%#x.", xc->pcState().pc());''' + m5panicIop = InstObjParams("m5panic", "M5panic", "PredOp", { "code": m5panicCode, "predicate_test": predicateTest }, @@ -332,6 +513,13 @@ let {{ join32to64(R1, R0), join32to64(R3, R2) );''' + + m5workbeginCode64 = '''PseudoInst::workbegin( + xc->tcBase(), + X0, + X1 + );''' + m5workbeginIop = InstObjParams("m5workbegin", "M5workbegin", "PredOp", { "code": m5workbeginCode, "predicate_test": predicateTest }, @@ -340,11 +528,26 @@ let {{ decoder_output += BasicConstructor.subst(m5workbeginIop) exec_output += PredOpExecute.subst(m5workbeginIop) + m5workbeginIop = InstObjParams("m5workbegin", "M5workbegin64", "PredOp", + { "code": m5workbeginCode64, + "predicate_test": predicateTest }, + ["IsNonSpeculative"]) + header_output += BasicDeclare.subst(m5workbeginIop) + decoder_output += BasicConstructor.subst(m5workbeginIop) + exec_output += PredOpExecute.subst(m5workbeginIop) + m5workendCode = '''PseudoInst::workend( xc->tcBase(), join32to64(R1, R0), join32to64(R3, R2) );''' + + m5workendCode64 = '''PseudoInst::workend( + xc->tcBase(), + X0, + X1 + );''' + m5workendIop = InstObjParams("m5workend", "M5workend", "PredOp", { "code": m5workendCode, "predicate_test": predicateTest }, @@ -353,4 +556,11 @@ let {{ decoder_output += BasicConstructor.subst(m5workendIop) exec_output += PredOpExecute.subst(m5workendIop) + m5workendIop = InstObjParams("m5workend", "M5workend64", "PredOp", + { "code": m5workendCode64, + "predicate_test": predicateTest }, + ["IsNonSpeculative"]) + header_output += BasicDeclare.subst(m5workendIop) + decoder_output += BasicConstructor.subst(m5workendIop) + exec_output += PredOpExecute.subst(m5workendIop) }}; diff --git a/src/arch/arm/isa/insts/macromem.isa b/src/arch/arm/isa/insts/macromem.isa index db36a3fff..f164595dd 100644 --- a/src/arch/arm/isa/insts/macromem.isa +++ b/src/arch/arm/isa/insts/macromem.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2010 ARM Limited +// Copyright (c) 2010-2013 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -91,7 +91,8 @@ let {{ SCTLR sctlr = Sctlr; CPSR new_cpsr = - cpsrWriteByInstr(old_cpsr, Spsr, 0xF, true, sctlr.nmfi); + cpsrWriteByInstr(old_cpsr, Spsr, Scr, Nsacr, 0xF, true, + sctlr.nmfi, xc->tcBase()); Cpsr = ~CondCodesMask & new_cpsr; CondCodesNZ = new_cpsr.nz; CondCodesC = new_cpsr.c; @@ -158,8 +159,8 @@ let {{ header_output = decoder_output = exec_output = '' - loadIops = (microLdrUopIop, microLdrRetUopIop, - microLdrFpUopIop, microLdrDBFpUopIop, microLdrDTFpUopIop) + loadIops = (microLdrUopIop, microLdrRetUopIop, microLdrFpUopIop, + microLdrDBFpUopIop, microLdrDTFpUopIop) storeIops = (microStrUopIop, microStrFpUopIop, microStrDBFpUopIop, microStrDTFpUopIop) for iop in loadIops + storeIops: @@ -178,7 +179,7 @@ let {{ let {{ exec_output = header_output = '' - eaCode = 'EA = URa + imm;' + eaCode = 'EA = XURa + imm;' for size in (1, 2, 3, 4, 6, 8, 12, 16): # Set up the memory access. @@ -592,6 +593,26 @@ let {{ URa = URb + shift_rm_imm(URc, shiftAmt, shiftType, OptShiftRmCondCodesC); ''' + microAddXiUopIop = InstObjParams('addxi_uop', 'MicroAddXiUop', + 'MicroIntImmXOp', + 'XURa = XURb + imm;', + ['IsMicroop']) + + microAddXiSpAlignUopIop = InstObjParams('addxi_uop', 'MicroAddXiSpAlignUop', + 'MicroIntImmXOp', ''' + if (isSP((IntRegIndex) urb) && bits(XURb, 3, 0) && + SPAlignmentCheckEnabled(xc->tcBase())) { + return new SPAlignmentFault(); + } + XURa = XURb + imm; + ''', ['IsMicroop']) + + microAddXERegUopIop = InstObjParams('addxr_uop', 'MicroAddXERegUop', + 'MicroIntRegXOp', + 'XURa = XURb + ' + \ + 'extendReg64(XURc, type, shiftAmt, 64);', + ['IsMicroop']) + microAddUopIop = InstObjParams('add_uop', 'MicroAddUop', 'MicroIntRegOp', {'code': microAddUopCode, @@ -604,6 +625,11 @@ let {{ 'predicate_test': predicateTest}, ['IsMicroop']) + microSubXiUopIop = InstObjParams('subxi_uop', 'MicroSubXiUop', + 'MicroIntImmXOp', + 'XURa = XURb - imm;', + ['IsMicroop']) + microSubUopCode = ''' URa = URb - shift_rm_imm(URc, shiftAmt, shiftType, OptShiftRmCondCodesC); ''' @@ -631,8 +657,8 @@ let {{ SCTLR sctlr = Sctlr; pNPC = URa; CPSR new_cpsr = - cpsrWriteByInstr(cpsrOrCondCodes, URb, - 0xF, true, sctlr.nmfi); + cpsrWriteByInstr(cpsrOrCondCodes, URb, Scr, Nsacr, + 0xF, true, sctlr.nmfi, xc->tcBase()); Cpsr = ~CondCodesMask & new_cpsr; NextThumb = new_cpsr.t; NextJazelle = new_cpsr.j; @@ -651,25 +677,37 @@ let {{ ['IsMicroop']) header_output = MicroIntImmDeclare.subst(microAddiUopIop) + \ + MicroIntImmDeclare.subst(microAddXiUopIop) + \ + MicroIntImmDeclare.subst(microAddXiSpAlignUopIop) + \ MicroIntImmDeclare.subst(microSubiUopIop) + \ + MicroIntImmDeclare.subst(microSubXiUopIop) + \ MicroIntRegDeclare.subst(microAddUopIop) + \ MicroIntRegDeclare.subst(microSubUopIop) + \ + MicroIntXERegDeclare.subst(microAddXERegUopIop) + \ MicroIntMovDeclare.subst(microUopRegMovIop) + \ MicroIntMovDeclare.subst(microUopRegMovRetIop) + \ MicroSetPCCPSRDeclare.subst(microUopSetPCCPSRIop) decoder_output = MicroIntImmConstructor.subst(microAddiUopIop) + \ + MicroIntImmXConstructor.subst(microAddXiUopIop) + \ + MicroIntImmXConstructor.subst(microAddXiSpAlignUopIop) + \ MicroIntImmConstructor.subst(microSubiUopIop) + \ + MicroIntImmXConstructor.subst(microSubXiUopIop) + \ MicroIntRegConstructor.subst(microAddUopIop) + \ MicroIntRegConstructor.subst(microSubUopIop) + \ + MicroIntXERegConstructor.subst(microAddXERegUopIop) + \ MicroIntMovConstructor.subst(microUopRegMovIop) + \ MicroIntMovConstructor.subst(microUopRegMovRetIop) + \ MicroSetPCCPSRConstructor.subst(microUopSetPCCPSRIop) exec_output = PredOpExecute.subst(microAddiUopIop) + \ + BasicExecute.subst(microAddXiUopIop) + \ + BasicExecute.subst(microAddXiSpAlignUopIop) + \ PredOpExecute.subst(microSubiUopIop) + \ + BasicExecute.subst(microSubXiUopIop) + \ PredOpExecute.subst(microAddUopIop) + \ PredOpExecute.subst(microSubUopIop) + \ + BasicExecute.subst(microAddXERegUopIop) + \ PredOpExecute.subst(microUopRegMovIop) + \ PredOpExecute.subst(microUopRegMovRetIop) + \ PredOpExecute.subst(microUopSetPCCPSRIop) @@ -681,6 +719,25 @@ let {{ header_output = MacroMemDeclare.subst(iop) decoder_output = MacroMemConstructor.subst(iop) + iop = InstObjParams("ldpstp", "LdpStp", 'PairMemOp', "", []) + header_output += PairMemDeclare.subst(iop) + decoder_output += PairMemConstructor.subst(iop) + + iopImm = InstObjParams("bigfpmemimm", "BigFpMemImm", "BigFpMemImmOp", "") + iopPre = InstObjParams("bigfpmempre", "BigFpMemPre", "BigFpMemPreOp", "") + iopPost = InstObjParams("bigfpmempost", "BigFpMemPost", "BigFpMemPostOp", "") + for iop in (iopImm, iopPre, iopPost): + header_output += BigFpMemImmDeclare.subst(iop) + decoder_output += BigFpMemImmConstructor.subst(iop) + + iop = InstObjParams("bigfpmemreg", "BigFpMemReg", "BigFpMemRegOp", "") + header_output += BigFpMemRegDeclare.subst(iop) + decoder_output += BigFpMemRegConstructor.subst(iop) + + iop = InstObjParams("bigfpmemlit", "BigFpMemLit", "BigFpMemLitOp", "") + header_output += BigFpMemLitDeclare.subst(iop) + decoder_output += BigFpMemLitConstructor.subst(iop) + iop = InstObjParams("vldmult", "VldMult", 'VldMultOp', "", []) header_output += VMemMultDeclare.subst(iop) decoder_output += VMemMultConstructor.subst(iop) diff --git a/src/arch/arm/isa/insts/mem.isa b/src/arch/arm/isa/insts/mem.isa index c39f1b14f..aed6bab0d 100644 --- a/src/arch/arm/isa/insts/mem.isa +++ b/src/arch/arm/isa/insts/mem.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2010 ARM Limited +// Copyright (c) 2010-2012 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -48,8 +48,8 @@ let {{ self.constructTemplate = eval(self.decConstBase + 'Constructor') def fillTemplates(self, name, Name, codeBlobs, memFlags, instFlags, - base = 'Memory', wbDecl = None, pcDecl = None, - rasPop = False): + base='Memory', wbDecl=None, pcDecl=None, + rasPop=False, size=4, sign=False, faCode=None): # Make sure flags are in lists (convert to lists if not). memFlags = makeList(memFlags) instFlags = makeList(instFlags) @@ -63,6 +63,22 @@ let {{ codeBlobs["ea_code"] = eaCode + if faCode: + # For AArch64 the fa_code snippet comes already assembled here + codeBlobs["fa_code"] = faCode + elif wbDecl == None: + codeBlobs["fa_code"] = ''' + if (dest != INTREG_PC) { + fault->annotate(ArmFault::SAS, %s); + fault->annotate(ArmFault::SSE, %s); + fault->annotate(ArmFault::SRT, dest); + } + ''' %("0" if size == 1 else + "1" if size == 2 else "2", + "true" if sign else "false") + else: + codeBlobs["fa_code"] = '' + macroName = Name instFlagsCopy = list(instFlags) codeBlobsCopy = dict(codeBlobs) @@ -108,6 +124,7 @@ let {{ "use_uops" : use_uops, "use_pc" : use_pc, "use_wb" : use_wb, + "fa_code" : '', "is_ras_pop" : is_ras_pop }, ['IsMacroop']) header_output += self.declareTemplate.subst(iop) @@ -176,8 +193,13 @@ let {{ return Name def buildMemSuffix(sign, size): - if size == 4: - memSuffix = '' + if size == 8: + memSuffix = '_ud' + elif size == 4: + if sign: + memSuffix = '_sw' + else: + memSuffix = '_uw' elif size == 2: if sign: memSuffix = '_sh' diff --git a/src/arch/arm/isa/insts/misc.isa b/src/arch/arm/isa/insts/misc.isa index b8425a240..678a125fb 100644 --- a/src/arch/arm/isa/insts/misc.isa +++ b/src/arch/arm/isa/insts/misc.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2010-2012 ARM Limited +// Copyright (c) 2010-2013 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -40,21 +40,102 @@ let {{ svcCode = ''' - if (FullSystem) { - fault = new SupervisorCall; - } else { - fault = new SupervisorCall(machInst); - } + fault = new SupervisorCall(machInst, imm); ''' - svcIop = InstObjParams("svc", "Svc", "PredOp", + svcIop = InstObjParams("svc", "Svc", "ImmOp", { "code": svcCode, "predicate_test": predicateTest }, ["IsSyscall", "IsNonSpeculative", "IsSerializeAfter"]) - header_output = BasicDeclare.subst(svcIop) - decoder_output = BasicConstructor.subst(svcIop) + header_output = ImmOpDeclare.subst(svcIop) + decoder_output = ImmOpConstructor.subst(svcIop) exec_output = PredOpExecute.subst(svcIop) + smcCode = ''' + HCR hcr = Hcr; + CPSR cpsr = Cpsr; + SCR scr = Scr; + + if ((cpsr.mode != MODE_USER) && FullSystem) { + if (ArmSystem::haveVirtualization(xc->tcBase()) && + !inSecureState(scr, cpsr) && (cpsr.mode != MODE_HYP) && hcr.tsc) { + fault = new HypervisorTrap(machInst, 0, EC_SMC_TO_HYP); + } else { + if (scr.scd) { + fault = disabledFault(); + } else { + fault = new SecureMonitorCall(machInst); + } + } + } else { + fault = disabledFault(); + } + ''' + + smcIop = InstObjParams("smc", "Smc", "PredOp", + { "code": smcCode, + "predicate_test": predicateTest }, + ["IsNonSpeculative", "IsSerializeAfter"]) + header_output += BasicDeclare.subst(smcIop) + decoder_output += BasicConstructor.subst(smcIop) + exec_output += PredOpExecute.subst(smcIop) + + hvcCode = ''' + CPSR cpsr = Cpsr; + SCR scr = Scr; + + // Filter out the various cases where this instruction isn't defined + if (!FullSystem || !ArmSystem::haveVirtualization(xc->tcBase()) || + (cpsr.mode == MODE_USER) || + (ArmSystem::haveSecurity(xc->tcBase()) && (!scr.ns || !scr.hce))) { + fault = disabledFault(); + } else { + fault = new HypervisorCall(machInst, imm); + } + ''' + + hvcIop = InstObjParams("hvc", "Hvc", "ImmOp", + { "code": hvcCode, + "predicate_test": predicateTest }, + ["IsNonSpeculative", "IsSerializeAfter"]) + header_output += ImmOpDeclare.subst(hvcIop) + decoder_output += ImmOpConstructor.subst(hvcIop) + exec_output += PredOpExecute.subst(hvcIop) + + eretCode = ''' + SCTLR sctlr = Sctlr; + CPSR old_cpsr = Cpsr; + old_cpsr.nz = CondCodesNZ; + old_cpsr.c = CondCodesC; + old_cpsr.v = CondCodesV; + old_cpsr.ge = CondCodesGE; + + CPSR new_cpsr = cpsrWriteByInstr(old_cpsr, Spsr, Scr, Nsacr, 0xF, + true, sctlr.nmfi, xc->tcBase()); + Cpsr = ~CondCodesMask & new_cpsr; + CondCodesNZ = new_cpsr.nz; + CondCodesC = new_cpsr.c; + CondCodesV = new_cpsr.v; + CondCodesGE = new_cpsr.ge; + + NextThumb = (new_cpsr).t; + NextJazelle = (new_cpsr).j; + NextItState = (((new_cpsr).it2 << 2) & 0xFC) + | ((new_cpsr).it1 & 0x3); + + NPC = (old_cpsr.mode == MODE_HYP) ? ElrHyp : LR; + ''' + + eretIop = InstObjParams("eret", "Eret", "PredOp", + { "code": eretCode, + "predicate_test": predicateTest }, + ["IsNonSpeculative", "IsSerializeAfter"]) + header_output += BasicDeclare.subst(eretIop) + decoder_output += BasicConstructor.subst(eretIop) + exec_output += PredOpExecute.subst(eretIop) + + + }}; let {{ @@ -87,6 +168,59 @@ let {{ decoder_output += MrsConstructor.subst(mrsSpsrIop) exec_output += PredOpExecute.subst(mrsSpsrIop) + mrsBankedRegCode = ''' + bool isIntReg; + int regIdx; + + if (decodeMrsMsrBankedReg(byteMask, r, isIntReg, regIdx, Cpsr, Scr, Nsacr)) { + if (isIntReg) { + Dest = DecodedBankedIntReg; + } else { + Dest = xc->readMiscReg(regIdx); + } + } else { + return new UndefinedInstruction(machInst, false, mnemonic); + } + ''' + mrsBankedRegIop = InstObjParams("mrs", "MrsBankedReg", "MrsOp", + { "code": mrsBankedRegCode, + "predicate_test": predicateTest }, + ["IsSerializeBefore"]) + header_output += MrsBankedRegDeclare.subst(mrsBankedRegIop) + decoder_output += MrsBankedRegConstructor.subst(mrsBankedRegIop) + exec_output += PredOpExecute.subst(mrsBankedRegIop) + + msrBankedRegCode = ''' + bool isIntReg; + int regIdx; + + if (decodeMrsMsrBankedReg(byteMask, r, isIntReg, regIdx, Cpsr, Scr, Nsacr)) { + if (isIntReg) { + // This is a bit nasty, you would have thought that + // DecodedBankedIntReg wouldn't be written to unless the + // conditions on the IF statements above are met, however if + // you look at the generated C code you'll find that they are. + // However this is safe as DecodedBankedIntReg (which is used + // in operands.isa to get the index of DecodedBankedIntReg) + // will return INTREG_DUMMY if its not a valid integer + // register, so redirecting the write to somewhere we don't + // care about. + DecodedBankedIntReg = Op1; + } else { + xc->setMiscReg(regIdx, Op1); + } + } else { + return new UndefinedInstruction(machInst, false, mnemonic); + } + ''' + msrBankedRegIop = InstObjParams("msr", "MsrBankedReg", "MsrRegOp", + { "code": msrBankedRegCode, + "predicate_test": predicateTest }, + ["IsSerializeAfter"]) + header_output += MsrBankedRegDeclare.subst(msrBankedRegIop) + decoder_output += MsrBankedRegConstructor.subst(msrBankedRegIop) + exec_output += PredOpExecute.subst(msrBankedRegIop) + msrCpsrRegCode = ''' SCTLR sctlr = Sctlr; CPSR old_cpsr = Cpsr; @@ -96,7 +230,8 @@ let {{ old_cpsr.ge = CondCodesGE; CPSR new_cpsr = - cpsrWriteByInstr(old_cpsr, Op1, byteMask, false, sctlr.nmfi); + cpsrWriteByInstr(old_cpsr, Op1, Scr, Nsacr, byteMask, false, + sctlr.nmfi, xc->tcBase()); Cpsr = ~CondCodesMask & new_cpsr; CondCodesNZ = new_cpsr.nz; CondCodesC = new_cpsr.c; @@ -128,7 +263,8 @@ let {{ old_cpsr.v = CondCodesV; old_cpsr.ge = CondCodesGE; CPSR new_cpsr = - cpsrWriteByInstr(old_cpsr, imm, byteMask, false, sctlr.nmfi); + cpsrWriteByInstr(old_cpsr, imm, Scr, Nsacr, byteMask, false, + sctlr.nmfi, xc->tcBase()); Cpsr = ~CondCodesMask & new_cpsr; CondCodesNZ = new_cpsr.nz; CondCodesC = new_cpsr.c; @@ -488,12 +624,10 @@ let {{ decoder_output += BasicConstructor.subst(bkptIop) exec_output += BasicExecute.subst(bkptIop) - nopIop = InstObjParams("nop", "NopInst", "PredOp", \ - { "code" : "", "predicate_test" : predicateTest }, - ['IsNop']) + nopIop = InstObjParams("nop", "NopInst", "ArmStaticInst", "", ['IsNop']) header_output += BasicDeclare.subst(nopIop) - decoder_output += BasicConstructor.subst(nopIop) - exec_output += PredOpExecute.subst(nopIop) + decoder_output += BasicConstructor64.subst(nopIop) + exec_output += BasicExecute.subst(nopIop) yieldIop = InstObjParams("yield", "YieldInst", "PredOp", \ { "code" : "", "predicate_test" : predicateTest }) @@ -502,14 +636,31 @@ let {{ exec_output += PredOpExecute.subst(yieldIop) wfeCode = ''' - // WFE Sleeps if SevMailbox==0 and no unmasked interrupts are pending + HCR hcr = Hcr; + CPSR cpsr = Cpsr; + SCR scr = Scr64; + SCTLR sctlr = Sctlr; + + // WFE Sleeps if SevMailbox==0 and no unmasked interrupts are pending, + ThreadContext *tc = xc->tcBase(); if (SevMailbox == 1) { SevMailbox = 0; - PseudoInst::quiesceSkip(xc->tcBase()); - } else if (xc->tcBase()->getCpuPtr()->getInterruptController()->checkInterrupts(xc->tcBase())) { - PseudoInst::quiesceSkip(xc->tcBase()); + PseudoInst::quiesceSkip(tc); + } else if (tc->getCpuPtr()->getInterruptController()->checkInterrupts(tc)) { + PseudoInst::quiesceSkip(tc); + } else if (cpsr.el == EL0 && !sctlr.ntwe) { + PseudoInst::quiesceSkip(tc); + fault = new SupervisorTrap(machInst, 0x1E00001, EC_TRAPPED_WFI_WFE); + } else if (ArmSystem::haveVirtualization(tc) && + !inSecureState(scr, cpsr) && (cpsr.mode != MODE_HYP) && + hcr.twe) { + PseudoInst::quiesceSkip(tc); + fault = new HypervisorTrap(machInst, 0x1E00001, EC_TRAPPED_WFI_WFE); + } else if (ArmSystem::haveSecurity(tc) && cpsr.el != EL3 && scr.twe) { + PseudoInst::quiesceSkip(tc); + fault = new SecureMonitorTrap(machInst, 0x1E00001, EC_TRAPPED_WFI_WFE); } else { - PseudoInst::quiesce(xc->tcBase()); + PseudoInst::quiesce(tc); } ''' wfePredFixUpCode = ''' @@ -528,12 +679,30 @@ let {{ exec_output += QuiescePredOpExecuteWithFixup.subst(wfeIop) wfiCode = ''' + HCR hcr = Hcr; + CPSR cpsr = Cpsr; + SCR scr = Scr64; + SCTLR sctlr = Sctlr; + // WFI doesn't sleep if interrupts are pending (masked or not) - if (xc->tcBase()->getCpuPtr()->getInterruptController()->checkRaw()) { - PseudoInst::quiesceSkip(xc->tcBase()); + ThreadContext *tc = xc->tcBase(); + if (tc->getCpuPtr()->getInterruptController()->checkWfiWake(hcr, cpsr, + scr)) { + PseudoInst::quiesceSkip(tc); + } else if (cpsr.el == EL0 && !sctlr.ntwi) { + PseudoInst::quiesceSkip(tc); + fault = new SupervisorTrap(machInst, 0x1E00000, EC_TRAPPED_WFI_WFE); + } else if (ArmSystem::haveVirtualization(tc) && hcr.twi && + (cpsr.mode != MODE_HYP) && !inSecureState(scr, cpsr)) { + PseudoInst::quiesceSkip(tc); + fault = new HypervisorTrap(machInst, 0x1E00000, EC_TRAPPED_WFI_WFE); + } else if (ArmSystem::haveSecurity(tc) && cpsr.el != EL3 && scr.twi) { + PseudoInst::quiesceSkip(tc); + fault = new SecureMonitorTrap(machInst, 0x1E00000, EC_TRAPPED_WFI_WFE); } else { - PseudoInst::quiesce(xc->tcBase()); + PseudoInst::quiesce(tc); } + tc->getCpuPtr()->clearInterrupt(INT_ABT, 0); ''' wfiIop = InstObjParams("wfi", "WfiInst", "PredOp", \ { "code" : wfiCode, "predicate_test" : predicateTest }, @@ -564,6 +733,16 @@ let {{ decoder_output += BasicConstructor.subst(sevIop) exec_output += PredOpExecute.subst(sevIop) + sevlCode = ''' + SevMailbox = 1; + ''' + sevlIop = InstObjParams("sevl", "SevlInst", "PredOp", \ + { "code" : sevlCode, "predicate_test" : predicateTest }, + ["IsNonSpeculative", "IsSquashAfter", "IsUnverifiable"]) + header_output += BasicDeclare.subst(sevlIop) + decoder_output += BasicConstructor.subst(sevlIop) + exec_output += BasicExecute.subst(sevlIop) + itIop = InstObjParams("it", "ItInst", "PredOp", \ { "code" : ";", "predicate_test" : predicateTest }, []) @@ -571,10 +750,7 @@ let {{ decoder_output += BasicConstructor.subst(itIop) exec_output += PredOpExecute.subst(itIop) unknownCode = ''' - if (FullSystem) - return new UndefinedInstruction; - else - return new UndefinedInstruction(machInst, true); + return new UndefinedInstruction(machInst, true); ''' unknownIop = InstObjParams("unknown", "Unknown", "UnknownOp", \ { "code": unknownCode, @@ -626,108 +802,152 @@ let {{ exec_output += PredOpExecute.subst(bfiIop) mrc14code = ''' - CPSR cpsr = Cpsr; - if (cpsr.mode == MODE_USER) { - if (FullSystem) - return new UndefinedInstruction; - else - return new UndefinedInstruction(false, mnemonic); + MiscRegIndex miscReg = (MiscRegIndex) xc->tcBase()->flattenMiscIndex(op1); + if (!canReadCoprocReg(miscReg, Scr, Cpsr, xc->tcBase())) { + return new UndefinedInstruction(machInst, false, mnemonic); + } + if (mcrMrc14TrapToHyp((const MiscRegIndex) op1, Hcr, Cpsr, Scr, Hdcr, + Hstr, Hcptr, imm)) { + return new HypervisorTrap(machInst, imm, EC_TRAPPED_CP14_MCR_MRC); } Dest = MiscOp1; ''' - mrc14Iop = InstObjParams("mrc", "Mrc14", "RegRegOp", + mrc14Iop = InstObjParams("mrc", "Mrc14", "RegRegImmOp", { "code": mrc14code, "predicate_test": predicateTest }, []) - header_output += RegRegOpDeclare.subst(mrc14Iop) - decoder_output += RegRegOpConstructor.subst(mrc14Iop) + header_output += RegRegImmOpDeclare.subst(mrc14Iop) + decoder_output += RegRegImmOpConstructor.subst(mrc14Iop) exec_output += PredOpExecute.subst(mrc14Iop) mcr14code = ''' - CPSR cpsr = Cpsr; - if (cpsr.mode == MODE_USER) { - if (FullSystem) - return new UndefinedInstruction; - else - return new UndefinedInstruction(false, mnemonic); + MiscRegIndex miscReg = (MiscRegIndex) xc->tcBase()->flattenMiscIndex(dest); + if (!canWriteCoprocReg(miscReg, Scr, Cpsr, xc->tcBase())) { + return new UndefinedInstruction(machInst, false, mnemonic); + } + if (mcrMrc14TrapToHyp(miscReg, Hcr, Cpsr, Scr, Hdcr, + Hstr, Hcptr, imm)) { + return new HypervisorTrap(machInst, imm, EC_TRAPPED_CP14_MCR_MRC); } MiscDest = Op1; ''' - mcr14Iop = InstObjParams("mcr", "Mcr14", "RegRegOp", + mcr14Iop = InstObjParams("mcr", "Mcr14", "RegRegImmOp", { "code": mcr14code, "predicate_test": predicateTest }, ["IsSerializeAfter","IsNonSpeculative"]) - header_output += RegRegOpDeclare.subst(mcr14Iop) - decoder_output += RegRegOpConstructor.subst(mcr14Iop) + header_output += RegRegImmOpDeclare.subst(mcr14Iop) + decoder_output += RegRegImmOpConstructor.subst(mcr14Iop) exec_output += PredOpExecute.subst(mcr14Iop) - mrc14UserIop = InstObjParams("mrc", "Mrc14User", "RegRegOp", - { "code": "Dest = MiscOp1;", - "predicate_test": predicateTest }, []) - header_output += RegRegOpDeclare.subst(mrc14UserIop) - decoder_output += RegRegOpConstructor.subst(mrc14UserIop) - exec_output += PredOpExecute.subst(mrc14UserIop) - - mcr14UserIop = InstObjParams("mcr", "Mcr14User", "RegRegOp", - { "code": "MiscDest = Op1", - "predicate_test": predicateTest }, - ["IsSerializeAfter","IsNonSpeculative"]) - header_output += RegRegOpDeclare.subst(mcr14UserIop) - decoder_output += RegRegOpConstructor.subst(mcr14UserIop) - exec_output += PredOpExecute.subst(mcr14UserIop) - mrc15code = ''' - CPSR cpsr = Cpsr; - if (cpsr.mode == MODE_USER) { - if (FullSystem) - return new UndefinedInstruction; - else - return new UndefinedInstruction(false, mnemonic); + int preFlatOp1 = flattenMiscRegNsBanked(op1, xc->tcBase()); + MiscRegIndex miscReg = (MiscRegIndex) + xc->tcBase()->flattenMiscIndex(preFlatOp1); + bool hypTrap = mcrMrc15TrapToHyp(miscReg, Hcr, Cpsr, Scr, Hdcr, Hstr, + Hcptr, imm); + bool canRead = canReadCoprocReg(miscReg, Scr, Cpsr, xc->tcBase()); + + // if we're in non secure PL1 mode then we can trap regargless of whether + // the register is accessable, in other modes we trap if only if the register + // IS accessable. + if (!canRead & !(hypTrap & !inUserMode(Cpsr) & !inSecureState(Scr, Cpsr))) { + return new UndefinedInstruction(machInst, false, mnemonic); } - Dest = MiscOp1; + if (hypTrap) { + return new HypervisorTrap(machInst, imm, EC_TRAPPED_CP15_MCR_MRC); + } + Dest = MiscNsBankedOp1; ''' - mrc15Iop = InstObjParams("mrc", "Mrc15", "RegRegOp", + mrc15Iop = InstObjParams("mrc", "Mrc15", "RegRegImmOp", { "code": mrc15code, "predicate_test": predicateTest }, []) - header_output += RegRegOpDeclare.subst(mrc15Iop) - decoder_output += RegRegOpConstructor.subst(mrc15Iop) + header_output += RegRegImmOpDeclare.subst(mrc15Iop) + decoder_output += RegRegImmOpConstructor.subst(mrc15Iop) exec_output += PredOpExecute.subst(mrc15Iop) mcr15code = ''' - CPSR cpsr = Cpsr; - if (cpsr.mode == MODE_USER) { - if (FullSystem) - return new UndefinedInstruction; - else - return new UndefinedInstruction(false, mnemonic); + int preFlatDest = flattenMiscRegNsBanked(dest, xc->tcBase()); + MiscRegIndex miscReg = (MiscRegIndex) + xc->tcBase()->flattenMiscIndex(preFlatDest); + bool hypTrap = mcrMrc15TrapToHyp(miscReg, Hcr, Cpsr, Scr, Hdcr, Hstr, + Hcptr, imm); + bool canWrite = canWriteCoprocReg(miscReg, Scr, Cpsr, xc->tcBase()); + + // if we're in non secure PL1 mode then we can trap regargless of whether + // the register is accessable, in other modes we trap if only if the register + // IS accessable. + if (!canWrite & !(hypTrap & !inUserMode(Cpsr) & !inSecureState(Scr, Cpsr))) { + return new UndefinedInstruction(machInst, false, mnemonic); } - MiscDest = Op1; + if (hypTrap) { + return new HypervisorTrap(machInst, imm, EC_TRAPPED_CP15_MCR_MRC); + } + MiscNsBankedDest = Op1; ''' - mcr15Iop = InstObjParams("mcr", "Mcr15", "RegRegOp", + mcr15Iop = InstObjParams("mcr", "Mcr15", "RegRegImmOp", { "code": mcr15code, "predicate_test": predicateTest }, ["IsSerializeAfter","IsNonSpeculative"]) - header_output += RegRegOpDeclare.subst(mcr15Iop) - decoder_output += RegRegOpConstructor.subst(mcr15Iop) + header_output += RegRegImmOpDeclare.subst(mcr15Iop) + decoder_output += RegRegImmOpConstructor.subst(mcr15Iop) exec_output += PredOpExecute.subst(mcr15Iop) - mrc15UserIop = InstObjParams("mrc", "Mrc15User", "RegRegOp", - { "code": "Dest = MiscOp1;", - "predicate_test": predicateTest }, []) - header_output += RegRegOpDeclare.subst(mrc15UserIop) - decoder_output += RegRegOpConstructor.subst(mrc15UserIop) - exec_output += PredOpExecute.subst(mrc15UserIop) - - mcr15UserIop = InstObjParams("mcr", "Mcr15User", "RegRegOp", - { "code": "MiscDest = Op1", - "predicate_test": predicateTest }, - ["IsSerializeAfter","IsNonSpeculative"]) - header_output += RegRegOpDeclare.subst(mcr15UserIop) - decoder_output += RegRegOpConstructor.subst(mcr15UserIop) - exec_output += PredOpExecute.subst(mcr15UserIop) + + mrrc15code = ''' + int preFlatOp1 = flattenMiscRegNsBanked(op1, xc->tcBase()); + MiscRegIndex miscReg = (MiscRegIndex) + xc->tcBase()->flattenMiscIndex(preFlatOp1); + bool hypTrap = mcrrMrrc15TrapToHyp(miscReg, Cpsr, Scr, Hstr, Hcr, imm); + bool canRead = canReadCoprocReg(miscReg, Scr, Cpsr, xc->tcBase()); + + // if we're in non secure PL1 mode then we can trap regargless of whether + // the register is accessable, in other modes we trap if only if the register + // IS accessable. + if (!canRead & !(hypTrap & !inUserMode(Cpsr) & !inSecureState(Scr, Cpsr))) { + return new UndefinedInstruction(machInst, false, mnemonic); + } + if (hypTrap) { + return new HypervisorTrap(machInst, imm, EC_TRAPPED_CP15_MCRR_MRRC); + } + Dest = bits(MiscNsBankedOp164, 63, 32); + Dest2 = bits(MiscNsBankedOp164, 31, 0); + ''' + mrrc15Iop = InstObjParams("mrrc", "Mrrc15", "MrrcOp", + { "code": mrrc15code, + "predicate_test": predicateTest }, []) + header_output += MrrcOpDeclare.subst(mrrc15Iop) + decoder_output += MrrcOpConstructor.subst(mrrc15Iop) + exec_output += PredOpExecute.subst(mrrc15Iop) + + + mcrr15code = ''' + int preFlatDest = flattenMiscRegNsBanked(dest, xc->tcBase()); + MiscRegIndex miscReg = (MiscRegIndex) + xc->tcBase()->flattenMiscIndex(preFlatDest); + bool hypTrap = mcrrMrrc15TrapToHyp(miscReg, Cpsr, Scr, Hstr, Hcr, imm); + bool canWrite = canWriteCoprocReg(miscReg, Scr, Cpsr, xc->tcBase()); + + // if we're in non secure PL1 mode then we can trap regargless of whether + // the register is accessable, in other modes we trap if only if the register + // IS accessable. + if (!canWrite & !(hypTrap & !inUserMode(Cpsr) & !inSecureState(Scr, Cpsr))) { + return new UndefinedInstruction(machInst, false, mnemonic); + } + if (hypTrap) { + return new HypervisorTrap(machInst, imm, EC_TRAPPED_CP15_MCRR_MRRC); + } + MiscNsBankedDest64 = ((uint64_t) Op1 << 32) | Op2; + ''' + mcrr15Iop = InstObjParams("mcrr", "Mcrr15", "McrrOp", + { "code": mcrr15code, + "predicate_test": predicateTest }, []) + header_output += McrrOpDeclare.subst(mcrr15Iop) + decoder_output += McrrOpConstructor.subst(mcrr15Iop) + exec_output += PredOpExecute.subst(mcrr15Iop) + enterxCode = ''' NextThumb = true; @@ -775,35 +995,53 @@ let {{ exec_output += PredOpExecute.subst(clrexIop) isbCode = ''' + // If the barrier is due to a CP15 access check for hyp traps + if ((imm != 0) && mcrMrc15TrapToHyp(MISCREG_CP15ISB, Hcr, Cpsr, Scr, + Hdcr, Hstr, Hcptr, imm)) { + return new HypervisorTrap(machInst, imm, + EC_TRAPPED_CP15_MCR_MRC); + } fault = new FlushPipe; ''' - isbIop = InstObjParams("isb", "Isb", "PredOp", + isbIop = InstObjParams("isb", "Isb", "ImmOp", {"code": isbCode, "predicate_test": predicateTest}, ['IsSerializeAfter']) - header_output += BasicDeclare.subst(isbIop) - decoder_output += BasicConstructor.subst(isbIop) + header_output += ImmOpDeclare.subst(isbIop) + decoder_output += ImmOpConstructor.subst(isbIop) exec_output += PredOpExecute.subst(isbIop) dsbCode = ''' + // If the barrier is due to a CP15 access check for hyp traps + if ((imm != 0) && mcrMrc15TrapToHyp(MISCREG_CP15DSB, Hcr, Cpsr, Scr, + Hdcr, Hstr, Hcptr, imm)) { + return new HypervisorTrap(machInst, imm, + EC_TRAPPED_CP15_MCR_MRC); + } fault = new FlushPipe; ''' - dsbIop = InstObjParams("dsb", "Dsb", "PredOp", + dsbIop = InstObjParams("dsb", "Dsb", "ImmOp", {"code": dsbCode, "predicate_test": predicateTest}, ['IsMemBarrier', 'IsSerializeAfter']) - header_output += BasicDeclare.subst(dsbIop) - decoder_output += BasicConstructor.subst(dsbIop) + header_output += ImmOpDeclare.subst(dsbIop) + decoder_output += ImmOpConstructor.subst(dsbIop) exec_output += PredOpExecute.subst(dsbIop) dmbCode = ''' + // If the barrier is due to a CP15 access check for hyp traps + if ((imm != 0) && mcrMrc15TrapToHyp(MISCREG_CP15DMB, Hcr, Cpsr, Scr, + Hdcr, Hstr, Hcptr, imm)) { + return new HypervisorTrap(machInst, imm, + EC_TRAPPED_CP15_MCR_MRC); + } ''' - dmbIop = InstObjParams("dmb", "Dmb", "PredOp", + dmbIop = InstObjParams("dmb", "Dmb", "ImmOp", {"code": dmbCode, "predicate_test": predicateTest}, ['IsMemBarrier']) - header_output += BasicDeclare.subst(dmbIop) - decoder_output += BasicConstructor.subst(dmbIop) + header_output += ImmOpDeclare.subst(dmbIop) + decoder_output += ImmOpConstructor.subst(dmbIop) exec_output += PredOpExecute.subst(dmbIop) dbgCode = ''' diff --git a/src/arch/arm/isa/insts/misc64.isa b/src/arch/arm/isa/insts/misc64.isa new file mode 100644 index 000000000..6ebbcc2ba --- /dev/null +++ b/src/arch/arm/isa/insts/misc64.isa @@ -0,0 +1,147 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2011-2013 ARM Limited +// All rights reserved +// +// The license below extends only to copyright in the software and shall +// not be construed as granting a license to any other intellectual +// property including but not limited to intellectual property relating +// to a hardware implementation of the functionality of the software +// licensed hereunder. You may use the software subject to the license +// terms below provided that you ensure that this notice is replicated +// unmodified and in its entirety in all distributions of the software, +// modified or unmodified, in source code or in binary form. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Gabe Black + +let {{ + svcCode = ''' + fault = new SupervisorCall(machInst, bits(machInst, 20, 5)); + ''' + + svcIop = InstObjParams("svc", "Svc64", "ArmStaticInst", + svcCode, ["IsSyscall", "IsNonSpeculative", + "IsSerializeAfter"]) + header_output = BasicDeclare.subst(svcIop) + decoder_output = BasicConstructor64.subst(svcIop) + exec_output = BasicExecute.subst(svcIop) + + # @todo: extend to take into account Virtualization. + smcCode = ''' + SCR scr = Scr64; + CPSR cpsr = Cpsr; + + if (!ArmSystem::haveSecurity(xc->tcBase()) || inUserMode(cpsr) || scr.smd) { + fault = disabledFault(); + } else { + fault = new SecureMonitorCall(machInst); + } + ''' + + smcIop = InstObjParams("smc", "Smc64", "ArmStaticInst", + smcCode, ["IsNonSpeculative", "IsSerializeAfter"]) + header_output += BasicDeclare.subst(smcIop) + decoder_output += BasicConstructor64.subst(smcIop) + exec_output += BasicExecute.subst(smcIop) + + def subst(templateBase, iop): + global header_output, decoder_output, exec_output + header_output += eval(templateBase + "Declare").subst(iop) + decoder_output += eval(templateBase + "Constructor").subst(iop) + exec_output += BasicExecute.subst(iop) + + bfmMaskCode = ''' + uint64_t bitMask; + int diff = imm2 - imm1; + if (imm1 <= imm2) { + bitMask = mask(diff + 1); + } else { + bitMask = mask(imm2 + 1); + bitMask = (bitMask >> imm1) | (bitMask << (intWidth - imm1)); + diff += intWidth; + } + uint64_t topBits M5_VAR_USED = ~mask(diff+1); + uint64_t result = (Op164 >> imm1) | (Op164 << (intWidth - imm1)); + result &= bitMask; + ''' + + bfmCode = bfmMaskCode + 'Dest64 = result | (Dest64 & ~bitMask);' + bfmIop = InstObjParams("bfm", "Bfm64", "RegRegImmImmOp64", bfmCode); + subst("RegRegImmImmOp64", bfmIop) + + ubfmCode = bfmMaskCode + 'Dest64 = result;' + ubfmIop = InstObjParams("ubfm", "Ubfm64", "RegRegImmImmOp64", ubfmCode); + subst("RegRegImmImmOp64", ubfmIop) + + sbfmCode = bfmMaskCode + \ + 'Dest64 = result | (bits(Op164, imm2) ? topBits : 0);' + sbfmIop = InstObjParams("sbfm", "Sbfm64", "RegRegImmImmOp64", sbfmCode); + subst("RegRegImmImmOp64", sbfmIop) + + extrCode = ''' + if (imm == 0) { + Dest64 = Op264; + } else { + Dest64 = (Op164 << (intWidth - imm)) | (Op264 >> imm); + } + ''' + extrIop = InstObjParams("extr", "Extr64", "RegRegRegImmOp64", extrCode); + subst("RegRegRegImmOp64", extrIop); + + unknownCode = ''' + return new UndefinedInstruction(machInst, true); + ''' + unknown64Iop = InstObjParams("unknown", "Unknown64", "UnknownOp64", + unknownCode) + header_output += BasicDeclare.subst(unknown64Iop) + decoder_output += BasicConstructor64.subst(unknown64Iop) + exec_output += BasicExecute.subst(unknown64Iop) + + isbIop = InstObjParams("isb", "Isb64", "ArmStaticInst", + "fault = new FlushPipe;", ['IsSerializeAfter']) + header_output += BasicDeclare.subst(isbIop) + decoder_output += BasicConstructor64.subst(isbIop) + exec_output += BasicExecute.subst(isbIop) + + dsbIop = InstObjParams("dsb", "Dsb64", "ArmStaticInst", + "fault = new FlushPipe;", + ['IsMemBarrier', 'IsSerializeAfter']) + header_output += BasicDeclare.subst(dsbIop) + decoder_output += BasicConstructor64.subst(dsbIop) + exec_output += BasicExecute.subst(dsbIop) + + dmbIop = InstObjParams("dmb", "Dmb64", "ArmStaticInst", "", + ['IsMemBarrier']) + header_output += BasicDeclare.subst(dmbIop) + decoder_output += BasicConstructor64.subst(dmbIop) + exec_output += BasicExecute.subst(dmbIop) + + clrexIop = InstObjParams("clrex", "Clrex64", "ArmStaticInst", + "LLSCLock = 0;") + header_output += BasicDeclare.subst(clrexIop) + decoder_output += BasicConstructor64.subst(clrexIop) + exec_output += BasicExecute.subst(clrexIop) +}}; diff --git a/src/arch/arm/isa/insts/neon.isa b/src/arch/arm/isa/insts/neon.isa index 876bb3bb7..ca5c3038c 100644 --- a/src/arch/arm/isa/insts/neon.isa +++ b/src/arch/arm/isa/insts/neon.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2010 ARM Limited +// Copyright (c) 2010-2011 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -94,8 +94,8 @@ output header {{ template <template <typename T> class Base> StaticInstPtr decodeNeonUThreeUSReg(unsigned size, - ExtMachInst machInst, IntRegIndex dest, - IntRegIndex op1, IntRegIndex op2) + ExtMachInst machInst, IntRegIndex dest, + IntRegIndex op1, IntRegIndex op2) { switch (size) { case 0: @@ -112,8 +112,8 @@ output header {{ template <template <typename T> class Base> StaticInstPtr decodeNeonSThreeUSReg(unsigned size, - ExtMachInst machInst, IntRegIndex dest, - IntRegIndex op1, IntRegIndex op2) + ExtMachInst machInst, IntRegIndex dest, + IntRegIndex op1, IntRegIndex op2) { switch (size) { case 0: @@ -129,6 +129,38 @@ output header {{ template <template <typename T> class Base> StaticInstPtr + decodeNeonSThreeHAndWReg(unsigned size, ExtMachInst machInst, + IntRegIndex dest, IntRegIndex op1, + IntRegIndex op2) + { + switch (size) { + case 1: + return new Base<int16_t>(machInst, dest, op1, op2); + case 2: + return new Base<int32_t>(machInst, dest, op1, op2); + default: + return new Unknown(machInst); + } + } + + template <template <typename T> class Base> + StaticInstPtr + decodeNeonSThreeImmHAndWReg(unsigned size, ExtMachInst machInst, + IntRegIndex dest, IntRegIndex op1, + IntRegIndex op2, uint64_t imm) + { + switch (size) { + case 1: + return new Base<int16_t>(machInst, dest, op1, op2, imm); + case 2: + return new Base<int32_t>(machInst, dest, op1, op2, imm); + default: + return new Unknown(machInst); + } + } + + template <template <typename T> class Base> + StaticInstPtr decodeNeonUSThreeUSReg(bool notSigned, unsigned size, ExtMachInst machInst, IntRegIndex dest, IntRegIndex op1, IntRegIndex op2) @@ -177,6 +209,38 @@ output header {{ template <template <typename T> class BaseD, template <typename T> class BaseQ> StaticInstPtr + decodeNeonSThreeXReg(bool q, unsigned size, + ExtMachInst machInst, IntRegIndex dest, + IntRegIndex op1, IntRegIndex op2) + { + if (q) { + return decodeNeonSThreeUReg<BaseQ>( + size, machInst, dest, op1, op2); + } else { + return decodeNeonSThreeUSReg<BaseD>( + size, machInst, dest, op1, op2); + } + } + + template <template <typename T> class BaseD, + template <typename T> class BaseQ> + StaticInstPtr + decodeNeonUThreeXReg(bool q, unsigned size, + ExtMachInst machInst, IntRegIndex dest, + IntRegIndex op1, IntRegIndex op2) + { + if (q) { + return decodeNeonUThreeUReg<BaseQ>( + size, machInst, dest, op1, op2); + } else { + return decodeNeonUThreeUSReg<BaseD>( + size, machInst, dest, op1, op2); + } + } + + template <template <typename T> class BaseD, + template <typename T> class BaseQ> + StaticInstPtr decodeNeonUSThreeSReg(bool q, bool notSigned, unsigned size, ExtMachInst machInst, IntRegIndex dest, IntRegIndex op1, IntRegIndex op2) @@ -241,6 +305,124 @@ output header {{ template <template <typename T> class BaseD, template <typename T> class BaseQ> StaticInstPtr + decodeNeonUThreeFpReg(bool q, unsigned size, ExtMachInst machInst, + IntRegIndex dest, IntRegIndex op1, IntRegIndex op2) + { + if (q) { + if (size) + return new BaseQ<uint64_t>(machInst, dest, op1, op2); + else + return new BaseQ<uint32_t>(machInst, dest, op1, op2); + } else { + if (size) + return new Unknown(machInst); + else + return new BaseD<uint32_t>(machInst, dest, op1, op2); + } + } + + template <template <typename T> class Base> + StaticInstPtr + decodeNeonUThreeScFpReg(bool size, ExtMachInst machInst, + IntRegIndex dest, IntRegIndex op1, IntRegIndex op2) + { + if (size) + return new Base<uint64_t>(machInst, dest, op1, op2); + else + return new Base<uint32_t>(machInst, dest, op1, op2); + } + + template <template <typename T> class Base> + StaticInstPtr + decodeNeonUThreeImmScFpReg(bool size, ExtMachInst machInst, + IntRegIndex dest, IntRegIndex op1, + IntRegIndex op2, uint64_t imm) + { + if (size) + return new Base<uint64_t>(machInst, dest, op1, op2, imm); + else + return new Base<uint32_t>(machInst, dest, op1, op2, imm); + } + + template <template <typename T> class BaseD, + template <typename T> class BaseQ> + StaticInstPtr + decodeNeonUThreeImmHAndWReg(bool q, unsigned size, ExtMachInst machInst, + IntRegIndex dest, IntRegIndex op1, + IntRegIndex op2, uint64_t imm) + { + if (q) { + switch (size) { + case 1: + return new BaseQ<uint16_t>(machInst, dest, op1, op2, imm); + case 2: + return new BaseQ<uint32_t>(machInst, dest, op1, op2, imm); + default: + return new Unknown(machInst); + } + } else { + switch (size) { + case 1: + return new BaseD<uint16_t>(machInst, dest, op1, op2, imm); + case 2: + return new BaseD<uint32_t>(machInst, dest, op1, op2, imm); + default: + return new Unknown(machInst); + } + } + } + + template <template <typename T> class BaseD, + template <typename T> class BaseQ> + StaticInstPtr + decodeNeonSThreeImmHAndWReg(bool q, unsigned size, ExtMachInst machInst, + IntRegIndex dest, IntRegIndex op1, + IntRegIndex op2, uint64_t imm) + { + if (q) { + switch (size) { + case 1: + return new BaseQ<int16_t>(machInst, dest, op1, op2, imm); + case 2: + return new BaseQ<int32_t>(machInst, dest, op1, op2, imm); + default: + return new Unknown(machInst); + } + } else { + switch (size) { + case 1: + return new BaseD<int16_t>(machInst, dest, op1, op2, imm); + case 2: + return new BaseD<int32_t>(machInst, dest, op1, op2, imm); + default: + return new Unknown(machInst); + } + } + } + + template <template <typename T> class BaseD, + template <typename T> class BaseQ> + StaticInstPtr + decodeNeonUThreeImmFpReg(bool q, unsigned size, ExtMachInst machInst, + IntRegIndex dest, IntRegIndex op1, + IntRegIndex op2, uint64_t imm) + { + if (q) { + if (size) + return new BaseQ<uint64_t>(machInst, dest, op1, op2, imm); + else + return new BaseQ<uint32_t>(machInst, dest, op1, op2, imm); + } else { + if (size) + return new Unknown(machInst); + else + return new BaseD<uint32_t>(machInst, dest, op1, op2, imm); + } + } + + template <template <typename T> class BaseD, + template <typename T> class BaseQ> + StaticInstPtr decodeNeonUTwoShiftReg(bool q, unsigned size, ExtMachInst machInst, IntRegIndex dest, IntRegIndex op1, uint64_t imm) @@ -345,6 +527,46 @@ output header {{ } } + template <template <typename T> class Base> + StaticInstPtr + decodeNeonUTwoShiftUReg(unsigned size, + ExtMachInst machInst, IntRegIndex dest, + IntRegIndex op1, uint64_t imm) + { + switch (size) { + case 0: + return new Base<uint8_t>(machInst, dest, op1, imm); + case 1: + return new Base<uint16_t>(machInst, dest, op1, imm); + case 2: + return new Base<uint32_t>(machInst, dest, op1, imm); + case 3: + return new Base<uint64_t>(machInst, dest, op1, imm); + default: + return new Unknown(machInst); + } + } + + template <template <typename T> class Base> + StaticInstPtr + decodeNeonSTwoShiftUReg(unsigned size, + ExtMachInst machInst, IntRegIndex dest, + IntRegIndex op1, uint64_t imm) + { + switch (size) { + case 0: + return new Base<int8_t>(machInst, dest, op1, imm); + case 1: + return new Base<int16_t>(machInst, dest, op1, imm); + case 2: + return new Base<int32_t>(machInst, dest, op1, imm); + case 3: + return new Base<int64_t>(machInst, dest, op1, imm); + default: + return new Unknown(machInst); + } + } + template <template <typename T> class BaseD, template <typename T> class BaseQ> StaticInstPtr @@ -411,6 +633,66 @@ output header {{ } } + template <template <typename T> class BaseD, + template <typename T> class BaseQ> + StaticInstPtr + decodeNeonUTwoShiftXReg(bool q, unsigned size, ExtMachInst machInst, + IntRegIndex dest, IntRegIndex op1, uint64_t imm) + { + if (q) { + return decodeNeonUTwoShiftUReg<BaseQ>( + size, machInst, dest, op1, imm); + } else { + return decodeNeonUTwoShiftUSReg<BaseD>( + size, machInst, dest, op1, imm); + } + } + + template <template <typename T> class BaseD, + template <typename T> class BaseQ> + StaticInstPtr + decodeNeonSTwoShiftXReg(bool q, unsigned size, ExtMachInst machInst, + IntRegIndex dest, IntRegIndex op1, uint64_t imm) + { + if (q) { + return decodeNeonSTwoShiftUReg<BaseQ>( + size, machInst, dest, op1, imm); + } else { + return decodeNeonSTwoShiftUSReg<BaseD>( + size, machInst, dest, op1, imm); + } + } + + template <template <typename T> class Base> + StaticInstPtr + decodeNeonUTwoShiftUFpReg(unsigned size, ExtMachInst machInst, + IntRegIndex dest, IntRegIndex op1, uint64_t imm) + { + if (size) + return new Base<uint64_t>(machInst, dest, op1, imm); + else + return new Base<uint32_t>(machInst, dest, op1, imm); + } + + template <template <typename T> class BaseD, + template <typename T> class BaseQ> + StaticInstPtr + decodeNeonUTwoShiftFpReg(bool q, unsigned size, ExtMachInst machInst, + IntRegIndex dest, IntRegIndex op1, uint64_t imm) + { + if (q) { + if (size) + return new BaseQ<uint64_t>(machInst, dest, op1, imm); + else + return new BaseQ<uint32_t>(machInst, dest, op1, imm); + } else { + if (size) + return new Unknown(machInst); + else + return new BaseD<uint32_t>(machInst, dest, op1, imm); + } + } + template <template <typename T> class Base> StaticInstPtr decodeNeonUTwoMiscUSReg(unsigned size, @@ -451,8 +733,8 @@ output header {{ template <typename T> class BaseQ> StaticInstPtr decodeNeonUTwoMiscSReg(bool q, unsigned size, - ExtMachInst machInst, IntRegIndex dest, - IntRegIndex op1) + ExtMachInst machInst, IntRegIndex dest, + IntRegIndex op1) { if (q) { return decodeNeonUTwoMiscUSReg<BaseQ>(size, machInst, dest, op1); @@ -465,8 +747,8 @@ output header {{ template <typename T> class BaseQ> StaticInstPtr decodeNeonSTwoMiscSReg(bool q, unsigned size, - ExtMachInst machInst, IntRegIndex dest, - IntRegIndex op1) + ExtMachInst machInst, IntRegIndex dest, + IntRegIndex op1) { if (q) { return decodeNeonSTwoMiscUSReg<BaseQ>(size, machInst, dest, op1); @@ -498,8 +780,8 @@ output header {{ template <template <typename T> class Base> StaticInstPtr decodeNeonSTwoMiscUReg(unsigned size, - ExtMachInst machInst, IntRegIndex dest, - IntRegIndex op1) + ExtMachInst machInst, IntRegIndex dest, + IntRegIndex op1) { switch (size) { case 0: @@ -559,6 +841,221 @@ output header {{ } } + template <template <typename T> class BaseD, + template <typename T> class BaseQ> + StaticInstPtr + decodeNeonUTwoMiscXReg(bool q, unsigned size, ExtMachInst machInst, + IntRegIndex dest, IntRegIndex op1) + { + if (q) { + return decodeNeonUTwoMiscUReg<BaseQ>(size, machInst, dest, op1); + } else { + return decodeNeonUTwoMiscUSReg<BaseD>(size, machInst, dest, op1); + } + } + + template <template <typename T> class BaseD, + template <typename T> class BaseQ> + StaticInstPtr + decodeNeonSTwoMiscXReg(bool q, unsigned size, ExtMachInst machInst, + IntRegIndex dest, IntRegIndex op1) + { + if (q) { + return decodeNeonSTwoMiscUReg<BaseQ>(size, machInst, dest, op1); + } else { + return decodeNeonSTwoMiscUSReg<BaseD>(size, machInst, dest, op1); + } + } + + template <template <typename T> class BaseD, + template <typename T> class BaseQ> + StaticInstPtr + decodeNeonUTwoMiscFpReg(bool q, unsigned size, ExtMachInst machInst, + IntRegIndex dest, IntRegIndex op1) + { + if (q) { + if (size) + return new BaseQ<uint64_t>(machInst, dest, op1); + else + return new BaseQ<uint32_t>(machInst, dest, op1); + } else { + if (size) + return new Unknown(machInst); + else + return new BaseD<uint32_t>(machInst, dest, op1); + } + } + + template <template <typename T> class BaseD, + template <typename T> class BaseQ> + StaticInstPtr + decodeNeonUTwoMiscPwiseScFpReg(unsigned size, ExtMachInst machInst, + IntRegIndex dest, IntRegIndex op1) + { + if (size) + return new BaseQ<uint64_t>(machInst, dest, op1); + else + return new BaseD<uint32_t>(machInst, dest, op1); + } + + template <template <typename T> class Base> + StaticInstPtr + decodeNeonUTwoMiscScFpReg(unsigned size, ExtMachInst machInst, + IntRegIndex dest, IntRegIndex op1) + { + if (size) + return new Base<uint64_t>(machInst, dest, op1); + else + return new Base<uint32_t>(machInst, dest, op1); + } + + template <template <typename T> class BaseD, + template <typename T> class BaseQ> + StaticInstPtr + decodeNeonUAcrossLanesReg(bool q, unsigned size, ExtMachInst machInst, + IntRegIndex dest, IntRegIndex op1) + { + if (q) { + switch (size) { + case 0x0: + return new BaseQ<uint8_t>(machInst, dest, op1); + case 0x1: + return new BaseQ<uint16_t>(machInst, dest, op1); + case 0x2: + return new BaseQ<uint32_t>(machInst, dest, op1); + default: + return new Unknown(machInst); + } + } else { + switch (size) { + case 0x0: + return new BaseD<uint8_t>(machInst, dest, op1); + case 0x1: + return new BaseD<uint16_t>(machInst, dest, op1); + default: + return new Unknown(machInst); + } + } + } + + template <template <typename T> class BaseD, + template <typename T> class BaseQ, + template <typename T> class BaseBQ> + StaticInstPtr + decodeNeonUAcrossLanesReg(bool q, unsigned size, ExtMachInst machInst, + IntRegIndex dest, IntRegIndex op1) + { + if (q) { + switch (size) { + case 0x0: + return new BaseQ<uint8_t>(machInst, dest, op1); + case 0x1: + return new BaseQ<uint16_t>(machInst, dest, op1); + case 0x2: + return new BaseBQ<uint32_t>(machInst, dest, op1); + default: + return new Unknown(machInst); + } + } else { + switch (size) { + case 0x0: + return new BaseD<uint8_t>(machInst, dest, op1); + case 0x1: + return new BaseD<uint16_t>(machInst, dest, op1); + default: + return new Unknown(machInst); + } + } + } + + template <template <typename T> class BaseD, + template <typename T> class BaseQ> + StaticInstPtr + decodeNeonSAcrossLanesReg(bool q, unsigned size, ExtMachInst machInst, + IntRegIndex dest, IntRegIndex op1) + { + if (q) { + switch (size) { + case 0x0: + return new BaseQ<int8_t>(machInst, dest, op1); + case 0x1: + return new BaseQ<int16_t>(machInst, dest, op1); + case 0x2: + return new BaseQ<int32_t>(machInst, dest, op1); + default: + return new Unknown(machInst); + } + } else { + switch (size) { + case 0x0: + return new BaseD<int8_t>(machInst, dest, op1); + case 0x1: + return new BaseD<int16_t>(machInst, dest, op1); + default: + return new Unknown(machInst); + } + } + } + + template <template <typename T> class BaseD, + template <typename T> class BaseQ, + template <typename T> class BaseBQ> + StaticInstPtr + decodeNeonUAcrossLanesLongReg(bool q, unsigned size, ExtMachInst machInst, + IntRegIndex dest, IntRegIndex op1) + { + if (q) { + switch (size) { + case 0x0: + return new BaseQ<uint8_t>(machInst, dest, op1); + case 0x1: + return new BaseQ<uint16_t>(machInst, dest, op1); + case 0x2: + return new BaseBQ<uint32_t>(machInst, dest, op1); + default: + return new Unknown(machInst); + } + } else { + switch (size) { + case 0x0: + return new BaseD<uint8_t>(machInst, dest, op1); + case 0x1: + return new BaseD<uint16_t>(machInst, dest, op1); + default: + return new Unknown(machInst); + } + } + } + + template <template <typename T> class BaseD, + template <typename T> class BaseQ, + template <typename T> class BaseBQ> + StaticInstPtr + decodeNeonSAcrossLanesLongReg(bool q, unsigned size, ExtMachInst machInst, + IntRegIndex dest, IntRegIndex op1) + { + if (q) { + switch (size) { + case 0x0: + return new BaseQ<int8_t>(machInst, dest, op1); + case 0x1: + return new BaseQ<int16_t>(machInst, dest, op1); + case 0x2: + return new BaseBQ<int32_t>(machInst, dest, op1); + default: + return new Unknown(machInst); + } + } else { + switch (size) { + case 0x0: + return new BaseD<int8_t>(machInst, dest, op1); + case 0x1: + return new BaseD<int16_t>(machInst, dest, op1); + default: + return new Unknown(machInst); + } + } + } }}; output exec {{ @@ -872,10 +1369,7 @@ let {{ readDestCode = 'destElem = gtoh(destReg.elements[i]);' eWalkCode += ''' if (imm < 0 && imm >= eCount) { - if (FullSystem) - fault = new UndefinedInstruction; - else - fault = new UndefinedInstruction(false, mnemonic); + fault = new UndefinedInstruction(machInst, false, mnemonic); } else { for (unsigned i = 0; i < eCount; i++) { Element srcElem1 = gtoh(srcReg1.elements[i]); @@ -926,10 +1420,7 @@ let {{ readDestCode = 'destElem = gtoh(destReg.elements[i]);' eWalkCode += ''' if (imm < 0 && imm >= eCount) { - if (FullSystem) - fault = new UndefinedInstruction; - else - fault = new UndefinedInstruction(false, mnemonic); + fault = new UndefinedInstruction(machInst, false, mnemonic); } else { for (unsigned i = 0; i < eCount; i++) { Element srcElem1 = gtoh(srcReg1.elements[i]); @@ -978,10 +1469,7 @@ let {{ readDestCode = 'destReg = destRegs[i];' eWalkCode += ''' if (imm < 0 && imm >= eCount) { - if (FullSystem) - fault = new UndefinedInstruction; - else - fault = new UndefinedInstruction(false, mnemonic); + fault = new UndefinedInstruction(machInst, false, mnemonic); } else { for (unsigned i = 0; i < rCount; i++) { FloatReg srcReg1 = srcRegs1[i]; @@ -2156,7 +2644,7 @@ let {{ bool done; destReg = processNans(fpscr, done, true, srcReg1, srcReg2); if (!done) { - destReg = binaryOp(fpscr, srcReg1, srcReg2, fpMaxS, + destReg = binaryOp(fpscr, srcReg1, srcReg2, fpMax<float>, true, true, VfpRoundNearest); } else if (flushToZero(srcReg1, srcReg2)) { fpscr.idc = 1; @@ -2171,7 +2659,7 @@ let {{ bool done; destReg = processNans(fpscr, done, true, srcReg1, srcReg2); if (!done) { - destReg = binaryOp(fpscr, srcReg1, srcReg2, fpMinS, + destReg = binaryOp(fpscr, srcReg1, srcReg2, fpMin<float>, true, true, VfpRoundNearest); } else if (flushToZero(srcReg1, srcReg2)) { fpscr.idc = 1; @@ -2234,6 +2722,24 @@ let {{ threeEqualRegInstFp("vmla", "NVmlaDFp", "SimdFloatMultAccOp", ("float",), 2, vmlafpCode, True) threeEqualRegInstFp("vmla", "NVmlaQFp", "SimdFloatMultAccOp", ("float",), 4, vmlafpCode, True) + vfmafpCode = ''' + FPSCR fpscr = (FPSCR) FpscrExc; + destReg = ternaryOp(fpscr, srcReg1, srcReg2, destReg, fpMulAdd<float>, + true, true, VfpRoundNearest); + FpscrExc = fpscr; + ''' + threeEqualRegInstFp("vfma", "NVfmaDFp", "SimdFloatMultAccOp", ("float",), 2, vfmafpCode, True) + threeEqualRegInstFp("vfma", "NVfmaQFp", "SimdFloatMultAccOp", ("float",), 4, vfmafpCode, True) + + vfmsfpCode = ''' + FPSCR fpscr = (FPSCR) FpscrExc; + destReg = ternaryOp(fpscr, -srcReg1, srcReg2, destReg, fpMulAdd<float>, + true, true, VfpRoundNearest); + FpscrExc = fpscr; + ''' + threeEqualRegInstFp("vfms", "NVfmsDFp", "SimdFloatMultAccOp", ("float",), 2, vfmsfpCode, True) + threeEqualRegInstFp("vfms", "NVfmsQFp", "SimdFloatMultAccOp", ("float",), 4, vfmsfpCode, True) + vmlsfpCode = ''' FPSCR fpscr = (FPSCR) FpscrExc; float mid = binaryOp(fpscr, srcReg1, srcReg2, fpMulS, @@ -2765,7 +3271,7 @@ let {{ fpscr.idc = 1; VfpSavedState state = prepFpState(VfpRoundNearest); __asm__ __volatile__("" : "=m" (srcElem1) : "m" (srcElem1)); - destReg = vfpFpSToFixed(srcElem1, false, false, imm); + destReg = vfpFpToFixed<float>(srcElem1, false, 32, imm); __asm__ __volatile__("" :: "m" (destReg)); finishVfp(fpscr, state, true); FpscrExc = fpscr; @@ -2781,7 +3287,7 @@ let {{ fpscr.idc = 1; VfpSavedState state = prepFpState(VfpRoundNearest); __asm__ __volatile__("" : "=m" (srcElem1) : "m" (srcElem1)); - destReg = vfpFpSToFixed(srcElem1, true, false, imm); + destReg = vfpFpToFixed<float>(srcElem1, true, 32, imm); __asm__ __volatile__("" :: "m" (destReg)); finishVfp(fpscr, state, true); FpscrExc = fpscr; @@ -2795,7 +3301,7 @@ let {{ FPSCR fpscr = (FPSCR) FpscrExc; VfpSavedState state = prepFpState(VfpRoundNearest); __asm__ __volatile__("" : "=m" (srcReg1) : "m" (srcReg1)); - destElem = vfpUFixedToFpS(true, true, srcReg1, false, imm); + destElem = vfpUFixedToFpS(true, true, srcReg1, 32, imm); __asm__ __volatile__("" :: "m" (destElem)); finishVfp(fpscr, state, true); FpscrExc = fpscr; @@ -2809,7 +3315,7 @@ let {{ FPSCR fpscr = (FPSCR) FpscrExc; VfpSavedState state = prepFpState(VfpRoundNearest); __asm__ __volatile__("" : "=m" (srcReg1) : "m" (srcReg1)); - destElem = vfpSFixedToFpS(true, true, srcReg1, false, imm); + destElem = vfpSFixedToFpS(true, true, srcReg1, 32, imm); __asm__ __volatile__("" :: "m" (destElem)); finishVfp(fpscr, state, true); FpscrExc = fpscr; @@ -3296,10 +3802,7 @@ let {{ } else { index -= eCount; if (index >= eCount) { - if (FullSystem) - fault = new UndefinedInstruction; - else - fault = new UndefinedInstruction(false, mnemonic); + fault = new UndefinedInstruction(machInst, false, mnemonic); } else { destReg.elements[i] = srcReg2.elements[index]; } diff --git a/src/arch/arm/isa/insts/neon64.isa b/src/arch/arm/isa/insts/neon64.isa new file mode 100644 index 000000000..e065761f4 --- /dev/null +++ b/src/arch/arm/isa/insts/neon64.isa @@ -0,0 +1,3355 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2012-2013 ARM Limited +// All rights reserved +// +// The license below extends only to copyright in the software and shall +// not be construed as granting a license to any other intellectual +// property including but not limited to intellectual property relating +// to a hardware implementation of the functionality of the software +// licensed hereunder. You may use the software subject to the license +// terms below provided that you ensure that this notice is replicated +// unmodified and in its entirety in all distributions of the software, +// modified or unmodified, in source code or in binary form. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Giacomo Gabrielli +// Mbou Eyole + +let {{ + + header_output = "" + exec_output = "" + + # FP types (FP operations always work with unsigned representations) + floatTypes = ("uint32_t", "uint64_t") + smallFloatTypes = ("uint32_t",) + + def threeEqualRegInstX(name, Name, opClass, types, rCount, op, + readDest=False, pairwise=False, scalar=False, + byElem=False): + assert (not pairwise) or ((not byElem) and (not scalar)) + global header_output, exec_output + eWalkCode = simd64EnabledCheckCode + ''' + RegVect srcReg1, destReg; + ''' + if byElem: + # 2nd register operand has to be read fully + eWalkCode += ''' + FullRegVect srcReg2; + ''' + else: + eWalkCode += ''' + RegVect srcReg2; + ''' + for reg in range(rCount): + eWalkCode += ''' + srcReg1.regs[%(reg)d] = htog(AA64FpOp1P%(reg)d_uw); + srcReg2.regs[%(reg)d] = htog(AA64FpOp2P%(reg)d_uw); + ''' % { "reg" : reg } + if readDest: + eWalkCode += ''' + destReg.regs[%(reg)d] = htog(AA64FpDestP%(reg)d_uw); + ''' % { "reg" : reg } + if byElem: + # 2nd operand has to be read fully + for reg in range(rCount, 4): + eWalkCode += ''' + srcReg2.regs[%(reg)d] = htog(AA64FpOp2P%(reg)d_uw); + ''' % { "reg" : reg } + readDestCode = '' + if readDest: + readDestCode = 'destElem = gtoh(destReg.elements[i]);' + if pairwise: + eWalkCode += ''' + for (unsigned i = 0; i < eCount; i++) { + Element srcElem1 = gtoh(2 * i < eCount ? + srcReg1.elements[2 * i] : + srcReg2.elements[2 * i - eCount]); + Element srcElem2 = gtoh(2 * i < eCount ? + srcReg1.elements[2 * i + 1] : + srcReg2.elements[2 * i + 1 - eCount]); + Element destElem; + %(readDest)s + %(op)s + destReg.elements[i] = htog(destElem); + } + ''' % { "op" : op, "readDest" : readDestCode } + else: + scalarCheck = ''' + if (i != 0) { + destReg.elements[i] = 0; + continue; + } + ''' + eWalkCode += ''' + for (unsigned i = 0; i < eCount; i++) { + %(scalarCheck)s + Element srcElem1 = gtoh(srcReg1.elements[i]); + Element srcElem2 = gtoh(srcReg2.elements[%(src2Index)s]); + Element destElem; + %(readDest)s + %(op)s + destReg.elements[i] = htog(destElem); + } + ''' % { "op" : op, "readDest" : readDestCode, + "scalarCheck" : scalarCheck if scalar else "", + "src2Index" : "imm" if byElem else "i" } + for reg in range(rCount): + eWalkCode += ''' + AA64FpDestP%(reg)d_uw = gtoh(destReg.regs[%(reg)d]); + ''' % { "reg" : reg } + if rCount < 4: # zero upper half + for reg in range(rCount, 4): + eWalkCode += ''' + AA64FpDestP%(reg)d_uw = 0; + ''' % { "reg" : reg } + iop = InstObjParams(name, Name, + "DataX2RegImmOp" if byElem else "DataX2RegOp", + { "code": eWalkCode, + "r_count": rCount, + "op_class": opClass }, []) + if byElem: + header_output += NeonX2RegImmOpDeclare.subst(iop) + else: + header_output += NeonX2RegOpDeclare.subst(iop) + exec_output += NeonXEqualRegOpExecute.subst(iop) + for type in types: + substDict = { "targs" : type, + "class_name" : Name } + exec_output += NeonXExecDeclare.subst(substDict) + + def threeUnequalRegInstX(name, Name, opClass, types, op, + bigSrc1, bigSrc2, bigDest, readDest, scalar=False, + byElem=False, hi=False): + assert not (scalar and hi) + global header_output, exec_output + src1Cnt = src2Cnt = destCnt = 2 + src1Prefix = src2Prefix = destPrefix = '' + if bigSrc1: + src1Cnt = 4 + src1Prefix = 'Big' + if bigSrc2: + src2Cnt = 4 + src2Prefix = 'Big' + if bigDest: + destCnt = 4 + destPrefix = 'Big' + if byElem: + src2Prefix = 'Full' + eWalkCode = simd64EnabledCheckCode + ''' + %sRegVect srcReg1; + %sRegVect srcReg2; + %sRegVect destReg; + ''' % (src1Prefix, src2Prefix, destPrefix) + srcReg1 = 0 + if hi and not bigSrc1: # long/widening operations + srcReg1 = 2 + for reg in range(src1Cnt): + eWalkCode += ''' + srcReg1.regs[%(reg)d] = htog(AA64FpOp1P%(srcReg1)d_uw); + ''' % { "reg" : reg, "srcReg1" : srcReg1 } + srcReg1 += 1 + srcReg2 = 0 + if (not byElem) and (hi and not bigSrc2): # long/widening operations + srcReg2 = 2 + for reg in range(src2Cnt): + eWalkCode += ''' + srcReg2.regs[%(reg)d] = htog(AA64FpOp2P%(srcReg2)d_uw); + ''' % { "reg" : reg, "srcReg2" : srcReg2 } + srcReg2 += 1 + if byElem: + # 2nd operand has to be read fully + for reg in range(src2Cnt, 4): + eWalkCode += ''' + srcReg2.regs[%(reg)d] = htog(AA64FpOp2P%(reg)d_uw); + ''' % { "reg" : reg } + if readDest: + for reg in range(destCnt): + eWalkCode += ''' + destReg.regs[%(reg)d] = htog(AA64FpDestP%(reg)d_uw); + ''' % { "reg" : reg } + readDestCode = '' + if readDest: + readDestCode = 'destElem = gtoh(destReg.elements[i]);' + scalarCheck = ''' + if (i != 0) { + destReg.elements[i] = 0; + continue; + } + ''' + eWalkCode += ''' + for (unsigned i = 0; i < eCount; i++) { + %(scalarCheck)s + %(src1Prefix)sElement srcElem1 = gtoh(srcReg1.elements[i]); + %(src1Prefix)sElement srcElem2 = gtoh(srcReg2.elements[%(src2Index)s]); + %(destPrefix)sElement destElem; + %(readDest)s + %(op)s + destReg.elements[i] = htog(destElem); + } + ''' % { "op" : op, "readDest" : readDestCode, + "src1Prefix" : src1Prefix, "src2Prefix" : src2Prefix, + "destPrefix" : destPrefix, + "scalarCheck" : scalarCheck if scalar else "", + "src2Index" : "imm" if byElem else "i" } + destReg = 0 + if hi and not bigDest: + # narrowing operations + destReg = 2 + for reg in range(destCnt): + eWalkCode += ''' + AA64FpDestP%(destReg)d_uw = gtoh(destReg.regs[%(reg)d]); + ''' % { "reg" : reg, "destReg": destReg } + destReg += 1 + if destCnt < 4 and not hi: # zero upper half + for reg in range(destCnt, 4): + eWalkCode += ''' + AA64FpDestP%(reg)d_uw = 0; + ''' % { "reg" : reg } + iop = InstObjParams(name, Name, + "DataX2RegImmOp" if byElem else "DataX2RegOp", + { "code": eWalkCode, + "r_count": 2, + "op_class": opClass }, []) + if byElem: + header_output += NeonX2RegImmOpDeclare.subst(iop) + else: + header_output += NeonX2RegOpDeclare.subst(iop) + exec_output += NeonXUnequalRegOpExecute.subst(iop) + for type in types: + substDict = { "targs" : type, + "class_name" : Name } + exec_output += NeonXExecDeclare.subst(substDict) + + def threeRegNarrowInstX(name, Name, opClass, types, op, readDest=False, + scalar=False, byElem=False, hi=False): + assert not byElem + threeUnequalRegInstX(name, Name, opClass, types, op, + True, True, False, readDest, scalar, byElem, hi) + + def threeRegLongInstX(name, Name, opClass, types, op, readDest=False, + scalar=False, byElem=False, hi=False): + threeUnequalRegInstX(name, Name, opClass, types, op, + False, False, True, readDest, scalar, byElem, hi) + + def threeRegWideInstX(name, Name, opClass, types, op, readDest=False, + scalar=False, byElem=False, hi=False): + assert not byElem + threeUnequalRegInstX(name, Name, opClass, types, op, + True, False, True, readDest, scalar, byElem, hi) + + def twoEqualRegInstX(name, Name, opClass, types, rCount, op, + readDest=False, scalar=False, byElem=False, + hasImm=False, isDup=False): + global header_output, exec_output + assert (not isDup) or byElem + if byElem: + hasImm = True + if isDup: + eWalkCode = simd64EnabledCheckCode + ''' + FullRegVect srcReg1; + RegVect destReg; + ''' + else: + eWalkCode = simd64EnabledCheckCode + ''' + RegVect srcReg1, destReg; + ''' + for reg in range(4 if isDup else rCount): + eWalkCode += ''' + srcReg1.regs[%(reg)d] = htog(AA64FpOp1P%(reg)d_uw); + ''' % { "reg" : reg } + if readDest: + eWalkCode += ''' + destReg.regs[%(reg)d] = htog(AA64FpDestP%(reg)d_uw); + ''' % { "reg" : reg } + readDestCode = '' + if readDest: + readDestCode = 'destElem = gtoh(destReg.elements[i]);' + scalarCheck = ''' + if (i != 0) { + destReg.elements[i] = 0; + continue; + } + ''' + eWalkCode += ''' + for (unsigned i = 0; i < eCount; i++) { + %(scalarCheck)s + unsigned j = i; + Element srcElem1 = gtoh(srcReg1.elements[%(src1Index)s]); + Element destElem; + %(readDest)s + %(op)s + destReg.elements[j] = htog(destElem); + } + ''' % { "op" : op, "readDest" : readDestCode, + "scalarCheck" : scalarCheck if scalar else "", + "src1Index" : "imm" if byElem else "i" } + for reg in range(rCount): + eWalkCode += ''' + AA64FpDestP%(reg)d_uw = gtoh(destReg.regs[%(reg)d]); + ''' % { "reg" : reg } + if rCount < 4: # zero upper half + for reg in range(rCount, 4): + eWalkCode += ''' + AA64FpDestP%(reg)d_uw = 0; + ''' % { "reg" : reg } + iop = InstObjParams(name, Name, + "DataX1RegImmOp" if hasImm else "DataX1RegOp", + { "code": eWalkCode, + "r_count": rCount, + "op_class": opClass }, []) + if hasImm: + header_output += NeonX1RegImmOpDeclare.subst(iop) + else: + header_output += NeonX1RegOpDeclare.subst(iop) + exec_output += NeonXEqualRegOpExecute.subst(iop) + for type in types: + substDict = { "targs" : type, + "class_name" : Name } + exec_output += NeonXExecDeclare.subst(substDict) + + def twoRegLongInstX(name, Name, opClass, types, op, readDest=False, + hi=False, hasImm=False): + global header_output, exec_output + eWalkCode = simd64EnabledCheckCode + ''' + RegVect srcReg1; + BigRegVect destReg; + ''' + destReg = 0 if not hi else 2 + for reg in range(2): + eWalkCode += ''' + srcReg1.regs[%(reg)d] = htog(AA64FpOp1P%(destReg)d_uw); + ''' % { "reg" : reg, "destReg": destReg } + destReg += 1 + destReg = 0 if not hi else 2 + if readDest: + for reg in range(4): + eWalkCode += ''' + destReg.regs[%(reg)d] = htog(AA64FpDestP%(reg)d_uw); + ''' % { "reg" : reg } + destReg += 1 + readDestCode = '' + if readDest: + readDestCode = 'destReg = gtoh(destReg.elements[i]);' + eWalkCode += ''' + for (unsigned i = 0; i < eCount; i++) { + Element srcElem1 = gtoh(srcReg1.elements[i]); + BigElement destElem; + %(readDest)s + %(op)s + destReg.elements[i] = htog(destElem); + } + ''' % { "op" : op, "readDest" : readDestCode } + for reg in range(4): + eWalkCode += ''' + AA64FpDestP%(reg)d_uw = gtoh(destReg.regs[%(reg)d]); + ''' % { "reg" : reg } + iop = InstObjParams(name, Name, + "DataX1RegImmOp" if hasImm else "DataX1RegOp", + { "code": eWalkCode, + "r_count": 2, + "op_class": opClass }, []) + if hasImm: + header_output += NeonX1RegImmOpDeclare.subst(iop) + else: + header_output += NeonX1RegOpDeclare.subst(iop) + exec_output += NeonXUnequalRegOpExecute.subst(iop) + for type in types: + substDict = { "targs" : type, + "class_name" : Name } + exec_output += NeonXExecDeclare.subst(substDict) + + def twoRegNarrowInstX(name, Name, opClass, types, op, readDest=False, + scalar=False, hi=False, hasImm=False): + global header_output, exec_output + eWalkCode = simd64EnabledCheckCode + ''' + BigRegVect srcReg1; + RegVect destReg; + ''' + for reg in range(4): + eWalkCode += ''' + srcReg1.regs[%(reg)d] = htog(AA64FpOp1P%(reg)d_uw); + ''' % { "reg" : reg } + if readDest: + for reg in range(2): + eWalkCode += ''' + destReg.regs[%(reg)d] = htog(AA64FpDestP%(reg)d_uw); + ''' % { "reg" : reg } + else: + eWalkCode += ''' + destReg.elements[0] = 0; + ''' % { "reg" : reg } + readDestCode = '' + if readDest: + readDestCode = 'destElem = gtoh(destReg.elements[i]);' + scalarCheck = ''' + if (i != 0) { + destReg.elements[i] = 0; + continue; + } + ''' + eWalkCode += ''' + for (unsigned i = 0; i < eCount; i++) { + %(scalarCheck)s + BigElement srcElem1 = gtoh(srcReg1.elements[i]); + Element destElem; + %(readDest)s + %(op)s + destReg.elements[i] = htog(destElem); + } + ''' % { "op" : op, "readDest" : readDestCode, + "scalarCheck" : scalarCheck if scalar else "" } + destReg = 0 if not hi else 2 + for reg in range(2): + eWalkCode += ''' + AA64FpDestP%(destReg)d_uw = gtoh(destReg.regs[%(reg)d]); + ''' % { "reg" : reg, "destReg": destReg } + destReg += 1 + if not hi: + for reg in range(2, 4): # zero upper half + eWalkCode += ''' + AA64FpDestP%(reg)d_uw = 0; + ''' % { "reg" : reg } + iop = InstObjParams(name, Name, + "DataX1RegImmOp" if hasImm else "DataX1RegOp", + { "code": eWalkCode, + "r_count": 2, + "op_class": opClass }, []) + if hasImm: + header_output += NeonX1RegImmOpDeclare.subst(iop) + else: + header_output += NeonX1RegOpDeclare.subst(iop) + exec_output += NeonXUnequalRegOpExecute.subst(iop) + for type in types: + substDict = { "targs" : type, + "class_name" : Name } + exec_output += NeonXExecDeclare.subst(substDict) + + def threeRegScrambleInstX(name, Name, opClass, types, rCount, op): + global header_output, exec_output + eWalkCode = simd64EnabledCheckCode + ''' + RegVect srcReg1, srcReg2, destReg; + ''' + for reg in range(rCount): + eWalkCode += ''' + srcReg1.regs[%(reg)d] = htog(AA64FpOp1P%(reg)d_uw); + srcReg2.regs[%(reg)d] = htog(AA64FpOp2P%(reg)d_uw); + ''' % { "reg" : reg } + eWalkCode += op + for reg in range(rCount): + eWalkCode += ''' + AA64FpDestP%(reg)d_uw = gtoh(destReg.regs[%(reg)d]); + ''' % { "reg" : reg } + if rCount < 4: + for reg in range(rCount, 4): + eWalkCode += ''' + AA64FpDestP%(reg)d_uw = 0; + ''' % { "reg" : reg } + iop = InstObjParams(name, Name, + "DataX2RegOp", + { "code": eWalkCode, + "r_count": rCount, + "op_class": opClass }, []) + header_output += NeonX2RegOpDeclare.subst(iop) + exec_output += NeonXEqualRegOpExecute.subst(iop) + for type in types: + substDict = { "targs" : type, + "class_name" : Name } + exec_output += NeonXExecDeclare.subst(substDict) + + def insFromVecElemInstX(name, Name, opClass, types, rCount): + global header_output, exec_output + eWalkCode = simd64EnabledCheckCode + ''' + FullRegVect srcReg1; + RegVect destReg; + ''' + for reg in range(4): + eWalkCode += ''' + srcReg1.regs[%(reg)d] = htog(AA64FpOp1P%(reg)d_uw); + ''' % { "reg" : reg } + for reg in range(rCount): + eWalkCode += ''' + destReg.regs[%(reg)d] = htog(AA64FpDestP%(reg)d_uw); + ''' % { "reg" : reg } + eWalkCode += ''' + Element srcElem1 = gtoh(srcReg1.elements[imm2]); + Element destElem = srcElem1; + destReg.elements[imm1] = htog(destElem); + ''' + for reg in range(rCount): + eWalkCode += ''' + AA64FpDestP%(reg)d_uw = gtoh(destReg.regs[%(reg)d]); + ''' % { "reg" : reg } + iop = InstObjParams(name, Name, + "DataX1Reg2ImmOp", + { "code": eWalkCode, + "r_count": rCount, + "op_class": opClass }, []) + header_output += NeonX1Reg2ImmOpDeclare.subst(iop) + exec_output += NeonXEqualRegOpExecute.subst(iop) + for type in types: + substDict = { "targs" : type, + "class_name" : Name } + exec_output += NeonXExecDeclare.subst(substDict) + + def twoRegPairwiseScInstX(name, Name, opClass, types, rCount, op): + global header_output, exec_output + eWalkCode = simd64EnabledCheckCode + ''' + RegVect srcReg1, destReg; + ''' + for reg in range(rCount): + eWalkCode += ''' + srcReg1.regs[%(reg)d] = htog(AA64FpOp1P%(reg)d_uw); + ''' % { "reg" : reg } + eWalkCode += ''' + Element srcElem1 = gtoh(srcReg1.elements[0]); + Element srcElem2 = gtoh(srcReg1.elements[1]); + Element destElem; + %(op)s + destReg.elements[0] = htog(destElem); + ''' % { "op" : op } + destCnt = rCount / 2 + for reg in range(destCnt): + eWalkCode += ''' + AA64FpDestP%(reg)d_uw = gtoh(destReg.regs[%(reg)d]); + ''' % { "reg" : reg } + for reg in range(destCnt, 4): # zero upper half + eWalkCode += ''' + AA64FpDestP%(reg)d_uw = 0; + ''' % { "reg" : reg } + iop = InstObjParams(name, Name, + "DataX1RegOp", + { "code": eWalkCode, + "r_count": rCount, + "op_class": opClass }, []) + header_output += NeonX1RegOpDeclare.subst(iop) + exec_output += NeonXEqualRegOpExecute.subst(iop) + for type in types: + substDict = { "targs" : type, + "class_name" : Name } + exec_output += NeonXExecDeclare.subst(substDict) + + def twoRegAcrossInstX(name, Name, opClass, types, rCount, op, + doubleDest=False, long=False): + global header_output, exec_output + destPrefix = "Big" if long else "" + eWalkCode = simd64EnabledCheckCode + ''' + RegVect srcReg1; + %sRegVect destReg; + ''' % destPrefix + for reg in range(rCount): + eWalkCode += ''' + srcReg1.regs[%(reg)d] = htog(AA64FpOp1P%(reg)d_uw); + ''' % { "reg" : reg } + eWalkCode += ''' + destReg.regs[0] = 0; + %(destPrefix)sElement destElem = 0; + for (unsigned i = 0; i < eCount; i++) { + Element srcElem1 = gtoh(srcReg1.elements[i]); + if (i == 0) { + destElem = srcElem1; + } else { + %(op)s + } + } + destReg.elements[0] = htog(destElem); + ''' % { "op" : op, "destPrefix" : destPrefix } + destCnt = 2 if doubleDest else 1 + for reg in range(destCnt): + eWalkCode += ''' + AA64FpDestP%(reg)d_uw = gtoh(destReg.regs[%(reg)d]); + ''' % { "reg" : reg } + for reg in range(destCnt, 4): # zero upper half + eWalkCode += ''' + AA64FpDestP%(reg)d_uw = 0; + ''' % { "reg" : reg } + iop = InstObjParams(name, Name, + "DataX1RegOp", + { "code": eWalkCode, + "r_count": rCount, + "op_class": opClass }, []) + header_output += NeonX1RegOpDeclare.subst(iop) + if long: + exec_output += NeonXUnequalRegOpExecute.subst(iop) + else: + exec_output += NeonXEqualRegOpExecute.subst(iop) + for type in types: + substDict = { "targs" : type, + "class_name" : Name } + exec_output += NeonXExecDeclare.subst(substDict) + + def twoRegCondenseInstX(name, Name, opClass, types, rCount, op, + readDest=False): + global header_output, exec_output + eWalkCode = simd64EnabledCheckCode + ''' + RegVect srcRegs; + BigRegVect destReg; + ''' + for reg in range(rCount): + eWalkCode += ''' + srcRegs.regs[%(reg)d] = htog(AA64FpOp1P%(reg)d_uw); + ''' % { "reg" : reg } + if readDest: + eWalkCode += ''' + destReg.regs[%(reg)d] = htog(AA64FpDestP%(reg)d_uw); + ''' % { "reg" : reg } + readDestCode = '' + if readDest: + readDestCode = 'destElem = gtoh(destReg.elements[i]);' + eWalkCode += ''' + for (unsigned i = 0; i < eCount / 2; i++) { + Element srcElem1 = gtoh(srcRegs.elements[2 * i]); + Element srcElem2 = gtoh(srcRegs.elements[2 * i + 1]); + BigElement destElem; + %(readDest)s + %(op)s + destReg.elements[i] = htog(destElem); + } + ''' % { "op" : op, "readDest" : readDestCode } + for reg in range(rCount): + eWalkCode += ''' + AA64FpDestP%(reg)d_uw = gtoh(destReg.regs[%(reg)d]); + ''' % { "reg" : reg } + if rCount < 4: # zero upper half + for reg in range(rCount, 4): + eWalkCode += ''' + AA64FpDestP%(reg)d_uw = 0; + ''' % { "reg" : reg } + iop = InstObjParams(name, Name, + "DataX1RegOp", + { "code": eWalkCode, + "r_count": rCount, + "op_class": opClass }, []) + header_output += NeonX1RegOpDeclare.subst(iop) + exec_output += NeonXUnequalRegOpExecute.subst(iop) + for type in types: + substDict = { "targs" : type, + "class_name" : Name } + exec_output += NeonXExecDeclare.subst(substDict) + + def oneRegImmInstX(name, Name, opClass, types, rCount, op, readDest=False): + global header_output, exec_output + eWalkCode = simd64EnabledCheckCode + ''' + RegVect destReg; + ''' + if readDest: + for reg in range(rCount): + eWalkCode += ''' + destReg.regs[%(reg)d] = htog(AA64FpDestP%(reg)d_uw); + ''' % { "reg" : reg } + readDestCode = '' + if readDest: + readDestCode = 'destElem = gtoh(destReg.elements[i]);' + eWalkCode += ''' + for (unsigned i = 0; i < eCount; i++) { + Element destElem; + %(readDest)s + %(op)s + destReg.elements[i] = htog(destElem); + } + ''' % { "op" : op, "readDest" : readDestCode } + for reg in range(rCount): + eWalkCode += ''' + AA64FpDestP%(reg)d_uw = gtoh(destReg.regs[%(reg)d]); + ''' % { "reg" : reg } + if rCount < 4: # zero upper half + for reg in range(rCount, 4): + eWalkCode += ''' + AA64FpDestP%(reg)d_uw = 0; + ''' % { "reg" : reg } + iop = InstObjParams(name, Name, + "DataXImmOnlyOp", + { "code": eWalkCode, + "r_count": rCount, + "op_class": opClass }, []) + header_output += NeonX1RegImmOnlyOpDeclare.subst(iop) + exec_output += NeonXEqualRegOpExecute.subst(iop) + for type in types: + substDict = { "targs" : type, + "class_name" : Name } + exec_output += NeonXExecDeclare.subst(substDict) + + def dupGprInstX(name, Name, opClass, types, rCount, gprSpec): + global header_output, exec_output + eWalkCode = simd64EnabledCheckCode + ''' + RegVect destReg; + for (unsigned i = 0; i < eCount; i++) { + destReg.elements[i] = htog((Element) %sOp1); + } + ''' % gprSpec + for reg in range(rCount): + eWalkCode += ''' + AA64FpDestP%(reg)d_uw = gtoh(destReg.regs[%(reg)d]); + ''' % { "reg" : reg } + if rCount < 4: # zero upper half + for reg in range(rCount, 4): + eWalkCode += ''' + AA64FpDestP%(reg)d_uw = 0; + ''' % { "reg" : reg } + iop = InstObjParams(name, Name, + "DataX1RegOp", + { "code": eWalkCode, + "r_count": rCount, + "op_class": opClass }, []) + header_output += NeonX1RegOpDeclare.subst(iop) + exec_output += NeonXEqualRegOpExecute.subst(iop) + for type in types: + substDict = { "targs" : type, + "class_name" : Name } + exec_output += NeonXExecDeclare.subst(substDict) + + def extInstX(name, Name, opClass, types, rCount, op): + global header_output, exec_output + eWalkCode = simd64EnabledCheckCode + ''' + RegVect srcReg1, srcReg2, destReg; + ''' + for reg in range(rCount): + eWalkCode += ''' + srcReg1.regs[%(reg)d] = htog(AA64FpOp1P%(reg)d_uw); + srcReg2.regs[%(reg)d] = htog(AA64FpOp2P%(reg)d_uw); + ''' % { "reg" : reg } + eWalkCode += op + for reg in range(rCount): + eWalkCode += ''' + AA64FpDestP%(reg)d_uw = gtoh(destReg.regs[%(reg)d]); + ''' % { "reg" : reg } + if rCount < 4: # zero upper half + for reg in range(rCount, 4): + eWalkCode += ''' + AA64FpDestP%(reg)d_uw = 0; + ''' % { "reg" : reg } + iop = InstObjParams(name, Name, + "DataX2RegImmOp", + { "code": eWalkCode, + "r_count": rCount, + "op_class": opClass }, []) + header_output += NeonX2RegImmOpDeclare.subst(iop) + exec_output += NeonXEqualRegOpExecute.subst(iop) + for type in types: + substDict = { "targs" : type, + "class_name" : Name } + exec_output += NeonXExecDeclare.subst(substDict) + + def insFromGprInstX(name, Name, opClass, types, rCount, gprSpec): + global header_output, exec_output + eWalkCode = simd64EnabledCheckCode + ''' + RegVect destReg; + ''' + for reg in range(rCount): + eWalkCode += ''' + destReg.regs[%(reg)d] = htog(AA64FpDestP%(reg)d_uw); + ''' % { "reg" : reg } + eWalkCode += ''' + destReg.elements[imm] = htog((Element) %sOp1); + ''' % gprSpec + for reg in range(rCount): + eWalkCode += ''' + AA64FpDestP%(reg)d_uw = gtoh(destReg.regs[%(reg)d]); + ''' % { "reg" : reg } + iop = InstObjParams(name, Name, + "DataX1RegImmOp", + { "code": eWalkCode, + "r_count": rCount, + "op_class": opClass }, []) + header_output += NeonX1RegImmOpDeclare.subst(iop) + exec_output += NeonXEqualRegOpExecute.subst(iop) + for type in types: + substDict = { "targs" : type, + "class_name" : Name } + exec_output += NeonXExecDeclare.subst(substDict) + + def insToGprInstX(name, Name, opClass, types, rCount, gprSpec, + signExt=False): + global header_output, exec_output + eWalkCode = simd64EnabledCheckCode + ''' + FullRegVect srcReg; + ''' + for reg in range(4): + eWalkCode += ''' + srcReg.regs[%(reg)d] = htog(AA64FpOp1P%(reg)d_uw); + ''' % { "reg" : reg } + if signExt: + eWalkCode += ''' + %sDest = sext<sizeof(Element) * 8>(srcReg.elements[imm]); + ''' % gprSpec + else: + eWalkCode += ''' + %sDest = srcReg.elements[imm]; + ''' % gprSpec + iop = InstObjParams(name, Name, + "DataX1RegImmOp", + { "code": eWalkCode, + "r_count": rCount, + "op_class": opClass }, []) + header_output += NeonX1RegImmOpDeclare.subst(iop) + exec_output += NeonXEqualRegOpExecute.subst(iop) + for type in types: + substDict = { "targs" : type, + "class_name" : Name } + exec_output += NeonXExecDeclare.subst(substDict) + + def tbxTblInstX(name, Name, opClass, types, length, isTbl, rCount): + global header_output, decoder_output, exec_output + code = simd64EnabledCheckCode + ''' + union + { + uint8_t bytes[64]; + FloatRegBits regs[16]; + } table; + + union + { + uint8_t bytes[%(rCount)d * 4]; + FloatRegBits regs[%(rCount)d]; + } destReg, srcReg2; + + const unsigned length = %(length)d; + const bool isTbl = %(isTbl)s; + ''' % { "rCount" : rCount, "length" : length, "isTbl" : isTbl } + for reg in range(rCount): + code += ''' + srcReg2.regs[%(reg)d] = htog(AA64FpOp2P%(reg)d_uw); + destReg.regs[%(reg)d] = htog(AA64FpDestP%(reg)d_uw); + ''' % { "reg" : reg } + for reg in range(16): + if reg < length * 4: + code += ''' + table.regs[%(reg)d] = htog(AA64FpOp1P%(p)dV%(v)dS_uw); + ''' % { "reg" : reg, "p" : reg % 4, "v" : reg / 4 } + else: + code += ''' + table.regs[%(reg)d] = 0; + ''' % { "reg" : reg } + code += ''' + for (unsigned i = 0; i < sizeof(destReg); i++) { + uint8_t index = srcReg2.bytes[i]; + if (index < 16 * length) { + destReg.bytes[i] = table.bytes[index]; + } else { + if (isTbl) + destReg.bytes[i] = 0; + // else destReg.bytes[i] unchanged + } + } + ''' + for reg in range(rCount): + code += ''' + AA64FpDestP%(reg)d_uw = gtoh(destReg.regs[%(reg)d]); + ''' % { "reg" : reg } + if rCount < 4: # zero upper half + for reg in range(rCount, 4): + code += ''' + AA64FpDestP%(reg)d_uw = 0; + ''' % { "reg" : reg } + iop = InstObjParams(name, Name, + "DataX2RegOp", + { "code": code, + "r_count": rCount, + "op_class": opClass }, []) + header_output += NeonX2RegOpDeclare.subst(iop) + exec_output += NeonXEqualRegOpExecute.subst(iop) + for type in types: + substDict = { "targs" : type, + "class_name" : Name } + exec_output += NeonXExecDeclare.subst(substDict) + + # ABS + absCode = ''' + if (srcElem1 < 0) { + destElem = -srcElem1; + } else { + destElem = srcElem1; + } + ''' + twoEqualRegInstX("abs", "AbsDX", "SimdAluOp", signedTypes, 2, absCode) + twoEqualRegInstX("abs", "AbsQX", "SimdAluOp", signedTypes, 4, absCode) + # ADD + addCode = "destElem = srcElem1 + srcElem2;" + threeEqualRegInstX("add", "AddDX", "SimdAddOp", unsignedTypes, 2, addCode) + threeEqualRegInstX("add", "AddQX", "SimdAddOp", unsignedTypes, 4, addCode) + # ADDHN, ADDHN2 + addhnCode = ''' + destElem = ((BigElement)srcElem1 + (BigElement)srcElem2) >> + (sizeof(Element) * 8); + ''' + threeRegNarrowInstX("addhn", "AddhnX", "SimdAddOp", smallUnsignedTypes, + addhnCode) + threeRegNarrowInstX("addhn2", "Addhn2X", "SimdAddOp", smallUnsignedTypes, + addhnCode, hi=True) + # ADDP (scalar) + twoRegPairwiseScInstX("addp", "AddpScQX", "SimdAddOp", ("uint64_t",), 4, + addCode) + # ADDP (vector) + threeEqualRegInstX("addp", "AddpDX", "SimdAddOp", smallUnsignedTypes, 2, + addCode, pairwise=True) + threeEqualRegInstX("addp", "AddpQX", "SimdAddOp", unsignedTypes, 4, + addCode, pairwise=True) + # ADDV + # Note: SimdAddOp can be a bit optimistic here + addAcrossCode = "destElem += srcElem1;" + twoRegAcrossInstX("addv", "AddvDX", "SimdAddOp", ("uint8_t", "uint16_t"), + 2, addAcrossCode) + twoRegAcrossInstX("addv", "AddvQX", "SimdAddOp", smallUnsignedTypes, 4, + addAcrossCode) + # AND + andCode = "destElem = srcElem1 & srcElem2;" + threeEqualRegInstX("and", "AndDX", "SimdAluOp", ("uint64_t",), 2, andCode) + threeEqualRegInstX("and", "AndQX", "SimdAluOp", ("uint64_t",), 4, andCode) + # BIC (immediate) + bicImmCode = "destElem &= ~imm;" + oneRegImmInstX("bic", "BicImmDX", "SimdAluOp", ("uint64_t",), 2, + bicImmCode, True) + oneRegImmInstX("bic", "BicImmQX", "SimdAluOp", ("uint64_t",), 4, + bicImmCode, True) + # BIC (register) + bicCode = "destElem = srcElem1 & ~srcElem2;" + threeEqualRegInstX("bic", "BicDX", "SimdAluOp", ("uint64_t",), 2, bicCode) + threeEqualRegInstX("bic", "BicQX", "SimdAluOp", ("uint64_t",), 4, bicCode) + # BIF + bifCode = "destElem = (destElem & srcElem2) | (srcElem1 & ~srcElem2);" + threeEqualRegInstX("bif", "BifDX", "SimdAluOp", ("uint64_t",), 2, bifCode, + True) + threeEqualRegInstX("bif", "BifQX", "SimdAluOp", ("uint64_t",), 4, bifCode, + True) + # BIT + bitCode = "destElem = (srcElem1 & srcElem2) | (destElem & ~srcElem2);" + threeEqualRegInstX("bit", "BitDX", "SimdAluOp", ("uint64_t",), 2, bitCode, + True) + threeEqualRegInstX("bit", "BitQX", "SimdAluOp", ("uint64_t",), 4, bitCode, + True) + # BSL + bslCode = "destElem = (srcElem1 & destElem) | (srcElem2 & ~destElem);" + threeEqualRegInstX("bsl", "BslDX", "SimdAluOp", ("uint64_t",), 2, bslCode, + True) + threeEqualRegInstX("bsl", "BslQX", "SimdAluOp", ("uint64_t",), 4, bslCode, + True) + # CLS + clsCode = ''' + unsigned count = 0; + if (srcElem1 < 0) { + srcElem1 <<= 1; + while (srcElem1 < 0 && count < sizeof(Element) * 8 - 1) { + count++; + srcElem1 <<= 1; + } + } else { + srcElem1 <<= 1; + while (srcElem1 >= 0 && count < sizeof(Element) * 8 - 1) { + count++; + srcElem1 <<= 1; + } + } + destElem = count; + ''' + twoEqualRegInstX("cls", "ClsDX", "SimdAluOp", smallSignedTypes, 2, clsCode) + twoEqualRegInstX("cls", "ClsQX", "SimdAluOp", smallSignedTypes, 4, clsCode) + # CLZ + clzCode = ''' + unsigned count = 0; + while (srcElem1 >= 0 && count < sizeof(Element) * 8) { + count++; + srcElem1 <<= 1; + } + destElem = count; + ''' + twoEqualRegInstX("clz", "ClzDX", "SimdAluOp", smallSignedTypes, 2, clzCode) + twoEqualRegInstX("clz", "ClzQX", "SimdAluOp", smallSignedTypes, 4, clzCode) + # CMEQ (register) + cmeqCode = "destElem = (srcElem1 == srcElem2) ? (Element)(-1) : 0;" + threeEqualRegInstX("cmeq", "CmeqDX", "SimdCmpOp", unsignedTypes, 2, + cmeqCode) + threeEqualRegInstX("cmeq", "CmeqQX", "SimdCmpOp", unsignedTypes, 4, + cmeqCode) + # CMEQ (zero) + cmeqZeroCode = "destElem = (srcElem1 == 0) ? (Element)(-1) : 0;" + twoEqualRegInstX("cmeq", "CmeqZeroDX", "SimdCmpOp", signedTypes, 2, + cmeqZeroCode) + twoEqualRegInstX("cmeq", "CmeqZeroQX", "SimdCmpOp", signedTypes, 4, + cmeqZeroCode) + # CMGE (register) + cmgeCode = "destElem = (srcElem1 >= srcElem2) ? (Element)(-1) : 0;" + threeEqualRegInstX("cmge", "CmgeDX", "SimdCmpOp", signedTypes, 2, cmgeCode) + threeEqualRegInstX("cmge", "CmgeQX", "SimdCmpOp", signedTypes, 4, cmgeCode) + # CMGE (zero) + cmgeZeroCode = "destElem = (srcElem1 >= 0) ? (Element)(-1) : 0;" + twoEqualRegInstX("cmge", "CmgeZeroDX", "SimdCmpOp", signedTypes, 2, + cmgeZeroCode) + twoEqualRegInstX("cmge", "CmgeZeroQX", "SimdCmpOp", signedTypes, 4, + cmgeZeroCode) + # CMGT (register) + cmgtCode = "destElem = (srcElem1 > srcElem2) ? (Element)(-1) : 0;" + threeEqualRegInstX("cmgt", "CmgtDX", "SimdCmpOp", signedTypes, 2, cmgtCode) + threeEqualRegInstX("cmgt", "CmgtQX", "SimdCmpOp", signedTypes, 4, cmgtCode) + # CMGT (zero) + cmgtZeroCode = "destElem = (srcElem1 > 0) ? (Element)(-1) : 0;" + twoEqualRegInstX("cmgt", "CmgtZeroDX", "SimdCmpOp", signedTypes, 2, + cmgtZeroCode) + twoEqualRegInstX("cmgt", "CmgtZeroQX", "SimdCmpOp", signedTypes, 4, + cmgtZeroCode) + # CMHI (register) + threeEqualRegInstX("cmhi", "CmhiDX", "SimdCmpOp", unsignedTypes, 2, + cmgtCode) + threeEqualRegInstX("cmhi", "CmhiQX", "SimdCmpOp", unsignedTypes, 4, + cmgtCode) + # CMHS (register) + threeEqualRegInstX("cmhs", "CmhsDX", "SimdCmpOp", unsignedTypes, 2, + cmgeCode) + threeEqualRegInstX("cmhs", "CmhsQX", "SimdCmpOp", unsignedTypes, 4, + cmgeCode) + # CMLE (zero) + cmleZeroCode = "destElem = (srcElem1 <= 0) ? (Element)(-1) : 0;" + twoEqualRegInstX("cmle", "CmleZeroDX", "SimdCmpOp", signedTypes, 2, + cmleZeroCode) + twoEqualRegInstX("cmle", "CmleZeroQX", "SimdCmpOp", signedTypes, 4, + cmleZeroCode) + # CMLT (zero) + cmltZeroCode = "destElem = (srcElem1 < 0) ? (Element)(-1) : 0;" + twoEqualRegInstX("cmlt", "CmltZeroDX", "SimdCmpOp", signedTypes, 2, + cmltZeroCode) + twoEqualRegInstX("cmlt", "CmltZeroQX", "SimdCmpOp", signedTypes, 4, + cmltZeroCode) + # CMTST (register) + tstCode = "destElem = (srcElem1 & srcElem2) ? (Element)(-1) : 0;" + threeEqualRegInstX("cmtst", "CmtstDX", "SimdAluOp", unsignedTypes, 2, + tstCode) + threeEqualRegInstX("cmtst", "CmtstQX", "SimdAluOp", unsignedTypes, 4, + tstCode) + # CNT + cntCode = ''' + unsigned count = 0; + while (srcElem1 && count < sizeof(Element) * 8) { + count += srcElem1 & 0x1; + srcElem1 >>= 1; + } + destElem = count; + ''' + twoEqualRegInstX("cnt", "CntDX", "SimdAluOp", ("uint8_t",), 2, cntCode) + twoEqualRegInstX("cnt", "CntQX", "SimdAluOp", ("uint8_t",), 4, cntCode) + # DUP (element) + dupCode = "destElem = srcElem1;" + twoEqualRegInstX("dup", "DupElemDX", "SimdMiscOp", smallUnsignedTypes, 2, + dupCode, isDup=True, byElem=True) + twoEqualRegInstX("dup", "DupElemQX", "SimdMiscOp", unsignedTypes, 4, + dupCode, isDup=True, byElem=True) + twoEqualRegInstX("dup", "DupElemScX", "SimdMiscOp", unsignedTypes, 4, + dupCode, isDup=True, byElem=True, scalar=True) + # DUP (general register) + dupGprInstX("dup", "DupGprWDX", "SimdMiscOp", smallUnsignedTypes, 2, 'W') + dupGprInstX("dup", "DupGprWQX", "SimdMiscOp", smallUnsignedTypes, 4, 'W') + dupGprInstX("dup", "DupGprXQX", "SimdMiscOp", ("uint64_t",), 4, 'X') + # EOR + eorCode = "destElem = srcElem1 ^ srcElem2;" + threeEqualRegInstX("eor", "EorDX", "SimdAluOp", ("uint64_t",), 2, eorCode) + threeEqualRegInstX("eor", "EorQX", "SimdAluOp", ("uint64_t",), 4, eorCode) + # EXT + extCode = ''' + for (unsigned i = 0; i < eCount; i++) { + unsigned index = i + imm; + if (index < eCount) { + destReg.elements[i] = srcReg1.elements[index]; + } else { + index -= eCount; + if (index >= eCount) { + fault = new UndefinedInstruction(machInst, false, mnemonic); + } else { + destReg.elements[i] = srcReg2.elements[index]; + } + } + } + ''' + extInstX("Ext", "ExtDX", "SimdMiscOp", ("uint8_t",), 2, extCode) + extInstX("Ext", "ExtQX", "SimdMiscOp", ("uint8_t",), 4, extCode) + # FABD + fpOp = ''' + FPSCR fpscr = (FPSCR) FpscrExc; + destElem = %s; + FpscrExc = fpscr; + ''' + fabdCode = fpOp % "fplibAbs<Element>(fplibSub(srcElem1, srcElem2, fpscr))" + threeEqualRegInstX("fabd", "FabdDX", "SimdFloatAddOp", smallFloatTypes, 2, + fabdCode) + threeEqualRegInstX("fabd", "FabdQX", "SimdFloatAddOp", floatTypes, 4, + fabdCode) + threeEqualRegInstX("fabd", "FabdScX", "SimdFloatAddOp", floatTypes, 4, + fabdCode, scalar=True) + # FABS + fabsCode = fpOp % "fplibAbs<Element>(srcElem1)" + twoEqualRegInstX("Abs", "FabsDX", "SimdFloatAluOp", smallFloatTypes, 2, + fabsCode) + twoEqualRegInstX("Abs", "FabsQX", "SimdFloatAluOp", floatTypes, 4, + fabsCode) + # FACGE + fpCmpAbsOp = fpOp % ("fplibCompare%s<Element>(fplibAbs<Element>(srcElem1)," + " fplibAbs<Element>(srcElem2), fpscr) ? -1 : 0") + facgeCode = fpCmpAbsOp % "GE" + threeEqualRegInstX("facge", "FacgeDX", "SimdFloatCmpOp", smallFloatTypes, + 2, facgeCode) + threeEqualRegInstX("facge", "FacgeQX", "SimdFloatCmpOp", floatTypes, 4, + facgeCode) + threeEqualRegInstX("facge", "FacgeScX", "SimdFloatCmpOp", floatTypes, 4, + facgeCode, scalar=True) + # FACGT + facgtCode = fpCmpAbsOp % "GT" + threeEqualRegInstX("facgt", "FacgtDX", "SimdFloatCmpOp", smallFloatTypes, + 2, facgtCode) + threeEqualRegInstX("facgt", "FacgtQX", "SimdFloatCmpOp", floatTypes, 4, + facgtCode) + threeEqualRegInstX("facgt", "FacgtScX", "SimdFloatCmpOp", floatTypes, 4, + facgtCode, scalar=True) + # FADD + fpBinOp = fpOp % "fplib%s<Element>(srcElem1, srcElem2, fpscr)" + faddCode = fpBinOp % "Add" + threeEqualRegInstX("fadd", "FaddDX", "SimdFloatAddOp", smallFloatTypes, 2, + faddCode) + threeEqualRegInstX("fadd", "FaddQX", "SimdFloatAddOp", floatTypes, 4, + faddCode) + # FADDP (scalar) + twoRegPairwiseScInstX("faddp", "FaddpScDX", "SimdFloatAddOp", + ("uint32_t",), 2, faddCode) + twoRegPairwiseScInstX("faddp", "FaddpScQX", "SimdFloatAddOp", + ("uint64_t",), 4, faddCode) + # FADDP (vector) + threeEqualRegInstX("faddp", "FaddpDX", "SimdFloatAddOp", smallFloatTypes, + 2, faddCode, pairwise=True) + threeEqualRegInstX("faddp", "FaddpQX", "SimdFloatAddOp", floatTypes, 4, + faddCode, pairwise=True) + # FCMEQ (register) + fpCmpOp = fpOp % ("fplibCompare%s<Element>(srcElem1, srcElem2, fpscr) ?" + " -1 : 0") + fcmeqCode = fpCmpOp % "EQ" + threeEqualRegInstX("fcmeq", "FcmeqDX", "SimdFloatCmpOp", smallFloatTypes, + 2, fcmeqCode) + threeEqualRegInstX("fcmeq", "FcmeqQX", "SimdFloatCmpOp", floatTypes, 4, + fcmeqCode) + threeEqualRegInstX("fcmeq", "FcmeqScX", "SimdFloatCmpOp", floatTypes, 4, + fcmeqCode, scalar=True) + # FCMEQ (zero) + fpCmpZeroOp = fpOp % "fplibCompare%s<Element>(srcElem1, 0, fpscr) ? -1 : 0" + fcmeqZeroCode = fpCmpZeroOp % "EQ" + twoEqualRegInstX("fcmeq", "FcmeqZeroDX", "SimdFloatCmpOp", smallFloatTypes, + 2, fcmeqZeroCode) + twoEqualRegInstX("fcmeq", "FcmeqZeroQX", "SimdFloatCmpOp", floatTypes, 4, + fcmeqZeroCode) + twoEqualRegInstX("fcmeq", "FcmeqZeroScX", "SimdFloatCmpOp", floatTypes, 4, + fcmeqZeroCode, scalar=True) + # FCMGE (register) + fcmgeCode = fpCmpOp % "GE" + threeEqualRegInstX("fcmge", "FcmgeDX", "SimdFloatCmpOp", smallFloatTypes, + 2, fcmgeCode) + threeEqualRegInstX("fcmge", "FcmgeQX", "SimdFloatCmpOp", floatTypes, 4, + fcmgeCode) + threeEqualRegInstX("fcmge", "FcmgeScX", "SimdFloatCmpOp", floatTypes, 4, + fcmgeCode, scalar=True) + # FCMGE (zero) + fcmgeZeroCode = fpCmpZeroOp % "GE" + twoEqualRegInstX("fcmge", "FcmgeZeroDX", "SimdFloatCmpOp", smallFloatTypes, + 2, fcmgeZeroCode) + twoEqualRegInstX("fcmge", "FcmgeZeroQX", "SimdFloatCmpOp", floatTypes, 4, + fcmgeZeroCode) + twoEqualRegInstX("fcmge", "FcmgeZeroScX", "SimdFloatCmpOp", floatTypes, 4, + fcmgeZeroCode, scalar=True) + # FCMGT (register) + fcmgtCode = fpCmpOp % "GT" + threeEqualRegInstX("fcmgt", "FcmgtDX", "SimdFloatCmpOp", smallFloatTypes, + 2, fcmgtCode) + threeEqualRegInstX("fcmgt", "FcmgtQX", "SimdFloatCmpOp", floatTypes, 4, + fcmgtCode) + threeEqualRegInstX("fcmgt", "FcmgtScX", "SimdFloatCmpOp", floatTypes, 4, + fcmgtCode, scalar=True) + # FCMGT (zero) + fcmgtZeroCode = fpCmpZeroOp % "GT" + twoEqualRegInstX("fcmgt", "FcmgtZeroDX", "SimdFloatCmpOp", smallFloatTypes, + 2, fcmgtZeroCode) + twoEqualRegInstX("fcmgt", "FcmgtZeroQX", "SimdFloatCmpOp", floatTypes, 4, + fcmgtZeroCode) + twoEqualRegInstX("fcmgt", "FcmgtZeroScX", "SimdFloatCmpOp", floatTypes, 4, + fcmgtZeroCode, scalar=True) + # FCMLE (zero) + fpCmpRevZeroOp = fpOp % ("fplibCompare%s<Element>(0, srcElem1, fpscr) ?" + " -1 : 0") + fcmleZeroCode = fpCmpRevZeroOp % "GE" + twoEqualRegInstX("fcmle", "FcmleZeroDX", "SimdFloatCmpOp", smallFloatTypes, + 2, fcmleZeroCode) + twoEqualRegInstX("fcmle", "FcmleZeroQX", "SimdFloatCmpOp", floatTypes, 4, + fcmleZeroCode) + twoEqualRegInstX("fcmle", "FcmleZeroScX", "SimdFloatCmpOp", floatTypes, 4, + fcmleZeroCode, scalar=True) + # FCMLT (zero) + fcmltZeroCode = fpCmpRevZeroOp % "GT" + twoEqualRegInstX("fcmlt", "FcmltZeroDX", "SimdFloatCmpOp", smallFloatTypes, + 2, fcmltZeroCode) + twoEqualRegInstX("fcmlt", "FcmltZeroQX", "SimdFloatCmpOp", floatTypes, 4, + fcmltZeroCode) + twoEqualRegInstX("fcmlt", "FcmltZeroScX", "SimdFloatCmpOp", floatTypes, 4, + fcmltZeroCode, scalar=True) + # FCVTAS + fcvtCode = fpOp % ("fplibFPToFixed<Element, Element>(" + "srcElem1, %s, %s, %s, fpscr)") + fcvtasCode = fcvtCode % ("0", "false", "FPRounding_TIEAWAY") + twoEqualRegInstX("fcvtas", "FcvtasDX", "SimdCvtOp", smallFloatTypes, 2, + fcvtasCode) + twoEqualRegInstX("fcvtas", "FcvtasQX", "SimdCvtOp", floatTypes, 4, + fcvtasCode) + twoEqualRegInstX("fcvtas", "FcvtasScX", "SimdCvtOp", floatTypes, 4, + fcvtasCode, scalar=True) + # FCVTAU + fcvtauCode = fcvtCode % ("0", "true", "FPRounding_TIEAWAY") + twoEqualRegInstX("fcvtau", "FcvtauDX", "SimdCvtOp", smallFloatTypes, 2, + fcvtauCode) + twoEqualRegInstX("fcvtau", "FcvtauQX", "SimdCvtOp", floatTypes, 4, + fcvtauCode) + twoEqualRegInstX("fcvtau", "FcvtauScX", "SimdCvtOp", floatTypes, 4, + fcvtauCode, scalar=True) + # FCVTL, FCVTL2 + fcvtlCode = fpOp % ("fplibConvert<Element, BigElement>(" + "srcElem1, FPCRRounding(fpscr), fpscr)") + twoRegLongInstX("fcvtl", "FcvtlX", "SimdCvtOp", ("uint16_t", "uint32_t"), + fcvtlCode) + twoRegLongInstX("fcvtl", "Fcvtl2X", "SimdCvtOp", ("uint16_t", "uint32_t"), + fcvtlCode, hi=True) + # FCVTMS + fcvtmsCode = fcvtCode % ("0", "false", "FPRounding_NEGINF") + twoEqualRegInstX("fcvtms", "FcvtmsDX", "SimdCvtOp", smallFloatTypes, 2, + fcvtmsCode) + twoEqualRegInstX("fcvtms", "FcvtmsQX", "SimdCvtOp", floatTypes, 4, + fcvtmsCode) + twoEqualRegInstX("fcvtms", "FcvtmsScX", "SimdCvtOp", floatTypes, 4, + fcvtmsCode, scalar=True) + # FCVTMU + fcvtmuCode = fcvtCode % ("0", "true", "FPRounding_NEGINF") + twoEqualRegInstX("fcvtmu", "FcvtmuDX", "SimdCvtOp", smallFloatTypes, 2, + fcvtmuCode) + twoEqualRegInstX("fcvtmu", "FcvtmuQX", "SimdCvtOp", floatTypes, 4, + fcvtmuCode) + twoEqualRegInstX("fcvtmu", "FcvtmuScX", "SimdCvtOp", floatTypes, 4, + fcvtmuCode, scalar=True) + # FCVTN, FCVTN2 + fcvtnCode = fpOp % ("fplibConvert<BigElement, Element>(" + "srcElem1, FPCRRounding(fpscr), fpscr)") + twoRegNarrowInstX("fcvtn", "FcvtnX", "SimdCvtOp", + ("uint16_t", "uint32_t"), fcvtnCode) + twoRegNarrowInstX("fcvtn", "Fcvtn2X", "SimdCvtOp", + ("uint16_t", "uint32_t"), fcvtnCode, hi=True) + # FCVTNS + fcvtnsCode = fcvtCode % ("0", "false", "FPRounding_TIEEVEN") + twoEqualRegInstX("fcvtns", "FcvtnsDX", "SimdCvtOp", smallFloatTypes, 2, + fcvtnsCode) + twoEqualRegInstX("fcvtns", "FcvtnsQX", "SimdCvtOp", floatTypes, 4, + fcvtnsCode) + twoEqualRegInstX("fcvtns", "FcvtnsScX", "SimdCvtOp", floatTypes, 4, + fcvtnsCode, scalar=True) + # FCVTNU + fcvtnuCode = fcvtCode % ("0", "true", "FPRounding_TIEEVEN") + twoEqualRegInstX("fcvtnu", "FcvtnuDX", "SimdCvtOp", smallFloatTypes, 2, + fcvtnuCode) + twoEqualRegInstX("fcvtnu", "FcvtnuQX", "SimdCvtOp", floatTypes, 4, + fcvtnuCode) + twoEqualRegInstX("fcvtnu", "FcvtnuScX", "SimdCvtOp", floatTypes, 4, + fcvtnuCode, scalar=True) + # FCVTPS + fcvtpsCode = fcvtCode % ("0", "false", "FPRounding_POSINF") + twoEqualRegInstX("fcvtps", "FcvtpsDX", "SimdCvtOp", smallFloatTypes, 2, + fcvtpsCode) + twoEqualRegInstX("fcvtps", "FcvtpsQX", "SimdCvtOp", floatTypes, 4, + fcvtpsCode) + twoEqualRegInstX("fcvtps", "FcvtpsScX", "SimdCvtOp", floatTypes, 4, + fcvtpsCode, scalar=True) + # FCVTPU + fcvtpuCode = fcvtCode % ("0", "true", "FPRounding_POSINF") + twoEqualRegInstX("fcvtpu", "FcvtpuDX", "SimdCvtOp", smallFloatTypes, 2, + fcvtpuCode) + twoEqualRegInstX("fcvtpu", "FcvtpuQX", "SimdCvtOp", floatTypes, 4, + fcvtpuCode) + twoEqualRegInstX("fcvtpu", "FcvtpuScX", "SimdCvtOp", floatTypes, 4, + fcvtpuCode, scalar=True) + # FCVTXN, FCVTXN2 + fcvtxnCode = fpOp % ("fplibConvert<BigElement, Element>(" + "srcElem1, FPRounding_ODD, fpscr)") + twoRegNarrowInstX("fcvtxn", "FcvtxnX", "SimdCvtOp", smallFloatTypes, + fcvtxnCode) + twoRegNarrowInstX("fcvtxn", "Fcvtxn2X", "SimdCvtOp", smallFloatTypes, + fcvtxnCode, hi=True) + twoRegNarrowInstX("fcvtxn", "FcvtxnScX", "SimdCvtOp", smallFloatTypes, + fcvtxnCode, scalar=True) + # FCVTZS (fixed-point) + fcvtzsCode = fcvtCode % ("imm", "false", "FPRounding_ZERO") + twoEqualRegInstX("fcvtzs", "FcvtzsFixedDX", "SimdCvtOp", smallFloatTypes, + 2, fcvtzsCode, hasImm=True) + twoEqualRegInstX("fcvtzs", "FcvtzsFixedQX", "SimdCvtOp", floatTypes, 4, + fcvtzsCode, hasImm=True) + twoEqualRegInstX("fcvtzs", "FcvtzsFixedScX", "SimdCvtOp", floatTypes, 4, + fcvtzsCode, hasImm=True, scalar=True) + # FCVTZS (integer) + fcvtzsIntCode = fcvtCode % ("0", "false", "FPRounding_ZERO") + twoEqualRegInstX("fcvtzs", "FcvtzsIntDX", "SimdCvtOp", smallFloatTypes, + 2, fcvtzsIntCode) + twoEqualRegInstX("fcvtzs", "FcvtzsIntQX", "SimdCvtOp", floatTypes, 4, + fcvtzsIntCode) + twoEqualRegInstX("fcvtzs", "FcvtzsIntScX", "SimdCvtOp", floatTypes, 4, + fcvtzsIntCode, scalar=True) + # FCVTZU (fixed-point) + fcvtzuCode = fcvtCode % ("imm", "true", "FPRounding_ZERO") + twoEqualRegInstX("fcvtzu", "FcvtzuFixedDX", "SimdCvtOp", smallFloatTypes, + 2, fcvtzuCode, hasImm=True) + twoEqualRegInstX("fcvtzu", "FcvtzuFixedQX", "SimdCvtOp", floatTypes, 4, + fcvtzuCode, hasImm=True) + twoEqualRegInstX("fcvtzu", "FcvtzuFixedScX", "SimdCvtOp", floatTypes, 4, + fcvtzuCode, hasImm=True, scalar=True) + # FCVTZU (integer) + fcvtzuIntCode = fcvtCode % ("0", "true", "FPRounding_ZERO") + twoEqualRegInstX("fcvtzu", "FcvtzuIntDX", "SimdCvtOp", smallFloatTypes, 2, + fcvtzuIntCode) + twoEqualRegInstX("fcvtzu", "FcvtzuIntQX", "SimdCvtOp", floatTypes, 4, + fcvtzuIntCode) + twoEqualRegInstX("fcvtzu", "FcvtzuIntScX", "SimdCvtOp", floatTypes, 4, + fcvtzuIntCode, scalar=True) + # FDIV + fdivCode = fpBinOp % "Div" + threeEqualRegInstX("fdiv", "FdivDX", "SimdFloatDivOp", smallFloatTypes, 2, + fdivCode) + threeEqualRegInstX("fdiv", "FdivQX", "SimdFloatDivOp", floatTypes, 4, + fdivCode) + # FMAX + fmaxCode = fpBinOp % "Max" + threeEqualRegInstX("fmax", "FmaxDX", "SimdFloatCmpOp", smallFloatTypes, 2, + fmaxCode) + threeEqualRegInstX("fmax", "FmaxQX", "SimdFloatCmpOp", floatTypes, 4, + fmaxCode) + # FMAXNM + fmaxnmCode = fpBinOp % "MaxNum" + threeEqualRegInstX("fmaxnm", "FmaxnmDX", "SimdFloatCmpOp", smallFloatTypes, + 2, fmaxnmCode) + threeEqualRegInstX("fmaxnm", "FmaxnmQX", "SimdFloatCmpOp", floatTypes, 4, + fmaxnmCode) + # FMAXNMP (scalar) + twoRegPairwiseScInstX("fmaxnmp", "FmaxnmpScDX", "SimdFloatCmpOp", + ("uint32_t",), 2, fmaxnmCode) + twoRegPairwiseScInstX("fmaxnmp", "FmaxnmpScQX", "SimdFloatCmpOp", + ("uint64_t",), 4, fmaxnmCode) + # FMAXNMP (vector) + threeEqualRegInstX("fmaxnmp", "FmaxnmpDX", "SimdFloatCmpOp", + smallFloatTypes, 2, fmaxnmCode, pairwise=True) + threeEqualRegInstX("fmaxnmp", "FmaxnmpQX", "SimdFloatCmpOp", floatTypes, 4, + fmaxnmCode, pairwise=True) + # FMAXNMV + # Note: SimdFloatCmpOp can be a bit optimistic here + fpAcrossOp = fpOp % "fplib%s<Element>(destElem, srcElem1, fpscr)" + fmaxnmAcrossCode = fpAcrossOp % "MaxNum" + twoRegAcrossInstX("fmaxnmv", "FmaxnmvQX", "SimdFloatCmpOp", ("uint32_t",), + 4, fmaxnmAcrossCode) + # FMAXP (scalar) + twoRegPairwiseScInstX("fmaxp", "FmaxpScDX", "SimdFloatCmpOp", + ("uint32_t",), 2, fmaxCode) + twoRegPairwiseScInstX("fmaxp", "FmaxpScQX", "SimdFloatCmpOp", + ("uint64_t",), 4, fmaxCode) + # FMAXP (vector) + threeEqualRegInstX("fmaxp", "FmaxpDX", "SimdFloatCmpOp", smallFloatTypes, + 2, fmaxCode, pairwise=True) + threeEqualRegInstX("fmaxp", "FmaxpQX", "SimdFloatCmpOp", floatTypes, 4, + fmaxCode, pairwise=True) + # FMAXV + # Note: SimdFloatCmpOp can be a bit optimistic here + fmaxAcrossCode = fpAcrossOp % "Max" + twoRegAcrossInstX("fmaxv", "FmaxvQX", "SimdFloatCmpOp", ("uint32_t",), 4, + fmaxAcrossCode) + # FMIN + fminCode = fpBinOp % "Min" + threeEqualRegInstX("fmin", "FminDX", "SimdFloatCmpOp", smallFloatTypes, 2, + fminCode) + threeEqualRegInstX("fmin", "FminQX", "SimdFloatCmpOp", floatTypes, 4, + fminCode) + # FMINNM + fminnmCode = fpBinOp % "MinNum" + threeEqualRegInstX("fminnm", "FminnmDX", "SimdFloatCmpOp", smallFloatTypes, + 2, fminnmCode) + threeEqualRegInstX("fminnm", "FminnmQX", "SimdFloatCmpOp", floatTypes, 4, + fminnmCode) + # FMINNMP (scalar) + twoRegPairwiseScInstX("fminnmp", "FminnmpScDX", "SimdFloatCmpOp", + ("uint32_t",), 2, fminnmCode) + twoRegPairwiseScInstX("fminnmp", "FminnmpScQX", "SimdFloatCmpOp", + ("uint64_t",), 4, fminnmCode) + # FMINNMP (vector) + threeEqualRegInstX("fminnmp", "FminnmpDX", "SimdFloatCmpOp", + smallFloatTypes, 2, fminnmCode, pairwise=True) + threeEqualRegInstX("fminnmp", "FminnmpQX", "SimdFloatCmpOp", floatTypes, 4, + fminnmCode, pairwise=True) + # FMINNMV + # Note: SimdFloatCmpOp can be a bit optimistic here + fminnmAcrossCode = fpAcrossOp % "MinNum" + twoRegAcrossInstX("fminnmv", "FminnmvQX", "SimdFloatCmpOp", ("uint32_t",), + 4, fminnmAcrossCode) + # FMINP (scalar) + twoRegPairwiseScInstX("fminp", "FminpScDX", "SimdFloatCmpOp", + ("uint32_t",), 2, fminCode) + twoRegPairwiseScInstX("fminp", "FminpScQX", "SimdFloatCmpOp", + ("uint64_t",), 4, fminCode) + # FMINP (vector) + threeEqualRegInstX("fminp", "FminpDX", "SimdFloatCmpOp", smallFloatTypes, + 2, fminCode, pairwise=True) + threeEqualRegInstX("fminp", "FminpQX", "SimdFloatCmpOp", floatTypes, 4, + fminCode, pairwise=True) + # FMINV + # Note: SimdFloatCmpOp can be a bit optimistic here + fminAcrossCode = fpAcrossOp % "Min" + twoRegAcrossInstX("fminv", "FminvQX", "SimdFloatCmpOp", ("uint32_t",), 4, + fminAcrossCode) + # FMLA (by element) + fmlaCode = fpOp % ("fplibMulAdd<Element>(" + "destElem, srcElem1, srcElem2, fpscr)") + threeEqualRegInstX("fmla", "FmlaElemDX", "SimdFloatMultAccOp", + smallFloatTypes, 2, fmlaCode, True, byElem=True) + threeEqualRegInstX("fmla", "FmlaElemQX", "SimdFloatMultAccOp", floatTypes, + 4, fmlaCode, True, byElem=True) + threeEqualRegInstX("fmla", "FmlaElemScX", "SimdFloatMultAccOp", floatTypes, + 4, fmlaCode, True, byElem=True, scalar=True) + # FMLA (vector) + threeEqualRegInstX("fmla", "FmlaDX", "SimdFloatMultAccOp", smallFloatTypes, + 2, fmlaCode, True) + threeEqualRegInstX("fmla", "FmlaQX", "SimdFloatMultAccOp", floatTypes, 4, + fmlaCode, True) + # FMLS (by element) + fmlsCode = fpOp % ("fplibMulAdd<Element>(destElem," + " fplibNeg<Element>(srcElem1), srcElem2, fpscr)") + threeEqualRegInstX("fmls", "FmlsElemDX", "SimdFloatMultAccOp", + smallFloatTypes, 2, fmlsCode, True, byElem=True) + threeEqualRegInstX("fmls", "FmlsElemQX", "SimdFloatMultAccOp", floatTypes, + 4, fmlsCode, True, byElem=True) + threeEqualRegInstX("fmls", "FmlsElemScX", "SimdFloatMultAccOp", floatTypes, + 4, fmlsCode, True, byElem=True, scalar=True) + # FMLS (vector) + threeEqualRegInstX("fmls", "FmlsDX", "SimdFloatMultAccOp", smallFloatTypes, + 2, fmlsCode, True) + threeEqualRegInstX("fmls", "FmlsQX", "SimdFloatMultAccOp", floatTypes, 4, + fmlsCode, True) + # FMOV + fmovCode = 'destElem = imm;' + oneRegImmInstX("fmov", "FmovDX", "SimdMiscOp", smallFloatTypes, 2, + fmovCode) + oneRegImmInstX("fmov", "FmovQX", "SimdMiscOp", floatTypes, 4, fmovCode) + # FMUL (by element) + fmulCode = fpBinOp % "Mul" + threeEqualRegInstX("fmul", "FmulElemDX", "SimdFloatMultOp", + smallFloatTypes, 2, fmulCode, byElem=True) + threeEqualRegInstX("fmul", "FmulElemQX", "SimdFloatMultOp", floatTypes, 4, + fmulCode, byElem=True) + threeEqualRegInstX("fmul", "FmulElemScX", "SimdFloatMultOp", floatTypes, 4, + fmulCode, byElem=True, scalar=True) + # FMUL (vector) + threeEqualRegInstX("fmul", "FmulDX", "SimdFloatMultOp", smallFloatTypes, 2, + fmulCode) + threeEqualRegInstX("fmul", "FmulQX", "SimdFloatMultOp", floatTypes, 4, + fmulCode) + # FMULX + fmulxCode = fpBinOp % "MulX" + threeEqualRegInstX("fmulx", "FmulxDX", "SimdFloatMultOp", smallFloatTypes, + 2, fmulxCode) + threeEqualRegInstX("fmulx", "FmulxQX", "SimdFloatMultOp", floatTypes, 4, + fmulxCode) + threeEqualRegInstX("fmulx", "FmulxScX", "SimdFloatMultOp", floatTypes, 4, + fmulxCode, scalar=True) + # FMULX (by element) + threeEqualRegInstX("fmulx", "FmulxElemDX", "SimdFloatMultOp", + smallFloatTypes, 2, fmulxCode, byElem=True) + threeEqualRegInstX("fmulx", "FmulxElemQX", "SimdFloatMultOp", floatTypes, + 4, fmulxCode, byElem=True) + threeEqualRegInstX("fmulx", "FmulxElemScX", "SimdFloatMultOp", floatTypes, + 4, fmulxCode, byElem=True, scalar=True) + # FNEG + fnegCode = fpOp % "fplibNeg<Element>(srcElem1)" + twoEqualRegInstX("Neg", "FnegDX", "SimdFloatAluOp", smallFloatTypes, 2, + fnegCode) + twoEqualRegInstX("Neg", "FnegQX", "SimdFloatAluOp", floatTypes, 4, + fnegCode) + # FRECPE + frecpeCode = fpOp % "fplibRecipEstimate<Element>(srcElem1, fpscr)" + twoEqualRegInstX("frecpe", "FrecpeDX", "SimdFloatMultAccOp", + smallFloatTypes, 2, frecpeCode) + twoEqualRegInstX("frecpe", "FrecpeQX", "SimdFloatMultAccOp", floatTypes, 4, + frecpeCode) + twoEqualRegInstX("frecpe", "FrecpeScX", "SimdFloatMultAccOp", floatTypes, + 4, frecpeCode, scalar=True) + # FRECPS + frecpsCode = fpBinOp % "RecipStepFused" + threeEqualRegInstX("frecps", "FrecpsDX", "SimdFloatMultAccOp", + smallFloatTypes, 2, frecpsCode) + threeEqualRegInstX("frecps", "FrecpsQX", "SimdFloatMultAccOp", floatTypes, + 4, frecpsCode) + threeEqualRegInstX("frecps", "FrecpsScX", "SimdFloatMultAccOp", floatTypes, + 4, frecpsCode, scalar=True) + # FRECPX + frecpxCode = fpOp % "fplibRecpX<Element>(srcElem1, fpscr)" + twoEqualRegInstX("frecpx", "FrecpxX", "SimdFloatMultAccOp", floatTypes, 4, + frecpxCode, scalar=True) + # FRINTA + frintCode = fpOp % "fplibRoundInt<Element>(srcElem1, %s, %s, fpscr)" + frintaCode = frintCode % ("FPRounding_TIEAWAY", "false") + twoEqualRegInstX("frinta", "FrintaDX", "SimdCvtOp", smallFloatTypes, 2, + frintaCode) + twoEqualRegInstX("frinta", "FrintaQX", "SimdCvtOp", floatTypes, 4, + frintaCode) + # FRINTI + frintiCode = frintCode % ("FPCRRounding(fpscr)", "false") + twoEqualRegInstX("frinti", "FrintiDX", "SimdCvtOp", smallFloatTypes, 2, + frintiCode) + twoEqualRegInstX("frinti", "FrintiQX", "SimdCvtOp", floatTypes, 4, + frintiCode) + # FRINTM + frintmCode = frintCode % ("FPRounding_NEGINF", "false") + twoEqualRegInstX("frintm", "FrintmDX", "SimdCvtOp", smallFloatTypes, 2, + frintmCode) + twoEqualRegInstX("frintm", "FrintmQX", "SimdCvtOp", floatTypes, 4, + frintmCode) + # FRINTN + frintnCode = frintCode % ("FPRounding_TIEEVEN", "false") + twoEqualRegInstX("frintn", "FrintnDX", "SimdCvtOp", smallFloatTypes, 2, + frintnCode) + twoEqualRegInstX("frintn", "FrintnQX", "SimdCvtOp", floatTypes, 4, + frintnCode) + # FRINTP + frintpCode = frintCode % ("FPRounding_POSINF", "false") + twoEqualRegInstX("frintp", "FrintpDX", "SimdCvtOp", smallFloatTypes, 2, + frintpCode) + twoEqualRegInstX("frintp", "FrintpQX", "SimdCvtOp", floatTypes, 4, + frintpCode) + # FRINTX + frintxCode = frintCode % ("FPCRRounding(fpscr)", "true") + twoEqualRegInstX("frintx", "FrintxDX", "SimdCvtOp", smallFloatTypes, 2, + frintxCode) + twoEqualRegInstX("frintx", "FrintxQX", "SimdCvtOp", floatTypes, 4, + frintxCode) + # FRINTZ + frintzCode = frintCode % ("FPRounding_ZERO", "false") + twoEqualRegInstX("frintz", "FrintzDX", "SimdCvtOp", smallFloatTypes, 2, + frintzCode) + twoEqualRegInstX("frintz", "FrintzQX", "SimdCvtOp", floatTypes, 4, + frintzCode) + # FRSQRTE + frsqrteCode = fpOp % "fplibRSqrtEstimate<Element>(srcElem1, fpscr)" + twoEqualRegInstX("frsqrte", "FrsqrteDX", "SimdFloatSqrtOp", + smallFloatTypes, 2, frsqrteCode) + twoEqualRegInstX("frsqrte", "FrsqrteQX", "SimdFloatSqrtOp", floatTypes, 4, + frsqrteCode) + twoEqualRegInstX("frsqrte", "FrsqrteScX", "SimdFloatSqrtOp", floatTypes, 4, + frsqrteCode, scalar=True) + # FRSQRTS + frsqrtsCode = fpBinOp % "RSqrtStepFused" + threeEqualRegInstX("frsqrts", "FrsqrtsDX", "SimdFloatMiscOp", + smallFloatTypes, 2, frsqrtsCode) + threeEqualRegInstX("frsqrts", "FrsqrtsQX", "SimdFloatMiscOp", floatTypes, + 4, frsqrtsCode) + threeEqualRegInstX("frsqrts", "FrsqrtsScX", "SimdFloatMiscOp", floatTypes, + 4, frsqrtsCode, scalar=True) + # FSQRT + fsqrtCode = fpOp % "fplibSqrt<Element>(srcElem1, fpscr)" + twoEqualRegInstX("fsqrt", "FsqrtDX", "SimdFloatSqrtOp", smallFloatTypes, 2, + fsqrtCode) + twoEqualRegInstX("fsqrt", "FsqrtQX", "SimdFloatSqrtOp", floatTypes, 4, + fsqrtCode) + # FSUB + fsubCode = fpBinOp % "Sub" + threeEqualRegInstX("fsub", "FsubDX", "SimdFloatAddOp", smallFloatTypes, 2, + fsubCode) + threeEqualRegInstX("fsub", "FsubQX", "SimdFloatAddOp", floatTypes, 4, + fsubCode) + # INS (element) + insFromVecElemInstX("ins", "InsElemX", "SimdMiscOp", unsignedTypes, 4) + # INS (general register) + insFromGprInstX("ins", "InsGprWX", "SimdMiscOp", smallUnsignedTypes, 4, + 'W') + insFromGprInstX("ins", "InsGprXX", "SimdMiscOp", unsignedTypes, 4, 'X') + # MLA (by element) + mlaCode = "destElem += srcElem1 * srcElem2;" + threeEqualRegInstX("mla", "MlaElemDX", "SimdMultAccOp", + ("uint16_t", "uint32_t"), 2, mlaCode, True, byElem=True) + threeEqualRegInstX("mla", "MlaElemQX", "SimdMultAccOp", + ("uint16_t", "uint32_t"), 4, mlaCode, True, byElem=True) + # MLA (vector) + threeEqualRegInstX("mla", "MlaDX", "SimdMultAccOp", smallUnsignedTypes, 2, + mlaCode, True) + threeEqualRegInstX("mla", "MlaQX", "SimdMultAccOp", smallUnsignedTypes, 4, + mlaCode, True) + # MLS (by element) + mlsCode = "destElem -= srcElem1 * srcElem2;" + threeEqualRegInstX("mls", "MlsElemDX", "SimdMultAccOp", + ("uint16_t", "uint32_t"), 2, mlsCode, True, byElem=True) + threeEqualRegInstX("mls", "MlsElemQX", "SimdMultAccOp", + ("uint16_t", "uint32_t"), 4, mlsCode, True, byElem=True) + # MLS (vector) + threeEqualRegInstX("mls", "MlsDX", "SimdMultAccOp", smallUnsignedTypes, 2, + mlsCode, True) + threeEqualRegInstX("mls", "MlsQX", "SimdMultAccOp", smallUnsignedTypes, 4, + mlsCode, True) + # MOV (element) -> alias to INS (element) + # MOV (from general) -> alias to INS (general register) + # MOV (scalar) -> alias to DUP (element) + # MOV (to general) -> alias to UMOV + # MOV (vector) -> alias to ORR (register) + # MOVI + movImmCode = "destElem = imm;" + oneRegImmInstX("movi", "MoviDX", "SimdMiscOp", ("uint64_t",), 2, + movImmCode) + oneRegImmInstX("movi", "MoviQX", "SimdMiscOp", ("uint64_t",), 4, + movImmCode) + # MUL (by element) + mulCode = "destElem = srcElem1 * srcElem2;" + threeEqualRegInstX("mul", "MulElemDX", "SimdMultOp", + ("uint16_t", "uint32_t"), 2, mulCode, byElem=True) + threeEqualRegInstX("mul", "MulElemQX", "SimdMultOp", + ("uint16_t", "uint32_t"), 4, mulCode, byElem=True) + # MUL (vector) + threeEqualRegInstX("mul", "MulDX", "SimdMultOp", smallUnsignedTypes, 2, + mulCode) + threeEqualRegInstX("mul", "MulQX", "SimdMultOp", smallUnsignedTypes, 4, + mulCode) + # MVN + mvnCode = "destElem = ~srcElem1;" + twoEqualRegInstX("mvn", "MvnDX", "SimdAluOp", ("uint64_t",), 2, mvnCode) + twoEqualRegInstX("mvn", "MvnQX", "SimdAluOp", ("uint64_t",), 4, mvnCode) + # MVNI + mvniCode = "destElem = ~imm;" + oneRegImmInstX("mvni", "MvniDX", "SimdAluOp", ("uint64_t",), 2, mvniCode) + oneRegImmInstX("mvni", "MvniQX", "SimdAluOp", ("uint64_t",), 4, mvniCode) + # NEG + negCode = "destElem = -srcElem1;" + twoEqualRegInstX("neg", "NegDX", "SimdAluOp", signedTypes, 2, negCode) + twoEqualRegInstX("neg", "NegQX", "SimdAluOp", signedTypes, 4, negCode) + # NOT -> alias to MVN + # ORN + ornCode = "destElem = srcElem1 | ~srcElem2;" + threeEqualRegInstX("orn", "OrnDX", "SimdAluOp", ("uint64_t",), 2, ornCode) + threeEqualRegInstX("orn", "OrnQX", "SimdAluOp", ("uint64_t",), 4, ornCode) + # ORR (immediate) + orrImmCode = "destElem |= imm;" + oneRegImmInstX("orr", "OrrImmDX", "SimdAluOp", ("uint64_t",), 2, + orrImmCode, True) + oneRegImmInstX("orr", "OrrImmQX", "SimdAluOp", ("uint64_t",), 4, + orrImmCode, True) + # ORR (register) + orrCode = "destElem = srcElem1 | srcElem2;" + threeEqualRegInstX("orr", "OrrDX", "SimdAluOp", ("uint64_t",), 2, orrCode) + threeEqualRegInstX("orr", "OrrQX", "SimdAluOp", ("uint64_t",), 4, orrCode) + # PMUL + pmulCode = ''' + destElem = 0; + for (unsigned j = 0; j < sizeof(Element) * 8; j++) { + if (bits(srcElem2, j)) + destElem ^= srcElem1 << j; + } + ''' + threeEqualRegInstX("pmul", "PmulDX", "SimdMultOp", ("uint8_t",), 2, + pmulCode) + threeEqualRegInstX("pmul", "PmulQX", "SimdMultOp", ("uint8_t",), 4, + pmulCode) + # PMULL, PMULL2 + # Note: 64-bit PMULL is not available (Crypto. Extension) + pmullCode = ''' + destElem = 0; + for (unsigned j = 0; j < sizeof(Element) * 8; j++) { + if (bits(srcElem2, j)) + destElem ^= (BigElement)srcElem1 << j; + } + ''' + threeRegLongInstX("pmull", "PmullX", "SimdMultOp", ("uint8_t",), pmullCode) + threeRegLongInstX("pmull", "Pmull2X", "SimdMultOp", ("uint8_t",), + pmullCode, hi=True) + # RADDHN, RADDHN2 + raddhnCode = ''' + destElem = ((BigElement)srcElem1 + (BigElement)srcElem2 + + ((BigElement)1 << (sizeof(Element) * 8 - 1))) >> + (sizeof(Element) * 8); + ''' + threeRegNarrowInstX("raddhn", "RaddhnX", "SimdAddOp", smallUnsignedTypes, + raddhnCode) + threeRegNarrowInstX("raddhn2", "Raddhn2X", "SimdAddOp", smallUnsignedTypes, + raddhnCode, hi=True) + # RBIT + rbitCode = ''' + destElem = 0; + Element temp = srcElem1; + for (int i = 0; i < 8 * sizeof(Element); i++) { + destElem = destElem | ((temp & 0x1) << + (8 * sizeof(Element) - 1 - i)); + temp >>= 1; + } + ''' + twoEqualRegInstX("rbit", "RbitDX", "SimdAluOp", ("uint8_t",), 2, rbitCode) + twoEqualRegInstX("rbit", "RbitQX", "SimdAluOp", ("uint8_t",), 4, rbitCode) + # REV16 + rev16Code = ''' + destElem = srcElem1; + unsigned groupSize = ((1 << 1) / sizeof(Element)); + unsigned reverseMask = (groupSize - 1); + j = i ^ reverseMask; + ''' + twoEqualRegInstX("rev16", "Rev16DX", "SimdAluOp", ("uint8_t",), 2, + rev16Code) + twoEqualRegInstX("rev16", "Rev16QX", "SimdAluOp", ("uint8_t",), 4, + rev16Code) + # REV32 + rev32Code = ''' + destElem = srcElem1; + unsigned groupSize = ((1 << 2) / sizeof(Element)); + unsigned reverseMask = (groupSize - 1); + j = i ^ reverseMask; + ''' + twoEqualRegInstX("rev32", "Rev32DX", "SimdAluOp", ("uint8_t", "uint16_t"), + 2, rev32Code) + twoEqualRegInstX("rev32", "Rev32QX", "SimdAluOp", ("uint8_t", "uint16_t"), + 4, rev32Code) + # REV64 + rev64Code = ''' + destElem = srcElem1; + unsigned groupSize = ((1 << 3) / sizeof(Element)); + unsigned reverseMask = (groupSize - 1); + j = i ^ reverseMask; + ''' + twoEqualRegInstX("rev64", "Rev64DX", "SimdAluOp", smallUnsignedTypes, 2, + rev64Code) + twoEqualRegInstX("rev64", "Rev64QX", "SimdAluOp", smallUnsignedTypes, 4, + rev64Code) + # RSHRN, RSHRN2 + rshrnCode = ''' + if (imm > sizeof(srcElem1) * 8) { + destElem = 0; + } else if (imm) { + Element rBit = bits(srcElem1, imm - 1); + destElem = ((srcElem1 >> (imm - 1)) >> 1) + rBit; + } else { + destElem = srcElem1; + } + ''' + twoRegNarrowInstX("rshrn", "RshrnX", "SimdShiftOp", smallUnsignedTypes, + rshrnCode, hasImm=True) + twoRegNarrowInstX("rshrn2", "Rshrn2X", "SimdShiftOp", smallUnsignedTypes, + rshrnCode, hasImm=True, hi=True) + # RSUBHN, RSUBHN2 + rsubhnCode = ''' + destElem = ((BigElement)srcElem1 - (BigElement)srcElem2 + + ((BigElement)1 << (sizeof(Element) * 8 - 1))) >> + (sizeof(Element) * 8); + ''' + threeRegNarrowInstX("rsubhn", "RsubhnX", "SimdAddOp", smallTypes, + rsubhnCode) + threeRegNarrowInstX("rsubhn2", "Rsubhn2X", "SimdAddOp", smallTypes, + rsubhnCode, hi=True) + # SABA + abaCode = ''' + destElem += (srcElem1 > srcElem2) ? (srcElem1 - srcElem2) : + (srcElem2 - srcElem1); + ''' + threeEqualRegInstX("saba", "SabaDX", "SimdAddAccOp", smallSignedTypes, 2, + abaCode, True) + threeEqualRegInstX("saba", "SabaQX", "SimdAddAccOp", smallSignedTypes, 4, + abaCode, True) + # SABAL, SABAL2 + abalCode = ''' + destElem += (srcElem1 > srcElem2) ? + ((BigElement)srcElem1 - (BigElement)srcElem2) : + ((BigElement)srcElem2 - (BigElement)srcElem1); + ''' + threeRegLongInstX("sabal", "SabalX", "SimdAddAccOp", smallSignedTypes, + abalCode, True) + threeRegLongInstX("sabal2", "Sabal2X", "SimdAddAccOp", smallSignedTypes, + abalCode, True, hi=True) + # SABD + abdCode = ''' + destElem = (srcElem1 > srcElem2) ? (srcElem1 - srcElem2) : + (srcElem2 - srcElem1); + ''' + threeEqualRegInstX("sabd", "SabdDX", "SimdAddOp", smallSignedTypes, 2, + abdCode) + threeEqualRegInstX("sabd", "SabdQX", "SimdAddOp", smallSignedTypes, 4, + abdCode) + # SABDL, SABDL2 + abdlCode = ''' + destElem = (srcElem1 > srcElem2) ? + ((BigElement)srcElem1 - (BigElement)srcElem2) : + ((BigElement)srcElem2 - (BigElement)srcElem1); + ''' + threeRegLongInstX("sabdl", "SabdlX", "SimdAddAccOp", smallSignedTypes, + abdlCode, True) + threeRegLongInstX("sabdl2", "Sabdl2X", "SimdAddAccOp", smallSignedTypes, + abdlCode, True, hi=True) + # SADALP + adalpCode = "destElem += (BigElement)srcElem1 + (BigElement)srcElem2;" + twoRegCondenseInstX("sadalp", "SadalpDX", "SimdAddOp", smallSignedTypes, 2, + adalpCode, True) + twoRegCondenseInstX("sadalp", "SadalpQX", "SimdAddOp", smallSignedTypes, 4, + adalpCode, True) + # SADDL, SADDL2 + addlwCode = "destElem = (BigElement)srcElem1 + (BigElement)srcElem2;" + threeRegLongInstX("saddl", "SaddlX", "SimdAddAccOp", smallSignedTypes, + addlwCode) + threeRegLongInstX("saddl2", "Saddl2X", "SimdAddAccOp", smallSignedTypes, + addlwCode, hi=True) + # SADDLP + twoRegCondenseInstX("saddlp", "SaddlpDX", "SimdAddOp", smallSignedTypes, 2, + addlwCode) + twoRegCondenseInstX("saddlp", "SaddlpQX", "SimdAddOp", smallSignedTypes, 4, + addlwCode) + # SADDLV + # Note: SimdAddOp can be a bit optimistic here + addAcrossLongCode = "destElem += (BigElement)srcElem1;" + twoRegAcrossInstX("saddlv", "SaddlvDX", "SimdAddOp", ("int8_t", "int16_t"), + 2, addAcrossLongCode, long=True) + twoRegAcrossInstX("saddlv", "SaddlvQX", "SimdAddOp", ("int8_t", "int16_t"), + 4, addAcrossLongCode, long=True) + twoRegAcrossInstX("saddlv", "SaddlvBQX", "SimdAddOp", ("int32_t",), 4, + addAcrossLongCode, doubleDest=True, long=True) + # SADDW, SADDW2 + threeRegWideInstX("saddw", "SaddwX", "SimdAddAccOp", smallSignedTypes, + addlwCode) + threeRegWideInstX("saddw2", "Saddw2X", "SimdAddAccOp", smallSignedTypes, + addlwCode, hi=True) + # SCVTF (fixed-point) + scvtfFixedCode = fpOp % ("fplibFixedToFP<Element>((int%d_t) srcElem1, imm," + " false, FPCRRounding(fpscr), fpscr)") + twoEqualRegInstX("scvtf", "ScvtfFixedDX", "SimdCvtOp", smallFloatTypes, 2, + scvtfFixedCode % 32, hasImm=True) + twoEqualRegInstX("scvtf", "ScvtfFixedSQX", "SimdCvtOp", smallFloatTypes, 4, + scvtfFixedCode % 32, hasImm=True) + twoEqualRegInstX("scvtf", "ScvtfFixedDQX", "SimdCvtOp", ("uint64_t",), 4, + scvtfFixedCode % 64, hasImm=True) + twoEqualRegInstX("scvtf", "ScvtfFixedScSX", "SimdCvtOp", smallFloatTypes, + 4, scvtfFixedCode % 32, hasImm=True, scalar=True) + twoEqualRegInstX("scvtf", "ScvtfFixedScDX", "SimdCvtOp", ("uint64_t",), 4, + scvtfFixedCode % 64, hasImm=True, scalar=True) + # SCVTF (integer) + scvtfIntCode = fpOp % ("fplibFixedToFP<Element>((int%d_t) srcElem1, 0," + " false, FPCRRounding(fpscr), fpscr)") + twoEqualRegInstX("scvtf", "ScvtfIntDX", "SimdCvtOp", smallFloatTypes, 2, + scvtfIntCode % 32) + twoEqualRegInstX("scvtf", "ScvtfIntSQX", "SimdCvtOp", smallFloatTypes, 4, + scvtfIntCode % 32) + twoEqualRegInstX("scvtf", "ScvtfIntDQX", "SimdCvtOp", ("uint64_t",), 4, + scvtfIntCode % 64) + twoEqualRegInstX("scvtf", "ScvtfIntScSX", "SimdCvtOp", smallFloatTypes, 4, + scvtfIntCode % 32, scalar=True) + twoEqualRegInstX("scvtf", "ScvtfIntScDX", "SimdCvtOp", ("uint64_t",), 4, + scvtfIntCode % 64, scalar=True) + # SHADD + haddCode = ''' + Element carryBit = + (((unsigned)srcElem1 & 0x1) + + ((unsigned)srcElem2 & 0x1)) >> 1; + // Use division instead of a shift to ensure the sign extension works + // right. The compiler will figure out if it can be a shift. Mask the + // inputs so they get truncated correctly. + destElem = (((srcElem1 & ~(Element)1) / 2) + + ((srcElem2 & ~(Element)1) / 2)) + carryBit; + ''' + threeEqualRegInstX("shadd", "ShaddDX", "SimdAddOp", smallSignedTypes, 2, + haddCode) + threeEqualRegInstX("shadd", "ShaddQX", "SimdAddOp", smallSignedTypes, 4, + haddCode) + # SHL + shlCode = ''' + if (imm >= sizeof(Element) * 8) + destElem = (srcElem1 << (sizeof(Element) * 8 - 1)) << 1; + else + destElem = srcElem1 << imm; + ''' + twoEqualRegInstX("shl", "ShlDX", "SimdShiftOp", unsignedTypes, 2, shlCode, + hasImm=True) + twoEqualRegInstX("shl", "ShlQX", "SimdShiftOp", unsignedTypes, 4, shlCode, + hasImm=True) + # SHLL, SHLL2 + shllCode = "destElem = ((BigElement)srcElem1) << (sizeof(Element) * 8);" + twoRegLongInstX("shll", "ShllX", "SimdShiftOp", smallTypes, shllCode) + twoRegLongInstX("shll", "Shll2X", "SimdShiftOp", smallTypes, shllCode, + hi=True) + # SHRN, SHRN2 + shrnCode = ''' + if (imm >= sizeof(srcElem1) * 8) { + destElem = 0; + } else { + destElem = srcElem1 >> imm; + } + ''' + twoRegNarrowInstX("shrn", "ShrnX", "SimdShiftOp", smallUnsignedTypes, + shrnCode, hasImm=True) + twoRegNarrowInstX("shrn2", "Shrn2X", "SimdShiftOp", smallUnsignedTypes, + shrnCode, hasImm=True, hi=True) + # SHSUB + hsubCode = ''' + Element borrowBit = + (((srcElem1 & 0x1) - (srcElem2 & 0x1)) >> 1) & 0x1; + // Use division instead of a shift to ensure the sign extension works + // right. The compiler will figure out if it can be a shift. Mask the + // inputs so they get truncated correctly. + destElem = (((srcElem1 & ~(Element)1) / 2) - + ((srcElem2 & ~(Element)1) / 2)) - borrowBit; + ''' + threeEqualRegInstX("shsub", "ShsubDX", "SimdAddOp", smallSignedTypes, 2, + hsubCode) + threeEqualRegInstX("shsub", "ShsubQX", "SimdAddOp", smallSignedTypes, 4, + hsubCode) + # SLI + sliCode = ''' + if (imm >= sizeof(Element) * 8) + destElem = destElem; + else + destElem = (srcElem1 << imm) | (destElem & mask(imm)); + ''' + twoEqualRegInstX("sli", "SliDX", "SimdShiftOp", unsignedTypes, 2, sliCode, + True, hasImm=True) + twoEqualRegInstX("sli", "SliQX", "SimdShiftOp", unsignedTypes, 4, sliCode, + True, hasImm=True) + # SMAX + maxCode = "destElem = (srcElem1 > srcElem2) ? srcElem1 : srcElem2;" + threeEqualRegInstX("smax", "SmaxDX", "SimdCmpOp", smallSignedTypes, 2, + maxCode) + threeEqualRegInstX("smax", "SmaxQX", "SimdCmpOp", smallSignedTypes, 4, + maxCode) + # SMAXP + threeEqualRegInstX("smaxp", "SmaxpDX", "SimdCmpOp", smallSignedTypes, 2, + maxCode, pairwise=True) + threeEqualRegInstX("smaxp", "SmaxpQX", "SimdCmpOp", smallSignedTypes, 4, + maxCode, pairwise=True) + # SMAXV + maxAcrossCode = ''' + if (i == 0 || srcElem1 > destElem) + destElem = srcElem1; + ''' + twoRegAcrossInstX("smaxv", "SmaxvDX", "SimdCmpOp", ("int8_t", "int16_t"), + 2, maxAcrossCode) + twoRegAcrossInstX("smaxv", "SmaxvQX", "SimdCmpOp", smallSignedTypes, 4, + maxAcrossCode) + # SMIN + minCode = "destElem = (srcElem1 < srcElem2) ? srcElem1 : srcElem2;" + threeEqualRegInstX("smin", "SminDX", "SimdCmpOp", smallSignedTypes, 2, + minCode) + threeEqualRegInstX("smin", "SminQX", "SimdCmpOp", smallSignedTypes, 4, + minCode) + # SMINP + threeEqualRegInstX("sminp", "SminpDX", "SimdCmpOp", smallSignedTypes, 2, + minCode, pairwise=True) + threeEqualRegInstX("sminp", "SminpQX", "SimdCmpOp", smallSignedTypes, 4, + minCode, pairwise=True) + # SMINV + minAcrossCode = ''' + if (i == 0 || srcElem1 < destElem) + destElem = srcElem1; + ''' + twoRegAcrossInstX("sminv", "SminvDX", "SimdCmpOp", ("int8_t", "int16_t"), + 2, minAcrossCode) + twoRegAcrossInstX("sminv", "SminvQX", "SimdCmpOp", smallSignedTypes, 4, + minAcrossCode) + # SMLAL, SMLAL2 (by element) + mlalCode = "destElem += (BigElement)srcElem1 * (BigElement)srcElem2;" + threeRegLongInstX("smlal", "SmlalElemX", "SimdMultAccOp", + ("int16_t", "int32_t"), mlalCode, True, byElem=True) + threeRegLongInstX("smlal", "SmlalElem2X", "SimdMultAccOp", + ("int16_t", "int32_t"), mlalCode, True, byElem=True, + hi=True) + # SMLAL, SMLAL2 (vector) + threeRegLongInstX("smlal", "SmlalX", "SimdMultAccOp", smallSignedTypes, + mlalCode, True) + threeRegLongInstX("smlal", "Smlal2X", "SimdMultAccOp", smallSignedTypes, + mlalCode, True, hi=True) + # SMLSL, SMLSL2 (by element) + mlslCode = "destElem -= (BigElement)srcElem1 * (BigElement)srcElem2;" + threeRegLongInstX("smlsl", "SmlslElemX", "SimdMultAccOp", smallSignedTypes, + mlslCode, True, byElem=True) + threeRegLongInstX("smlsl", "SmlslElem2X", "SimdMultAccOp", + smallSignedTypes, mlslCode, True, byElem=True, hi=True) + # SMLSL, SMLSL2 (vector) + threeRegLongInstX("smlsl", "SmlslX", "SimdMultAccOp", smallSignedTypes, + mlslCode, True) + threeRegLongInstX("smlsl", "Smlsl2X", "SimdMultAccOp", smallSignedTypes, + mlslCode, True, hi=True) + # SMOV + insToGprInstX("smov", "SmovWX", "SimdMiscOp", ("int8_t", "int16_t"), 4, + 'W', True) + insToGprInstX("smov", "SmovXX", "SimdMiscOp", smallSignedTypes, 4, 'X', + True) + # SMULL, SMULL2 (by element) + mullCode = "destElem = (BigElement)srcElem1 * (BigElement)srcElem2;" + threeRegLongInstX("smull", "SmullElemX", "SimdMultOp", smallSignedTypes, + mullCode, byElem=True) + threeRegLongInstX("smull", "SmullElem2X", "SimdMultOp", smallSignedTypes, + mullCode, byElem=True, hi=True) + # SMULL, SMULL2 (vector) + threeRegLongInstX("smull", "SmullX", "SimdMultOp", smallSignedTypes, + mullCode) + threeRegLongInstX("smull", "Smull2X", "SimdMultOp", smallSignedTypes, + mullCode, hi=True) + # SQABS + sqabsCode = ''' + FPSCR fpscr = (FPSCR) FpscrQc; + if (srcElem1 == (Element)((Element)1 << (sizeof(Element) * 8 - 1))) { + fpscr.qc = 1; + destElem = ~srcElem1; + } else if (srcElem1 < 0) { + destElem = -srcElem1; + } else { + destElem = srcElem1; + } + FpscrQc = fpscr; + ''' + twoEqualRegInstX("sqabs", "SqabsDX", "SimdAluOp", smallSignedTypes, 2, + sqabsCode) + twoEqualRegInstX("sqabs", "SqabsQX", "SimdAluOp", signedTypes, 4, + sqabsCode) + twoEqualRegInstX("sqabs", "SqabsScX", "SimdAluOp", signedTypes, 4, + sqabsCode, scalar=True) + # SQADD + sqaddCode = ''' + destElem = srcElem1 + srcElem2; + FPSCR fpscr = (FPSCR) FpscrQc; + bool negDest = (destElem < 0); + bool negSrc1 = (srcElem1 < 0); + bool negSrc2 = (srcElem2 < 0); + if ((negDest != negSrc1) && (negSrc1 == negSrc2)) { + destElem = (Element)1 << (sizeof(Element) * 8 - 1); + if (negDest) + destElem -= 1; + fpscr.qc = 1; + } + FpscrQc = fpscr; + ''' + threeEqualRegInstX("sqadd", "SqaddDX", "SimdAddOp", smallSignedTypes, 2, + sqaddCode) + threeEqualRegInstX("sqadd", "SqaddQX", "SimdAddOp", signedTypes, 4, + sqaddCode) + threeEqualRegInstX("sqadd", "SqaddScX", "SimdAddOp", signedTypes, 4, + sqaddCode, scalar=True) + # SQDMLAL, SQDMLAL2 (by element) + qdmlalCode = ''' + FPSCR fpscr = (FPSCR) FpscrQc; + BigElement midElem = (2 * (int64_t)srcElem1 * (int64_t)srcElem2); + Element maxNeg = (Element)1 << (sizeof(Element) * 8 - 1); + Element halfNeg = maxNeg / 2; + if ((srcElem1 == maxNeg && srcElem2 == maxNeg) || + (srcElem1 == halfNeg && srcElem2 == maxNeg) || + (srcElem1 == maxNeg && srcElem2 == halfNeg)) { + midElem = ~((BigElement)maxNeg << (sizeof(Element) * 8)); + fpscr.qc = 1; + } + bool negPreDest = ltz(destElem); + destElem += midElem; + bool negDest = ltz(destElem); + bool negMid = ltz(midElem); + if (negPreDest == negMid && negMid != negDest) { + destElem = mask(sizeof(BigElement) * 8 - 1); + if (negPreDest) + destElem = ~destElem; + fpscr.qc = 1; + } + FpscrQc = fpscr; + ''' + threeRegLongInstX("sqdmlal", "SqdmlalElemX", "SimdMultAccOp", + ("int16_t", "int32_t"), qdmlalCode, True, byElem=True) + threeRegLongInstX("sqdmlal", "SqdmlalElem2X", "SimdMultAccOp", + ("int16_t", "int32_t"), qdmlalCode, True, byElem=True, + hi=True) + threeRegLongInstX("sqdmlal", "SqdmlalElemScX", "SimdMultAccOp", + ("int16_t", "int32_t"), qdmlalCode, True, byElem=True, + scalar=True) + # SQDMLAL, SQDMLAL2 (vector) + threeRegLongInstX("sqdmlal", "SqdmlalX", "SimdMultAccOp", + ("int16_t", "int32_t"), qdmlalCode, True) + threeRegLongInstX("sqdmlal", "Sqdmlal2X", "SimdMultAccOp", + ("int16_t", "int32_t"), qdmlalCode, True, hi=True) + threeRegLongInstX("sqdmlal", "SqdmlalScX", "SimdMultAccOp", + ("int16_t", "int32_t"), qdmlalCode, True, scalar=True) + # SQDMLSL, SQDMLSL2 (by element) + qdmlslCode = ''' + FPSCR fpscr = (FPSCR) FpscrQc; + BigElement midElem = (2 * (int64_t)srcElem1 * (int64_t)srcElem2); + Element maxNeg = (Element)1 << (sizeof(Element) * 8 - 1); + Element halfNeg = maxNeg / 2; + if ((srcElem1 == maxNeg && srcElem2 == maxNeg) || + (srcElem1 == halfNeg && srcElem2 == maxNeg) || + (srcElem1 == maxNeg && srcElem2 == halfNeg)) { + midElem = ~((BigElement)maxNeg << (sizeof(Element) * 8)); + fpscr.qc = 1; + } + bool negPreDest = ltz(destElem); + destElem -= midElem; + bool negDest = ltz(destElem); + bool posMid = ltz((BigElement)-midElem); + if (negPreDest == posMid && posMid != negDest) { + destElem = mask(sizeof(BigElement) * 8 - 1); + if (negPreDest) + destElem = ~destElem; + fpscr.qc = 1; + } + FpscrQc = fpscr; + ''' + threeRegLongInstX("sqdmlsl", "SqdmlslElemX", "SimdMultAccOp", + ("int16_t", "int32_t"), qdmlslCode, True, byElem=True) + threeRegLongInstX("sqdmlsl", "SqdmlslElem2X", "SimdMultAccOp", + ("int16_t", "int32_t"), qdmlslCode, True, byElem=True, + hi=True) + threeRegLongInstX("sqdmlsl", "SqdmlslElemScX", "SimdMultAccOp", + ("int16_t", "int32_t"), qdmlslCode, True, byElem=True, + scalar=True) + # SQDMLSL, SQDMLSL2 (vector) + threeRegLongInstX("sqdmlsl", "SqdmlslX", "SimdMultAccOp", + ("int16_t", "int32_t"), qdmlslCode, True) + threeRegLongInstX("sqdmlsl", "Sqdmlsl2X", "SimdMultAccOp", + ("int16_t", "int32_t"), qdmlslCode, True, hi=True) + threeRegLongInstX("sqdmlsl", "SqdmlslScX", "SimdMultAccOp", + ("int16_t", "int32_t"), qdmlslCode, True, scalar=True) + # SQDMULH (by element) + sqdmulhCode = ''' + FPSCR fpscr = (FPSCR) FpscrQc; + destElem = (2 * (int64_t)srcElem1 * (int64_t)srcElem2) >> + (sizeof(Element) * 8); + if (srcElem1 == srcElem2 && + srcElem1 == (Element)((Element)1 << + (sizeof(Element) * 8 - 1))) { + destElem = ~srcElem1; + fpscr.qc = 1; + } + FpscrQc = fpscr; + ''' + threeEqualRegInstX("sqdmulh", "SqdmulhElemDX", "SimdMultOp", + ("int16_t", "int32_t"), 2, sqdmulhCode, byElem=True) + threeEqualRegInstX("sqdmulh", "SqdmulhElemQX", "SimdMultOp", + ("int16_t", "int32_t"), 4, sqdmulhCode, byElem=True) + threeEqualRegInstX("sqdmulh", "SqdmulhElemScX", "SimdMultOp", + ("int16_t", "int32_t"), 4, sqdmulhCode, byElem=True, + scalar=True) + # SQDMULH (vector) + threeEqualRegInstX("sqdmulh", "SqdmulhDX", "SimdMultOp", + ("int16_t", "int32_t"), 2, sqdmulhCode) + threeEqualRegInstX("sqdmulh", "SqdmulhQX", "SimdMultOp", + ("int16_t", "int32_t"), 4, sqdmulhCode) + threeEqualRegInstX("sqdmulh", "SqdmulhScX", "SimdMultOp", + ("int16_t", "int32_t"), 4, sqdmulhCode, scalar=True) + # SQDMULL, SQDMULL2 (by element) + qdmullCode = ''' + FPSCR fpscr = (FPSCR) FpscrQc; + destElem = (2 * (int64_t)srcElem1 * (int64_t)srcElem2); + if (srcElem1 == srcElem2 && + srcElem1 == (Element)((Element)1 << + (Element)(sizeof(Element) * 8 - 1))) { + destElem = ~((BigElement)srcElem1 << (sizeof(Element) * 8)); + fpscr.qc = 1; + } + FpscrQc = fpscr; + ''' + threeRegLongInstX("sqdmull", "SqdmullElemX", "SimdMultOp", + ("int16_t", "int32_t"), qdmullCode, True, byElem=True) + threeRegLongInstX("sqdmull", "SqdmullElem2X", "SimdMultOp", + ("int16_t", "int32_t"), qdmullCode, True, byElem=True, + hi=True) + threeRegLongInstX("sqdmull", "SqdmullElemScX", "SimdMultOp", + ("int16_t", "int32_t"), qdmullCode, True, byElem=True, + scalar=True) + # SQDMULL, SQDMULL2 (vector) + threeRegLongInstX("sqdmull", "SqdmullX", "SimdMultOp", + ("int16_t", "int32_t"), qdmullCode, True) + threeRegLongInstX("sqdmull", "Sqdmull2X", "SimdMultOp", + ("int16_t", "int32_t"), qdmullCode, True, hi=True) + threeRegLongInstX("sqdmull", "SqdmullScX", "SimdMultOp", + ("int16_t", "int32_t"), qdmullCode, True, scalar=True) + # SQNEG + sqnegCode = ''' + FPSCR fpscr = (FPSCR) FpscrQc; + if (srcElem1 == (Element)((Element)1 << (sizeof(Element) * 8 - 1))) { + fpscr.qc = 1; + destElem = ~srcElem1; + } else { + destElem = -srcElem1; + } + FpscrQc = fpscr; + ''' + twoEqualRegInstX("sqneg", "SqnegDX", "SimdAluOp", smallSignedTypes, 2, + sqnegCode) + twoEqualRegInstX("sqneg", "SqnegQX", "SimdAluOp", signedTypes, 4, + sqnegCode) + twoEqualRegInstX("sqneg", "SqnegScX", "SimdAluOp", signedTypes, 4, + sqnegCode, scalar=True) + # SQRDMULH (by element) + sqrdmulhCode = ''' + FPSCR fpscr = (FPSCR) FpscrQc; + destElem = (2 * (int64_t)srcElem1 * (int64_t)srcElem2 + + ((int64_t)1 << (sizeof(Element) * 8 - 1))) >> + (sizeof(Element) * 8); + Element maxNeg = (Element)1 << (sizeof(Element) * 8 - 1); + Element halfNeg = maxNeg / 2; + if ((srcElem1 == maxNeg && srcElem2 == maxNeg) || + (srcElem1 == halfNeg && srcElem2 == maxNeg) || + (srcElem1 == maxNeg && srcElem2 == halfNeg)) { + if (destElem < 0) { + destElem = mask(sizeof(Element) * 8 - 1); + } else { + destElem = (Element)1 << (sizeof(Element) * 8 - 1); + } + fpscr.qc = 1; + } + FpscrQc = fpscr; + ''' + threeEqualRegInstX("sqrdmulh", "SqrdmulhElemDX", "SimdMultOp", + ("int16_t", "int32_t"), 2, sqrdmulhCode, byElem=True) + threeEqualRegInstX("sqrdmulh", "SqrdmulhElemQX", "SimdMultOp", + ("int16_t", "int32_t"), 4, sqrdmulhCode, byElem=True) + threeEqualRegInstX("sqrdmulh", "SqrdmulhElemScX", "SimdMultOp", + ("int16_t", "int32_t"), 4, sqrdmulhCode, byElem=True, + scalar=True) + # SQRDMULH (vector) + threeEqualRegInstX("sqrdmulh", "SqrdmulhDX", "SimdMultOp", + ("int16_t", "int32_t"), 2, sqrdmulhCode) + threeEqualRegInstX("sqrdmulh", "SqrdmulhQX", "SimdMultOp", + ("int16_t", "int32_t"), 4, sqrdmulhCode) + threeEqualRegInstX("sqrdmulh", "SqrdmulhScX", "SimdMultOp", + ("int16_t", "int32_t"), 4, sqrdmulhCode, scalar=True) + # SQRSHL + sqrshlCode = ''' + int16_t shiftAmt = (int8_t)srcElem2; + FPSCR fpscr = (FPSCR) FpscrQc; + if (shiftAmt < 0) { + shiftAmt = -shiftAmt; + Element rBit = 0; + if (shiftAmt <= sizeof(Element) * 8) + rBit = bits(srcElem1, shiftAmt - 1); + if (shiftAmt > sizeof(Element) * 8 && srcElem1 < 0) + rBit = 1; + if (shiftAmt >= sizeof(Element) * 8) { + shiftAmt = sizeof(Element) * 8 - 1; + destElem = 0; + } else { + destElem = (srcElem1 >> shiftAmt); + } + // Make sure the right shift sign extended when it should. + if (srcElem1 < 0 && destElem >= 0) { + destElem |= -((Element)1 << (sizeof(Element) * 8 - + 1 - shiftAmt)); + } + destElem += rBit; + } else if (shiftAmt > 0) { + bool sat = false; + if (shiftAmt >= sizeof(Element) * 8) { + if (srcElem1 != 0) + sat = true; + else + destElem = 0; + } else { + if (bits((uint64_t) srcElem1, sizeof(Element) * 8 - 1, + sizeof(Element) * 8 - 1 - shiftAmt) != + ((srcElem1 < 0) ? mask(shiftAmt + 1) : 0)) { + sat = true; + } else { + destElem = srcElem1 << shiftAmt; + } + } + if (sat) { + fpscr.qc = 1; + destElem = mask(sizeof(Element) * 8 - 1); + if (srcElem1 < 0) + destElem = ~destElem; + } + } else { + destElem = srcElem1; + } + FpscrQc = fpscr; + ''' + threeEqualRegInstX("sqrshl", "SqrshlDX", "SimdCmpOp", smallSignedTypes, 2, + sqrshlCode) + threeEqualRegInstX("sqrshl", "SqrshlQX", "SimdCmpOp", signedTypes, 4, + sqrshlCode) + threeEqualRegInstX("sqrshl", "SqrshlScX", "SimdCmpOp", signedTypes, 4, + sqrshlCode, scalar=True) + # SQRSHRN, SQRSHRN2 + sqrshrnCode = ''' + FPSCR fpscr = (FPSCR) FpscrQc; + if (imm > sizeof(srcElem1) * 8) { + if (srcElem1 != 0 && srcElem1 != -1) + fpscr.qc = 1; + destElem = 0; + } else if (imm) { + BigElement mid = (srcElem1 >> (imm - 1)); + uint64_t rBit = mid & 0x1; + mid >>= 1; + mid |= -(mid & ((BigElement)1 << + (sizeof(BigElement) * 8 - 1 - imm))); + mid += rBit; + if (mid != (Element)mid) { + destElem = mask(sizeof(Element) * 8 - 1); + if (srcElem1 < 0) + destElem = ~destElem; + fpscr.qc = 1; + } else { + destElem = mid; + } + } else { + if (srcElem1 != (Element)srcElem1) { + destElem = mask(sizeof(Element) * 8 - 1); + if (srcElem1 < 0) + destElem = ~destElem; + fpscr.qc = 1; + } else { + destElem = srcElem1; + } + } + FpscrQc = fpscr; + ''' + twoRegNarrowInstX("sqrshrn", "SqrshrnX", "SimdShiftOp", smallSignedTypes, + sqrshrnCode, hasImm=True) + twoRegNarrowInstX("sqrshrn2", "Sqrshrn2X", "SimdShiftOp", smallSignedTypes, + sqrshrnCode, hasImm=True, hi=True) + twoRegNarrowInstX("sqrshrn", "SqrshrnScX", "SimdShiftOp", smallSignedTypes, + sqrshrnCode, hasImm=True, scalar=True) + # SQRSHRUN, SQRSHRUN2 + sqrshrunCode = ''' + FPSCR fpscr = (FPSCR) FpscrQc; + if (imm > sizeof(srcElem1) * 8) { + if (srcElem1 != 0) + fpscr.qc = 1; + destElem = 0; + } else if (imm) { + BigElement mid = (srcElem1 >> (imm - 1)); + uint64_t rBit = mid & 0x1; + mid >>= 1; + mid |= -(mid & ((BigElement)1 << + (sizeof(BigElement) * 8 - 1 - imm))); + mid += rBit; + if (bits(mid, sizeof(BigElement) * 8 - 1, + sizeof(Element) * 8) != 0) { + if (srcElem1 < 0) { + destElem = 0; + } else { + destElem = mask(sizeof(Element) * 8); + } + fpscr.qc = 1; + } else { + destElem = mid; + } + } else { + if (srcElem1 < 0) { + fpscr.qc = 1; + destElem = 0; + } else { + destElem = srcElem1; + } + } + FpscrQc = fpscr; + ''' + twoRegNarrowInstX("sqrshrun", "SqrshrunX", "SimdShiftOp", smallSignedTypes, + sqrshrunCode, hasImm=True) + twoRegNarrowInstX("sqrshrun", "Sqrshrun2X", "SimdShiftOp", + smallSignedTypes, sqrshrunCode, hasImm=True, hi=True) + twoRegNarrowInstX("sqrshrun", "SqrshrunScX", "SimdShiftOp", + smallSignedTypes, sqrshrunCode, hasImm=True, scalar=True) + # SQSHL (immediate) + sqshlImmCode = ''' + FPSCR fpscr = (FPSCR) FpscrQc; + if (imm >= sizeof(Element) * 8) { + if (srcElem1 != 0) { + destElem = (Element)1 << (sizeof(Element) * 8 - 1); + if (srcElem1 > 0) + destElem = ~destElem; + fpscr.qc = 1; + } else { + destElem = 0; + } + } else if (imm) { + destElem = (srcElem1 << imm); + uint64_t topBits = bits((uint64_t)srcElem1, + sizeof(Element) * 8 - 1, + sizeof(Element) * 8 - 1 - imm); + if (topBits != 0 && topBits != mask(imm + 1)) { + destElem = (Element)1 << (sizeof(Element) * 8 - 1); + if (srcElem1 > 0) + destElem = ~destElem; + fpscr.qc = 1; + } + } else { + destElem = srcElem1; + } + FpscrQc = fpscr; + ''' + twoEqualRegInstX("sqshl", "SqshlImmDX", "SimdAluOp", smallSignedTypes, 2, + sqshlImmCode, hasImm=True) + twoEqualRegInstX("sqshl", "SqshlImmQX", "SimdAluOp", signedTypes, 4, + sqshlImmCode, hasImm=True) + twoEqualRegInstX("sqshl", "SqshlImmScX", "SimdAluOp", signedTypes, 4, + sqshlImmCode, hasImm=True, scalar=True) + # SQSHL (register) + sqshlCode = ''' + int16_t shiftAmt = (int8_t)srcElem2; + FPSCR fpscr = (FPSCR) FpscrQc; + if (shiftAmt < 0) { + shiftAmt = -shiftAmt; + if (shiftAmt >= sizeof(Element) * 8) { + shiftAmt = sizeof(Element) * 8 - 1; + destElem = 0; + } else { + destElem = (srcElem1 >> shiftAmt); + } + // Make sure the right shift sign extended when it should. + if (srcElem1 < 0 && destElem >= 0) { + destElem |= -((Element)1 << (sizeof(Element) * 8 - + 1 - shiftAmt)); + } + } else if (shiftAmt > 0) { + bool sat = false; + if (shiftAmt >= sizeof(Element) * 8) { + if (srcElem1 != 0) + sat = true; + else + destElem = 0; + } else { + if (bits((uint64_t) srcElem1, sizeof(Element) * 8 - 1, + sizeof(Element) * 8 - 1 - shiftAmt) != + ((srcElem1 < 0) ? mask(shiftAmt + 1) : 0)) { + sat = true; + } else { + destElem = srcElem1 << shiftAmt; + } + } + if (sat) { + fpscr.qc = 1; + destElem = mask(sizeof(Element) * 8 - 1); + if (srcElem1 < 0) + destElem = ~destElem; + } + } else { + destElem = srcElem1; + } + FpscrQc = fpscr; + ''' + threeEqualRegInstX("sqshl", "SqshlDX", "SimdAluOp", smallSignedTypes, 2, + sqshlCode) + threeEqualRegInstX("sqshl", "SqshlQX", "SimdAluOp", signedTypes, 4, + sqshlCode) + threeEqualRegInstX("sqshl", "SqshlScX", "SimdAluOp", signedTypes, 4, + sqshlCode, scalar=True) + # SQSHLU + sqshluCode = ''' + FPSCR fpscr = (FPSCR) FpscrQc; + if (imm >= sizeof(Element) * 8) { + if (srcElem1 < 0) { + destElem = 0; + fpscr.qc = 1; + } else if (srcElem1 > 0) { + destElem = mask(sizeof(Element) * 8); + fpscr.qc = 1; + } else { + destElem = 0; + } + } else if (imm) { + destElem = (srcElem1 << imm); + uint64_t topBits = bits((uint64_t)srcElem1, + sizeof(Element) * 8 - 1, + sizeof(Element) * 8 - imm); + if (srcElem1 < 0) { + destElem = 0; + fpscr.qc = 1; + } else if (topBits != 0) { + destElem = mask(sizeof(Element) * 8); + fpscr.qc = 1; + } + } else { + if (srcElem1 < 0) { + fpscr.qc = 1; + destElem = 0; + } else { + destElem = srcElem1; + } + } + FpscrQc = fpscr; + ''' + twoEqualRegInstX("sqshlu", "SqshluDX", "SimdAluOp", smallSignedTypes, 2, + sqshluCode, hasImm=True) + twoEqualRegInstX("sqshlu", "SqshluQX", "SimdAluOp", signedTypes, 4, + sqshluCode, hasImm=True) + twoEqualRegInstX("sqshlu", "SqshluScX", "SimdAluOp", signedTypes, 4, + sqshluCode, hasImm=True, scalar=True) + # SQSHRN, SQSHRN2 + sqshrnCode = ''' + FPSCR fpscr = (FPSCR) FpscrQc; + if (imm > sizeof(srcElem1) * 8) { + if (srcElem1 != 0 && srcElem1 != -1) + fpscr.qc = 1; + destElem = 0; + } else if (imm) { + BigElement mid = ((srcElem1 >> (imm - 1)) >> 1); + mid |= -(mid & ((BigElement)1 << + (sizeof(BigElement) * 8 - 1 - imm))); + if (mid != (Element)mid) { + destElem = mask(sizeof(Element) * 8 - 1); + if (srcElem1 < 0) + destElem = ~destElem; + fpscr.qc = 1; + } else { + destElem = mid; + } + } else { + destElem = srcElem1; + } + FpscrQc = fpscr; + ''' + twoRegNarrowInstX("sqshrn", "SqshrnX", "SimdShiftOp", smallSignedTypes, + sqshrnCode, hasImm=True) + twoRegNarrowInstX("sqshrn2", "Sqshrn2X", "SimdShiftOp", smallSignedTypes, + sqshrnCode, hasImm=True, hi=True) + twoRegNarrowInstX("sqshrn", "SqshrnScX", "SimdShiftOp", smallSignedTypes, + sqshrnCode, hasImm=True, scalar=True) + # SQSHRUN, SQSHRUN2 + sqshrunCode = ''' + FPSCR fpscr = (FPSCR) FpscrQc; + if (imm > sizeof(srcElem1) * 8) { + if (srcElem1 != 0) + fpscr.qc = 1; + destElem = 0; + } else if (imm) { + BigElement mid = ((srcElem1 >> (imm - 1)) >> 1); + if (bits(mid, sizeof(BigElement) * 8 - 1, + sizeof(Element) * 8) != 0) { + if (srcElem1 < 0) { + destElem = 0; + } else { + destElem = mask(sizeof(Element) * 8); + } + fpscr.qc = 1; + } else { + destElem = mid; + } + } else { + destElem = srcElem1; + } + FpscrQc = fpscr; + ''' + twoRegNarrowInstX("sqshrun", "SqshrunX", "SimdShiftOp", smallSignedTypes, + sqshrunCode, hasImm=True) + twoRegNarrowInstX("sqshrun", "Sqshrun2X", "SimdShiftOp", smallSignedTypes, + sqshrunCode, hasImm=True, hi=True) + twoRegNarrowInstX("sqshrun", "SqshrunScX", "SimdShiftOp", smallSignedTypes, + sqshrunCode, hasImm=True, scalar=True) + # SQSUB + sqsubCode = ''' + destElem = srcElem1 - srcElem2; + FPSCR fpscr = (FPSCR) FpscrQc; + bool negDest = (destElem < 0); + bool negSrc1 = (srcElem1 < 0); + bool posSrc2 = (srcElem2 >= 0); + if ((negDest != negSrc1) && (negSrc1 == posSrc2)) { + destElem = (Element)1 << (sizeof(Element) * 8 - 1); + if (negDest) + destElem -= 1; + fpscr.qc = 1; + } + FpscrQc = fpscr; + ''' + threeEqualRegInstX("sqsub", "SqsubDX", "SimdAddOp", smallSignedTypes, 2, + sqsubCode) + threeEqualRegInstX("sqsub", "SqsubQX", "SimdAddOp", signedTypes, 4, + sqsubCode) + threeEqualRegInstX("sqsub", "SqsubScX", "SimdAddOp", signedTypes, 4, + sqsubCode, scalar=True) + # SQXTN, SQXTN2 + sqxtnCode = ''' + FPSCR fpscr = (FPSCR) FpscrQc; + destElem = srcElem1; + if ((BigElement)destElem != srcElem1) { + fpscr.qc = 1; + destElem = mask(sizeof(Element) * 8 - 1); + if (srcElem1 < 0) + destElem = ~destElem; + } + FpscrQc = fpscr; + ''' + twoRegNarrowInstX("sqxtn", "SqxtnX", "SimdMiscOp", smallSignedTypes, + sqxtnCode) + twoRegNarrowInstX("sqxtn", "Sqxtn2X", "SimdMiscOp", smallSignedTypes, + sqxtnCode, hi=True) + twoRegNarrowInstX("sqxtn", "SqxtnScX", "SimdMiscOp", smallSignedTypes, + sqxtnCode, scalar=True) + # SQXTUN, SQXTUN2 + sqxtunCode = ''' + FPSCR fpscr = (FPSCR) FpscrQc; + destElem = srcElem1; + if (srcElem1 < 0 || + ((BigElement)destElem & mask(sizeof(Element) * 8)) != srcElem1) { + fpscr.qc = 1; + destElem = mask(sizeof(Element) * 8); + if (srcElem1 < 0) + destElem = ~destElem; + } + FpscrQc = fpscr; + ''' + twoRegNarrowInstX("sqxtun", "SqxtunX", "SimdMiscOp", smallSignedTypes, + sqxtunCode) + twoRegNarrowInstX("sqxtun", "Sqxtun2X", "SimdMiscOp", smallSignedTypes, + sqxtunCode, hi=True) + twoRegNarrowInstX("sqxtun", "SqxtunScX", "SimdMiscOp", smallSignedTypes, + sqxtunCode, scalar=True) + # SRHADD + rhaddCode = ''' + Element carryBit = + (((unsigned)srcElem1 & 0x1) + + ((unsigned)srcElem2 & 0x1) + 1) >> 1; + // Use division instead of a shift to ensure the sign extension works + // right. The compiler will figure out if it can be a shift. Mask the + // inputs so they get truncated correctly. + destElem = (((srcElem1 & ~(Element)1) / 2) + + ((srcElem2 & ~(Element)1) / 2)) + carryBit; + ''' + threeEqualRegInstX("srhadd", "SrhaddDX", "SimdAddOp", smallSignedTypes, 2, + rhaddCode) + threeEqualRegInstX("srhadd", "SrhaddQX", "SimdAddOp", smallSignedTypes, 4, + rhaddCode) + # SRI + sriCode = ''' + if (imm >= sizeof(Element) * 8) + destElem = destElem; + else + destElem = (srcElem1 >> imm) | + (destElem & ~mask(sizeof(Element) * 8 - imm)); + ''' + twoEqualRegInstX("sri", "SriDX", "SimdShiftOp", unsignedTypes, 2, sriCode, + True, hasImm=True) + twoEqualRegInstX("sri", "SriQX", "SimdShiftOp", unsignedTypes, 4, sriCode, + True, hasImm=True) + # SRSHL + rshlCode = ''' + int16_t shiftAmt = (int8_t)srcElem2; + if (shiftAmt < 0) { + shiftAmt = -shiftAmt; + Element rBit = 0; + if (shiftAmt <= sizeof(Element) * 8) + rBit = bits(srcElem1, shiftAmt - 1); + if (shiftAmt > sizeof(Element) * 8 && ltz(srcElem1)) + rBit = 1; + if (shiftAmt >= sizeof(Element) * 8) { + shiftAmt = sizeof(Element) * 8 - 1; + destElem = 0; + } else { + destElem = (srcElem1 >> shiftAmt); + } + // Make sure the right shift sign extended when it should. + if (ltz(srcElem1) && !ltz(destElem)) { + destElem |= -((Element)1 << (sizeof(Element) * 8 - + 1 - shiftAmt)); + } + destElem += rBit; + } else if (shiftAmt > 0) { + if (shiftAmt >= sizeof(Element) * 8) { + destElem = 0; + } else { + destElem = srcElem1 << shiftAmt; + } + } else { + destElem = srcElem1; + } + ''' + threeEqualRegInstX("srshl", "SrshlDX", "SimdShiftOp", signedTypes, 2, + rshlCode) + threeEqualRegInstX("srshl", "SrshlQX", "SimdShiftOp", signedTypes, 4, + rshlCode) + # SRSHR + rshrCode = ''' + if (imm > sizeof(srcElem1) * 8) { + destElem = 0; + } else if (imm) { + Element rBit = bits(srcElem1, imm - 1); + destElem = ((srcElem1 >> (imm - 1)) >> 1) + rBit; + } else { + destElem = srcElem1; + } + ''' + twoEqualRegInstX("srshr", "SrshrDX", "SimdShiftOp", signedTypes, 2, + rshrCode, hasImm=True) + twoEqualRegInstX("srshr", "SrshrQX", "SimdShiftOp", signedTypes, 4, + rshrCode, hasImm=True) + # SRSRA + rsraCode = ''' + if (imm > sizeof(srcElem1) * 8) { + destElem += 0; + } else if (imm) { + Element rBit = bits(srcElem1, imm - 1); + destElem += ((srcElem1 >> (imm - 1)) >> 1) + rBit; + } else { + destElem += srcElem1; + } + ''' + twoEqualRegInstX("srsra", "SrsraDX", "SimdShiftOp", signedTypes, 2, + rsraCode, True, hasImm=True) + twoEqualRegInstX("srsra", "SrsraQX", "SimdShiftOp", signedTypes, 4, + rsraCode, True, hasImm=True) + # SSHL + shlCode = ''' + int16_t shiftAmt = (int8_t)srcElem2; + if (shiftAmt < 0) { + shiftAmt = -shiftAmt; + if (shiftAmt >= sizeof(Element) * 8) { + shiftAmt = sizeof(Element) * 8 - 1; + destElem = 0; + } else { + destElem = (srcElem1 >> shiftAmt); + } + // Make sure the right shift sign extended when it should. + if (ltz(srcElem1) && !ltz(destElem)) { + destElem |= -((Element)1 << (sizeof(Element) * 8 - + 1 - shiftAmt)); + } + } else { + if (shiftAmt >= sizeof(Element) * 8) { + destElem = 0; + } else { + destElem = srcElem1 << shiftAmt; + } + } + ''' + threeEqualRegInstX("sshl", "SshlDX", "SimdShiftOp", signedTypes, 2, + shlCode) + threeEqualRegInstX("sshl", "SshlQX", "SimdShiftOp", signedTypes, 4, + shlCode) + # SSHLL, SSHLL2 + shllCode = ''' + if (imm >= sizeof(destElem) * 8) { + destElem = 0; + } else { + destElem = (BigElement)srcElem1 << imm; + } + ''' + twoRegLongInstX("sshll", "SshllX", "SimdShiftOp", smallSignedTypes, + shllCode, hasImm=True) + twoRegLongInstX("sshll", "Sshll2X", "SimdShiftOp", smallSignedTypes, + shllCode, hasImm=True, hi=True) + # SSHR + shrCode = ''' + if (imm >= sizeof(srcElem1) * 8) { + if (ltz(srcElem1)) + destElem = -1; + else + destElem = 0; + } else { + destElem = srcElem1 >> imm; + } + ''' + twoEqualRegInstX("sshr", "SshrDX", "SimdShiftOp", signedTypes, 2, shrCode, + hasImm=True) + twoEqualRegInstX("sshr", "SshrQX", "SimdShiftOp", signedTypes, 4, shrCode, + hasImm=True) + # SSRA + sraCode = ''' + Element mid;; + if (imm >= sizeof(srcElem1) * 8) { + mid = ltz(srcElem1) ? -1 : 0; + } else { + mid = srcElem1 >> imm; + if (ltz(srcElem1) && !ltz(mid)) { + mid |= -(mid & ((Element)1 << + (sizeof(Element) * 8 - 1 - imm))); + } + } + destElem += mid; + ''' + twoEqualRegInstX("ssra", "SsraDX", "SimdShiftOp", signedTypes, 2, sraCode, + True, hasImm=True) + twoEqualRegInstX("ssra", "SsraQX", "SimdShiftOp", signedTypes, 4, sraCode, + True, hasImm=True) + # SSUBL + sublwCode = "destElem = (BigElement)srcElem1 - (BigElement)srcElem2;" + threeRegLongInstX("ssubl", "SsublX", "SimdAddOp", smallSignedTypes, + sublwCode) + threeRegLongInstX("ssubl2", "Ssubl2X", "SimdAddOp", smallSignedTypes, + sublwCode, hi=True) + # SSUBW + threeRegWideInstX("ssubw", "SsubwX", "SimdAddOp", smallSignedTypes, + sublwCode) + threeRegWideInstX("ssubw2", "Ssubw2X", "SimdAddOp", smallSignedTypes, + sublwCode, hi=True) + # SUB + subCode = "destElem = srcElem1 - srcElem2;" + threeEqualRegInstX("sub", "SubDX", "SimdAddOp", unsignedTypes, 2, subCode) + threeEqualRegInstX("sub", "SubQX", "SimdAddOp", unsignedTypes, 4, subCode) + # SUBHN, SUBHN2 + subhnCode = ''' + destElem = ((BigElement)srcElem1 - (BigElement)srcElem2) >> + (sizeof(Element) * 8); + ''' + threeRegNarrowInstX("subhn", "SubhnX", "SimdAddOp", smallUnsignedTypes, + subhnCode) + threeRegNarrowInstX("subhn2", "Subhn2X", "SimdAddOp", smallUnsignedTypes, + subhnCode, hi=True) + # SUQADD + suqaddCode = ''' + FPSCR fpscr = (FPSCR) FpscrQc; + Element tmp = destElem + srcElem1; + if (bits(destElem, sizeof(Element) * 8 - 1) == 0) { + if (bits(tmp, sizeof(Element) * 8 - 1) == 1 || + tmp < srcElem1 || tmp < destElem) { + destElem = (((Element) 1) << (sizeof(Element) * 8 - 1)) - 1; + fpscr.qc = 1; + } else { + destElem = tmp; + } + } else { + Element absDestElem = (~destElem) + 1; + if (absDestElem < srcElem1) { + // Still check for positive sat., no need to check for negative sat. + if (bits(tmp, sizeof(Element) * 8 - 1) == 1) { + destElem = (((Element) 1) << (sizeof(Element) * 8 - 1)) - 1; + fpscr.qc = 1; + } else { + destElem = tmp; + } + } else { + destElem = tmp; + } + } + FpscrQc = fpscr; + ''' + twoEqualRegInstX("suqadd", "SuqaddDX", "SimdAddOp", smallUnsignedTypes, 2, + suqaddCode, True) + twoEqualRegInstX("suqadd", "SuqaddQX", "SimdAddOp", unsignedTypes, 4, + suqaddCode, True) + twoEqualRegInstX("suqadd", "SuqaddScX", "SimdAddOp", unsignedTypes, 4, + suqaddCode, True, scalar=True) + # SXTL -> alias to SSHLL + # TBL + tbxTblInstX("tbl", "Tbl1DX", "SimdMiscOp", ("uint8_t",), 1, "true", 2) + tbxTblInstX("tbl", "Tbl1QX", "SimdMiscOp", ("uint8_t",), 1, "true", 4) + tbxTblInstX("tbl", "Tbl2DX", "SimdMiscOp", ("uint8_t",), 2, "true", 2) + tbxTblInstX("tbl", "Tbl2QX", "SimdMiscOp", ("uint8_t",), 2, "true", 4) + tbxTblInstX("tbl", "Tbl3DX", "SimdMiscOp", ("uint8_t",), 3, "true", 2) + tbxTblInstX("tbl", "Tbl3QX", "SimdMiscOp", ("uint8_t",), 3, "true", 4) + tbxTblInstX("tbl", "Tbl4DX", "SimdMiscOp", ("uint8_t",), 4, "true", 2) + tbxTblInstX("tbl", "Tbl4QX", "SimdMiscOp", ("uint8_t",), 4, "true", 4) + # TBX + tbxTblInstX("tbx", "Tbx1DX", "SimdMiscOp", ("uint8_t",), 1, "false", 2) + tbxTblInstX("tbx", "Tbx1QX", "SimdMiscOp", ("uint8_t",), 1, "false", 4) + tbxTblInstX("tbx", "Tbx2DX", "SimdMiscOp", ("uint8_t",), 2, "false", 2) + tbxTblInstX("tbx", "Tbx2QX", "SimdMiscOp", ("uint8_t",), 2, "false", 4) + tbxTblInstX("tbx", "Tbx3DX", "SimdMiscOp", ("uint8_t",), 3, "false", 2) + tbxTblInstX("tbx", "Tbx3QX", "SimdMiscOp", ("uint8_t",), 3, "false", 4) + tbxTblInstX("tbx", "Tbx4DX", "SimdMiscOp", ("uint8_t",), 4, "false", 2) + tbxTblInstX("tbx", "Tbx4QX", "SimdMiscOp", ("uint8_t",), 4, "false", 4) + # TRN1 + trnCode = ''' + unsigned part = %s; + for (unsigned i = 0; i < eCount / 2; i++) { + destReg.elements[2 * i] = srcReg1.elements[2 * i + part]; + destReg.elements[2 * i + 1] = srcReg2.elements[2 * i + part]; + } + ''' + threeRegScrambleInstX("trn1", "Trn1DX", "SimdAluOp", smallUnsignedTypes, 2, + trnCode % "0") + threeRegScrambleInstX("trn1", "Trn1QX", "SimdAluOp", unsignedTypes, 4, + trnCode % "0") + # TRN2 + threeRegScrambleInstX("trn2", "Trn2DX", "SimdAluOp", smallUnsignedTypes, 2, + trnCode % "1") + threeRegScrambleInstX("trn2", "Trn2QX", "SimdAluOp", unsignedTypes, 4, + trnCode % "1") + # UABA + threeEqualRegInstX("uaba", "UabaDX", "SimdAddAccOp", smallUnsignedTypes, 2, + abaCode, True) + threeEqualRegInstX("uaba", "UabaQX", "SimdAddAccOp", smallUnsignedTypes, 4, + abaCode, True) + # UABAL, UABAL2 + threeRegLongInstX("uabal", "UabalX", "SimdAddAccOp", smallUnsignedTypes, + abalCode, True) + threeRegLongInstX("uabal2", "Uabal2X", "SimdAddAccOp", smallUnsignedTypes, + abalCode, True, hi=True) + # UABD + threeEqualRegInstX("uabd", "UabdDX", "SimdAddOp", smallUnsignedTypes, 2, + abdCode) + threeEqualRegInstX("uabd", "UabdQX", "SimdAddOp", smallUnsignedTypes, 4, + abdCode) + # UABDL, UABDL2 + threeRegLongInstX("uabdl", "UabdlX", "SimdAddAccOp", smallUnsignedTypes, + abdlCode, True) + threeRegLongInstX("uabdl2", "Uabdl2X", "SimdAddAccOp", smallUnsignedTypes, + abdlCode, True, hi=True) + # UADALP + twoRegCondenseInstX("uadalp", "UadalpDX", "SimdAddOp", smallUnsignedTypes, + 2, adalpCode, True) + twoRegCondenseInstX("uadalp", "UadalpQX", "SimdAddOp", smallUnsignedTypes, + 4, adalpCode, True) + # UADDL, UADDL2 + threeRegLongInstX("uaddl", "UaddlX", "SimdAddAccOp", smallUnsignedTypes, + addlwCode) + threeRegLongInstX("uaddl2", "Uaddl2X", "SimdAddAccOp", smallUnsignedTypes, + addlwCode, hi=True) + # UADDLP + twoRegCondenseInstX("uaddlp", "UaddlpDX", "SimdAddOp", smallUnsignedTypes, + 2, addlwCode) + twoRegCondenseInstX("uaddlp", "UaddlpQX", "SimdAddOp", smallUnsignedTypes, + 4, addlwCode) + # UADDLV + twoRegAcrossInstX("uaddlv", "UaddlvDX", "SimdAddOp", + ("uint8_t", "uint16_t"), 2, addAcrossLongCode, long=True) + twoRegAcrossInstX("uaddlv", "UaddlvQX", "SimdAddOp", + ("uint8_t", "uint16_t"), 4, addAcrossLongCode, long=True) + twoRegAcrossInstX("uaddlv", "UaddlvBQX", "SimdAddOp", ("uint32_t",), 4, + addAcrossLongCode, doubleDest=True, long=True) + # UADDW + threeRegWideInstX("uaddw", "UaddwX", "SimdAddAccOp", smallUnsignedTypes, + addlwCode) + threeRegWideInstX("uaddw2", "Uaddw2X", "SimdAddAccOp", smallUnsignedTypes, + addlwCode, hi=True) + # UCVTF (fixed-point) + ucvtfFixedCode = fpOp % ("fplibFixedToFP<Element>(srcElem1, imm, true," + " FPCRRounding(fpscr), fpscr)") + twoEqualRegInstX("ucvtf", "UcvtfFixedDX", "SimdCvtOp", smallFloatTypes, 2, + ucvtfFixedCode, hasImm=True) + twoEqualRegInstX("ucvtf", "UcvtfFixedQX", "SimdCvtOp", floatTypes, 4, + ucvtfFixedCode, hasImm=True) + twoEqualRegInstX("ucvtf", "UcvtfFixedScX", "SimdCvtOp", floatTypes, 4, + ucvtfFixedCode, hasImm=True, scalar=True) + # UCVTF (integer) + ucvtfIntCode = fpOp % ("fplibFixedToFP<Element>(srcElem1, 0, true," + " FPCRRounding(fpscr), fpscr)") + twoEqualRegInstX("ucvtf", "UcvtfIntDX", "SimdCvtOp", smallFloatTypes, 2, + ucvtfIntCode) + twoEqualRegInstX("ucvtf", "UcvtfIntQX", "SimdCvtOp", floatTypes, 4, + ucvtfIntCode) + twoEqualRegInstX("ucvtf", "UcvtfIntScX", "SimdCvtOp", floatTypes, 4, + ucvtfIntCode, scalar=True) + # UHADD + threeEqualRegInstX("uhadd", "UhaddDX", "SimdAddOp", smallUnsignedTypes, 2, + haddCode) + threeEqualRegInstX("uhadd", "UhaddQX", "SimdAddOp", smallUnsignedTypes, 4, + haddCode) + # UHSUB + threeEqualRegInstX("uhsub", "UhsubDX", "SimdAddOp", smallUnsignedTypes, 2, + hsubCode) + threeEqualRegInstX("uhsub", "UhsubQX", "SimdAddOp", smallUnsignedTypes, 4, + hsubCode) + # UMAX + threeEqualRegInstX("umax", "UmaxDX", "SimdCmpOp", smallUnsignedTypes, 2, + maxCode) + threeEqualRegInstX("umax", "UmaxQX", "SimdCmpOp", smallUnsignedTypes, 4, + maxCode) + # UMAXP + threeEqualRegInstX("umaxp", "UmaxpDX", "SimdCmpOp", smallUnsignedTypes, 2, + maxCode, pairwise=True) + threeEqualRegInstX("umaxp", "UmaxpQX", "SimdCmpOp", smallUnsignedTypes, 4, + maxCode, pairwise=True) + # UMAXV + twoRegAcrossInstX("umaxv", "UmaxvDX", "SimdCmpOp", ("uint8_t", "uint16_t"), + 2, maxAcrossCode) + twoRegAcrossInstX("umaxv", "UmaxvQX", "SimdCmpOp", smallUnsignedTypes, 4, + maxAcrossCode) + # UMIN + threeEqualRegInstX("umin", "UminDX", "SimdCmpOp", smallUnsignedTypes, 2, + minCode) + threeEqualRegInstX("umin", "UminQX", "SimdCmpOp", smallUnsignedTypes, 4, + minCode) + # UMINP + threeEqualRegInstX("uminp", "UminpDX", "SimdCmpOp", smallUnsignedTypes, 2, + minCode, pairwise=True) + threeEqualRegInstX("uminp", "UminpQX", "SimdCmpOp", smallUnsignedTypes, 4, + minCode, pairwise=True) + # UMINV + twoRegAcrossInstX("uminv", "UminvDX", "SimdCmpOp", ("uint8_t", "uint16_t"), + 2, minAcrossCode) + twoRegAcrossInstX("uminv", "UminvQX", "SimdCmpOp", smallUnsignedTypes, 4, + minAcrossCode) + # UMLAL (by element) + threeRegLongInstX("umlal", "UmlalElemX", "SimdMultAccOp", + smallUnsignedTypes, mlalCode, True, byElem=True) + threeRegLongInstX("umlal", "UmlalElem2X", "SimdMultAccOp", + smallUnsignedTypes, mlalCode, True, byElem=True, hi=True) + # UMLAL (vector) + threeRegLongInstX("umlal", "UmlalX", "SimdMultAccOp", smallUnsignedTypes, + mlalCode, True) + threeRegLongInstX("umlal", "Umlal2X", "SimdMultAccOp", smallUnsignedTypes, + mlalCode, True, hi=True) + # UMLSL (by element) + threeRegLongInstX("umlsl", "UmlslElemX", "SimdMultAccOp", + smallUnsignedTypes, mlslCode, True, byElem=True) + threeRegLongInstX("umlsl", "UmlslElem2X", "SimdMultAccOp", + smallUnsignedTypes, mlslCode, True, byElem=True, hi=True) + # UMLSL (vector) + threeRegLongInstX("umlsl", "UmlslX", "SimdMultAccOp", smallUnsignedTypes, + mlslCode, True) + threeRegLongInstX("umlsl", "Umlsl2X", "SimdMultAccOp", smallUnsignedTypes, + mlslCode, True, hi=True) + # UMOV + insToGprInstX("umov", "UmovWX", "SimdMiscOp", smallUnsignedTypes, 4, 'W') + insToGprInstX("umov", "UmovXX", "SimdMiscOp", ("uint64_t",), 4, 'X') + # UMULL, UMULL2 (by element) + threeRegLongInstX("umull", "UmullElemX", "SimdMultOp", smallUnsignedTypes, + mullCode, byElem=True) + threeRegLongInstX("umull", "UmullElem2X", "SimdMultOp", smallUnsignedTypes, + mullCode, byElem=True, hi=True) + # UMULL, UMULL2 (vector) + threeRegLongInstX("umull", "UmullX", "SimdMultOp", smallUnsignedTypes, + mullCode) + threeRegLongInstX("umull", "Umull2X", "SimdMultOp", smallUnsignedTypes, + mullCode, hi=True) + # UQADD + uqaddCode = ''' + destElem = srcElem1 + srcElem2; + FPSCR fpscr = (FPSCR) FpscrQc; + if (destElem < srcElem1 || destElem < srcElem2) { + destElem = (Element)(-1); + fpscr.qc = 1; + } + FpscrQc = fpscr; + ''' + threeEqualRegInstX("uqadd", "UqaddDX", "SimdAddOp", smallUnsignedTypes, 2, + uqaddCode) + threeEqualRegInstX("uqadd", "UqaddQX", "SimdAddOp", unsignedTypes, 4, + uqaddCode) + threeEqualRegInstX("uqadd", "UqaddScX", "SimdAddOp", unsignedTypes, 4, + uqaddCode, scalar=True) + # UQRSHL + uqrshlCode = ''' + int16_t shiftAmt = (int8_t)srcElem2; + FPSCR fpscr = (FPSCR) FpscrQc; + if (shiftAmt < 0) { + shiftAmt = -shiftAmt; + Element rBit = 0; + if (shiftAmt <= sizeof(Element) * 8) + rBit = bits(srcElem1, shiftAmt - 1); + if (shiftAmt >= sizeof(Element) * 8) { + shiftAmt = sizeof(Element) * 8 - 1; + destElem = 0; + } else { + destElem = (srcElem1 >> shiftAmt); + } + destElem += rBit; + } else { + if (shiftAmt >= sizeof(Element) * 8) { + if (srcElem1 != 0) { + destElem = mask(sizeof(Element) * 8); + fpscr.qc = 1; + } else { + destElem = 0; + } + } else { + if (bits(srcElem1, sizeof(Element) * 8 - 1, + sizeof(Element) * 8 - shiftAmt)) { + destElem = mask(sizeof(Element) * 8); + fpscr.qc = 1; + } else { + destElem = srcElem1 << shiftAmt; + } + } + } + FpscrQc = fpscr; + ''' + threeEqualRegInstX("uqrshl", "UqrshlDX", "SimdCmpOp", smallUnsignedTypes, + 2, uqrshlCode) + threeEqualRegInstX("uqrshl", "UqrshlQX", "SimdCmpOp", unsignedTypes, 4, + uqrshlCode) + threeEqualRegInstX("uqrshl", "UqrshlScX", "SimdCmpOp", unsignedTypes, 4, + uqrshlCode, scalar=True) + # UQRSHRN + uqrshrnCode = ''' + FPSCR fpscr = (FPSCR) FpscrQc; + if (imm > sizeof(srcElem1) * 8) { + if (srcElem1 != 0) + fpscr.qc = 1; + destElem = 0; + } else if (imm) { + BigElement mid = (srcElem1 >> (imm - 1)); + uint64_t rBit = mid & 0x1; + mid >>= 1; + mid += rBit; + if (mid != (Element)mid) { + destElem = mask(sizeof(Element) * 8); + fpscr.qc = 1; + } else { + destElem = mid; + } + } else { + if (srcElem1 != (Element)srcElem1) { + destElem = mask(sizeof(Element) * 8 - 1); + fpscr.qc = 1; + } else { + destElem = srcElem1; + } + } + FpscrQc = fpscr; + ''' + twoRegNarrowInstX("uqrshrn", "UqrshrnX", "SimdShiftOp", smallUnsignedTypes, + uqrshrnCode, hasImm=True) + twoRegNarrowInstX("uqrshrn2", "Uqrshrn2X", "SimdShiftOp", + smallUnsignedTypes, uqrshrnCode, hasImm=True, hi=True) + twoRegNarrowInstX("uqrshrn", "UqrshrnScX", "SimdShiftOp", + smallUnsignedTypes, uqrshrnCode, hasImm=True, + scalar=True) + # UQSHL (immediate) + uqshlImmCode = ''' + FPSCR fpscr = (FPSCR) FpscrQc; + if (imm >= sizeof(Element) * 8) { + if (srcElem1 != 0) { + destElem = mask(sizeof(Element) * 8); + fpscr.qc = 1; + } else { + destElem = 0; + } + } else if (imm) { + destElem = (srcElem1 << imm); + uint64_t topBits = bits((uint64_t)srcElem1, + sizeof(Element) * 8 - 1, + sizeof(Element) * 8 - imm); + if (topBits != 0) { + destElem = mask(sizeof(Element) * 8); + fpscr.qc = 1; + } + } else { + destElem = srcElem1; + } + FpscrQc = fpscr; + ''' + twoEqualRegInstX("uqshl", "UqshlImmDX", "SimdAluOp", smallUnsignedTypes, 2, + uqshlImmCode, hasImm=True) + twoEqualRegInstX("uqshl", "UqshlImmQX", "SimdAluOp", unsignedTypes, 4, + uqshlImmCode, hasImm=True) + twoEqualRegInstX("uqshl", "UqshlImmScX", "SimdAluOp", unsignedTypes, 4, + uqshlImmCode, hasImm=True, scalar=True) + # UQSHL (register) + uqshlCode = ''' + int16_t shiftAmt = (int8_t)srcElem2; + FPSCR fpscr = (FPSCR) FpscrQc; + if (shiftAmt < 0) { + shiftAmt = -shiftAmt; + if (shiftAmt >= sizeof(Element) * 8) { + shiftAmt = sizeof(Element) * 8 - 1; + destElem = 0; + } else { + destElem = (srcElem1 >> shiftAmt); + } + } else if (shiftAmt > 0) { + if (shiftAmt >= sizeof(Element) * 8) { + if (srcElem1 != 0) { + destElem = mask(sizeof(Element) * 8); + fpscr.qc = 1; + } else { + destElem = 0; + } + } else { + if (bits(srcElem1, sizeof(Element) * 8 - 1, + sizeof(Element) * 8 - shiftAmt)) { + destElem = mask(sizeof(Element) * 8); + fpscr.qc = 1; + } else { + destElem = srcElem1 << shiftAmt; + } + } + } else { + destElem = srcElem1; + } + FpscrQc = fpscr; + ''' + threeEqualRegInstX("uqshl", "UqshlDX", "SimdAluOp", smallUnsignedTypes, 2, + uqshlCode) + threeEqualRegInstX("uqshl", "UqshlQX", "SimdAluOp", unsignedTypes, 4, + uqshlCode) + threeEqualRegInstX("uqshl", "UqshlScX", "SimdAluOp", unsignedTypes, 4, + uqshlCode, scalar=True) + # UQSHRN, UQSHRN2 + uqshrnCode = ''' + FPSCR fpscr = (FPSCR) FpscrQc; + if (imm > sizeof(srcElem1) * 8) { + if (srcElem1 != 0) + fpscr.qc = 1; + destElem = 0; + } else if (imm) { + BigElement mid = ((srcElem1 >> (imm - 1)) >> 1); + if (mid != (Element)mid) { + destElem = mask(sizeof(Element) * 8); + fpscr.qc = 1; + } else { + destElem = mid; + } + } else { + destElem = srcElem1; + } + FpscrQc = fpscr; + ''' + twoRegNarrowInstX("uqshrn", "UqshrnX", "SimdShiftOp", smallUnsignedTypes, + uqshrnCode, hasImm=True) + twoRegNarrowInstX("uqshrn2", "Uqshrn2X", "SimdShiftOp", smallUnsignedTypes, + uqshrnCode, hasImm=True, hi=True) + twoRegNarrowInstX("uqshrn", "UqshrnScX", "SimdShiftOp", smallUnsignedTypes, + uqshrnCode, hasImm=True, scalar=True) + # UQSUB + uqsubCode = ''' + destElem = srcElem1 - srcElem2; + FPSCR fpscr = (FPSCR) FpscrQc; + if (destElem > srcElem1) { + destElem = 0; + fpscr.qc = 1; + } + FpscrQc = fpscr; + ''' + threeEqualRegInstX("uqsub", "UqsubDX", "SimdAddOp", smallUnsignedTypes, 2, + uqsubCode) + threeEqualRegInstX("uqsub", "UqsubQX", "SimdAddOp", unsignedTypes, 4, + uqsubCode) + threeEqualRegInstX("uqsub", "UqsubScX", "SimdAddOp", unsignedTypes, 4, + uqsubCode, scalar=True) + # UQXTN + uqxtnCode = ''' + FPSCR fpscr = (FPSCR) FpscrQc; + destElem = srcElem1; + if ((BigElement)destElem != srcElem1) { + fpscr.qc = 1; + destElem = mask(sizeof(Element) * 8); + } + FpscrQc = fpscr; + ''' + twoRegNarrowInstX("uqxtn", "UqxtnX", "SimdMiscOp", smallUnsignedTypes, + uqxtnCode) + twoRegNarrowInstX("uqxtn", "Uqxtn2X", "SimdMiscOp", smallUnsignedTypes, + uqxtnCode, hi=True) + twoRegNarrowInstX("uqxtn", "UqxtnScX", "SimdMiscOp", smallUnsignedTypes, + uqxtnCode, scalar=True) + # URECPE + urecpeCode = "destElem = unsignedRecipEstimate(srcElem1);" + twoEqualRegInstX("urecpe", "UrecpeDX", "SimdMultAccOp", ("uint32_t",), 2, + urecpeCode) + twoEqualRegInstX("urecpe", "UrecpeQX", "SimdMultAccOp", ("uint32_t",), 4, + urecpeCode) + # URHADD + threeEqualRegInstX("urhadd", "UrhaddDX", "SimdAddOp", smallUnsignedTypes, + 2, rhaddCode) + threeEqualRegInstX("urhadd", "UrhaddQX", "SimdAddOp", smallUnsignedTypes, + 4, rhaddCode) + # URSHL + threeEqualRegInstX("urshl", "UrshlDX", "SimdShiftOp", unsignedTypes, 2, + rshlCode) + threeEqualRegInstX("urshl", "UrshlQX", "SimdShiftOp", unsignedTypes, 4, + rshlCode) + # URSHR + twoEqualRegInstX("urshr", "UrshrDX", "SimdShiftOp", unsignedTypes, 2, + rshrCode, hasImm=True) + twoEqualRegInstX("urshr", "UrshrQX", "SimdShiftOp", unsignedTypes, 4, + rshrCode, hasImm=True) + # URSQRTE + ursqrteCode = "destElem = unsignedRSqrtEstimate(srcElem1);" + twoEqualRegInstX("ursqrte", "UrsqrteDX", "SimdSqrtOp", ("uint32_t",), 2, + ursqrteCode) + twoEqualRegInstX("ursqrte", "UrsqrteQX", "SimdSqrtOp", ("uint32_t",), 4, + ursqrteCode) + # URSRA + twoEqualRegInstX("ursra", "UrsraDX", "SimdShiftOp", unsignedTypes, 2, + rsraCode, True, hasImm=True) + twoEqualRegInstX("ursra", "UrsraQX", "SimdShiftOp", unsignedTypes, 4, + rsraCode, True, hasImm=True) + # USHL + threeEqualRegInstX("ushl", "UshlDX", "SimdShiftOp", unsignedTypes, 2, + shlCode) + threeEqualRegInstX("ushl", "UshlQX", "SimdShiftOp", unsignedTypes, 4, + shlCode) + # USHLL, USHLL2 + twoRegLongInstX("ushll", "UshllX", "SimdShiftOp", smallUnsignedTypes, + shllCode, hasImm=True) + twoRegLongInstX("ushll", "Ushll2X", "SimdShiftOp", smallUnsignedTypes, + shllCode, hi=True, hasImm=True) + # USHR + twoEqualRegInstX("ushr", "UshrDX", "SimdShiftOp", unsignedTypes, 2, + shrCode, hasImm=True) + twoEqualRegInstX("ushr", "UshrQX", "SimdShiftOp", unsignedTypes, 4, + shrCode, hasImm=True) + # USQADD + usqaddCode = ''' + FPSCR fpscr = (FPSCR) FpscrQc; + Element tmp = destElem + srcElem1; + if (bits(srcElem1, sizeof(Element) * 8 - 1) == 0) { + if (tmp < srcElem1 || tmp < destElem) { + destElem = (Element)(-1); + fpscr.qc = 1; + } else { + destElem = tmp; + } + } else { + Element absSrcElem1 = (~srcElem1) + 1; + if (absSrcElem1 > destElem) { + destElem = 0; + fpscr.qc = 1; + } else { + destElem = tmp; + } + } + FpscrQc = fpscr; + ''' + twoEqualRegInstX("usqadd", "UsqaddDX", "SimdAddOp", smallUnsignedTypes, 2, + usqaddCode, True) + twoEqualRegInstX("usqadd", "UsqaddQX", "SimdAddOp", unsignedTypes, 4, + usqaddCode, True) + twoEqualRegInstX("usqadd", "UsqaddScX", "SimdAddOp", unsignedTypes, 4, + usqaddCode, True, scalar=True) + # USRA + twoEqualRegInstX("usra", "UsraDX", "SimdShiftOp", unsignedTypes, 2, + sraCode, True, hasImm=True) + twoEqualRegInstX("usra", "UsraQX", "SimdShiftOp", unsignedTypes, 4, + sraCode, True, hasImm=True) + # USUBL + threeRegLongInstX("usubl", "UsublX", "SimdAddOp", smallUnsignedTypes, + sublwCode) + threeRegLongInstX("usubl2", "Usubl2X", "SimdAddOp", smallUnsignedTypes, + sublwCode, hi=True) + # USUBW + threeRegWideInstX("usubw", "UsubwX", "SimdAddOp", smallUnsignedTypes, + sublwCode) + threeRegWideInstX("usubw2", "Usubw2X", "SimdAddOp", smallUnsignedTypes, + sublwCode, hi=True) + # UXTL -> alias to USHLL + # UZP1 + uzpCode = ''' + unsigned part = %s; + for (unsigned i = 0; i < eCount / 2; i++) { + destReg.elements[i] = srcReg1.elements[2 * i + part]; + destReg.elements[eCount / 2 + i] = srcReg2.elements[2 * i + part]; + } + ''' + threeRegScrambleInstX("Uzp1", "Uzp1DX", "SimdAluOp", smallUnsignedTypes, 2, + uzpCode % "0") + threeRegScrambleInstX("Uzp1", "Uzp1QX", "SimdAluOp", unsignedTypes, 4, + uzpCode % "0") + # UZP2 + threeRegScrambleInstX("Uzp2", "Uzp2DX", "SimdAluOp", smallUnsignedTypes, 2, + uzpCode % "1") + threeRegScrambleInstX("Uzp2", "Uzp2QX", "SimdAluOp", unsignedTypes, 4, + uzpCode % "1") + # XTN, XTN2 + xtnCode = "destElem = srcElem1;" + twoRegNarrowInstX("Xtn", "XtnX", "SimdMiscOp", smallUnsignedTypes, xtnCode) + twoRegNarrowInstX("Xtn", "Xtn2X", "SimdMiscOp", smallUnsignedTypes, + xtnCode, hi=True) + # ZIP1 + zipCode = ''' + unsigned base = %s; + for (unsigned i = 0; i < eCount / 2; i++) { + destReg.elements[2 * i] = srcReg1.elements[base + i]; + destReg.elements[2 * i + 1] = srcReg2.elements[base + i]; + } + ''' + threeRegScrambleInstX("zip1", "Zip1DX", "SimdAluOp", smallUnsignedTypes, 2, + zipCode % "0") + threeRegScrambleInstX("zip1", "Zip1QX", "SimdAluOp", unsignedTypes, 4, + zipCode % "0") + # ZIP2 + threeRegScrambleInstX("zip2", "Zip2DX", "SimdAluOp", smallUnsignedTypes, 2, + zipCode % "eCount / 2") + threeRegScrambleInstX("zip2", "Zip2QX", "SimdAluOp", unsignedTypes, 4, + zipCode % "eCount / 2") + +}}; diff --git a/src/arch/arm/isa/insts/neon64_mem.isa b/src/arch/arm/isa/insts/neon64_mem.isa new file mode 100644 index 000000000..32a37f87e --- /dev/null +++ b/src/arch/arm/isa/insts/neon64_mem.isa @@ -0,0 +1,471 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2012-2013 ARM Limited +// All rights reserved +// +// The license below extends only to copyright in the software and shall +// not be construed as granting a license to any other intellectual +// property including but not limited to intellectual property relating +// to a hardware implementation of the functionality of the software +// licensed hereunder. You may use the software subject to the license +// terms below provided that you ensure that this notice is replicated +// unmodified and in its entirety in all distributions of the software, +// modified or unmodified, in source code or in binary form. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Mbou Eyole +// Giacomo Gabrielli + +let {{ + + header_output = '' + decoder_output = '' + exec_output = '' + + def mkMemAccMicroOp(name): + global header_output, decoder_output, exec_output + SPAlignmentCheckCodeNeon = ''' + if (baseIsSP && bits(XURa, 3, 0) && + SPAlignmentCheckEnabled(xc->tcBase())) { + return new SPAlignmentFault(); + } + ''' + eaCode = SPAlignmentCheckCodeNeon + ''' + EA = XURa + imm; + ''' + memDecl = ''' + const int MaxNumBytes = 16; + union MemUnion { + uint8_t bytes[MaxNumBytes]; + uint32_t floatRegBits[MaxNumBytes / 4]; + }; + ''' + + # Do endian conversion for all the elements + convCode = ''' + VReg x = {0, 0}; + + x.lo = (((XReg) memUnion.floatRegBits[1]) << 32) | + (XReg) memUnion.floatRegBits[0]; + x.hi = (((XReg) memUnion.floatRegBits[3]) << 32) | + (XReg) memUnion.floatRegBits[2]; + + const unsigned eCount = 16 / (1 << eSize); + + if (isBigEndian64(xc->tcBase())) { + for (unsigned i = 0; i < eCount; i++) { + switch (eSize) { + case 0x3: // 64-bit + writeVecElem(&x, (XReg) gtobe( + (uint64_t) readVecElem(x, i, eSize)), i, eSize); + break; + case 0x2: // 32-bit + writeVecElem(&x, (XReg) gtobe( + (uint32_t) readVecElem(x, i, eSize)), i, eSize); + break; + case 0x1: // 16-bit + writeVecElem(&x, (XReg) gtobe( + (uint16_t) readVecElem(x, i, eSize)), i, eSize); + break; + default: // 8-bit + break; // Nothing to do here + } + } + } else { + for (unsigned i = 0; i < eCount; i++) { + switch (eSize) { + case 0x3: // 64-bit + writeVecElem(&x, (XReg) gtole( + (uint64_t) readVecElem(x, i, eSize)), i, eSize); + break; + case 0x2: // 32-bit + writeVecElem(&x, (XReg) gtole( + (uint32_t) readVecElem(x, i, eSize)), i, eSize); + break; + case 0x1: // 16-bit + writeVecElem(&x, (XReg) gtole( + (uint16_t) readVecElem(x, i, eSize)), i, eSize); + break; + default: // 8-bit + break; // Nothing to do here + } + } + } + + memUnion.floatRegBits[0] = (uint32_t) x.lo; + memUnion.floatRegBits[1] = (uint32_t) (x.lo >> 32); + memUnion.floatRegBits[2] = (uint32_t) x.hi; + memUnion.floatRegBits[3] = (uint32_t) (x.hi >> 32); + ''' + + # Offload everything into registers + regSetCode = '' + for reg in range(4): + regSetCode += ''' + AA64FpDestP%(reg)d_uw = gtoh(memUnion.floatRegBits[%(reg)d]); + ''' % { 'reg' : reg } + + # Pull everything in from registers + regGetCode = '' + for reg in range(4): + regGetCode += ''' + memUnion.floatRegBits[%(reg)d] = htog(AA64FpDestP%(reg)d_uw); + ''' % { 'reg' : reg } + + loadMemAccCode = convCode + regSetCode + storeMemAccCode = regGetCode + convCode + + loadIop = InstObjParams(name + 'ld', + 'MicroNeonLoad64', + 'MicroNeonMemOp', + { 'mem_decl' : memDecl, + 'memacc_code' : loadMemAccCode, + 'ea_code' : simd64EnabledCheckCode + eaCode, + }, + [ 'IsMicroop', 'IsMemRef', 'IsLoad' ]) + storeIop = InstObjParams(name + 'st', + 'MicroNeonStore64', + 'MicroNeonMemOp', + { 'mem_decl' : memDecl, + 'memacc_code' : storeMemAccCode, + 'ea_code' : simd64EnabledCheckCode + eaCode, + }, + [ 'IsMicroop', 'IsMemRef', 'IsStore' ]) + + exec_output += NeonLoadExecute64.subst(loadIop) + \ + NeonLoadInitiateAcc64.subst(loadIop) + \ + NeonLoadCompleteAcc64.subst(loadIop) + \ + NeonStoreExecute64.subst(storeIop) + \ + NeonStoreInitiateAcc64.subst(storeIop) + \ + NeonStoreCompleteAcc64.subst(storeIop) + header_output += MicroNeonMemDeclare64.subst(loadIop) + \ + MicroNeonMemDeclare64.subst(storeIop) + + def mkMarshalMicroOp(name, Name): + global header_output, decoder_output, exec_output + + getInputCodeOp1L = '' + for v in range(4): + for p in range(4): + getInputCodeOp1L += ''' + writeVecElem(&input[%(v)d], (XReg) AA64FpOp1P%(p)dV%(v)d_uw, + %(p)d, 0x2); + ''' % { 'v' : v, 'p' : p } + + getInputCodeOp1S = '' + for v in range(4): + for p in range(4): + getInputCodeOp1S += ''' + writeVecElem(&input[%(v)d], (XReg) AA64FpOp1P%(p)dV%(v)dS_uw, + %(p)d, 0x2); + ''' % { 'v' : v, 'p' : p } + + if name == 'deint_neon_uop': + + eCode = ''' + VReg input[4]; // input data from scratch area + VReg output[2]; // output data to arch. SIMD regs + VReg temp; + temp.lo = 0; + temp.hi = 0; + ''' + for p in range(4): + eCode += ''' + writeVecElem(&temp, (XReg) AA64FpDestP%(p)dV1L_uw, %(p)d, 0x2); + ''' % { 'p' : p } + eCode += getInputCodeOp1L + + # Note that numRegs is not always the same as numStructElems; in + # particular, for LD1/ST1, numStructElems is 1 but numRegs can be + # 1, 2, 3 or 4 + + eCode += ''' + output[0].lo = 0; + output[0].hi = 0; + output[1].lo = 0; + output[1].hi = 0; + + int eCount = dataSize / (8 << eSize); + int eSizeBytes = 1 << eSize; // element size in bytes + int numBytes = step * dataSize / 4; + int totNumBytes = numRegs * dataSize / 8; + + int structElemNo, pos, a, b; + XReg data; + + for (int r = 0; r < 2; ++r) { + for (int i = 0; i < eCount; ++i) { + if (numBytes < totNumBytes) { + structElemNo = r + (step * 2); + if (numStructElems == 1) { + pos = (eSizeBytes * i) + + (eCount * structElemNo * eSizeBytes); + } else { + pos = (numStructElems * eSizeBytes * i) + + (structElemNo * eSizeBytes); + } + a = pos / 16; + b = (pos % 16) / eSizeBytes; + data = (XReg) readVecElem(input[a], (XReg) b, + eSize); + writeVecElem(&output[r], data, i, eSize); + numBytes += eSizeBytes; + } + } + } + ''' + for p in range(4): + eCode += ''' + AA64FpDestP%(p)dV0L_uw = (uint32_t) readVecElem(output[0], + %(p)d, 0x2); + ''' % { 'p' : p } + eCode += ''' + if ((numRegs % 2 == 0) || (numRegs == 3 && step == 0)) { + ''' + for p in range(4): + eCode += ''' + AA64FpDestP%(p)dV1L_uw = (uint32_t) readVecElem( + output[1], %(p)d, 0x2); + ''' % { 'p' : p } + eCode += ''' + } else { + ''' + for p in range(4): + eCode += ''' + AA64FpDestP%(p)dV1L_uw = (uint32_t) readVecElem(temp, + %(p)d, 0x2); + ''' % { 'p' : p } + eCode += ''' + } + ''' + + iop = InstObjParams(name, Name, 'MicroNeonMixOp64', + { 'code' : eCode }, ['IsMicroop']) + header_output += MicroNeonMixDeclare64.subst(iop) + exec_output += MicroNeonMixExecute64.subst(iop) + + elif name == 'int_neon_uop': + + eCode = ''' + VReg input[4]; // input data from arch. SIMD regs + VReg output[2]; // output data to scratch area + ''' + + eCode += getInputCodeOp1S + + # Note that numRegs is not always the same as numStructElems; in + # particular, for LD1/ST1, numStructElems is 1 but numRegs can be + # 1, 2, 3 or 4 + + eCode += ''' + int eCount = dataSize / (8 << eSize); + int eSizeBytes = 1 << eSize; + int totNumBytes = numRegs * dataSize / 8; + int numOutputElems = 128 / (8 << eSize); + int stepOffset = step * 32; + + for (int i = 0; i < 2; ++i) { + output[i].lo = 0; + output[i].hi = 0; + } + + int r = 0, k = 0, i, j; + XReg data; + + for (int pos = stepOffset; pos < 32 + stepOffset; + pos += eSizeBytes) { + if (pos < totNumBytes) { + if (numStructElems == 1) { + i = (pos / eSizeBytes) % eCount; + j = pos / (eCount * eSizeBytes); + } else { + i = pos / (numStructElems * eSizeBytes); + j = (pos % (numStructElems * eSizeBytes)) / + eSizeBytes; + } + data = (XReg) readVecElem(input[j], (XReg) i, eSize); + writeVecElem(&output[r], data, k, eSize); + k++; + if (k == numOutputElems){ + k = 0; + ++r; + } + } + } + ''' + for v in range(2): + for p in range(4): + eCode += ''' + AA64FpDestP%(p)dV%(v)d_uw = (uint32_t) readVecElem( + output[%(v)d], %(p)d, 0x2); + ''' % { 'v': v, 'p': p} + + iop = InstObjParams(name, Name, 'MicroNeonMixOp64', + { 'code' : eCode }, ['IsMicroop']) + header_output += MicroNeonMixDeclare64.subst(iop) + exec_output += MicroNeonMixExecute64.subst(iop) + + elif name == 'unpack_neon_uop': + + eCode = ''' + VReg input[4]; //input data from scratch area + VReg output[2]; //output data to arch. SIMD regs + ''' + + eCode += getInputCodeOp1L + + # Fill output regs with register data initially. Note that + # elements in output register outside indexed lanes are left + # untouched + for v in range(2): + for p in range(4): + eCode += ''' + writeVecElem(&output[%(v)d], (XReg) AA64FpDestP%(p)dV%(v)dL_uw, + %(p)d, 0x2); + ''' % { 'v': v, 'p': p} + eCode += ''' + int eCount = dataSize / (8 << eSize); + int eCount128 = 128 / (8 << eSize); + int eSizeBytes = 1 << eSize; + int totNumBytes = numStructElems * eSizeBytes; + int numInputElems = eCount128; + int stepOffset = step * 2 * eSizeBytes; + int stepLimit = 2 * eSizeBytes; + + int r = 0, i, j; + XReg data; + + for (int pos = stepOffset; pos < stepLimit + stepOffset; + pos += eSizeBytes) { + if (pos < totNumBytes) { + r = pos / eSizeBytes; + j = r / numInputElems; + i = r % numInputElems; + data = (XReg) readVecElem(input[j], (XReg) i, eSize); + + if (replicate) { + for (int i = 0; i < eCount128; ++i) { + if (i < eCount) { + writeVecElem(&output[r % 2], data, i, + eSize); + } else { // zero extend if necessary + writeVecElem(&output[r % 2], (XReg) 0, i, + eSize); + } + } + } else { + writeVecElem(&output[r % 2], data, lane, eSize); + } + } + } + ''' + for v in range(2): + for p in range(4): + eCode += ''' + AA64FpDestP%(p)dV%(v)dL_uw = (uint32_t) readVecElem( + output[%(v)d], %(p)d, 0x2); + ''' % { 'v' : v, 'p' : p } + + iop = InstObjParams(name, Name, 'MicroNeonMixLaneOp64', + { 'code' : eCode }, ['IsMicroop']) + header_output += MicroNeonMixLaneDeclare64.subst(iop) + exec_output += MicroNeonMixExecute64.subst(iop) + + elif name == 'pack_neon_uop': + + eCode = ''' + VReg input[4]; // input data from arch. SIMD regs + VReg output[2]; // output data to scratch area + ''' + + eCode += getInputCodeOp1S + + eCode += ''' + int eSizeBytes = 1 << eSize; + int numOutputElems = 128 / (8 << eSize); + int totNumBytes = numStructElems * eSizeBytes; + int stepOffset = step * 32; + int stepLimit = 32; + + int r = 0, i, j; + XReg data; + + for (int i = 0; i < 2; ++i) { + output[i].lo = 0; + output[i].hi = 0; + } + + for (int pos = stepOffset; pos < stepLimit + stepOffset; + pos += eSizeBytes) { + if (pos < totNumBytes) { + r = pos / 16; + j = pos / eSizeBytes; + i = (pos / eSizeBytes) % numOutputElems; + data = (XReg) readVecElem(input[j], lane, eSize); + writeVecElem(&output[r % 2], data, i, eSize); + } + } + ''' + + for v in range(2): + for p in range(4): + eCode += ''' + AA64FpDestP%(p)dV%(v)d_uw = (uint32_t) readVecElem( + output[%(v)d], %(p)d, 0x2); + ''' % { 'v' : v, 'p' : p } + + iop = InstObjParams(name, Name, 'MicroNeonMixLaneOp64', + { 'code' : eCode }, ['IsMicroop']) + header_output += MicroNeonMixLaneDeclare64.subst(iop) + exec_output += MicroNeonMixExecute64.subst(iop) + + # Generate instructions + mkMemAccMicroOp('mem_neon_uop') + mkMarshalMicroOp('deint_neon_uop', 'MicroDeintNeon64') + mkMarshalMicroOp('int_neon_uop', 'MicroIntNeon64') + mkMarshalMicroOp('unpack_neon_uop', 'MicroUnpackNeon64') + mkMarshalMicroOp('pack_neon_uop', 'MicroPackNeon64') + +}}; + +let {{ + + iop = InstObjParams('vldmult64', 'VldMult64', 'VldMultOp64', '', []) + header_output += VMemMultDeclare64.subst(iop) + decoder_output += VMemMultConstructor64.subst(iop) + + iop = InstObjParams('vstmult64', 'VstMult64', 'VstMultOp64', '', []) + header_output += VMemMultDeclare64.subst(iop) + decoder_output += VMemMultConstructor64.subst(iop) + + iop = InstObjParams('vldsingle64', 'VldSingle64', 'VldSingleOp64', '', []) + header_output += VMemSingleDeclare64.subst(iop) + decoder_output += VMemSingleConstructor64.subst(iop) + + iop = InstObjParams('vstsingle64', 'VstSingle64', 'VstSingleOp64', '', []) + header_output += VMemSingleDeclare64.subst(iop) + decoder_output += VMemSingleConstructor64.subst(iop) + +}}; diff --git a/src/arch/arm/isa/insts/str.isa b/src/arch/arm/isa/insts/str.isa index 80846053b..3f595692a 100644 --- a/src/arch/arm/isa/insts/str.isa +++ b/src/arch/arm/isa/insts/str.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2010 ARM Limited +// Copyright (c) 2010-2011 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -38,6 +38,7 @@ // Authors: Gabe Black let {{ + import math header_output = "" decoder_output = "" @@ -77,7 +78,9 @@ let {{ (newHeader, newDecoder, newExec) = self.fillTemplates(self.name, self.Name, codeBlobs, - self.memFlags, self.instFlags, base, wbDecl) + self.memFlags, self.instFlags, + base, wbDecl, None, False, + self.size, self.sign) header_output += newHeader decoder_output += newDecoder @@ -171,7 +174,7 @@ let {{ self.size, self.sign, self.user) # Add memory request flags where necessary - self.memFlags.append("%d" % (self.size - 1)) + self.memFlags.append("%d" % int(math.log(self.size, 2))) if self.user: self.memFlags.append("ArmISA::TLB::UserMode") diff --git a/src/arch/arm/isa/insts/str64.isa b/src/arch/arm/isa/insts/str64.isa new file mode 100644 index 000000000..c15dca16e --- /dev/null +++ b/src/arch/arm/isa/insts/str64.isa @@ -0,0 +1,372 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2011-2013 ARM Limited +// All rights reserved +// +// The license below extends only to copyright in the software and shall +// not be construed as granting a license to any other intellectual +// property including but not limited to intellectual property relating +// to a hardware implementation of the functionality of the software +// licensed hereunder. You may use the software subject to the license +// terms below provided that you ensure that this notice is replicated +// unmodified and in its entirety in all distributions of the software, +// modified or unmodified, in source code or in binary form. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Gabe Black + +let {{ + + header_output = "" + decoder_output = "" + exec_output = "" + + class StoreInst64(LoadStoreInst): + execBase = 'Store64' + micro = False + + def __init__(self, mnem, Name, size=4, user=False, flavor="normal", + top = False): + super(StoreInst64, self).__init__() + + self.name = mnem + self.Name = Name + self.size = size + self.user = user + self.flavor = flavor + self.top = top + + self.memFlags = ["ArmISA::TLB::MustBeOne"] + self.instFlags = [] + self.codeBlobs = { "postacc_code" : "" } + + # Add memory request flags where necessary + if self.user: + self.memFlags.append("ArmISA::TLB::UserMode") + + if self.flavor in ("relexp", "exp"): + # For exclusive pair ops alignment check is based on total size + self.memFlags.append("%d" % int(math.log(self.size, 2) + 1)) + elif not (self.size == 16 and self.top): + # Only the first microop should perform alignment checking. + self.memFlags.append("%d" % int(math.log(self.size, 2))) + + if self.flavor not in ("release", "relex", "exclusive", + "relexp", "exp"): + self.memFlags.append("ArmISA::TLB::AllowUnaligned") + + if self.micro: + self.instFlags.append("IsMicroop") + + if self.flavor in ("release", "relex", "relexp"): + self.instFlags.extend(["IsMemBarrier", + "IsWriteBarrier", + "IsReadBarrier"]) + if self.flavor in ("relex", "exclusive", "exp", "relexp"): + self.instFlags.append("IsStoreConditional") + self.memFlags.append("Request::LLSC") + + def emitHelper(self, base = 'Memory64', wbDecl = None): + global header_output, decoder_output, exec_output + + # If this is a microop itself, don't allow anything that would + # require further microcoding. + if self.micro: + assert not wbDecl + + fa_code = None + if not self.micro and self.flavor in ("normal", "release"): + fa_code = ''' + fault->annotate(ArmFault::SAS, %s); + fault->annotate(ArmFault::SSE, false); + fault->annotate(ArmFault::SRT, dest); + fault->annotate(ArmFault::SF, %s); + fault->annotate(ArmFault::AR, %s); + ''' % ("0" if self.size == 1 else + "1" if self.size == 2 else + "2" if self.size == 4 else "3", + "true" if self.size == 8 else "false", + "true" if self.flavor == "release" else "false") + + (newHeader, newDecoder, newExec) = \ + self.fillTemplates(self.name, self.Name, self.codeBlobs, + self.memFlags, self.instFlags, + base, wbDecl, faCode=fa_code) + + header_output += newHeader + decoder_output += newDecoder + exec_output += newExec + + def buildEACode(self): + # Address computation + eaCode = "" + if self.flavor == "fp": + eaCode += vfp64EnabledCheckCode + + eaCode += SPAlignmentCheckCode + "EA = XBase" + if self.size == 16: + if self.top: + eaCode += " + (isBigEndian64(xc->tcBase()) ? 0 : 8)" + else: + eaCode += " + (isBigEndian64(xc->tcBase()) ? 8 : 0)" + if not self.post: + eaCode += self.offset + eaCode += ";" + + self.codeBlobs["ea_code"] = eaCode + + + class StoreImmInst64(StoreInst64): + def __init__(self, *args, **kargs): + super(StoreImmInst64, self).__init__(*args, **kargs) + self.offset = "+ imm" + + self.wbDecl = "MicroAddXiUop(machInst, base, base, imm);" + + class StoreRegInst64(StoreInst64): + def __init__(self, *args, **kargs): + super(StoreRegInst64, self).__init__(*args, **kargs) + self.offset = "+ extendReg64(XOffset, type, shiftAmt, 64)" + + self.wbDecl = \ + "MicroAddXERegUop(machInst, base, base, " + \ + " offset, type, shiftAmt);" + + class StoreRawRegInst64(StoreInst64): + def __init__(self, *args, **kargs): + super(StoreRawRegInst64, self).__init__(*args, **kargs) + self.offset = "" + + class StoreSingle64(StoreInst64): + def emit(self): + self.buildEACode() + + # Code that actually handles the access + if self.flavor == "fp": + if self.size in (1, 2, 4): + accCode = ''' + Mem%(suffix)s = + cSwap(AA64FpDestP0%(suffix)s, isBigEndian64(xc->tcBase())); + ''' + elif self.size == 8 or (self.size == 16 and not self.top): + accCode = ''' + uint64_t data = AA64FpDestP1_uw; + data = (data << 32) | AA64FpDestP0_uw; + Mem%(suffix)s = cSwap(data, isBigEndian64(xc->tcBase())); + ''' + elif self.size == 16 and self.top: + accCode = ''' + uint64_t data = AA64FpDestP3_uw; + data = (data << 32) | AA64FpDestP2_uw; + Mem%(suffix)s = cSwap(data, isBigEndian64(xc->tcBase())); + ''' + else: + accCode = \ + 'Mem%(suffix)s = cSwap(XDest%(suffix)s, isBigEndian64(xc->tcBase()));' + if self.size == 16: + accCode = accCode % \ + { "suffix" : buildMemSuffix(False, 8) } + else: + accCode = accCode % \ + { "suffix" : buildMemSuffix(False, self.size) } + + self.codeBlobs["memacc_code"] = accCode + + if self.flavor in ("relex", "exclusive"): + self.instFlags.append("IsStoreConditional") + self.memFlags.append("Request::LLSC") + + # Push it out to the output files + wbDecl = None + if self.writeback and not self.micro: + wbDecl = self.wbDecl + self.emitHelper(self.base, wbDecl) + + class StoreDouble64(StoreInst64): + def emit(self): + self.buildEACode() + + # Code that actually handles the access + if self.flavor == "fp": + accCode = ''' + uint64_t data = AA64FpDest2P0_uw; + data = (data << 32) | AA64FpDestP0_uw; + Mem_ud = cSwap(data, isBigEndian64(xc->tcBase())); + ''' + else: + if self.size == 4: + accCode = ''' + uint64_t data = XDest2_uw; + data = (data << 32) | XDest_uw; + Mem_ud = cSwap(data, isBigEndian64(xc->tcBase())); + ''' + elif self.size == 8: + accCode = ''' + // This temporary needs to be here so that the parser + // will correctly identify this instruction as a store. + Twin64_t temp; + temp.a = XDest_ud; + temp.b = XDest2_ud; + Mem_tud = temp; + ''' + self.codeBlobs["memacc_code"] = accCode + + # Push it out to the output files + wbDecl = None + if self.writeback and not self.micro: + wbDecl = self.wbDecl + self.emitHelper(self.base, wbDecl) + + class StoreImm64(StoreImmInst64, StoreSingle64): + decConstBase = 'LoadStoreImm64' + base = 'ArmISA::MemoryImm64' + writeback = False + post = False + + class StorePre64(StoreImmInst64, StoreSingle64): + decConstBase = 'LoadStoreImm64' + base = 'ArmISA::MemoryPreIndex64' + writeback = True + post = False + + class StorePost64(StoreImmInst64, StoreSingle64): + decConstBase = 'LoadStoreImm64' + base = 'ArmISA::MemoryPostIndex64' + writeback = True + post = True + + class StoreReg64(StoreRegInst64, StoreSingle64): + decConstBase = 'LoadStoreReg64' + base = 'ArmISA::MemoryReg64' + writeback = False + post = False + + class StoreRaw64(StoreRawRegInst64, StoreSingle64): + decConstBase = 'LoadStoreRaw64' + base = 'ArmISA::MemoryRaw64' + writeback = False + post = False + + class StoreEx64(StoreRawRegInst64, StoreSingle64): + decConstBase = 'LoadStoreEx64' + base = 'ArmISA::MemoryEx64' + writeback = False + post = False + execBase = 'StoreEx64' + def __init__(self, *args, **kargs): + super(StoreEx64, self).__init__(*args, **kargs) + self.codeBlobs["postacc_code"] = "XResult = !writeResult;" + + def buildStores64(mnem, NameBase, size, flavor="normal"): + StoreImm64(mnem, NameBase + "_IMM", size, flavor=flavor).emit() + StorePre64(mnem, NameBase + "_PRE", size, flavor=flavor).emit() + StorePost64(mnem, NameBase + "_POST", size, flavor=flavor).emit() + StoreReg64(mnem, NameBase + "_REG", size, flavor=flavor).emit() + + buildStores64("strb", "STRB64", 1) + buildStores64("strh", "STRH64", 2) + buildStores64("str", "STRW64", 4) + buildStores64("str", "STRX64", 8) + buildStores64("str", "STRBFP64", 1, flavor="fp") + buildStores64("str", "STRHFP64", 2, flavor="fp") + buildStores64("str", "STRSFP64", 4, flavor="fp") + buildStores64("str", "STRDFP64", 8, flavor="fp") + + StoreImm64("sturb", "STURB64_IMM", 1).emit() + StoreImm64("sturh", "STURH64_IMM", 2).emit() + StoreImm64("stur", "STURW64_IMM", 4).emit() + StoreImm64("stur", "STURX64_IMM", 8).emit() + StoreImm64("stur", "STURBFP64_IMM", 1, flavor="fp").emit() + StoreImm64("stur", "STURHFP64_IMM", 2, flavor="fp").emit() + StoreImm64("stur", "STURSFP64_IMM", 4, flavor="fp").emit() + StoreImm64("stur", "STURDFP64_IMM", 8, flavor="fp").emit() + + StoreImm64("sttrb", "STTRB64_IMM", 1, user=True).emit() + StoreImm64("sttrh", "STTRH64_IMM", 2, user=True).emit() + StoreImm64("sttr", "STTRW64_IMM", 4, user=True).emit() + StoreImm64("sttr", "STTRX64_IMM", 8, user=True).emit() + + StoreRaw64("stlr", "STLRX64", 8, flavor="release").emit() + StoreRaw64("stlr", "STLRW64", 4, flavor="release").emit() + StoreRaw64("stlrh", "STLRH64", 2, flavor="release").emit() + StoreRaw64("stlrb", "STLRB64", 1, flavor="release").emit() + + StoreEx64("stlxr", "STLXRX64", 8, flavor="relex").emit() + StoreEx64("stlxr", "STLXRW64", 4, flavor="relex").emit() + StoreEx64("stlxrh", "STLXRH64", 2, flavor="relex").emit() + StoreEx64("stlxrb", "STLXRB64", 1, flavor="relex").emit() + + StoreEx64("stxr", "STXRX64", 8, flavor="exclusive").emit() + StoreEx64("stxr", "STXRW64", 4, flavor="exclusive").emit() + StoreEx64("stxrh", "STXRH64", 2, flavor="exclusive").emit() + StoreEx64("stxrb", "STXRB64", 1, flavor="exclusive").emit() + + class StoreImmU64(StoreImm64): + decConstBase = 'LoadStoreImmU64' + micro = True + + class StoreImmDU64(StoreImmInst64, StoreDouble64): + decConstBase = 'LoadStoreImmDU64' + base = 'ArmISA::MemoryDImm64' + micro = True + post = False + writeback = False + + class StoreImmDEx64(StoreImmInst64, StoreDouble64): + execBase = 'StoreEx64' + decConstBase = 'StoreImmDEx64' + base = 'ArmISA::MemoryDImmEx64' + micro = False + post = False + writeback = False + def __init__(self, *args, **kargs): + super(StoreImmDEx64, self).__init__(*args, **kargs) + self.codeBlobs["postacc_code"] = "XResult = !writeResult;" + + class StoreRegU64(StoreReg64): + decConstBase = 'LoadStoreRegU64' + micro = True + + StoreImmDEx64("stlxp", "STLXPW64", 4, flavor="relexp").emit() + StoreImmDEx64("stlxp", "STLXPX64", 8, flavor="relexp").emit() + StoreImmDEx64("stxp", "STXPW64", 4, flavor="exp").emit() + StoreImmDEx64("stxp", "STXPX64", 8, flavor="exp").emit() + + StoreImmU64("strxi_uop", "MicroStrXImmUop", 8).emit() + StoreRegU64("strxr_uop", "MicroStrXRegUop", 8).emit() + StoreImmU64("strfpxi_uop", "MicroStrFpXImmUop", 8, flavor="fp").emit() + StoreRegU64("strfpxr_uop", "MicroStrFpXRegUop", 8, flavor="fp").emit() + StoreImmU64("strqbfpxi_uop", "MicroStrQBFpXImmUop", + 16, flavor="fp", top=False).emit() + StoreRegU64("strqbfpxr_uop", "MicroStrQBFpXRegUop", + 16, flavor="fp", top=False).emit() + StoreImmU64("strqtfpxi_uop", "MicroStrQTFpXImmUop", + 16, flavor="fp", top=True).emit() + StoreRegU64("strqtfpxr_uop", "MicroStrQTFpXRegUop", + 16, flavor="fp", top=True).emit() + StoreImmDU64("strdxi_uop", "MicroStrDXImmUop", 4).emit() + StoreImmDU64("strdfpxi_uop", "MicroStrDFpXImmUop", 4, flavor="fp").emit() + +}}; diff --git a/src/arch/arm/isa/insts/swap.isa b/src/arch/arm/isa/insts/swap.isa index b42a1c4b2..f2ceed28e 100644 --- a/src/arch/arm/isa/insts/swap.isa +++ b/src/arch/arm/isa/insts/swap.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2010 ARM Limited +// Copyright (c) 2010-2011 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -73,10 +73,7 @@ let {{ swpPreAccCode = ''' if (!((SCTLR)Sctlr).sw) { - if (FullSystem) - return new UndefinedInstruction; - else - return new UndefinedInstruction(false, mnemonic); + return new UndefinedInstruction(machInst, false, mnemonic); } ''' diff --git a/src/arch/arm/isa/operands.isa b/src/arch/arm/isa/operands.isa index 64deef044..7a1213377 100644 --- a/src/arch/arm/isa/operands.isa +++ b/src/arch/arm/isa/operands.isa @@ -1,5 +1,5 @@ // -*- mode:c++ -*- -// Copyright (c) 2010 ARM Limited +// Copyright (c) 2010-2013 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -80,6 +80,31 @@ let {{ xc->%(func)s(this, %(op_idx)s, %(final_val)s); } ''' + aarch64Read = ''' + ((xc->%(func)s(this, %(op_idx)s)) & mask(intWidth)) + ''' + aarch64Write = ''' + xc->%(func)s(this, %(op_idx)s, (%(final_val)s) & mask(intWidth)) + ''' + aarchX64Read = ''' + ((xc->%(func)s(this, %(op_idx)s)) & mask(aarch64 ? 64 : 32)) + ''' + aarchX64Write = ''' + xc->%(func)s(this, %(op_idx)s, (%(final_val)s) & mask(aarch64 ? 64 : 32)) + ''' + aarchW64Read = ''' + ((xc->%(func)s(this, %(op_idx)s)) & mask(32)) + ''' + aarchW64Write = ''' + xc->%(func)s(this, %(op_idx)s, (%(final_val)s) & mask(32)) + ''' + cntrlNsBankedWrite = ''' + xc->setMiscReg(flattenMiscRegNsBanked(dest, xc->tcBase()), %(final_val)s) + ''' + + cntrlNsBankedRead = ''' + xc->readMiscReg(flattenMiscRegNsBanked(op1, xc->tcBase())) + ''' #PCState operands need to have a sorting index (the number at the end) #less than all the integer registers which might update the PC. That way @@ -99,6 +124,18 @@ let {{ return ('IntReg', 'uw', idx, 'IsInteger', srtNormal, maybePCRead, maybePCWrite) + def intReg64(idx): + return ('IntReg', 'ud', idx, 'IsInteger', srtNormal, + aarch64Read, aarch64Write) + + def intRegX64(idx, id = srtNormal): + return ('IntReg', 'ud', idx, 'IsInteger', id, + aarchX64Read, aarchX64Write) + + def intRegW64(idx, id = srtNormal): + return ('IntReg', 'ud', idx, 'IsInteger', id, + aarchW64Read, aarchW64Write) + def intRegNPC(idx): return ('IntReg', 'uw', idx, 'IsInteger', srtNormal) @@ -120,26 +157,49 @@ let {{ def cntrlReg(idx, id = srtNormal, type = 'uw'): return ('ControlReg', type, idx, None, id) + def cntrlNsBankedReg(idx, id = srtNormal, type = 'uw'): + return ('ControlReg', type, idx, (None, None, 'IsControl'), id, cntrlNsBankedRead, cntrlNsBankedWrite) + + def cntrlNsBankedReg64(idx, id = srtNormal, type = 'ud'): + return ('ControlReg', type, idx, (None, None, 'IsControl'), id, cntrlNsBankedRead, cntrlNsBankedWrite) + def cntrlRegNC(idx, id = srtNormal, type = 'uw'): return ('ControlReg', type, idx, None, id) def pcStateReg(idx, id): - return ('PCState', 'uw', idx, (None, None, 'IsControl'), id) + return ('PCState', 'ud', idx, (None, None, 'IsControl'), id) }}; def operands {{ #Abstracted integer reg operands 'Dest': intReg('dest'), + 'Dest64': intReg64('dest'), + 'XDest': intRegX64('dest'), + 'WDest': intRegW64('dest'), 'IWDest': intRegIWPC('dest'), 'AIWDest': intRegAIWPC('dest'), 'Dest2': intReg('dest2'), + 'XDest2': intRegX64('dest2'), + 'FDest2': floatReg('dest2'), 'Result': intReg('result'), + 'XResult': intRegX64('result'), + 'XBase': intRegX64('base', id = srtBase), 'Base': intRegAPC('base', id = srtBase), + 'XOffset': intRegX64('offset'), 'Index': intReg('index'), 'Shift': intReg('shift'), 'Op1': intReg('op1'), 'Op2': intReg('op2'), 'Op3': intReg('op3'), + 'Op164': intReg64('op1'), + 'Op264': intReg64('op2'), + 'Op364': intReg64('op3'), + 'XOp1': intRegX64('op1'), + 'XOp2': intRegX64('op2'), + 'XOp3': intRegX64('op3'), + 'WOp1': intRegW64('op1'), + 'WOp2': intRegW64('op2'), + 'WOp3': intRegW64('op3'), 'Reg0': intReg('reg0'), 'Reg1': intReg('reg1'), 'Reg2': intReg('reg2'), @@ -147,13 +207,19 @@ def operands {{ #Fixed index integer reg operands 'SpMode': intRegNPC('intRegInMode((OperatingMode)regMode, INTREG_SP)'), + 'DecodedBankedIntReg': intRegNPC('decodeMrsMsrBankedIntRegIndex(byteMask, r)'), 'LR': intRegNPC('INTREG_LR'), + 'XLR': intRegX64('INTREG_X30'), 'R7': intRegNPC('7'), # First four arguments are passed in registers 'R0': intRegNPC('0'), 'R1': intRegNPC('1'), 'R2': intRegNPC('2'), 'R3': intRegNPC('3'), + 'X0': intRegX64('0'), + 'X1': intRegX64('1'), + 'X2': intRegX64('2'), + 'X3': intRegX64('3'), #Pseudo integer condition code registers 'CondCodesNZ': intRegCC('INTREG_CONDCODES_NZ'), @@ -230,9 +296,95 @@ def operands {{ 'FpOp2P2': floatReg('(op2 + 2)'), 'FpOp2P3': floatReg('(op2 + 3)'), + # Create AArch64 unpacked view of the FP registers + 'AA64FpOp1P0': floatReg('((op1 * 4) + 0)'), + 'AA64FpOp1P1': floatReg('((op1 * 4) + 1)'), + 'AA64FpOp1P2': floatReg('((op1 * 4) + 2)'), + 'AA64FpOp1P3': floatReg('((op1 * 4) + 3)'), + 'AA64FpOp2P0': floatReg('((op2 * 4) + 0)'), + 'AA64FpOp2P1': floatReg('((op2 * 4) + 1)'), + 'AA64FpOp2P2': floatReg('((op2 * 4) + 2)'), + 'AA64FpOp2P3': floatReg('((op2 * 4) + 3)'), + 'AA64FpOp3P0': floatReg('((op3 * 4) + 0)'), + 'AA64FpOp3P1': floatReg('((op3 * 4) + 1)'), + 'AA64FpOp3P2': floatReg('((op3 * 4) + 2)'), + 'AA64FpOp3P3': floatReg('((op3 * 4) + 3)'), + 'AA64FpDestP0': floatReg('((dest * 4) + 0)'), + 'AA64FpDestP1': floatReg('((dest * 4) + 1)'), + 'AA64FpDestP2': floatReg('((dest * 4) + 2)'), + 'AA64FpDestP3': floatReg('((dest * 4) + 3)'), + 'AA64FpDest2P0': floatReg('((dest2 * 4) + 0)'), + 'AA64FpDest2P1': floatReg('((dest2 * 4) + 1)'), + 'AA64FpDest2P2': floatReg('((dest2 * 4) + 2)'), + 'AA64FpDest2P3': floatReg('((dest2 * 4) + 3)'), + + 'AA64FpOp1P0V0': floatReg('((((op1+0)) * 4) + 0)'), + 'AA64FpOp1P1V0': floatReg('((((op1+0)) * 4) + 1)'), + 'AA64FpOp1P2V0': floatReg('((((op1+0)) * 4) + 2)'), + 'AA64FpOp1P3V0': floatReg('((((op1+0)) * 4) + 3)'), + + 'AA64FpOp1P0V1': floatReg('((((op1+1)) * 4) + 0)'), + 'AA64FpOp1P1V1': floatReg('((((op1+1)) * 4) + 1)'), + 'AA64FpOp1P2V1': floatReg('((((op1+1)) * 4) + 2)'), + 'AA64FpOp1P3V1': floatReg('((((op1+1)) * 4) + 3)'), + + 'AA64FpOp1P0V2': floatReg('((((op1+2)) * 4) + 0)'), + 'AA64FpOp1P1V2': floatReg('((((op1+2)) * 4) + 1)'), + 'AA64FpOp1P2V2': floatReg('((((op1+2)) * 4) + 2)'), + 'AA64FpOp1P3V2': floatReg('((((op1+2)) * 4) + 3)'), + + 'AA64FpOp1P0V3': floatReg('((((op1+3)) * 4) + 0)'), + 'AA64FpOp1P1V3': floatReg('((((op1+3)) * 4) + 1)'), + 'AA64FpOp1P2V3': floatReg('((((op1+3)) * 4) + 2)'), + 'AA64FpOp1P3V3': floatReg('((((op1+3)) * 4) + 3)'), + + 'AA64FpOp1P0V0S': floatReg('((((op1+0)%32) * 4) + 0)'), + 'AA64FpOp1P1V0S': floatReg('((((op1+0)%32) * 4) + 1)'), + 'AA64FpOp1P2V0S': floatReg('((((op1+0)%32) * 4) + 2)'), + 'AA64FpOp1P3V0S': floatReg('((((op1+0)%32) * 4) + 3)'), + + 'AA64FpOp1P0V1S': floatReg('((((op1+1)%32) * 4) + 0)'), + 'AA64FpOp1P1V1S': floatReg('((((op1+1)%32) * 4) + 1)'), + 'AA64FpOp1P2V1S': floatReg('((((op1+1)%32) * 4) + 2)'), + 'AA64FpOp1P3V1S': floatReg('((((op1+1)%32) * 4) + 3)'), + + 'AA64FpOp1P0V2S': floatReg('((((op1+2)%32) * 4) + 0)'), + 'AA64FpOp1P1V2S': floatReg('((((op1+2)%32) * 4) + 1)'), + 'AA64FpOp1P2V2S': floatReg('((((op1+2)%32) * 4) + 2)'), + 'AA64FpOp1P3V2S': floatReg('((((op1+2)%32) * 4) + 3)'), + + 'AA64FpOp1P0V3S': floatReg('((((op1+3)%32) * 4) + 0)'), + 'AA64FpOp1P1V3S': floatReg('((((op1+3)%32) * 4) + 1)'), + 'AA64FpOp1P2V3S': floatReg('((((op1+3)%32) * 4) + 2)'), + 'AA64FpOp1P3V3S': floatReg('((((op1+3)%32) * 4) + 3)'), + + 'AA64FpDestP0V0': floatReg('((((dest+0)) * 4) + 0)'), + 'AA64FpDestP1V0': floatReg('((((dest+0)) * 4) + 1)'), + 'AA64FpDestP2V0': floatReg('((((dest+0)) * 4) + 2)'), + 'AA64FpDestP3V0': floatReg('((((dest+0)) * 4) + 3)'), + + 'AA64FpDestP0V1': floatReg('((((dest+1)) * 4) + 0)'), + 'AA64FpDestP1V1': floatReg('((((dest+1)) * 4) + 1)'), + 'AA64FpDestP2V1': floatReg('((((dest+1)) * 4) + 2)'), + 'AA64FpDestP3V1': floatReg('((((dest+1)) * 4) + 3)'), + + 'AA64FpDestP0V0L': floatReg('((((dest+0)%32) * 4) + 0)'), + 'AA64FpDestP1V0L': floatReg('((((dest+0)%32) * 4) + 1)'), + 'AA64FpDestP2V0L': floatReg('((((dest+0)%32) * 4) + 2)'), + 'AA64FpDestP3V0L': floatReg('((((dest+0)%32) * 4) + 3)'), + + 'AA64FpDestP0V1L': floatReg('((((dest+1)%32) * 4) + 0)'), + 'AA64FpDestP1V1L': floatReg('((((dest+1)%32) * 4) + 1)'), + 'AA64FpDestP2V1L': floatReg('((((dest+1)%32) * 4) + 2)'), + 'AA64FpDestP3V1L': floatReg('((((dest+1)%32) * 4) + 3)'), + #Abstracted control reg operands 'MiscDest': cntrlReg('dest'), 'MiscOp1': cntrlReg('op1'), + 'MiscNsBankedDest': cntrlNsBankedReg('dest'), + 'MiscNsBankedOp1': cntrlNsBankedReg('op1'), + 'MiscNsBankedDest64': cntrlNsBankedReg64('dest'), + 'MiscNsBankedOp164': cntrlNsBankedReg64('op1'), #Fixed index control regs 'Cpsr': cntrlReg('MISCREG_CPSR', srtCpsr), @@ -244,22 +396,41 @@ def operands {{ 'FpscrQc': cntrlRegNC('MISCREG_FPSCR_QC'), 'FpscrExc': cntrlRegNC('MISCREG_FPSCR_EXC'), 'Cpacr': cntrlReg('MISCREG_CPACR'), + 'Cpacr64': cntrlReg('MISCREG_CPACR_EL1'), 'Fpexc': cntrlRegNC('MISCREG_FPEXC'), + 'Nsacr': cntrlReg('MISCREG_NSACR'), + 'ElrHyp': cntrlRegNC('MISCREG_ELR_HYP'), + 'Hcr': cntrlReg('MISCREG_HCR'), + 'Hcr64': cntrlReg('MISCREG_HCR_EL2'), + 'Hdcr': cntrlReg('MISCREG_HDCR'), + 'Hcptr': cntrlReg('MISCREG_HCPTR'), + 'CptrEl264': cntrlReg('MISCREG_CPTR_EL2'), + 'CptrEl364': cntrlReg('MISCREG_CPTR_EL3'), + 'Hstr': cntrlReg('MISCREG_HSTR'), + 'Scr': cntrlReg('MISCREG_SCR'), + 'Scr64': cntrlReg('MISCREG_SCR_EL3'), 'Sctlr': cntrlRegNC('MISCREG_SCTLR'), 'SevMailbox': cntrlRegNC('MISCREG_SEV_MAILBOX'), 'LLSCLock': cntrlRegNC('MISCREG_LOCKFLAG'), + 'Dczid' : cntrlRegNC('MISCREG_DCZID_EL0'), #Register fields for microops 'URa' : intReg('ura'), + 'XURa' : intRegX64('ura'), + 'WURa' : intRegW64('ura'), 'IWRa' : intRegIWPC('ura'), 'Fa' : floatReg('ura'), + 'FaP1' : floatReg('ura + 1'), 'URb' : intReg('urb'), + 'XURb' : intRegX64('urb'), 'URc' : intReg('urc'), + 'XURc' : intRegX64('urc'), #Memory Operand 'Mem': ('Mem', 'uw', None, ('IsMemRef', 'IsLoad', 'IsStore'), srtNormal), #PCState fields + 'RawPC': pcStateReg('pc', srtPC), 'PC': pcStateReg('instPC', srtPC), 'NPC': pcStateReg('instNPC', srtPC), 'pNPC': pcStateReg('instNPC', srtEPC), diff --git a/src/arch/arm/isa/templates/basic.isa b/src/arch/arm/isa/templates/basic.isa index b3878b89a..de4506e05 100644 --- a/src/arch/arm/isa/templates/basic.isa +++ b/src/arch/arm/isa/templates/basic.isa @@ -1,5 +1,17 @@ // -*- mode:c++ -*- +// Copyright (c) 2011 ARM Limited +// All rights reserved +// +// The license below extends only to copyright in the software and shall +// not be construed as granting a license to any other intellectual +// property including but not limited to intellectual property relating +// to a hardware implementation of the functionality of the software +// licensed hereunder. You may use the software subject to the license +// terms below provided that you ensure that this notice is replicated +// unmodified and in its entirety in all distributions of the software, +// modified or unmodified, in source code or in binary form. +// // Copyright (c) 2007-2008 The Florida State University // All rights reserved. // @@ -60,6 +72,13 @@ def template BasicConstructor {{ } }}; +def template BasicConstructor64 {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst) : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s) + { + %(constructor)s; + } +}}; + // Basic instruction class execute method template. def template BasicExecute {{ diff --git a/src/arch/arm/isa/templates/branch64.isa b/src/arch/arm/isa/templates/branch64.isa new file mode 100644 index 000000000..84b3e6ae7 --- /dev/null +++ b/src/arch/arm/isa/templates/branch64.isa @@ -0,0 +1,141 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2011 ARM Limited +// All rights reserved +// +// The license below extends only to copyright in the software and shall +// not be construed as granting a license to any other intellectual +// property including but not limited to intellectual property relating +// to a hardware implementation of the functionality of the software +// licensed hereunder. You may use the software subject to the license +// terms below provided that you ensure that this notice is replicated +// unmodified and in its entirety in all distributions of the software, +// modified or unmodified, in source code or in binary form. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Gabe Black + +def template BranchImm64Declare {{ +class %(class_name)s : public %(base_class)s +{ + public: + // Constructor + %(class_name)s(ExtMachInst machInst, int64_t _imm); + %(BasicExecDeclare)s +}; +}}; + +def template BranchImm64Constructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + int64_t _imm) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, _imm) + { + %(constructor)s; + } +}}; + +def template BranchImmCond64Declare {{ +class %(class_name)s : public %(base_class)s +{ + public: + // Constructor + %(class_name)s(ExtMachInst machInst, int64_t _imm, + ConditionCode _condCode); + %(BasicExecDeclare)s +}; +}}; + +def template BranchImmCond64Constructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + int64_t _imm, + ConditionCode _condCode) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _imm, _condCode) + { + %(constructor)s; + } +}}; + +def template BranchReg64Declare {{ +class %(class_name)s : public %(base_class)s +{ + public: + // Constructor + %(class_name)s(ExtMachInst machInst, IntRegIndex _op1); + %(BasicExecDeclare)s +}; +}}; + +def template BranchReg64Constructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _op1) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, _op1) + { + %(constructor)s; + } +}}; + +def template BranchImmReg64Declare {{ +class %(class_name)s : public %(base_class)s +{ + public: + // Constructor + %(class_name)s(ExtMachInst machInst, + int64_t imm, IntRegIndex _op1); + %(BasicExecDeclare)s +}; +}}; + +def template BranchImmReg64Constructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + int64_t _imm, + IntRegIndex _op1) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, _imm, _op1) + { + %(constructor)s; + } +}}; + +def template BranchImmImmReg64Declare {{ +class %(class_name)s : public %(base_class)s +{ + public: + // Constructor + %(class_name)s(ExtMachInst machInst, int64_t _imm1, int64_t _imm2, + IntRegIndex _op1); + %(BasicExecDeclare)s +}; +}}; + +def template BranchImmImmReg64Constructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + int64_t _imm1, int64_t _imm2, + IntRegIndex _op1) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _imm1, _imm2, _op1) + { + %(constructor)s; + } +}}; diff --git a/src/arch/arm/isa/templates/data64.isa b/src/arch/arm/isa/templates/data64.isa new file mode 100644 index 000000000..b6f7ce8d0 --- /dev/null +++ b/src/arch/arm/isa/templates/data64.isa @@ -0,0 +1,279 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2011 ARM Limited +// All rights reserved +// +// The license below extends only to copyright in the software and shall +// not be construed as granting a license to any other intellectual +// property including but not limited to intellectual property relating +// to a hardware implementation of the functionality of the software +// licensed hereunder. You may use the software subject to the license +// terms below provided that you ensure that this notice is replicated +// unmodified and in its entirety in all distributions of the software, +// modified or unmodified, in source code or in binary form. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Gabe Black + +def template DataXImmDeclare {{ +class %(class_name)s : public %(base_class)s +{ + public: + // Constructor + %(class_name)s(ExtMachInst machInst, IntRegIndex _dest, + IntRegIndex _op1, uint64_t _imm); + %(BasicExecDeclare)s +}; +}}; + +def template DataXImmConstructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, + IntRegIndex _op1, + uint64_t _imm) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _op1, _imm) + { + %(constructor)s; + } +}}; + +def template DataXSRegDeclare {{ +class %(class_name)s : public %(base_class)s +{ + public: + // Constructor + %(class_name)s(ExtMachInst machInst, IntRegIndex _dest, + IntRegIndex _op1, IntRegIndex _op2, + int32_t _shiftAmt, ArmShiftType _shiftType); + %(BasicExecDeclare)s +}; +}}; + +def template DataXSRegConstructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, + IntRegIndex _op1, + IntRegIndex _op2, + int32_t _shiftAmt, + ArmShiftType _shiftType) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _op1, _op2, _shiftAmt, _shiftType) + { + %(constructor)s; + } +}}; + +def template DataXERegDeclare {{ +class %(class_name)s : public %(base_class)s +{ + public: + // Constructor + %(class_name)s(ExtMachInst machInst, IntRegIndex _dest, + IntRegIndex _op1, IntRegIndex _op2, + ArmExtendType _extendType, int32_t _shiftAmt); + %(BasicExecDeclare)s +}; +}}; + +def template DataXERegConstructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, + IntRegIndex _op1, + IntRegIndex _op2, + ArmExtendType _extendType, + int32_t _shiftAmt) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _op1, _op2, _extendType, _shiftAmt) + { + %(constructor)s; + } +}}; + +def template DataX1RegDeclare {{ +class %(class_name)s : public %(base_class)s +{ + public: + // Constructor + %(class_name)s(ExtMachInst machInst, IntRegIndex _dest, + IntRegIndex _op1); + %(BasicExecDeclare)s +}; +}}; + +def template DataX1RegConstructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, + IntRegIndex _op1) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, _dest, _op1) + { + %(constructor)s; + } +}}; + +def template DataX2RegDeclare {{ +class %(class_name)s : public %(base_class)s +{ + public: + // Constructor + %(class_name)s(ExtMachInst machInst, IntRegIndex _dest, + IntRegIndex _op1, IntRegIndex _op2); + %(BasicExecDeclare)s +}; +}}; + +def template DataX2RegConstructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, + IntRegIndex _op1, + IntRegIndex _op2) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _op1, _op2) + { + %(constructor)s; + } +}}; + +def template DataX2RegImmDeclare {{ +class %(class_name)s : public %(base_class)s +{ + public: + // Constructor + %(class_name)s(ExtMachInst machInst, IntRegIndex _dest, + IntRegIndex _op1, IntRegIndex _op2, uint64_t _imm); + %(BasicExecDeclare)s +}; +}}; + +def template DataX2RegImmConstructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, + IntRegIndex _op1, + IntRegIndex _op2, + uint64_t _imm) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _op1, _op2, _imm) + { + %(constructor)s; + } +}}; + +def template DataX3RegDeclare {{ +class %(class_name)s : public %(base_class)s +{ + public: + // Constructor + %(class_name)s(ExtMachInst machInst, IntRegIndex _dest, + IntRegIndex _op1, IntRegIndex _op2, IntRegIndex _op3); + %(BasicExecDeclare)s +}; +}}; + +def template DataX3RegConstructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, + IntRegIndex _op1, + IntRegIndex _op2, + IntRegIndex _op3) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _op1, _op2, _op3) + { + %(constructor)s; + } +}}; + +def template DataXCondCompImmDeclare {{ +class %(class_name)s : public %(base_class)s +{ + public: + // Constructor + %(class_name)s(ExtMachInst machInst, IntRegIndex _op1, + uint64_t _imm, ConditionCode _condCode, uint8_t _defCc); + %(BasicExecDeclare)s +}; +}}; + +def template DataXCondCompImmConstructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _op1, + uint64_t _imm, + ConditionCode _condCode, + uint8_t _defCc) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _op1, _imm, _condCode, _defCc) + { + %(constructor)s; + } +}}; + +def template DataXCondCompRegDeclare {{ +class %(class_name)s : public %(base_class)s +{ + public: + // Constructor + %(class_name)s(ExtMachInst machInst, IntRegIndex _op1, + IntRegIndex _op2, ConditionCode _condCode, + uint8_t _defCc); + %(BasicExecDeclare)s +}; +}}; + +def template DataXCondCompRegConstructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _op1, + IntRegIndex _op2, + ConditionCode _condCode, + uint8_t _defCc) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _op1, _op2, _condCode, _defCc) + { + %(constructor)s; + } +}}; + +def template DataXCondSelDeclare {{ +class %(class_name)s : public %(base_class)s +{ + public: + // Constructor + %(class_name)s(ExtMachInst machInst, IntRegIndex _dest, + IntRegIndex _op1, IntRegIndex _op2, + ConditionCode _condCode); + %(BasicExecDeclare)s +}; +}}; + +def template DataXCondSelConstructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, + IntRegIndex _op1, + IntRegIndex _op2, + ConditionCode _condCode) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _op1, _op2, _condCode) + { + %(constructor)s; + } +}}; diff --git a/src/arch/arm/isa/templates/macromem.isa b/src/arch/arm/isa/templates/macromem.isa index 195204a95..465090660 100644 --- a/src/arch/arm/isa/templates/macromem.isa +++ b/src/arch/arm/isa/templates/macromem.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2010 ARM Limited +// Copyright (c) 2010-2013 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -338,6 +338,18 @@ def template MicroIntImmConstructor {{ } }}; +def template MicroIntImmXConstructor {{ + %(class_name)s::%(class_name)s(ExtMachInst machInst, + RegIndex _ura, + RegIndex _urb, + int32_t _imm) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _ura, _urb, _imm) + { + %(constructor)s; + } +}}; + def template MicroIntRegDeclare {{ class %(class_name)s : public %(base_class)s { @@ -349,6 +361,28 @@ def template MicroIntRegDeclare {{ }; }}; +def template MicroIntXERegConstructor {{ + %(class_name)s::%(class_name)s(ExtMachInst machInst, + RegIndex _ura, RegIndex _urb, RegIndex _urc, + ArmExtendType _type, uint32_t _shiftAmt) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _ura, _urb, _urc, _type, _shiftAmt) + { + %(constructor)s; + } +}}; + +def template MicroIntXERegDeclare {{ + class %(class_name)s : public %(base_class)s + { + public: + %(class_name)s(ExtMachInst machInst, + RegIndex _ura, RegIndex _urb, RegIndex _urc, + ArmExtendType _type, uint32_t _shiftAmt); + %(BasicExecDeclare)s + }; +}}; + def template MicroIntRegConstructor {{ %(class_name)s::%(class_name)s(ExtMachInst machInst, RegIndex _ura, RegIndex _urb, RegIndex _urc, @@ -402,6 +436,96 @@ def template MacroMemConstructor {{ }}; +def template BigFpMemImmDeclare {{ +class %(class_name)s : public %(base_class)s +{ + public: + // Constructor + %(class_name)s(const char *mnemonic, ExtMachInst machInst, + bool load, IntRegIndex dest, IntRegIndex base, int64_t imm); + %(BasicExecPanic)s +}; +}}; + +def template BigFpMemImmConstructor {{ +%(class_name)s::%(class_name)s(const char *mnemonic, ExtMachInst machInst, + bool load, IntRegIndex dest, IntRegIndex base, int64_t imm) + : %(base_class)s(mnemonic, machInst, %(op_class)s, load, dest, base, imm) +{ + %(constructor)s; +} +}}; + +def template BigFpMemRegDeclare {{ +class %(class_name)s : public %(base_class)s +{ + public: + // Constructor + %(class_name)s(const char *mnemonic, ExtMachInst machInst, + bool load, IntRegIndex dest, IntRegIndex base, + IntRegIndex offset, ArmExtendType type, int64_t imm); + %(BasicExecPanic)s +}; +}}; + +def template BigFpMemRegConstructor {{ +%(class_name)s::%(class_name)s(const char *mnemonic, ExtMachInst machInst, + bool load, IntRegIndex dest, IntRegIndex base, + IntRegIndex offset, ArmExtendType type, int64_t imm) + : %(base_class)s(mnemonic, machInst, %(op_class)s, load, dest, base, + offset, type, imm) +{ + %(constructor)s; +} +}}; + +def template BigFpMemLitDeclare {{ +class %(class_name)s : public %(base_class)s +{ + public: + // Constructor + %(class_name)s(const char *mnemonic, ExtMachInst machInst, + IntRegIndex dest, int64_t imm); + %(BasicExecPanic)s +}; +}}; + +def template BigFpMemLitConstructor {{ +%(class_name)s::%(class_name)s(const char *mnemonic, ExtMachInst machInst, + IntRegIndex dest, int64_t imm) + : %(base_class)s(mnemonic, machInst, %(op_class)s, dest, imm) +{ + %(constructor)s; +} +}}; + +def template PairMemDeclare {{ +class %(class_name)s : public %(base_class)s +{ + public: + // Constructor + %(class_name)s(const char *mnemonic, ExtMachInst machInst, + uint32_t size, bool fp, bool load, bool noAlloc, bool signExt, + bool exclusive, bool acrel, uint32_t imm, + AddrMode mode, IntRegIndex rn, IntRegIndex rt, + IntRegIndex rt2); + %(BasicExecPanic)s +}; +}}; + +def template PairMemConstructor {{ +%(class_name)s::%(class_name)s(const char *mnemonic, ExtMachInst machInst, + uint32_t size, bool fp, bool load, bool noAlloc, bool signExt, + bool exclusive, bool acrel, uint32_t imm, AddrMode mode, + IntRegIndex rn, IntRegIndex rt, IntRegIndex rt2) + : %(base_class)s(mnemonic, machInst, %(op_class)s, size, + fp, load, noAlloc, signExt, exclusive, acrel, + imm, mode, rn, rt, rt2) +{ + %(constructor)s; +} +}}; + def template VMemMultDeclare {{ class %(class_name)s : public %(base_class)s { diff --git a/src/arch/arm/isa/templates/mem.isa b/src/arch/arm/isa/templates/mem.isa index 871378f3f..7682c277d 100644 --- a/src/arch/arm/isa/templates/mem.isa +++ b/src/arch/arm/isa/templates/mem.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2010 ARM Limited +// Copyright (c) 2010, 2012 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -697,6 +697,11 @@ def template LoadStoreImmDeclare {{ %(InitiateAccDeclare)s %(CompleteAccDeclare)s + + virtual void + annotateFault(ArmFault *fault) { + %(fa_code)s + } }; }}; @@ -763,6 +768,11 @@ def template StoreRegDeclare {{ %(InitiateAccDeclare)s %(CompleteAccDeclare)s + + virtual void + annotateFault(ArmFault *fault) { + %(fa_code)s + } }; }}; @@ -808,6 +818,11 @@ def template LoadRegDeclare {{ %(InitiateAccDeclare)s %(CompleteAccDeclare)s + + virtual void + annotateFault(ArmFault *fault) { + %(fa_code)s + } }; }}; @@ -828,6 +843,11 @@ def template LoadImmDeclare {{ %(InitiateAccDeclare)s %(CompleteAccDeclare)s + + virtual void + annotateFault(ArmFault *fault) { + %(fa_code)s + } }; }}; diff --git a/src/arch/arm/isa/templates/mem64.isa b/src/arch/arm/isa/templates/mem64.isa new file mode 100644 index 000000000..87dcba988 --- /dev/null +++ b/src/arch/arm/isa/templates/mem64.isa @@ -0,0 +1,686 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2011-2013 ARM Limited +// All rights reserved +// +// The license below extends only to copyright in the software and shall +// not be construed as granting a license to any other intellectual +// property including but not limited to intellectual property relating +// to a hardware implementation of the functionality of the software +// licensed hereunder. You may use the software subject to the license +// terms below provided that you ensure that this notice is replicated +// unmodified and in its entirety in all distributions of the software, +// modified or unmodified, in source code or in binary form. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Gabe Black + +let {{ + SPAlignmentCheckCode = ''' + if (baseIsSP && bits(XBase, 3, 0) && + SPAlignmentCheckEnabled(xc->tcBase())) { + return new SPAlignmentFault(); + } + ''' +}}; + +def template Load64Execute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(op_decl)s; + %(op_rd)s; + %(ea_code)s; + + if (fault == NoFault) { + fault = readMemAtomic(xc, traceData, EA, Mem, memAccessFlags); + %(memacc_code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + +def template Store64Execute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(op_decl)s; + %(op_rd)s; + %(ea_code)s; + + if (fault == NoFault) { + %(memacc_code)s; + } + + if (fault == NoFault) { + fault = writeMemAtomic(xc, traceData, Mem, EA, + memAccessFlags, NULL); + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + +def template Store64InitiateAcc {{ + Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(op_decl)s; + %(op_rd)s; + %(ea_code)s; + + if (fault == NoFault) { + %(memacc_code)s; + } + + if (fault == NoFault) { + fault = writeMemTiming(xc, traceData, Mem, EA, memAccessFlags, + NULL); + } + + return fault; + } +}}; + +def template StoreEx64Execute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(op_decl)s; + %(op_rd)s; + %(ea_code)s; + + if (fault == NoFault) { + %(memacc_code)s; + } + + uint64_t writeResult = 0; + if (fault == NoFault) { + fault = writeMemAtomic(xc, traceData, Mem, EA, memAccessFlags, + &writeResult); + } + + if (fault == NoFault) { + %(postacc_code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + +def template StoreEx64InitiateAcc {{ + Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(op_decl)s; + %(op_rd)s; + %(ea_code)s; + + if (fault == NoFault) { + %(memacc_code)s; + } + + if (fault == NoFault) { + fault = writeMemTiming(xc, traceData, Mem, EA, memAccessFlags, + NULL); + } + + return fault; + } +}}; + +def template Load64InitiateAcc {{ + Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(op_src_decl)s; + %(op_rd)s; + %(ea_code)s; + + if (fault == NoFault) { + fault = readMemTiming(xc, traceData, EA, Mem, memAccessFlags); + } + + return fault; + } +}}; + +def template Load64CompleteAcc {{ + Fault %(class_name)s::completeAcc(PacketPtr pkt, + %(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + + %(op_decl)s; + %(op_rd)s; + + // ARM instructions will not have a pkt if the predicate is false + getMem(pkt, Mem, traceData); + + if (fault == NoFault) { + %(memacc_code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + +def template Store64CompleteAcc {{ + Fault %(class_name)s::completeAcc(PacketPtr pkt, + %(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + return NoFault; + } +}}; + +def template StoreEx64CompleteAcc {{ + Fault %(class_name)s::completeAcc(PacketPtr pkt, + %(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + + %(op_decl)s; + %(op_rd)s; + + uint64_t writeResult = pkt->req->getExtraData(); + %(postacc_code)s; + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + +def template DCStore64Declare {{ + class %(class_name)s : public %(base_class)s + { + public: + + /// Constructor. + %(class_name)s(ExtMachInst machInst, IntRegIndex _base, IntRegIndex _dest, uint64_t _imm); + + %(BasicExecDeclare)s + %(InitiateAccDeclare)s + %(CompleteAccDeclare)s + + virtual void + annotateFault(ArmFault *fault) { + %(fa_code)s + } + }; +}}; + +def template DCStore64Constructor {{ + %(class_name)s::%(class_name)s(ExtMachInst machInst, IntRegIndex _base, IntRegIndex _dest, uint64_t _imm) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + (IntRegIndex)_base, _dest, _imm) + { + %(constructor)s; + assert(!%(use_uops)d); + } +}}; + +def template DCStore64Execute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(op_decl)s; + %(op_rd)s; + %(ea_code)s; + + + if (fault == NoFault) { + %(memacc_code)s; + } + + if (fault == NoFault) { + fault = xc->writeMem(NULL, op_size, EA, memAccessFlags, NULL); + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + +def template DCStore64InitiateAcc {{ + Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(op_decl)s; + %(op_rd)s; + %(ea_code)s; + + if (fault == NoFault) { + %(memacc_code)s; + } + + if (fault == NoFault) { + fault = xc->writeMem(NULL, op_size, EA, memAccessFlags, NULL); + } + + return fault; + } +}}; + + +def template LoadStoreImm64Declare {{ + class %(class_name)s : public %(base_class)s + { + public: + + /// Constructor. + %(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, IntRegIndex _base, int64_t _imm); + + %(BasicExecDeclare)s + %(InitiateAccDeclare)s + %(CompleteAccDeclare)s + + virtual void + annotateFault(ArmFault *fault) { + %(fa_code)s + } + }; +}}; + +def template LoadStoreImmU64Declare {{ + class %(class_name)s : public %(base_class)s + { + public: + + /// Constructor. + %(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, IntRegIndex _base, int64_t _imm, + bool noAlloc = false, bool exclusive = false, + bool acrel = false); + + %(BasicExecDeclare)s + %(InitiateAccDeclare)s + %(CompleteAccDeclare)s + + virtual void + annotateFault(ArmFault *fault) { + %(fa_code)s + } + }; +}}; + +def template LoadStoreImmDU64Declare {{ + class %(class_name)s : public %(base_class)s + { + public: + + /// Constructor. + %(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, IntRegIndex _dest2, IntRegIndex _base, + int64_t _imm = 0, bool noAlloc = false, bool exclusive = false, + bool acrel = false); + + %(BasicExecDeclare)s + %(InitiateAccDeclare)s + %(CompleteAccDeclare)s + + virtual void + annotateFault(ArmFault *fault) { + %(fa_code)s + } + }; +}}; + +def template StoreImmDEx64Declare {{ + /** + * Static instruction class for "%(mnemonic)s". + */ + class %(class_name)s : public %(base_class)s + { + public: + + /// Constructor. + %(class_name)s(ExtMachInst machInst, + IntRegIndex _result, IntRegIndex _dest, IntRegIndex _dest2, + IntRegIndex _base, int64_t _imm = 0); + + %(BasicExecDeclare)s + + %(InitiateAccDeclare)s + + %(CompleteAccDeclare)s + }; +}}; + + +def template LoadStoreReg64Declare {{ + class %(class_name)s : public %(base_class)s + { + public: + + /// Constructor. + %(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, IntRegIndex _base, IntRegIndex _offset, + ArmExtendType _type, uint32_t _shiftAmt); + + %(BasicExecDeclare)s + %(InitiateAccDeclare)s + %(CompleteAccDeclare)s + + virtual void + annotateFault(ArmFault *fault) { + %(fa_code)s + } + }; +}}; + +def template LoadStoreRegU64Declare {{ + class %(class_name)s : public %(base_class)s + { + public: + + /// Constructor. + %(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, IntRegIndex _base, IntRegIndex _offset, + ArmExtendType _type, uint32_t _shiftAmt, + bool noAlloc = false, bool exclusive = false, + bool acrel = false); + + %(BasicExecDeclare)s + %(InitiateAccDeclare)s + %(CompleteAccDeclare)s + + virtual void + annotateFault(ArmFault *fault) { + %(fa_code)s + } + }; +}}; + +def template LoadStoreRaw64Declare {{ + class %(class_name)s : public %(base_class)s + { + public: + + /// Constructor. + %(class_name)s(ExtMachInst machInst, IntRegIndex _dest, + IntRegIndex _base); + + %(BasicExecDeclare)s + %(InitiateAccDeclare)s + %(CompleteAccDeclare)s + + virtual void + annotateFault(ArmFault *fault) { + %(fa_code)s + } + }; +}}; + +def template LoadStoreEx64Declare {{ + class %(class_name)s : public %(base_class)s + { + public: + + /// Constructor. + %(class_name)s(ExtMachInst machInst, IntRegIndex _dest, + IntRegIndex _base, IntRegIndex _result); + + %(BasicExecDeclare)s + %(InitiateAccDeclare)s + %(CompleteAccDeclare)s + + virtual void + annotateFault(ArmFault *fault) { + %(fa_code)s + } + }; +}}; + +def template LoadStoreLit64Declare {{ + class %(class_name)s : public %(base_class)s + { + public: + + /// Constructor. + %(class_name)s(ExtMachInst machInst, IntRegIndex _dest, int64_t _imm); + + %(BasicExecDeclare)s + %(InitiateAccDeclare)s + %(CompleteAccDeclare)s + + virtual void + annotateFault(ArmFault *fault) { + %(fa_code)s + } + }; +}}; + +def template LoadStoreLitU64Declare {{ + class %(class_name)s : public %(base_class)s + { + public: + + /// Constructor. + %(class_name)s(ExtMachInst machInst, IntRegIndex _dest, int64_t _imm, + bool noAlloc = false, bool exclusive = false, + bool acrel = false); + + %(BasicExecDeclare)s + %(InitiateAccDeclare)s + %(CompleteAccDeclare)s + + virtual void + annotateFault(ArmFault *fault) { + %(fa_code)s + } + }; +}}; + +def template LoadStoreImm64Constructor {{ + %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, IntRegIndex _base, int64_t _imm) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + (IntRegIndex)_dest, (IntRegIndex)_base, _imm) + { + %(constructor)s; +#if %(use_uops)d + assert(numMicroops >= 2); + uops = new StaticInstPtr[numMicroops]; + uops[0] = new %(acc_name)s(machInst, _dest, _base, _imm); + uops[0]->setDelayedCommit(); + uops[1] = new %(wb_decl)s; + uops[1]->setLastMicroop(); +#endif + } +}}; + +def template LoadStoreImmU64Constructor {{ + %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, IntRegIndex _base, int64_t _imm, + bool noAlloc, bool exclusive, bool acrel) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _base, _imm) + { + %(constructor)s; + assert(!%(use_uops)d); + setExcAcRel(exclusive, acrel); + } +}}; + +def template LoadStoreImmDU64Constructor {{ + %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, IntRegIndex _dest2, IntRegIndex _base, + int64_t _imm, bool noAlloc, bool exclusive, bool acrel) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _dest2, _base, _imm) + { + %(constructor)s; + assert(!%(use_uops)d); + setExcAcRel(exclusive, acrel); + } +}}; + +def template StoreImmDEx64Constructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _result, IntRegIndex _dest, IntRegIndex _dest2, + IntRegIndex _base, int64_t _imm) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _result, _dest, _dest2, _base, _imm) + { + %(constructor)s; + assert(!%(use_uops)d); + } +}}; + + +def template LoadStoreReg64Constructor {{ + %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, IntRegIndex _base, IntRegIndex _offset, + ArmExtendType _type, uint32_t _shiftAmt) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _base, _offset, _type, _shiftAmt) + { + %(constructor)s; +#if %(use_uops)d + assert(numMicroops >= 2); + uops = new StaticInstPtr[numMicroops]; + uops[0] = new %(acc_name)s(machInst, _dest, _base, _offset, + _type, _shiftAmt); + uops[0]->setDelayedCommit(); + uops[1] = new %(wb_decl)s; + uops[1]->setLastMicroop(); +#endif + } +}}; + +def template LoadStoreRegU64Constructor {{ + %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, IntRegIndex _base, IntRegIndex _offset, + ArmExtendType _type, uint32_t _shiftAmt, + bool noAlloc, bool exclusive, bool acrel) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _base, _offset, _type, _shiftAmt) + { + %(constructor)s; + assert(!%(use_uops)d); + setExcAcRel(exclusive, acrel); + } +}}; + +def template LoadStoreRaw64Constructor {{ + %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, IntRegIndex _base) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, _dest, _base) + { + %(constructor)s; + } +}}; + +def template LoadStoreEx64Constructor {{ + %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, IntRegIndex _base, IntRegIndex _result) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _base, _result) + { + %(constructor)s; + } +}}; + +def template LoadStoreLit64Constructor {{ + %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, int64_t _imm) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + (IntRegIndex)_dest, _imm) + { + %(constructor)s; +#if %(use_uops)d + assert(numMicroops >= 2); + uops = new StaticInstPtr[numMicroops]; + uops[0] = new %(acc_name)s(machInst, _dest, _imm); + uops[0]->setDelayedCommit(); + uops[1] = new %(wb_decl)s; + uops[1]->setLastMicroop(); +#endif + } +}}; + +def template LoadStoreLitU64Constructor {{ + %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, int64_t _imm, + bool noAlloc, bool exclusive, bool acrel) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + (IntRegIndex)_dest, _imm) + { + %(constructor)s; + assert(!%(use_uops)d); + setExcAcRel(exclusive, acrel); + } +}}; diff --git a/src/arch/arm/isa/templates/misc.isa b/src/arch/arm/isa/templates/misc.isa index 212897aa0..36db5b6c2 100644 --- a/src/arch/arm/isa/templates/misc.isa +++ b/src/arch/arm/isa/templates/misc.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2010 ARM Limited +// Copyright (c) 2010-2013 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -62,6 +62,69 @@ def template MrsConstructor {{ } }}; +def template MrsBankedRegDeclare {{ +class %(class_name)s : public %(base_class)s +{ + protected: + uint8_t byteMask; + bool r; + + public: + // Constructor + %(class_name)s(ExtMachInst machInst, IntRegIndex _dest, + uint8_t _sysM, bool _r); + %(BasicExecDeclare)s +}; +}}; + +def template MrsBankedRegConstructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, + uint8_t _sysM, + bool _r) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, _dest), + byteMask(_sysM), r(_r) + { + %(constructor)s; + if (!(condCode == COND_AL || condCode == COND_UC)) { + for (int x = 0; x < _numDestRegs; x++) { + _srcRegIdx[_numSrcRegs++] = _destRegIdx[x]; + } + } + } +}}; + +def template MsrBankedRegDeclare {{ +class %(class_name)s : public %(base_class)s +{ + protected: + bool r; + + public: + // Constructor + %(class_name)s(ExtMachInst machInst, IntRegIndex _op1, + uint8_t _sysM, bool _r); + %(BasicExecDeclare)s +}; +}}; + +def template MsrBankedRegConstructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _op1, + uint8_t _sysM, + bool _r) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, _op1, _sysM), + r(_r) + { + %(constructor)s; + if (!(condCode == COND_AL || condCode == COND_UC)) { + for (int x = 0; x < _numDestRegs; x++) { + _srcRegIdx[_numSrcRegs++] = _destRegIdx[x]; + } + } + } +}}; + def template MsrRegDeclare {{ class %(class_name)s : public %(base_class)s { @@ -114,6 +177,66 @@ def template MsrImmConstructor {{ } }}; +def template MrrcOpDeclare {{ +class %(class_name)s : public %(base_class)s +{ + protected: + public: + // Constructor + %(class_name)s(ExtMachInst machInst, IntRegIndex _op1, + IntRegIndex _dest, IntRegIndex _dest2, uint32_t imm); + %(BasicExecDeclare)s +}; +}}; + +def template MrrcOpConstructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex op1, + IntRegIndex dest, + IntRegIndex dest2, + uint32_t imm) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, op1, dest, + dest2, imm) + { + %(constructor)s; + if (!(condCode == COND_AL || condCode == COND_UC)) { + for (int x = 0; x < _numDestRegs; x++) { + _srcRegIdx[_numSrcRegs++] = _destRegIdx[x]; + } + } + } +}}; + +def template McrrOpDeclare {{ +class %(class_name)s : public %(base_class)s +{ + protected: + public: + // Constructor + %(class_name)s(ExtMachInst machInst, IntRegIndex _op1, IntRegIndex _op2, + IntRegIndex _dest, uint32_t imm); + %(BasicExecDeclare)s +}; +}}; + +def template McrrOpConstructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex op1, + IntRegIndex op2, + IntRegIndex dest, + uint32_t imm) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, op1, op2, + dest, imm) + { + %(constructor)s; + if (!(condCode == COND_AL || condCode == COND_UC)) { + for (int x = 0; x < _numDestRegs; x++) { + _srcRegIdx[_numSrcRegs++] = _destRegIdx[x]; + } + } + } +}}; + def template ImmOpDeclare {{ class %(class_name)s : public %(base_class)s { @@ -310,6 +433,35 @@ def template RegRegImmOpConstructor {{ } }}; +def template RegImmImmOpDeclare {{ +class %(class_name)s : public %(base_class)s +{ + protected: + public: + // Constructor + %(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, uint64_t _imm1, uint64_t _imm2); + %(BasicExecDeclare)s +}; +}}; + +def template RegImmImmOpConstructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, + uint64_t _imm1, + uint64_t _imm2) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _imm1, _imm2) + { + %(constructor)s; + if (!(condCode == COND_AL || condCode == COND_UC)) { + for (int x = 0; x < _numDestRegs; x++) { + _srcRegIdx[_numSrcRegs++] = _destRegIdx[x]; + } + } + } +}}; + def template RegRegImmImmOpDeclare {{ class %(class_name)s : public %(base_class)s { diff --git a/src/arch/arm/isa/templates/misc64.isa b/src/arch/arm/isa/templates/misc64.isa new file mode 100644 index 000000000..09d3d4470 --- /dev/null +++ b/src/arch/arm/isa/templates/misc64.isa @@ -0,0 +1,91 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2011 ARM Limited +// All rights reserved +// +// The license below extends only to copyright in the software and shall +// not be construed as granting a license to any other intellectual +// property including but not limited to intellectual property relating +// to a hardware implementation of the functionality of the software +// licensed hereunder. You may use the software subject to the license +// terms below provided that you ensure that this notice is replicated +// unmodified and in its entirety in all distributions of the software, +// modified or unmodified, in source code or in binary form. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Gabe Black + +def template RegRegImmImmOp64Declare {{ +class %(class_name)s : public %(base_class)s +{ + protected: + public: + // Constructor + %(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, IntRegIndex _op1, + uint64_t _imm1, uint64_t _imm2); + %(BasicExecDeclare)s +}; +}}; + +def template RegRegImmImmOp64Constructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, + IntRegIndex _op1, + uint64_t _imm1, + uint64_t _imm2) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _op1, _imm1, _imm2) + { + %(constructor)s; + } +}}; + +def template RegRegRegImmOp64Declare {{ +class %(class_name)s : public %(base_class)s +{ + protected: + public: + // Constructor + %(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, IntRegIndex _op1, + IntRegIndex _op2, uint64_t _imm); + %(BasicExecDeclare)s +}; +}}; + +def template RegRegRegImmOp64Constructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, + IntRegIndex _op1, + IntRegIndex _op2, + uint64_t _imm) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _op1, _op2, _imm) + { + %(constructor)s; + } +}}; + diff --git a/src/arch/arm/isa/templates/neon.isa b/src/arch/arm/isa/templates/neon.isa index 573d245b8..ffa6b53d4 100644 --- a/src/arch/arm/isa/templates/neon.isa +++ b/src/arch/arm/isa/templates/neon.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2010 ARM Limited +// Copyright (c) 2010-2012 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -39,8 +39,26 @@ let {{ simdEnabledCheckCode = ''' - if (!neonEnabled(Cpacr, Cpsr, Fpexc)) - return disabledFault(); + { + uint32_t issEnCheck; + bool trapEnCheck; + uint32_t seq; + if (!vfpNeonEnabled(seq, Hcptr, Nsacr, Cpacr, Cpsr, issEnCheck, + trapEnCheck, xc->tcBase(), Fpexc, true)) + {return disabledFault();} + if (trapEnCheck) { + CPSR cpsrEnCheck = Cpsr; + if (cpsrEnCheck.mode == MODE_HYP) { + return new UndefinedInstruction(machInst, issEnCheck, + EC_TRAPPED_HCPTR); + } else { + if (!inSecureState(Scr, Cpsr)) { + return new HypervisorTrap(machInst, issEnCheck, + EC_TRAPPED_HCPTR); + } + } + } + } ''' }}; diff --git a/src/arch/arm/isa/templates/neon64.isa b/src/arch/arm/isa/templates/neon64.isa new file mode 100644 index 000000000..d20e4e653 --- /dev/null +++ b/src/arch/arm/isa/templates/neon64.isa @@ -0,0 +1,527 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2012-2013 ARM Limited +// All rights reserved +// +// The license below extends only to copyright in the software and shall +// not be construed as granting a license to any other intellectual +// property including but not limited to intellectual property relating +// to a hardware implementation of the functionality of the software +// licensed hereunder. You may use the software subject to the license +// terms below provided that you ensure that this notice is replicated +// unmodified and in its entirety in all distributions of the software, +// modified or unmodified, in source code or in binary form. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Mbou Eyole +// Giacomo Gabrielli + +let {{ + simd64EnabledCheckCode = vfp64EnabledCheckCode +}}; + +def template NeonX2RegOpDeclare {{ +template <class _Element> +class %(class_name)s : public %(base_class)s +{ + protected: + typedef _Element Element; + public: + // Constructor + %(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _op1, _op2) + { + %(constructor)s; + } + + %(BasicExecDeclare)s +}; +}}; + +def template NeonX2RegImmOpDeclare {{ +template <class _Element> +class %(class_name)s : public %(base_class)s +{ + protected: + typedef _Element Element; + public: + // Constructor + %(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2, + uint64_t _imm) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _op1, _op2, _imm) + { + %(constructor)s; + } + + %(BasicExecDeclare)s +}; +}}; + +def template NeonX1RegOpDeclare {{ +template <class _Element> +class %(class_name)s : public %(base_class)s +{ + protected: + typedef _Element Element; + public: + // Constructor + %(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, IntRegIndex _op1) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _op1) + { + %(constructor)s; + } + + %(BasicExecDeclare)s +}; +}}; + +def template NeonX1RegImmOpDeclare {{ +template <class _Element> +class %(class_name)s : public %(base_class)s +{ + protected: + typedef _Element Element; + public: + // Constructor + %(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, IntRegIndex _op1, uint64_t _imm) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _op1, _imm) + { + %(constructor)s; + } + + %(BasicExecDeclare)s +}; +}}; + +def template NeonX1Reg2ImmOpDeclare {{ +template <class _Element> +class %(class_name)s : public %(base_class)s +{ + protected: + typedef _Element Element; + public: + // Constructor + %(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, IntRegIndex _op1, uint64_t _imm1, + uint64_t _imm2) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _op1, _imm1, _imm2) + { + %(constructor)s; + } + + %(BasicExecDeclare)s +}; +}}; + +def template NeonX1RegImmOnlyOpDeclare {{ +template <class _Element> +class %(class_name)s : public %(base_class)s +{ + protected: + typedef _Element Element; + public: + // Constructor + %(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, uint64_t _imm) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _imm) + { + %(constructor)s; + } + + %(BasicExecDeclare)s +}; +}}; + +def template NeonXExecDeclare {{ + template + Fault %(class_name)s<%(targs)s>::execute( + %(CPU_exec_context)s *, Trace::InstRecord *) const; +}}; + +def template NeonXEqualRegOpExecute {{ + template <class Element> + Fault %(class_name)s<Element>::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + %(op_decl)s; + %(op_rd)s; + + const unsigned rCount = %(r_count)d; + const unsigned eCount = rCount * sizeof(FloatRegBits) / sizeof(Element); + const unsigned eCountFull = 4 * sizeof(FloatRegBits) / sizeof(Element); + + union RegVect { + FloatRegBits regs[rCount]; + Element elements[eCount]; + }; + + union FullRegVect { + FloatRegBits regs[4]; + Element elements[eCountFull]; + }; + + %(code)s; + if (fault == NoFault) + { + %(op_wb)s; + } + + return fault; + } +}}; + +def template NeonXUnequalRegOpExecute {{ + template <class Element> + Fault %(class_name)s<Element>::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + typedef typename bigger_type_t<Element>::type BigElement; + Fault fault = NoFault; + %(op_decl)s; + %(op_rd)s; + + const unsigned rCount = %(r_count)d; + const unsigned eCount = rCount * sizeof(FloatRegBits) / sizeof(Element); + const unsigned eCountFull = 4 * sizeof(FloatRegBits) / sizeof(Element); + + union RegVect { + FloatRegBits regs[rCount]; + Element elements[eCount]; + BigElement bigElements[eCount / 2]; + }; + + union BigRegVect { + FloatRegBits regs[2 * rCount]; + BigElement elements[eCount]; + }; + + union FullRegVect { + FloatRegBits regs[4]; + Element elements[eCountFull]; + }; + + %(code)s; + if (fault == NoFault) + { + %(op_wb)s; + } + + return fault; + } +}}; + +def template MicroNeonMemDeclare64 {{ + class %(class_name)s : public %(base_class)s + { + protected: + // True if the base register is SP (used for SP alignment checking) + bool baseIsSP; + // Access size in bytes + uint8_t accSize; + // Vector element size (0 -> 8-bit, 1 -> 16-bit, 2 -> 32-bit, + // 3 -> 64-bit) + uint8_t eSize; + + public: + %(class_name)s(ExtMachInst machInst, RegIndex _dest, RegIndex _ura, + uint32_t _imm, unsigned extraMemFlags, bool _baseIsSP, + uint8_t _accSize, uint8_t _eSize) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, _dest, + _ura, _imm), + baseIsSP(_baseIsSP), accSize(_accSize), eSize(_eSize) + { + memAccessFlags |= extraMemFlags; + %(constructor)s; + } + + %(BasicExecDeclare)s + %(InitiateAccDeclare)s + %(CompleteAccDeclare)s + }; +}}; + +def template NeonLoadExecute64 {{ + Fault %(class_name)s::execute( + %(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(op_decl)s; + %(mem_decl)s; + %(op_rd)s; + %(ea_code)s; + + MemUnion memUnion; + uint8_t *dataPtr = memUnion.bytes; + + if (fault == NoFault) { + fault = xc->readMem(EA, dataPtr, accSize, memAccessFlags); + %(memacc_code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + +def template NeonLoadInitiateAcc64 {{ + Fault %(class_name)s::initiateAcc( + %(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(op_decl)s; + %(mem_decl)s; + %(op_rd)s; + %(ea_code)s; + + MemUnion memUnion; + uint8_t *dataPtr = memUnion.bytes; + + if (fault == NoFault) { + fault = xc->readMem(EA, dataPtr, accSize, memAccessFlags); + } + + return fault; + } +}}; + +def template NeonLoadCompleteAcc64 {{ + Fault %(class_name)s::completeAcc( + PacketPtr pkt, %(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + + %(mem_decl)s; + %(op_decl)s; + %(op_rd)s; + + MemUnion &memUnion = *(MemUnion *)pkt->getPtr<uint8_t>(); + + if (fault == NoFault) { + %(memacc_code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + +def template NeonStoreExecute64 {{ + Fault %(class_name)s::execute( + %(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(op_decl)s; + %(mem_decl)s; + %(op_rd)s; + %(ea_code)s; + + MemUnion memUnion; + uint8_t *dataPtr = memUnion.bytes; + + if (fault == NoFault) { + %(memacc_code)s; + } + + if (fault == NoFault) { + fault = xc->writeMem(dataPtr, accSize, EA, memAccessFlags, + NULL); + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + +def template NeonStoreInitiateAcc64 {{ + Fault %(class_name)s::initiateAcc( + %(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(op_decl)s; + %(mem_decl)s; + %(op_rd)s; + %(ea_code)s; + + MemUnion memUnion; + if (fault == NoFault) { + %(memacc_code)s; + } + + if (fault == NoFault) { + fault = xc->writeMem(memUnion.bytes, accSize, EA, memAccessFlags, + NULL); + } + + return fault; + } +}}; + +def template NeonStoreCompleteAcc64 {{ + Fault %(class_name)s::completeAcc( + PacketPtr pkt, %(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + return NoFault; + } +}}; + +def template VMemMultDeclare64 {{ + class %(class_name)s : public %(base_class)s + { + public: + // Constructor + %(class_name)s(ExtMachInst machInst, RegIndex rn, RegIndex vd, + RegIndex rm, uint8_t eSize, uint8_t dataSize, + uint8_t numStructElems, uint8_t numRegs, bool wb); + %(BasicExecPanic)s + }; +}}; + +def template VMemSingleDeclare64 {{ + class %(class_name)s : public %(base_class)s + { + public: + // Constructor + %(class_name)s(ExtMachInst machInst, RegIndex rn, RegIndex vd, + RegIndex rm, uint8_t eSize, uint8_t dataSize, + uint8_t numStructElems, uint8_t index, bool wb, + bool replicate = false); + %(BasicExecPanic)s + }; +}}; + +def template VMemMultConstructor64 {{ + %(class_name)s::%(class_name)s( + ExtMachInst machInst, RegIndex rn, RegIndex vd, RegIndex rm, + uint8_t _eSize, uint8_t _dataSize, uint8_t _numStructElems, + uint8_t _numRegs, bool _wb) : + %(base_class)s( + "%(mnemonic)s", machInst, %(op_class)s, rn, vd, rm, + _eSize, _dataSize, _numStructElems, _numRegs, _wb) + { + %(constructor)s; + } +}}; + +def template VMemSingleConstructor64 {{ + %(class_name)s::%(class_name)s( + ExtMachInst machInst, RegIndex rn, RegIndex vd, RegIndex rm, + uint8_t _eSize, uint8_t _dataSize, uint8_t _numStructElems, + uint8_t _index, bool _wb, bool _replicate) : + %(base_class)s( + "%(mnemonic)s", machInst, %(op_class)s, rn, vd, rm, + _eSize, _dataSize, _numStructElems, _index, _wb, + _replicate) + { + %(constructor)s; + } +}}; + +def template MicroNeonMixDeclare64 {{ + class %(class_name)s : public %(base_class)s + { + public: + %(class_name)s(ExtMachInst machInst, RegIndex _dest, RegIndex _op1, + uint8_t _eSize, uint8_t _dataSize, + uint8_t _numStructElems, uint8_t _numRegs, + uint8_t _step) : + %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _op1, _eSize, _dataSize, _numStructElems, + _numRegs, _step) + { + %(constructor)s; + } + + %(BasicExecDeclare)s + }; +}}; + +def template MicroNeonMixLaneDeclare64 {{ + class %(class_name)s : public %(base_class)s + { + public: + %(class_name)s(ExtMachInst machInst, RegIndex _dest, RegIndex _op1, + uint8_t _eSize, uint8_t _dataSize, + uint8_t _numStructElems, uint8_t _lane, uint8_t _step, + bool _replicate = false) : + %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _op1, _eSize, _dataSize, _numStructElems, + _lane, _step, _replicate) + { + %(constructor)s; + } + + %(BasicExecDeclare)s + }; +}}; + +def template MicroNeonMixExecute64 {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + uint64_t resTemp = 0; + resTemp = resTemp; + %(op_decl)s; + %(op_rd)s; + + %(code)s; + if (fault == NoFault) + { + %(op_wb)s; + } + + return fault; + } +}}; diff --git a/src/arch/arm/isa/templates/templates.isa b/src/arch/arm/isa/templates/templates.isa index 148139225..2263cdff4 100644 --- a/src/arch/arm/isa/templates/templates.isa +++ b/src/arch/arm/isa/templates/templates.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2010 ARM Limited +// Copyright (c) 2010-2011 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -40,26 +40,37 @@ //Basic instruction templates ##include "basic.isa" +//Templates for AArch64 bit data instructions. +##include "data64.isa" + //Templates for predicated instructions ##include "pred.isa" //Templates for memory instructions ##include "mem.isa" +//Templates for AArch64 memory instructions +##include "mem64.isa" + //Miscellaneous instructions that don't fit elsewhere ##include "misc.isa" +##include "misc64.isa" //Templates for microcoded memory instructions ##include "macromem.isa" //Templates for branches ##include "branch.isa" +##include "branch64.isa" //Templates for multiplies ##include "mult.isa" //Templates for VFP instructions ##include "vfp.isa" +##include "vfp64.isa" //Templates for Neon instructions ##include "neon.isa" + +##include "neon64.isa" diff --git a/src/arch/arm/isa/templates/vfp.isa b/src/arch/arm/isa/templates/vfp.isa index 90dd751ff..176b6604c 100644 --- a/src/arch/arm/isa/templates/vfp.isa +++ b/src/arch/arm/isa/templates/vfp.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2010 ARM Limited +// Copyright (c) 2010-2013 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -39,32 +39,117 @@ let {{ vfpEnabledCheckCode = ''' - if (!vfpEnabled(Cpacr, Cpsr, Fpexc)) - return disabledFault(); + uint32_t issEnCheck; + bool trapEnCheck; + uint32_t seq; + if (!vfpNeonEnabled(seq,Hcptr, Nsacr, Cpacr, Cpsr, issEnCheck, + trapEnCheck, xc->tcBase(), Fpexc)) + {return disabledFault();} + if (trapEnCheck) { + CPSR cpsrEnCheck = Cpsr; + if (cpsrEnCheck.mode == MODE_HYP) { + return new UndefinedInstruction(machInst, issEnCheck, + EC_TRAPPED_HCPTR); + } else { + if (!inSecureState(Scr, Cpsr)) { + return new HypervisorTrap(machInst, issEnCheck, + EC_TRAPPED_HCPTR); + } + } + } + ''' + + vfp64EnabledCheckCode = ''' + CPSR cpsrEnCheck = Cpsr; + ExceptionLevel el = (ExceptionLevel) (uint8_t) cpsrEnCheck.el; + if (!vfpNeon64Enabled(Cpacr64, el)) + return new SupervisorTrap(machInst, 0x1E00000, + EC_TRAPPED_SIMD_FP); + + if (ArmSystem::haveVirtualization(xc->tcBase()) && el <= EL2) { + HCPTR cptrEnCheck = xc->tcBase()->readMiscReg(MISCREG_CPTR_EL2); + if (cptrEnCheck.tfp) + return new HypervisorTrap(machInst, 0x1E00000, + EC_TRAPPED_SIMD_FP); + } + + if (ArmSystem::haveSecurity(xc->tcBase())) { + HCPTR cptrEnCheck = xc->tcBase()->readMiscReg(MISCREG_CPTR_EL3); + if (cptrEnCheck.tfp) + return new SecureMonitorTrap(machInst, 0x1E00000, + EC_TRAPPED_SIMD_FP); + } ''' vmsrEnabledCheckCode = ''' - if (!vfpEnabled(Cpacr, Cpsr)) + uint32_t issEnCheck; + bool trapEnCheck; + uint32_t seq; + if (!vfpNeonEnabled(seq,Hcptr, Nsacr, Cpacr, Cpsr, issEnCheck, + trapEnCheck, xc->tcBase())) if (dest != (int)MISCREG_FPEXC && dest != (int)MISCREG_FPSID) - return disabledFault(); + {return disabledFault();} if (!inPrivilegedMode(Cpsr)) if (dest != (int)MISCREG_FPSCR) return disabledFault(); - + if (trapEnCheck) { + CPSR cpsrEnCheck = Cpsr; + if (cpsrEnCheck.mode == MODE_HYP) { + return new UndefinedInstruction(machInst, issEnCheck, + EC_TRAPPED_HCPTR); + } else { + if (!inSecureState(Scr, Cpsr)) { + return new HypervisorTrap(machInst, issEnCheck, + EC_TRAPPED_HCPTR); + } + } + } ''' vmrsEnabledCheckCode = ''' - if (!vfpEnabled(Cpacr, Cpsr)) + uint32_t issEnCheck; + bool trapEnCheck; + uint32_t seq; + if (!vfpNeonEnabled(seq,Hcptr, Nsacr, Cpacr, Cpsr, issEnCheck, + trapEnCheck, xc->tcBase())) if (op1 != (int)MISCREG_FPEXC && op1 != (int)MISCREG_FPSID && op1 != (int)MISCREG_MVFR0 && op1 != (int)MISCREG_MVFR1) - return disabledFault(); + {return disabledFault();} if (!inPrivilegedMode(Cpsr)) if (op1 != (int)MISCREG_FPSCR) return disabledFault(); + if (trapEnCheck) { + CPSR cpsrEnCheck = Cpsr; + if (cpsrEnCheck.mode == MODE_HYP) { + return new UndefinedInstruction(machInst, issEnCheck, + EC_TRAPPED_HCPTR); + } else { + if (!inSecureState(Scr, Cpsr)) { + return new HypervisorTrap(machInst, issEnCheck, + EC_TRAPPED_HCPTR); + } + } + } ''' vmrsApsrEnabledCheckCode = ''' - if (!vfpEnabled(Cpacr, Cpsr)) - return disabledFault(); + uint32_t issEnCheck; + bool trapEnCheck; + uint32_t seq; + if (!vfpNeonEnabled(seq,Hcptr, Nsacr, Cpacr, Cpsr, issEnCheck, + trapEnCheck, xc->tcBase())) + {return disabledFault();} + if (trapEnCheck) { + CPSR cpsrEnCheck = Cpsr; + if (cpsrEnCheck.mode == MODE_HYP) { + return new UndefinedInstruction(machInst, issEnCheck, + EC_TRAPPED_HCPTR); + } else { + if (!inSecureState(Scr, Cpsr)) { + return new HypervisorTrap(machInst, issEnCheck, + EC_TRAPPED_HCPTR); + } + } + } ''' }}; diff --git a/src/arch/arm/isa/templates/vfp64.isa b/src/arch/arm/isa/templates/vfp64.isa new file mode 100644 index 000000000..518cedaae --- /dev/null +++ b/src/arch/arm/isa/templates/vfp64.isa @@ -0,0 +1,140 @@ +// -*- mode:c++ -*- + +// Copyright (c) 2012 ARM Limited +// All rights reserved +// +// The license below extends only to copyright in the software and shall +// not be construed as granting a license to any other intellectual +// property including but not limited to intellectual property relating +// to a hardware implementation of the functionality of the software +// licensed hereunder. You may use the software subject to the license +// terms below provided that you ensure that this notice is replicated +// unmodified and in its entirety in all distributions of the software, +// modified or unmodified, in source code or in binary form. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Thomas Grocutt + +def template AA64FpRegRegOpConstructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, IntRegIndex _op1, + VfpMicroMode mode) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _op1, mode) + { + %(constructor)s; + for (int x = 0; x < _numDestRegs; x++) { + _srcRegIdx[_numSrcRegs++] = _destRegIdx[x]; + } + } +}}; + +def template AA64FpRegRegOpConstructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, IntRegIndex _op1, + VfpMicroMode mode) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _op1, mode) + { + %(constructor)s; + for (int x = 0; x < _numDestRegs; x++) { + _srcRegIdx[_numSrcRegs++] = _destRegIdx[x]; + } + } +}}; + +def template AA64FpRegImmOpConstructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, uint64_t _imm, VfpMicroMode mode) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _imm, mode) + { + %(constructor)s; + for (int x = 0; x < _numDestRegs; x++) { + _srcRegIdx[_numSrcRegs++] = _destRegIdx[x]; + } + } +}}; + +def template AA64FpRegRegImmOpConstructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, + IntRegIndex _op1, + uint64_t _imm, + VfpMicroMode mode) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _op1, _imm, mode) + { + %(constructor)s; + for (int x = 0; x < _numDestRegs; x++) { + _srcRegIdx[_numSrcRegs++] = _destRegIdx[x]; + } + } +}}; + +def template AA64FpRegRegRegOpConstructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, + IntRegIndex _op1, + IntRegIndex _op2, + VfpMicroMode mode) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _op1, _op2, mode) + { + %(constructor)s; + for (int x = 0; x < _numDestRegs; x++) { + _srcRegIdx[_numSrcRegs++] = _destRegIdx[x]; + } + } +}}; + +def template AA64FpRegRegRegRegOpDeclare {{ +class %(class_name)s : public %(base_class)s +{ + public: + // Constructor + %(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2, + IntRegIndex _op3, VfpMicroMode mode = VfpNotAMicroop); + %(BasicExecDeclare)s +}; +}}; + +def template AA64FpRegRegRegRegOpConstructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst, + IntRegIndex _dest, + IntRegIndex _op1, + IntRegIndex _op2, + IntRegIndex _op3, + VfpMicroMode mode) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _dest, _op1, _op2, _op3, mode) + { + %(constructor)s; + for (int x = 0; x < _numDestRegs; x++) { + _srcRegIdx[_numSrcRegs++] = _destRegIdx[x]; + } + } +}}; diff --git a/src/arch/arm/isa_traits.hh b/src/arch/arm/isa_traits.hh index 742ca2037..506c5009c 100644 --- a/src/arch/arm/isa_traits.hh +++ b/src/arch/arm/isa_traits.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010, 2012 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -95,6 +95,9 @@ namespace ArmISA const Addr PAddrImplMask = (ULL(1) << PABits) - 1; + // Max. physical address range in bits supported by the architecture + const unsigned MaxPhysAddrRange = 48; + // return a no-op instruction... used for instruction fetch faults const ExtMachInst NoopMachInst = 0x01E320F000ULL; @@ -124,6 +127,8 @@ namespace ArmISA INT_IRQ, INT_FIQ, INT_SEV, // Special interrupt for recieving SEV's + INT_VIRT_IRQ, + INT_VIRT_FIQ, NumInterruptTypes }; } // namespace ArmISA diff --git a/src/arch/arm/linux/linux.cc b/src/arch/arm/linux/linux.cc index 1e3a1e725..62519d38b 100644 --- a/src/arch/arm/linux/linux.cc +++ b/src/arch/arm/linux/linux.cc @@ -1,4 +1,16 @@ /* + * Copyright (c) 2011 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * * Copyright (c) 2003-2005 The Regents of The University of Michigan * Copyright (c) 2007-2008 The Florida State University * All rights reserved. @@ -34,55 +46,108 @@ #include "arch/arm/linux/linux.hh" // open(2) flags translation table -OpenFlagTransTable ArmLinux::openFlagTable[] = { +OpenFlagTransTable ArmLinux32::openFlagTable[] = { +#ifdef _MSC_VER + { ArmLinux32::TGT_O_RDONLY, _O_RDONLY }, + { ArmLinux32::TGT_O_WRONLY, _O_WRONLY }, + { ArmLinux32::TGT_O_RDWR, _O_RDWR }, + { ArmLinux32::TGT_O_APPEND, _O_APPEND }, + { ArmLinux32::TGT_O_CREAT, _O_CREAT }, + { ArmLinux32::TGT_O_TRUNC, _O_TRUNC }, + { ArmLinux32::TGT_O_EXCL, _O_EXCL }, +#ifdef _O_NONBLOCK + { ArmLinux32::TGT_O_NONBLOCK, _O_NONBLOCK }, +#endif +#ifdef _O_NOCTTY + { ArmLinux32::TGT_O_NOCTTY, _O_NOCTTY }, +#endif +#ifdef _O_SYNC + { ArmLinux32::TGT_O_SYNC, _O_SYNC }, +#endif +#else /* !_MSC_VER */ + { ArmLinux32::TGT_O_RDONLY, O_RDONLY }, + { ArmLinux32::TGT_O_WRONLY, O_WRONLY }, + { ArmLinux32::TGT_O_RDWR, O_RDWR }, + { ArmLinux32::TGT_O_CREAT, O_CREAT }, + { ArmLinux32::TGT_O_EXCL, O_EXCL }, + { ArmLinux32::TGT_O_NOCTTY, O_NOCTTY }, + { ArmLinux32::TGT_O_TRUNC, O_TRUNC }, + { ArmLinux32::TGT_O_APPEND, O_APPEND }, + { ArmLinux32::TGT_O_NONBLOCK, O_NONBLOCK }, +#ifdef O_SYNC + { ArmLinux32::TGT_O_SYNC, O_SYNC }, +#endif +#ifdef FASYNC + { ArmLinux32::TGT_FASYNC, FASYNC }, +#endif +#ifdef O_DIRECT + { ArmLinux32::TGT_O_DIRECT, O_DIRECT }, +#endif +#ifdef O_LARGEFILE + { ArmLinux32::TGT_O_LARGEFILE, O_LARGEFILE }, +#endif +#ifdef O_DIRECTORY + { ArmLinux32::TGT_O_DIRECTORY, O_DIRECTORY }, +#endif +#ifdef O_NOFOLLOW + { ArmLinux32::TGT_O_NOFOLLOW, O_NOFOLLOW }, +#endif +#endif /* _MSC_VER */ +}; + +const int ArmLinux32::NUM_OPEN_FLAGS = sizeof(ArmLinux32::openFlagTable) / + sizeof(ArmLinux32::openFlagTable[0]); + +// open(2) flags translation table +OpenFlagTransTable ArmLinux64::openFlagTable[] = { #ifdef _MSC_VER - { ArmLinux::TGT_O_RDONLY, _O_RDONLY }, - { ArmLinux::TGT_O_WRONLY, _O_WRONLY }, - { ArmLinux::TGT_O_RDWR, _O_RDWR }, - { ArmLinux::TGT_O_APPEND, _O_APPEND }, - { ArmLinux::TGT_O_CREAT, _O_CREAT }, - { ArmLinux::TGT_O_TRUNC, _O_TRUNC }, - { ArmLinux::TGT_O_EXCL, _O_EXCL }, + { ArmLinux64::TGT_O_RDONLY, _O_RDONLY }, + { ArmLinux64::TGT_O_WRONLY, _O_WRONLY }, + { ArmLinux64::TGT_O_RDWR, _O_RDWR }, + { ArmLinux64::TGT_O_APPEND, _O_APPEND }, + { ArmLinux64::TGT_O_CREAT, _O_CREAT }, + { ArmLinux64::TGT_O_TRUNC, _O_TRUNC }, + { ArmLinux64::TGT_O_EXCL, _O_EXCL }, #ifdef _O_NONBLOCK - { ArmLinux::TGT_O_NONBLOCK, _O_NONBLOCK }, + { ArmLinux64::TGT_O_NONBLOCK, _O_NONBLOCK }, #endif #ifdef _O_NOCTTY - { ArmLinux::TGT_O_NOCTTY, _O_NOCTTY }, + { ArmLinux64::TGT_O_NOCTTY, _O_NOCTTY }, #endif #ifdef _O_SYNC - { ArmLinux::TGT_O_SYNC, _O_SYNC }, + { ArmLinux64::TGT_O_SYNC, _O_SYNC }, #endif #else /* !_MSC_VER */ - { ArmLinux::TGT_O_RDONLY, O_RDONLY }, - { ArmLinux::TGT_O_WRONLY, O_WRONLY }, - { ArmLinux::TGT_O_RDWR, O_RDWR }, - { ArmLinux::TGT_O_CREAT, O_CREAT }, - { ArmLinux::TGT_O_EXCL, O_EXCL }, - { ArmLinux::TGT_O_NOCTTY, O_NOCTTY }, - { ArmLinux::TGT_O_TRUNC, O_TRUNC }, - { ArmLinux::TGT_O_APPEND, O_APPEND }, - { ArmLinux::TGT_O_NONBLOCK, O_NONBLOCK }, + { ArmLinux64::TGT_O_RDONLY, O_RDONLY }, + { ArmLinux64::TGT_O_WRONLY, O_WRONLY }, + { ArmLinux64::TGT_O_RDWR, O_RDWR }, + { ArmLinux64::TGT_O_CREAT, O_CREAT }, + { ArmLinux64::TGT_O_EXCL, O_EXCL }, + { ArmLinux64::TGT_O_NOCTTY, O_NOCTTY }, + { ArmLinux64::TGT_O_TRUNC, O_TRUNC }, + { ArmLinux64::TGT_O_APPEND, O_APPEND }, + { ArmLinux64::TGT_O_NONBLOCK, O_NONBLOCK }, #ifdef O_SYNC - { ArmLinux::TGT_O_SYNC, O_SYNC }, + { ArmLinux64::TGT_O_SYNC, O_SYNC }, #endif #ifdef FASYNC - { ArmLinux::TGT_FASYNC, FASYNC }, + { ArmLinux64::TGT_FASYNC, FASYNC }, #endif #ifdef O_DIRECT - { ArmLinux::TGT_O_DIRECT, O_DIRECT }, + { ArmLinux64::TGT_O_DIRECT, O_DIRECT }, #endif #ifdef O_LARGEFILE - { ArmLinux::TGT_O_LARGEFILE, O_LARGEFILE }, + { ArmLinux64::TGT_O_LARGEFILE, O_LARGEFILE }, #endif #ifdef O_DIRECTORY - { ArmLinux::TGT_O_DIRECTORY, O_DIRECTORY }, + { ArmLinux64::TGT_O_DIRECTORY, O_DIRECTORY }, #endif #ifdef O_NOFOLLOW - { ArmLinux::TGT_O_NOFOLLOW, O_NOFOLLOW }, + { ArmLinux64::TGT_O_NOFOLLOW, O_NOFOLLOW }, #endif #endif /* _MSC_VER */ }; -const int ArmLinux::NUM_OPEN_FLAGS = - (sizeof(ArmLinux::openFlagTable)/sizeof(ArmLinux::openFlagTable[0])); +const int ArmLinux64::NUM_OPEN_FLAGS = sizeof(ArmLinux64::openFlagTable) / + sizeof(ArmLinux64::openFlagTable[0]); diff --git a/src/arch/arm/linux/linux.hh b/src/arch/arm/linux/linux.hh index 5a3e68a78..fbf5d2185 100644 --- a/src/arch/arm/linux/linux.hh +++ b/src/arch/arm/linux/linux.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010, 2011-2012 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -47,7 +47,7 @@ #include "kern/linux/linux.hh" -class ArmLinux : public Linux +class ArmLinux32 : public Linux { public: @@ -123,8 +123,10 @@ class ArmLinux : public Linux uint16_t st_uid; uint16_t st_gid; uint32_t st_rdev; + uint32_t __pad1; uint32_t st_size; uint32_t st_blksize; + uint32_t __pad2; uint32_t st_blocks; uint32_t st_atimeX; uint32_t st_atime_nsec; @@ -198,8 +200,192 @@ class ArmLinux : public Linux int32_t tms_cutime; //!< user time of children int32_t tms_cstime; //!< system time of children }; +}; + +class ArmLinux64 : public Linux +{ + public: + + /// This table maps the target open() flags to the corresponding + /// host open() flags. + static OpenFlagTransTable openFlagTable[]; + + /// Number of entries in openFlagTable[]. + static const int NUM_OPEN_FLAGS; + + //@{ + /// Basic ARM Linux types + typedef uint64_t size_t; + typedef uint64_t off_t; + typedef int64_t time_t; + typedef int64_t clock_t; + //@} + + //@{ + /// open(2) flag values. + static const int TGT_O_RDONLY = 00000000; //!< O_RDONLY + static const int TGT_O_WRONLY = 00000001; //!< O_WRONLY + static const int TGT_O_RDWR = 00000002; //!< O_RDWR + static const int TGT_O_CREAT = 00000100; //!< O_CREAT + static const int TGT_O_EXCL = 00000200; //!< O_EXCL + static const int TGT_O_NOCTTY = 00000400; //!< O_NOCTTY + static const int TGT_O_TRUNC = 00001000; //!< O_TRUNC + static const int TGT_O_APPEND = 00002000; //!< O_APPEND + static const int TGT_O_NONBLOCK = 00004000; //!< O_NONBLOCK + static const int TGT_O_SYNC = 00010000; //!< O_SYNC + static const int TGT_FASYNC = 00020000; //!< FASYNC + static const int TGT_O_DIRECT = 00040000; //!< O_DIRECT + static const int TGT_O_LARGEFILE = 00100000; //!< O_LARGEFILE + static const int TGT_O_DIRECTORY = 00200000; //!< O_DIRECTORY + static const int TGT_O_NOFOLLOW = 00400000; //!< O_NOFOLLOW + static const int TGT_O_NOATIME = 01000000; //!< O_NOATIME + static const int TGT_O_CLOEXEC = 02000000; //!< O_NOATIME + //@} + /// For mmap(). + static const unsigned TGT_MAP_ANONYMOUS = 0x20; + static const unsigned TGT_MAP_FIXED = 0x10; + //@{ + /// For getrusage(). + static const int TGT_RUSAGE_SELF = 0; + static const int TGT_RUSAGE_CHILDREN = -1; + static const int TGT_RUSAGE_BOTH = -2; + //@} + + //@{ + /// ioctl() command codes. + static const unsigned TIOCGETP_ = 0x5401; + static const unsigned TIOCSETP_ = 0x80067409; + static const unsigned TIOCSETN_ = 0x8006740a; + static const unsigned TIOCSETC_ = 0x80067411; + static const unsigned TIOCGETC_ = 0x40067412; + static const unsigned FIONREAD_ = 0x4004667f; + static const unsigned TIOCISATTY_ = 0x2000745e; + static const unsigned TIOCGETS_ = 0x402c7413; + static const unsigned TIOCGETA_ = 0x5405; + static const unsigned TCSETAW_ = 0x5407; // 2.6.15 kernel + //@} + + /// For table(). + static const int TBL_SYSINFO = 12; + + /// Resource enumeration for getrlimit(). + enum rlimit_resources { + TGT_RLIMIT_CPU = 0, + TGT_RLIMIT_FSIZE = 1, + TGT_RLIMIT_DATA = 2, + TGT_RLIMIT_STACK = 3, + TGT_RLIMIT_CORE = 4, + TGT_RLIMIT_RSS = 5, + TGT_RLIMIT_NPROC = 6, + TGT_RLIMIT_NOFILE = 7, + TGT_RLIMIT_MEMLOCK = 8, + TGT_RLIMIT_AS = 9, + TGT_RLIMIT_LOCKS = 10 + }; + + /// Limit struct for getrlimit/setrlimit. + struct rlimit { + uint64_t rlim_cur; //!< soft limit + uint64_t rlim_max; //!< hard limit + }; + + /// For gettimeofday(). + struct timeval { + int64_t tv_sec; //!< seconds + int64_t tv_usec; //!< microseconds + }; + + // For writev/readv + struct tgt_iovec { + uint64_t iov_base; // void * + uint64_t iov_len; + }; + + typedef struct { + uint64_t st_dev; + uint64_t st_ino; + uint64_t st_nlink; + uint32_t st_mode; + uint32_t st_uid; + uint32_t st_gid; + uint32_t __pad0; + uint64_t st_rdev; + uint64_t st_size; + uint64_t st_blksize; + uint64_t st_blocks; + uint64_t st_atimeX; + uint64_t st_atime_nsec; + uint64_t st_mtimeX; + uint64_t st_mtime_nsec; + uint64_t st_ctimeX; + uint64_t st_ctime_nsec; + } tgt_stat; + + typedef struct { + uint64_t st_dev; + uint64_t st_ino; + uint32_t st_mode; + uint32_t st_nlink; + uint32_t st_uid; + uint32_t st_gid; + uint32_t __pad0; + uint64_t st_rdev; + uint64_t st_size; + uint64_t st_blksize; + uint64_t st_blocks; + uint64_t st_atimeX; + uint64_t st_atime_nsec; + uint64_t st_mtimeX; + uint64_t st_mtime_nsec; + uint64_t st_ctimeX; + uint64_t st_ctime_nsec; + } tgt_stat64; + + typedef struct { + int64_t uptime; /* Seconds since boot */ + uint64_t loads[3]; /* 1, 5, and 15 minute load averages */ + uint64_t totalram; /* Total usable main memory size */ + uint64_t freeram; /* Available memory size */ + uint64_t sharedram; /* Amount of shared memory */ + uint64_t bufferram; /* Memory used by buffers */ + uint64_t totalswap; /* Total swap space size */ + uint64_t freeswap; /* swap space still available */ + uint16_t procs; /* Number of current processes */ + uint16_t pad; + uint64_t totalhigh; /* Total high memory size */ + uint64_t freehigh; /* Available high memory size */ + uint32_t mem_unit; /* Memory unit size in bytes */ + } tgt_sysinfo; + + /// For getrusage(). + struct rusage { + struct timeval ru_utime; //!< user time used + struct timeval ru_stime; //!< system time used + int64_t ru_maxrss; //!< max rss + int64_t ru_ixrss; //!< integral shared memory size + int64_t ru_idrss; //!< integral unshared data " + int64_t ru_isrss; //!< integral unshared stack " + int64_t ru_minflt; //!< page reclaims - total vmfaults + int64_t ru_majflt; //!< page faults + int64_t ru_nswap; //!< swaps + int64_t ru_inblock; //!< block input operations + int64_t ru_oublock; //!< block output operations + int64_t ru_msgsnd; //!< messages sent + int64_t ru_msgrcv; //!< messages received + int64_t ru_nsignals; //!< signals received + int64_t ru_nvcsw; //!< voluntary context switches + int64_t ru_nivcsw; //!< involuntary " + }; + + /// For times(). + struct tms { + int64_t tms_utime; //!< user time + int64_t tms_stime; //!< system time + int64_t tms_cutime; //!< user time of children + int64_t tms_cstime; //!< system time of children + }; }; #endif diff --git a/src/arch/arm/linux/process.cc b/src/arch/arm/linux/process.cc index 169565a04..e34a813ea 100644 --- a/src/arch/arm/linux/process.cc +++ b/src/arch/arm/linux/process.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -41,6 +41,7 @@ * Authors: Korey Sewell * Stephen Hines * Ali Saidi + * Giacomo Gabrielli */ #include "arch/arm/linux/linux.hh" @@ -58,8 +59,8 @@ using namespace ArmISA; /// Target uname() handler. static SyscallReturn -unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process, - ThreadContext *tc) +unameFunc32(SyscallDesc *desc, int callnum, LiveProcess *process, + ThreadContext *tc) { int index = 0; TypedBufferArg<Linux::utsname> name(process->getSyscallArg(tc, index)); @@ -74,13 +75,56 @@ unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process, return 0; } -SyscallDesc ArmLinuxProcess::syscallDescs[] = { +/// Target uname() handler. +static SyscallReturn +unameFunc64(SyscallDesc *desc, int callnum, LiveProcess *process, + ThreadContext *tc) +{ + int index = 0; + TypedBufferArg<Linux::utsname> name(process->getSyscallArg(tc, index)); + + strcpy(name->sysname, "Linux"); + strcpy(name->nodename, "gem5"); + strcpy(name->release, "3.7.0+"); + strcpy(name->version, "#1 SMP Sat Dec 1 00:00:00 GMT 2012"); + strcpy(name->machine, "armv8l"); + + name.copyOut(tc->getMemProxy()); + return 0; +} + +/// Target set_tls() handler. +static SyscallReturn +setTLSFunc32(SyscallDesc *desc, int callnum, LiveProcess *process, + ThreadContext *tc) +{ + int index = 0; + uint32_t tlsPtr = process->getSyscallArg(tc, index); + + tc->getMemProxy().writeBlob(ArmLinuxProcess32::commPage + 0x0ff0, + (uint8_t *)&tlsPtr, sizeof(tlsPtr)); + tc->setMiscReg(MISCREG_TPIDRURO,tlsPtr); + return 0; +} + +static SyscallReturn +setTLSFunc64(SyscallDesc *desc, int callnum, LiveProcess *process, + ThreadContext *tc) +{ + int index = 0; + uint32_t tlsPtr = process->getSyscallArg(tc, index); + + tc->setMiscReg(MISCREG_TPIDRRO_EL0, tlsPtr); + return 0; +} + +static SyscallDesc syscallDescs32[] = { /* 0 */ SyscallDesc("syscall", unimplementedFunc), /* 1 */ SyscallDesc("exit", exitFunc), /* 2 */ SyscallDesc("fork", unimplementedFunc), /* 3 */ SyscallDesc("read", readFunc), /* 4 */ SyscallDesc("write", writeFunc), - /* 5 */ SyscallDesc("open", openFunc<ArmLinux>), + /* 5 */ SyscallDesc("open", openFunc<ArmLinux32>), /* 6 */ SyscallDesc("close", closeFunc), /* 7 */ SyscallDesc("unused#7", unimplementedFunc), /* 8 */ SyscallDesc("creat", unimplementedFunc), @@ -88,9 +132,9 @@ SyscallDesc ArmLinuxProcess::syscallDescs[] = { /* 10 */ SyscallDesc("unlink", unlinkFunc), /* 11 */ SyscallDesc("execve", unimplementedFunc), /* 12 */ SyscallDesc("chdir", unimplementedFunc), - /* 13 */ SyscallDesc("time", timeFunc<ArmLinux>), + /* 13 */ SyscallDesc("time", timeFunc<ArmLinux32>), /* 14 */ SyscallDesc("mknod", unimplementedFunc), - /* 15 */ SyscallDesc("chmod", chmodFunc<ArmLinux>), + /* 15 */ SyscallDesc("chmod", chmodFunc<ArmLinux32>), /* 16 */ SyscallDesc("lchown", chownFunc), /* 17 */ SyscallDesc("unused#17", unimplementedFunc), /* 18 */ SyscallDesc("unused#18", unimplementedFunc), @@ -118,7 +162,7 @@ SyscallDesc ArmLinuxProcess::syscallDescs[] = { /* 40 */ SyscallDesc("rmdir", unimplementedFunc), /* 41 */ SyscallDesc("dup", dupFunc), /* 42 */ SyscallDesc("pipe", pipePseudoFunc), - /* 43 */ SyscallDesc("times", timesFunc<ArmLinux>), + /* 43 */ SyscallDesc("times", timesFunc<ArmLinux32>), /* 44 */ SyscallDesc("unused#44", unimplementedFunc), /* 45 */ SyscallDesc("brk", brkFunc), /* 46 */ SyscallDesc("setgid", unimplementedFunc), @@ -129,7 +173,7 @@ SyscallDesc ArmLinuxProcess::syscallDescs[] = { /* 51 */ SyscallDesc("acct", unimplementedFunc), /* 52 */ SyscallDesc("umount2", unimplementedFunc), /* 53 */ SyscallDesc("unused#53", unimplementedFunc), - /* 54 */ SyscallDesc("ioctl", ioctlFunc<ArmLinux>), + /* 54 */ SyscallDesc("ioctl", ioctlFunc<ArmLinux32>), /* 55 */ SyscallDesc("fcntl", fcntlFunc), /* 56 */ SyscallDesc("unused#56", unimplementedFunc), /* 57 */ SyscallDesc("setpgid", unimplementedFunc), @@ -151,9 +195,9 @@ SyscallDesc ArmLinuxProcess::syscallDescs[] = { /* 73 */ SyscallDesc("sigpending", unimplementedFunc), /* 74 */ SyscallDesc("sethostname", ignoreFunc), /* 75 */ SyscallDesc("setrlimit", ignoreFunc), - /* 76 */ SyscallDesc("getrlimit", getrlimitFunc<ArmLinux>), - /* 77 */ SyscallDesc("getrusage", getrusageFunc<ArmLinux>), - /* 78 */ SyscallDesc("gettimeofday", gettimeofdayFunc<ArmLinux>), + /* 76 */ SyscallDesc("getrlimit", getrlimitFunc<ArmLinux32>), + /* 77 */ SyscallDesc("getrusage", getrusageFunc<ArmLinux32>), + /* 78 */ SyscallDesc("gettimeofday", gettimeofdayFunc<ArmLinux32>), /* 79 */ SyscallDesc("settimeofday", unimplementedFunc), /* 80 */ SyscallDesc("getgroups", unimplementedFunc), /* 81 */ SyscallDesc("setgroups", unimplementedFunc), @@ -165,7 +209,7 @@ SyscallDesc ArmLinuxProcess::syscallDescs[] = { /* 87 */ SyscallDesc("swapon", unimplementedFunc), /* 88 */ SyscallDesc("reboot", unimplementedFunc), /* 89 */ SyscallDesc("readdir", unimplementedFunc), - /* 90 */ SyscallDesc("mmap", mmapFunc<ArmLinux>), + /* 90 */ SyscallDesc("mmap", mmapFunc<ArmLinux32>), /* 91 */ SyscallDesc("munmap", munmapFunc), /* 92 */ SyscallDesc("truncate", truncateFunc), /* 93 */ SyscallDesc("ftruncate", ftruncateFunc), @@ -181,9 +225,9 @@ SyscallDesc ArmLinuxProcess::syscallDescs[] = { /* 103 */ SyscallDesc("syslog", unimplementedFunc), /* 104 */ SyscallDesc("setitimer", unimplementedFunc), /* 105 */ SyscallDesc("getitimer", unimplementedFunc), - /* 106 */ SyscallDesc("stat", statFunc<ArmLinux>), + /* 106 */ SyscallDesc("stat", statFunc<ArmLinux32>), /* 107 */ SyscallDesc("lstat", unimplementedFunc), - /* 108 */ SyscallDesc("fstat", fstatFunc<ArmLinux>), + /* 108 */ SyscallDesc("fstat", fstatFunc<ArmLinux32>), /* 109 */ SyscallDesc("unused#109", unimplementedFunc), /* 110 */ SyscallDesc("unused#101", unimplementedFunc), /* 111 */ SyscallDesc("vhangup", unimplementedFunc), @@ -191,17 +235,17 @@ SyscallDesc ArmLinuxProcess::syscallDescs[] = { /* 113 */ SyscallDesc("syscall", unimplementedFunc), /* 114 */ SyscallDesc("wait4", unimplementedFunc), /* 115 */ SyscallDesc("swapoff", unimplementedFunc), - /* 116 */ SyscallDesc("sysinfo", sysinfoFunc<ArmLinux>), + /* 116 */ SyscallDesc("sysinfo", sysinfoFunc<ArmLinux32>), /* 117 */ SyscallDesc("ipc", unimplementedFunc), /* 118 */ SyscallDesc("fsync", unimplementedFunc), /* 119 */ SyscallDesc("sigreturn", unimplementedFunc), /* 120 */ SyscallDesc("clone", cloneFunc), /* 121 */ SyscallDesc("setdomainname", unimplementedFunc), - /* 122 */ SyscallDesc("uname", unameFunc), + /* 122 */ SyscallDesc("uname", unameFunc32), /* 123 */ SyscallDesc("unused#123", unimplementedFunc), /* 124 */ SyscallDesc("adjtimex", unimplementedFunc), /* 125 */ SyscallDesc("mprotect", ignoreFunc), - /* 126 */ SyscallDesc("sigprocmask", unimplementedFunc), + /* 126 */ SyscallDesc("sigprocmask", ignoreWarnOnceFunc), /* 127 */ SyscallDesc("unused#127", unimplementedFunc), /* 128 */ SyscallDesc("init_module", unimplementedFunc), /* 129 */ SyscallDesc("delete_module", unimplementedFunc), @@ -221,7 +265,7 @@ SyscallDesc ArmLinuxProcess::syscallDescs[] = { /* 143 */ SyscallDesc("flock", unimplementedFunc), /* 144 */ SyscallDesc("msync", unimplementedFunc), /* 145 */ SyscallDesc("readv", unimplementedFunc), - /* 146 */ SyscallDesc("writev", writevFunc<ArmLinux>), + /* 146 */ SyscallDesc("writev", writevFunc<ArmLinux32>), /* 147 */ SyscallDesc("getsid", unimplementedFunc), /* 148 */ SyscallDesc("fdatasync", unimplementedFunc), /* 149 */ SyscallDesc("sysctl", unimplementedFunc), @@ -238,7 +282,7 @@ SyscallDesc ArmLinuxProcess::syscallDescs[] = { /* 160 */ SyscallDesc("sched_get_priority_min", unimplementedFunc), /* 161 */ SyscallDesc("sched_rr_get_interval", unimplementedFunc), /* 162 */ SyscallDesc("nanosleep", ignoreWarnOnceFunc), - /* 163 */ SyscallDesc("mremap", mremapFunc<ArmLinux>), // ARM-specific + /* 163 */ SyscallDesc("mremap", mremapFunc<ArmLinux32>), // ARM-specific /* 164 */ SyscallDesc("setresuid", unimplementedFunc), /* 165 */ SyscallDesc("getresuid", unimplementedFunc), /* 166 */ SyscallDesc("unused#166", unimplementedFunc), @@ -266,13 +310,13 @@ SyscallDesc ArmLinuxProcess::syscallDescs[] = { /* 188 */ SyscallDesc("unused#188", unimplementedFunc), /* 189 */ SyscallDesc("unused#189", unimplementedFunc), /* 190 */ SyscallDesc("vfork", unimplementedFunc), - /* 191 */ SyscallDesc("getrlimit", getrlimitFunc<ArmLinux>), - /* 192 */ SyscallDesc("mmap2", mmapFunc<ArmLinux>), + /* 191 */ SyscallDesc("getrlimit", getrlimitFunc<ArmLinux32>), + /* 192 */ SyscallDesc("mmap2", mmapFunc<ArmLinux32>), /* 193 */ SyscallDesc("truncate64", unimplementedFunc), /* 194 */ SyscallDesc("ftruncate64", ftruncate64Func), - /* 195 */ SyscallDesc("stat64", stat64Func<ArmLinux>), - /* 196 */ SyscallDesc("lstat64", lstat64Func<ArmLinux>), - /* 197 */ SyscallDesc("fstat64", fstat64Func<ArmLinux>), + /* 195 */ SyscallDesc("stat64", stat64Func<ArmLinux32>), + /* 196 */ SyscallDesc("lstat64", lstat64Func<ArmLinux32>), + /* 197 */ SyscallDesc("fstat64", fstat64Func<ArmLinux32>), /* 198 */ SyscallDesc("lchown", unimplementedFunc), /* 199 */ SyscallDesc("getuid", getuidFunc), /* 200 */ SyscallDesc("getgid", getgidFunc), @@ -319,7 +363,7 @@ SyscallDesc ArmLinuxProcess::syscallDescs[] = { /* 241 */ SyscallDesc("sched_setaffinity", unimplementedFunc), /* 242 */ SyscallDesc("sched_getaffinity", unimplementedFunc), /* 243 */ SyscallDesc("io_setup", unimplementedFunc), - /* 244 */ SyscallDesc("io_destory", unimplementedFunc), + /* 244 */ SyscallDesc("io_destroy", unimplementedFunc), /* 245 */ SyscallDesc("io_getevents", unimplementedFunc), /* 246 */ SyscallDesc("io_submit", unimplementedFunc), /* 247 */ SyscallDesc("io_cancel", unimplementedFunc), @@ -441,68 +485,1187 @@ SyscallDesc ArmLinuxProcess::syscallDescs[] = { /* 363 */ SyscallDesc("sys_rt_tgsigqueueinfo", unimplementedFunc), /* 364 */ SyscallDesc("sys_perf_event_open", unimplementedFunc), /* 365 */ SyscallDesc("sys_recvmmsg", unimplementedFunc), - }; -/// Target set_tls() handler. -static SyscallReturn -setTLSFunc(SyscallDesc *desc, int callnum, LiveProcess *process, - ThreadContext *tc) -{ - int index = 0; - uint32_t tlsPtr = process->getSyscallArg(tc, index); - - tc->getMemProxy().writeBlob(ArmLinuxProcess::commPage + 0x0ff0, - (uint8_t *)&tlsPtr, sizeof(tlsPtr)); - tc->setMiscReg(MISCREG_TPIDRURO,tlsPtr); - return 0; -} +static SyscallDesc syscallDescs64[] = { + /* 0 */ SyscallDesc("io_setup", unimplementedFunc), + /* 1 */ SyscallDesc("io_destroy", unimplementedFunc), + /* 2 */ SyscallDesc("io_submit", unimplementedFunc), + /* 3 */ SyscallDesc("io_cancel", unimplementedFunc), + /* 4 */ SyscallDesc("io_getevents", unimplementedFunc), + /* 5 */ SyscallDesc("setxattr", unimplementedFunc), + /* 6 */ SyscallDesc("lsetxattr", unimplementedFunc), + /* 7 */ SyscallDesc("fsetxattr", unimplementedFunc), + /* 8 */ SyscallDesc("getxattr", unimplementedFunc), + /* 9 */ SyscallDesc("lgetxattr", unimplementedFunc), + /* 10 */ SyscallDesc("fgetxattr", unimplementedFunc), + /* 11 */ SyscallDesc("listxattr", unimplementedFunc), + /* 12 */ SyscallDesc("llistxattr", unimplementedFunc), + /* 13 */ SyscallDesc("flistxattr", unimplementedFunc), + /* 14 */ SyscallDesc("removexattr", unimplementedFunc), + /* 15 */ SyscallDesc("lremovexattr", unimplementedFunc), + /* 16 */ SyscallDesc("fremovexattr", unimplementedFunc), + /* 17 */ SyscallDesc("getcwd", getcwdFunc), + /* 18 */ SyscallDesc("lookup_dcookie", unimplementedFunc), + /* 19 */ SyscallDesc("eventfd2", unimplementedFunc), + /* 20 */ SyscallDesc("epoll_create1", unimplementedFunc), + /* 21 */ SyscallDesc("epoll_ctl", unimplementedFunc), + /* 22 */ SyscallDesc("epoll_pwait", unimplementedFunc), + /* 23 */ SyscallDesc("dup", dupFunc), + /* 24 */ SyscallDesc("dup3", unimplementedFunc), + /* 25 */ SyscallDesc("fcntl64", fcntl64Func), + /* 26 */ SyscallDesc("inotify_init1", unimplementedFunc), + /* 27 */ SyscallDesc("inotify_add_watch", unimplementedFunc), + /* 28 */ SyscallDesc("inotify_rm_watch", unimplementedFunc), + /* 29 */ SyscallDesc("ioctl", ioctlFunc<ArmLinux64>), + /* 30 */ SyscallDesc("ioprio_set", unimplementedFunc), + /* 31 */ SyscallDesc("ioprio_get", unimplementedFunc), + /* 32 */ SyscallDesc("flock", unimplementedFunc), + /* 33 */ SyscallDesc("mknodat", unimplementedFunc), + /* 34 */ SyscallDesc("mkdirat", unimplementedFunc), + /* 35 */ SyscallDesc("unlinkat", unimplementedFunc), + /* 36 */ SyscallDesc("symlinkat", unimplementedFunc), + /* 37 */ SyscallDesc("linkat", unimplementedFunc), + /* 38 */ SyscallDesc("renameat", unimplementedFunc), + /* 39 */ SyscallDesc("umount2", unimplementedFunc), + /* 40 */ SyscallDesc("mount", unimplementedFunc), + /* 41 */ SyscallDesc("pivot_root", unimplementedFunc), + /* 42 */ SyscallDesc("nfsservctl", unimplementedFunc), + /* 43 */ SyscallDesc("statfs64", unimplementedFunc), + /* 44 */ SyscallDesc("fstatfs64", unimplementedFunc), + /* 45 */ SyscallDesc("truncate64", unimplementedFunc), + /* 46 */ SyscallDesc("ftruncate64", ftruncate64Func), + /* 47 */ SyscallDesc("fallocate", unimplementedFunc), + /* 48 */ SyscallDesc("faccessat", unimplementedFunc), + /* 49 */ SyscallDesc("chdir", unimplementedFunc), + /* 50 */ SyscallDesc("fchdir", unimplementedFunc), + /* 51 */ SyscallDesc("chroot", unimplementedFunc), + /* 52 */ SyscallDesc("fchmod", unimplementedFunc), + /* 53 */ SyscallDesc("fchmodat", unimplementedFunc), + /* 54 */ SyscallDesc("fchownat", unimplementedFunc), + /* 55 */ SyscallDesc("fchown", unimplementedFunc), + /* 56 */ SyscallDesc("openat", openatFunc<ArmLinux64>), + /* 57 */ SyscallDesc("close", closeFunc), + /* 58 */ SyscallDesc("vhangup", unimplementedFunc), + /* 59 */ SyscallDesc("pipe2", unimplementedFunc), + /* 60 */ SyscallDesc("quotactl", unimplementedFunc), + /* 61 */ SyscallDesc("getdents64", unimplementedFunc), + /* 62 */ SyscallDesc("llseek", lseekFunc), + /* 63 */ SyscallDesc("read", readFunc), + /* 64 */ SyscallDesc("write", writeFunc), + /* 65 */ SyscallDesc("readv", unimplementedFunc), + /* 66 */ SyscallDesc("writev", writevFunc<ArmLinux64>), + /* 67 */ SyscallDesc("pread64", unimplementedFunc), + /* 68 */ SyscallDesc("pwrite64", unimplementedFunc), + /* 69 */ SyscallDesc("preadv", unimplementedFunc), + /* 70 */ SyscallDesc("pwritev", unimplementedFunc), + /* 71 */ SyscallDesc("sendfile64", unimplementedFunc), + /* 72 */ SyscallDesc("pselect6", unimplementedFunc), + /* 73 */ SyscallDesc("ppoll", unimplementedFunc), + /* 74 */ SyscallDesc("signalfd4", unimplementedFunc), + /* 75 */ SyscallDesc("vmsplice", unimplementedFunc), + /* 76 */ SyscallDesc("splice", unimplementedFunc), + /* 77 */ SyscallDesc("tee", unimplementedFunc), + /* 78 */ SyscallDesc("readlinkat", unimplementedFunc), + /* 79 */ SyscallDesc("fstatat64", fstatat64Func<ArmLinux64>), + /* 80 */ SyscallDesc("fstat64", fstat64Func<ArmLinux64>), + /* 81 */ SyscallDesc("sync", unimplementedFunc), + /* 82 */ SyscallDesc("fsync", unimplementedFunc), + /* 83 */ SyscallDesc("fdatasync", unimplementedFunc), + /* 84 */ SyscallDesc("sync_file_range", unimplementedFunc), + /* 85 */ SyscallDesc("timerfd_create", unimplementedFunc), + /* 86 */ SyscallDesc("timerfd_settime", unimplementedFunc), + /* 87 */ SyscallDesc("timerfd_gettime", unimplementedFunc), + /* 88 */ SyscallDesc("utimensat", unimplementedFunc), + /* 89 */ SyscallDesc("acct", unimplementedFunc), + /* 90 */ SyscallDesc("capget", unimplementedFunc), + /* 91 */ SyscallDesc("capset", unimplementedFunc), + /* 92 */ SyscallDesc("personality", unimplementedFunc), + /* 93 */ SyscallDesc("exit", exitFunc), + /* 94 */ SyscallDesc("exit_group", exitGroupFunc), + /* 95 */ SyscallDesc("waitid", unimplementedFunc), + /* 96 */ SyscallDesc("set_tid_address", unimplementedFunc), + /* 97 */ SyscallDesc("unshare", unimplementedFunc), + /* 98 */ SyscallDesc("futex", unimplementedFunc), + /* 99 */ SyscallDesc("set_robust_list", unimplementedFunc), + /* 100 */ SyscallDesc("get_robust_list", unimplementedFunc), + /* 101 */ SyscallDesc("nanosleep", ignoreWarnOnceFunc), + /* 102 */ SyscallDesc("getitimer", unimplementedFunc), + /* 103 */ SyscallDesc("setitimer", unimplementedFunc), + /* 104 */ SyscallDesc("kexec_load", unimplementedFunc), + /* 105 */ SyscallDesc("init_module", unimplementedFunc), + /* 106 */ SyscallDesc("delete_module", unimplementedFunc), + /* 107 */ SyscallDesc("timer_create", unimplementedFunc), + /* 108 */ SyscallDesc("timer_gettime", unimplementedFunc), + /* 109 */ SyscallDesc("timer_getoverrun", unimplementedFunc), + /* 110 */ SyscallDesc("timer_settime", unimplementedFunc), + /* 111 */ SyscallDesc("timer_delete", unimplementedFunc), + /* 112 */ SyscallDesc("clock_settime", unimplementedFunc), + /* 113 */ SyscallDesc("clock_gettime", unimplementedFunc), + /* 114 */ SyscallDesc("clock_getres", unimplementedFunc), + /* 115 */ SyscallDesc("clock_nanosleep", unimplementedFunc), + /* 116 */ SyscallDesc("syslog", unimplementedFunc), + /* 117 */ SyscallDesc("ptrace", unimplementedFunc), + /* 118 */ SyscallDesc("sched_setparam", unimplementedFunc), + /* 119 */ SyscallDesc("sched_setscheduler", unimplementedFunc), + /* 120 */ SyscallDesc("sched_getscheduler", unimplementedFunc), + /* 121 */ SyscallDesc("sched_getparam", unimplementedFunc), + /* 122 */ SyscallDesc("sched_setaffinity", unimplementedFunc), + /* 123 */ SyscallDesc("sched_getaffinity", unimplementedFunc), + /* 124 */ SyscallDesc("sched_yield", unimplementedFunc), + /* 125 */ SyscallDesc("sched_get_priority_max", unimplementedFunc), + /* 126 */ SyscallDesc("sched_get_priority_min", unimplementedFunc), + /* 127 */ SyscallDesc("sched_rr_get_interval", unimplementedFunc), + /* 128 */ SyscallDesc("restart_syscall", unimplementedFunc), + /* 129 */ SyscallDesc("kill", ignoreFunc), + /* 130 */ SyscallDesc("tkill", unimplementedFunc), + /* 131 */ SyscallDesc("tgkill", unimplementedFunc), + /* 132 */ SyscallDesc("sigaltstack", unimplementedFunc), + /* 133 */ SyscallDesc("rt_sigsuspend", unimplementedFunc), + /* 134 */ SyscallDesc("rt_sigaction", ignoreFunc), + /* 135 */ SyscallDesc("rt_sigprocmask", ignoreWarnOnceFunc), + /* 136 */ SyscallDesc("rt_sigpending", unimplementedFunc), + /* 137 */ SyscallDesc("rt_sigtimedwait", unimplementedFunc), + /* 138 */ SyscallDesc("rt_sigqueueinfo", ignoreFunc), + /* 139 */ SyscallDesc("rt_sigreturn", unimplementedFunc), + /* 140 */ SyscallDesc("setpriority", unimplementedFunc), + /* 141 */ SyscallDesc("getpriority", unimplementedFunc), + /* 142 */ SyscallDesc("reboot", unimplementedFunc), + /* 143 */ SyscallDesc("setregid", unimplementedFunc), + /* 144 */ SyscallDesc("setgid", unimplementedFunc), + /* 145 */ SyscallDesc("setreuid", unimplementedFunc), + /* 146 */ SyscallDesc("setuid", unimplementedFunc), + /* 147 */ SyscallDesc("setresuid", unimplementedFunc), + /* 148 */ SyscallDesc("getresuid", unimplementedFunc), + /* 149 */ SyscallDesc("setresgid", unimplementedFunc), + /* 150 */ SyscallDesc("getresgid", unimplementedFunc), + /* 151 */ SyscallDesc("setfsuid", unimplementedFunc), + /* 152 */ SyscallDesc("setfsgid", unimplementedFunc), + /* 153 */ SyscallDesc("times", timesFunc<ArmLinux64>), + /* 154 */ SyscallDesc("setpgid", unimplementedFunc), + /* 155 */ SyscallDesc("getpgid", unimplementedFunc), + /* 156 */ SyscallDesc("getsid", unimplementedFunc), + /* 157 */ SyscallDesc("setsid", unimplementedFunc), + /* 158 */ SyscallDesc("getgroups", unimplementedFunc), + /* 159 */ SyscallDesc("setgroups", unimplementedFunc), + /* 160 */ SyscallDesc("uname", unameFunc64), + /* 161 */ SyscallDesc("sethostname", ignoreFunc), + /* 162 */ SyscallDesc("setdomainname", unimplementedFunc), + /* 163 */ SyscallDesc("getrlimit", getrlimitFunc<ArmLinux64>), + /* 164 */ SyscallDesc("setrlimit", ignoreFunc), + /* 165 */ SyscallDesc("getrusage", getrusageFunc<ArmLinux64>), + /* 166 */ SyscallDesc("umask", unimplementedFunc), + /* 167 */ SyscallDesc("prctl", unimplementedFunc), + /* 168 */ SyscallDesc("getcpu", unimplementedFunc), + /* 169 */ SyscallDesc("gettimeofday", gettimeofdayFunc<ArmLinux64>), + /* 170 */ SyscallDesc("settimeofday", unimplementedFunc), + /* 171 */ SyscallDesc("adjtimex", unimplementedFunc), + /* 172 */ SyscallDesc("getpid", getpidFunc), + /* 173 */ SyscallDesc("getppid", getppidFunc), + /* 174 */ SyscallDesc("getuid", getuidFunc), + /* 175 */ SyscallDesc("geteuid", geteuidFunc), + /* 176 */ SyscallDesc("getgid", getgidFunc), + /* 177 */ SyscallDesc("getegid", getegidFunc), + /* 178 */ SyscallDesc("gettid", unimplementedFunc), + /* 179 */ SyscallDesc("sysinfo", sysinfoFunc<ArmLinux64>), + /* 180 */ SyscallDesc("mq_open", unimplementedFunc), + /* 181 */ SyscallDesc("mq_unlink", unimplementedFunc), + /* 182 */ SyscallDesc("mq_timedsend", unimplementedFunc), + /* 183 */ SyscallDesc("mq_timedreceive", unimplementedFunc), + /* 184 */ SyscallDesc("mq_notify", unimplementedFunc), + /* 185 */ SyscallDesc("mq_getsetattr", unimplementedFunc), + /* 186 */ SyscallDesc("msgget", unimplementedFunc), + /* 187 */ SyscallDesc("msgctl", unimplementedFunc), + /* 188 */ SyscallDesc("msgrcv", unimplementedFunc), + /* 189 */ SyscallDesc("msgsnd", unimplementedFunc), + /* 190 */ SyscallDesc("semget", unimplementedFunc), + /* 191 */ SyscallDesc("semctl", unimplementedFunc), + /* 192 */ SyscallDesc("semtimedop", unimplementedFunc), + /* 193 */ SyscallDesc("semop", unimplementedFunc), + /* 194 */ SyscallDesc("shmget", unimplementedFunc), + /* 195 */ SyscallDesc("shmctl", unimplementedFunc), + /* 196 */ SyscallDesc("shmat", unimplementedFunc), + /* 197 */ SyscallDesc("shmdt", unimplementedFunc), + /* 198 */ SyscallDesc("socket", unimplementedFunc), + /* 199 */ SyscallDesc("socketpair", unimplementedFunc), + /* 200 */ SyscallDesc("bind", unimplementedFunc), + /* 201 */ SyscallDesc("listen", unimplementedFunc), + /* 202 */ SyscallDesc("accept", unimplementedFunc), + /* 203 */ SyscallDesc("connect", unimplementedFunc), + /* 204 */ SyscallDesc("getsockname", unimplementedFunc), + /* 205 */ SyscallDesc("getpeername", unimplementedFunc), + /* 206 */ SyscallDesc("sendto", unimplementedFunc), + /* 207 */ SyscallDesc("recvfrom", unimplementedFunc), + /* 208 */ SyscallDesc("setsockopt", unimplementedFunc), + /* 209 */ SyscallDesc("getsockopt", unimplementedFunc), + /* 210 */ SyscallDesc("shutdown", unimplementedFunc), + /* 211 */ SyscallDesc("sendmsg", unimplementedFunc), + /* 212 */ SyscallDesc("recvmsg", unimplementedFunc), + /* 213 */ SyscallDesc("readahead", unimplementedFunc), + /* 214 */ SyscallDesc("brk", brkFunc), + /* 215 */ SyscallDesc("munmap", munmapFunc), + /* 216 */ SyscallDesc("mremap", mremapFunc<ArmLinux64>), + /* 217 */ SyscallDesc("add_key", unimplementedFunc), + /* 218 */ SyscallDesc("request_key", unimplementedFunc), + /* 219 */ SyscallDesc("keyctl", unimplementedFunc), + /* 220 */ SyscallDesc("clone", unimplementedFunc), + /* 221 */ SyscallDesc("execve", unimplementedFunc), + /* 222 */ SyscallDesc("mmap2", mmapFunc<ArmLinux64>), + /* 223 */ SyscallDesc("fadvise64_64", unimplementedFunc), + /* 224 */ SyscallDesc("swapon", unimplementedFunc), + /* 225 */ SyscallDesc("swapoff", unimplementedFunc), + /* 226 */ SyscallDesc("mprotect", ignoreFunc), + /* 227 */ SyscallDesc("msync", unimplementedFunc), + /* 228 */ SyscallDesc("mlock", unimplementedFunc), + /* 229 */ SyscallDesc("munlock", unimplementedFunc), + /* 230 */ SyscallDesc("mlockall", unimplementedFunc), + /* 231 */ SyscallDesc("munlockall", unimplementedFunc), + /* 232 */ SyscallDesc("mincore", unimplementedFunc), + /* 233 */ SyscallDesc("madvise", unimplementedFunc), + /* 234 */ SyscallDesc("remap_file_pages", unimplementedFunc), + /* 235 */ SyscallDesc("mbind", unimplementedFunc), + /* 236 */ SyscallDesc("get_mempolicy", unimplementedFunc), + /* 237 */ SyscallDesc("set_mempolicy", unimplementedFunc), + /* 238 */ SyscallDesc("migrate_pages", unimplementedFunc), + /* 239 */ SyscallDesc("move_pages", unimplementedFunc), + /* 240 */ SyscallDesc("rt_tgsigqueueinfo", unimplementedFunc), + /* 241 */ SyscallDesc("perf_event_open", unimplementedFunc), + /* 242 */ SyscallDesc("accept4", unimplementedFunc), + /* 243 */ SyscallDesc("recvmmsg", unimplementedFunc), + /* 244 */ SyscallDesc("unused#244", unimplementedFunc), + /* 245 */ SyscallDesc("unused#245", unimplementedFunc), + /* 246 */ SyscallDesc("unused#246", unimplementedFunc), + /* 247 */ SyscallDesc("unused#247", unimplementedFunc), + /* 248 */ SyscallDesc("unused#248", unimplementedFunc), + /* 249 */ SyscallDesc("unused#249", unimplementedFunc), + /* 250 */ SyscallDesc("unused#250", unimplementedFunc), + /* 251 */ SyscallDesc("unused#251", unimplementedFunc), + /* 252 */ SyscallDesc("unused#252", unimplementedFunc), + /* 253 */ SyscallDesc("unused#253", unimplementedFunc), + /* 254 */ SyscallDesc("unused#254", unimplementedFunc), + /* 255 */ SyscallDesc("unused#255", unimplementedFunc), + /* 256 */ SyscallDesc("unused#256", unimplementedFunc), + /* 257 */ SyscallDesc("unused#257", unimplementedFunc), + /* 258 */ SyscallDesc("unused#258", unimplementedFunc), + /* 259 */ SyscallDesc("unused#259", unimplementedFunc), + /* 260 */ SyscallDesc("wait4", unimplementedFunc), + /* 261 */ SyscallDesc("prlimit64", unimplementedFunc), + /* 262 */ SyscallDesc("fanotify_init", unimplementedFunc), + /* 263 */ SyscallDesc("fanotify_mark", unimplementedFunc), + /* 264 */ SyscallDesc("name_to_handle_at", unimplementedFunc), + /* 265 */ SyscallDesc("open_by_handle_at", unimplementedFunc), + /* 266 */ SyscallDesc("clock_adjtime", unimplementedFunc), + /* 267 */ SyscallDesc("syncfs", unimplementedFunc), + /* 268 */ SyscallDesc("setns", unimplementedFunc), + /* 269 */ SyscallDesc("sendmmsg", unimplementedFunc), + /* 270 */ SyscallDesc("process_vm_readv", unimplementedFunc), + /* 271 */ SyscallDesc("process_vm_writev", unimplementedFunc), + /* 272 */ SyscallDesc("unused#272", unimplementedFunc), + /* 273 */ SyscallDesc("unused#273", unimplementedFunc), + /* 274 */ SyscallDesc("unused#274", unimplementedFunc), + /* 275 */ SyscallDesc("unused#275", unimplementedFunc), + /* 276 */ SyscallDesc("unused#276", unimplementedFunc), + /* 277 */ SyscallDesc("unused#277", unimplementedFunc), + /* 278 */ SyscallDesc("unused#278", unimplementedFunc), + /* 279 */ SyscallDesc("unused#279", unimplementedFunc), + /* 280 */ SyscallDesc("unused#280", unimplementedFunc), + /* 281 */ SyscallDesc("unused#281", unimplementedFunc), + /* 282 */ SyscallDesc("unused#282", unimplementedFunc), + /* 283 */ SyscallDesc("unused#283", unimplementedFunc), + /* 284 */ SyscallDesc("unused#284", unimplementedFunc), + /* 285 */ SyscallDesc("unused#285", unimplementedFunc), + /* 286 */ SyscallDesc("unused#286", unimplementedFunc), + /* 287 */ SyscallDesc("unused#287", unimplementedFunc), + /* 288 */ SyscallDesc("unused#288", unimplementedFunc), + /* 289 */ SyscallDesc("unused#289", unimplementedFunc), + /* 290 */ SyscallDesc("unused#290", unimplementedFunc), + /* 291 */ SyscallDesc("unused#291", unimplementedFunc), + /* 292 */ SyscallDesc("unused#292", unimplementedFunc), + /* 293 */ SyscallDesc("unused#293", unimplementedFunc), + /* 294 */ SyscallDesc("unused#294", unimplementedFunc), + /* 295 */ SyscallDesc("unused#295", unimplementedFunc), + /* 296 */ SyscallDesc("unused#296", unimplementedFunc), + /* 297 */ SyscallDesc("unused#297", unimplementedFunc), + /* 298 */ SyscallDesc("unused#298", unimplementedFunc), + /* 299 */ SyscallDesc("unused#299", unimplementedFunc), + /* 300 */ SyscallDesc("unused#300", unimplementedFunc), + /* 301 */ SyscallDesc("unused#301", unimplementedFunc), + /* 302 */ SyscallDesc("unused#302", unimplementedFunc), + /* 303 */ SyscallDesc("unused#303", unimplementedFunc), + /* 304 */ SyscallDesc("unused#304", unimplementedFunc), + /* 305 */ SyscallDesc("unused#305", unimplementedFunc), + /* 306 */ SyscallDesc("unused#306", unimplementedFunc), + /* 307 */ SyscallDesc("unused#307", unimplementedFunc), + /* 308 */ SyscallDesc("unused#308", unimplementedFunc), + /* 309 */ SyscallDesc("unused#309", unimplementedFunc), + /* 310 */ SyscallDesc("unused#310", unimplementedFunc), + /* 311 */ SyscallDesc("unused#311", unimplementedFunc), + /* 312 */ SyscallDesc("unused#312", unimplementedFunc), + /* 313 */ SyscallDesc("unused#313", unimplementedFunc), + /* 314 */ SyscallDesc("unused#314", unimplementedFunc), + /* 315 */ SyscallDesc("unused#315", unimplementedFunc), + /* 316 */ SyscallDesc("unused#316", unimplementedFunc), + /* 317 */ SyscallDesc("unused#317", unimplementedFunc), + /* 318 */ SyscallDesc("unused#318", unimplementedFunc), + /* 319 */ SyscallDesc("unused#319", unimplementedFunc), + /* 320 */ SyscallDesc("unused#320", unimplementedFunc), + /* 321 */ SyscallDesc("unused#321", unimplementedFunc), + /* 322 */ SyscallDesc("unused#322", unimplementedFunc), + /* 323 */ SyscallDesc("unused#323", unimplementedFunc), + /* 324 */ SyscallDesc("unused#324", unimplementedFunc), + /* 325 */ SyscallDesc("unused#325", unimplementedFunc), + /* 326 */ SyscallDesc("unused#326", unimplementedFunc), + /* 327 */ SyscallDesc("unused#327", unimplementedFunc), + /* 328 */ SyscallDesc("unused#328", unimplementedFunc), + /* 329 */ SyscallDesc("unused#329", unimplementedFunc), + /* 330 */ SyscallDesc("unused#330", unimplementedFunc), + /* 331 */ SyscallDesc("unused#331", unimplementedFunc), + /* 332 */ SyscallDesc("unused#332", unimplementedFunc), + /* 333 */ SyscallDesc("unused#333", unimplementedFunc), + /* 334 */ SyscallDesc("unused#334", unimplementedFunc), + /* 335 */ SyscallDesc("unused#335", unimplementedFunc), + /* 336 */ SyscallDesc("unused#336", unimplementedFunc), + /* 337 */ SyscallDesc("unused#337", unimplementedFunc), + /* 338 */ SyscallDesc("unused#338", unimplementedFunc), + /* 339 */ SyscallDesc("unused#339", unimplementedFunc), + /* 340 */ SyscallDesc("unused#340", unimplementedFunc), + /* 341 */ SyscallDesc("unused#341", unimplementedFunc), + /* 342 */ SyscallDesc("unused#342", unimplementedFunc), + /* 343 */ SyscallDesc("unused#343", unimplementedFunc), + /* 344 */ SyscallDesc("unused#344", unimplementedFunc), + /* 345 */ SyscallDesc("unused#345", unimplementedFunc), + /* 346 */ SyscallDesc("unused#346", unimplementedFunc), + /* 347 */ SyscallDesc("unused#347", unimplementedFunc), + /* 348 */ SyscallDesc("unused#348", unimplementedFunc), + /* 349 */ SyscallDesc("unused#349", unimplementedFunc), + /* 350 */ SyscallDesc("unused#350", unimplementedFunc), + /* 351 */ SyscallDesc("unused#351", unimplementedFunc), + /* 352 */ SyscallDesc("unused#352", unimplementedFunc), + /* 353 */ SyscallDesc("unused#353", unimplementedFunc), + /* 354 */ SyscallDesc("unused#354", unimplementedFunc), + /* 355 */ SyscallDesc("unused#355", unimplementedFunc), + /* 356 */ SyscallDesc("unused#356", unimplementedFunc), + /* 357 */ SyscallDesc("unused#357", unimplementedFunc), + /* 358 */ SyscallDesc("unused#358", unimplementedFunc), + /* 359 */ SyscallDesc("unused#359", unimplementedFunc), + /* 360 */ SyscallDesc("unused#360", unimplementedFunc), + /* 361 */ SyscallDesc("unused#361", unimplementedFunc), + /* 362 */ SyscallDesc("unused#362", unimplementedFunc), + /* 363 */ SyscallDesc("unused#363", unimplementedFunc), + /* 364 */ SyscallDesc("unused#364", unimplementedFunc), + /* 365 */ SyscallDesc("unused#365", unimplementedFunc), + /* 366 */ SyscallDesc("unused#366", unimplementedFunc), + /* 367 */ SyscallDesc("unused#367", unimplementedFunc), + /* 368 */ SyscallDesc("unused#368", unimplementedFunc), + /* 369 */ SyscallDesc("unused#369", unimplementedFunc), + /* 370 */ SyscallDesc("unused#370", unimplementedFunc), + /* 371 */ SyscallDesc("unused#371", unimplementedFunc), + /* 372 */ SyscallDesc("unused#372", unimplementedFunc), + /* 373 */ SyscallDesc("unused#373", unimplementedFunc), + /* 374 */ SyscallDesc("unused#374", unimplementedFunc), + /* 375 */ SyscallDesc("unused#375", unimplementedFunc), + /* 376 */ SyscallDesc("unused#376", unimplementedFunc), + /* 377 */ SyscallDesc("unused#377", unimplementedFunc), + /* 378 */ SyscallDesc("unused#378", unimplementedFunc), + /* 379 */ SyscallDesc("unused#379", unimplementedFunc), + /* 380 */ SyscallDesc("unused#380", unimplementedFunc), + /* 381 */ SyscallDesc("unused#381", unimplementedFunc), + /* 382 */ SyscallDesc("unused#382", unimplementedFunc), + /* 383 */ SyscallDesc("unused#383", unimplementedFunc), + /* 384 */ SyscallDesc("unused#384", unimplementedFunc), + /* 385 */ SyscallDesc("unused#385", unimplementedFunc), + /* 386 */ SyscallDesc("unused#386", unimplementedFunc), + /* 387 */ SyscallDesc("unused#387", unimplementedFunc), + /* 388 */ SyscallDesc("unused#388", unimplementedFunc), + /* 389 */ SyscallDesc("unused#389", unimplementedFunc), + /* 390 */ SyscallDesc("unused#390", unimplementedFunc), + /* 391 */ SyscallDesc("unused#391", unimplementedFunc), + /* 392 */ SyscallDesc("unused#392", unimplementedFunc), + /* 393 */ SyscallDesc("unused#393", unimplementedFunc), + /* 394 */ SyscallDesc("unused#394", unimplementedFunc), + /* 395 */ SyscallDesc("unused#395", unimplementedFunc), + /* 396 */ SyscallDesc("unused#396", unimplementedFunc), + /* 397 */ SyscallDesc("unused#397", unimplementedFunc), + /* 398 */ SyscallDesc("unused#398", unimplementedFunc), + /* 399 */ SyscallDesc("unused#399", unimplementedFunc), + /* 400 */ SyscallDesc("unused#400", unimplementedFunc), + /* 401 */ SyscallDesc("unused#401", unimplementedFunc), + /* 402 */ SyscallDesc("unused#402", unimplementedFunc), + /* 403 */ SyscallDesc("unused#403", unimplementedFunc), + /* 404 */ SyscallDesc("unused#404", unimplementedFunc), + /* 405 */ SyscallDesc("unused#405", unimplementedFunc), + /* 406 */ SyscallDesc("unused#406", unimplementedFunc), + /* 407 */ SyscallDesc("unused#407", unimplementedFunc), + /* 408 */ SyscallDesc("unused#408", unimplementedFunc), + /* 409 */ SyscallDesc("unused#409", unimplementedFunc), + /* 410 */ SyscallDesc("unused#410", unimplementedFunc), + /* 411 */ SyscallDesc("unused#411", unimplementedFunc), + /* 412 */ SyscallDesc("unused#412", unimplementedFunc), + /* 413 */ SyscallDesc("unused#413", unimplementedFunc), + /* 414 */ SyscallDesc("unused#414", unimplementedFunc), + /* 415 */ SyscallDesc("unused#415", unimplementedFunc), + /* 416 */ SyscallDesc("unused#416", unimplementedFunc), + /* 417 */ SyscallDesc("unused#417", unimplementedFunc), + /* 418 */ SyscallDesc("unused#418", unimplementedFunc), + /* 419 */ SyscallDesc("unused#419", unimplementedFunc), + /* 420 */ SyscallDesc("unused#420", unimplementedFunc), + /* 421 */ SyscallDesc("unused#421", unimplementedFunc), + /* 422 */ SyscallDesc("unused#422", unimplementedFunc), + /* 423 */ SyscallDesc("unused#423", unimplementedFunc), + /* 424 */ SyscallDesc("unused#424", unimplementedFunc), + /* 425 */ SyscallDesc("unused#425", unimplementedFunc), + /* 426 */ SyscallDesc("unused#426", unimplementedFunc), + /* 427 */ SyscallDesc("unused#427", unimplementedFunc), + /* 428 */ SyscallDesc("unused#428", unimplementedFunc), + /* 429 */ SyscallDesc("unused#429", unimplementedFunc), + /* 430 */ SyscallDesc("unused#430", unimplementedFunc), + /* 431 */ SyscallDesc("unused#431", unimplementedFunc), + /* 432 */ SyscallDesc("unused#432", unimplementedFunc), + /* 433 */ SyscallDesc("unused#433", unimplementedFunc), + /* 434 */ SyscallDesc("unused#434", unimplementedFunc), + /* 435 */ SyscallDesc("unused#435", unimplementedFunc), + /* 436 */ SyscallDesc("unused#436", unimplementedFunc), + /* 437 */ SyscallDesc("unused#437", unimplementedFunc), + /* 438 */ SyscallDesc("unused#438", unimplementedFunc), + /* 439 */ SyscallDesc("unused#439", unimplementedFunc), + /* 440 */ SyscallDesc("unused#440", unimplementedFunc), + /* 441 */ SyscallDesc("unused#441", unimplementedFunc), + /* 442 */ SyscallDesc("unused#442", unimplementedFunc), + /* 443 */ SyscallDesc("unused#443", unimplementedFunc), + /* 444 */ SyscallDesc("unused#444", unimplementedFunc), + /* 445 */ SyscallDesc("unused#445", unimplementedFunc), + /* 446 */ SyscallDesc("unused#446", unimplementedFunc), + /* 447 */ SyscallDesc("unused#447", unimplementedFunc), + /* 448 */ SyscallDesc("unused#448", unimplementedFunc), + /* 449 */ SyscallDesc("unused#449", unimplementedFunc), + /* 450 */ SyscallDesc("unused#450", unimplementedFunc), + /* 451 */ SyscallDesc("unused#451", unimplementedFunc), + /* 452 */ SyscallDesc("unused#452", unimplementedFunc), + /* 453 */ SyscallDesc("unused#453", unimplementedFunc), + /* 454 */ SyscallDesc("unused#454", unimplementedFunc), + /* 455 */ SyscallDesc("unused#455", unimplementedFunc), + /* 456 */ SyscallDesc("unused#456", unimplementedFunc), + /* 457 */ SyscallDesc("unused#457", unimplementedFunc), + /* 458 */ SyscallDesc("unused#458", unimplementedFunc), + /* 459 */ SyscallDesc("unused#459", unimplementedFunc), + /* 460 */ SyscallDesc("unused#460", unimplementedFunc), + /* 461 */ SyscallDesc("unused#461", unimplementedFunc), + /* 462 */ SyscallDesc("unused#462", unimplementedFunc), + /* 463 */ SyscallDesc("unused#463", unimplementedFunc), + /* 464 */ SyscallDesc("unused#464", unimplementedFunc), + /* 465 */ SyscallDesc("unused#465", unimplementedFunc), + /* 466 */ SyscallDesc("unused#466", unimplementedFunc), + /* 467 */ SyscallDesc("unused#467", unimplementedFunc), + /* 468 */ SyscallDesc("unused#468", unimplementedFunc), + /* 469 */ SyscallDesc("unused#469", unimplementedFunc), + /* 470 */ SyscallDesc("unused#470", unimplementedFunc), + /* 471 */ SyscallDesc("unused#471", unimplementedFunc), + /* 472 */ SyscallDesc("unused#472", unimplementedFunc), + /* 473 */ SyscallDesc("unused#473", unimplementedFunc), + /* 474 */ SyscallDesc("unused#474", unimplementedFunc), + /* 475 */ SyscallDesc("unused#475", unimplementedFunc), + /* 476 */ SyscallDesc("unused#476", unimplementedFunc), + /* 477 */ SyscallDesc("unused#477", unimplementedFunc), + /* 478 */ SyscallDesc("unused#478", unimplementedFunc), + /* 479 */ SyscallDesc("unused#479", unimplementedFunc), + /* 480 */ SyscallDesc("unused#480", unimplementedFunc), + /* 481 */ SyscallDesc("unused#481", unimplementedFunc), + /* 482 */ SyscallDesc("unused#482", unimplementedFunc), + /* 483 */ SyscallDesc("unused#483", unimplementedFunc), + /* 484 */ SyscallDesc("unused#484", unimplementedFunc), + /* 485 */ SyscallDesc("unused#485", unimplementedFunc), + /* 486 */ SyscallDesc("unused#486", unimplementedFunc), + /* 487 */ SyscallDesc("unused#487", unimplementedFunc), + /* 488 */ SyscallDesc("unused#488", unimplementedFunc), + /* 489 */ SyscallDesc("unused#489", unimplementedFunc), + /* 490 */ SyscallDesc("unused#490", unimplementedFunc), + /* 491 */ SyscallDesc("unused#491", unimplementedFunc), + /* 492 */ SyscallDesc("unused#492", unimplementedFunc), + /* 493 */ SyscallDesc("unused#493", unimplementedFunc), + /* 494 */ SyscallDesc("unused#494", unimplementedFunc), + /* 495 */ SyscallDesc("unused#495", unimplementedFunc), + /* 496 */ SyscallDesc("unused#496", unimplementedFunc), + /* 497 */ SyscallDesc("unused#497", unimplementedFunc), + /* 498 */ SyscallDesc("unused#498", unimplementedFunc), + /* 499 */ SyscallDesc("unused#499", unimplementedFunc), + /* 500 */ SyscallDesc("unused#500", unimplementedFunc), + /* 501 */ SyscallDesc("unused#501", unimplementedFunc), + /* 502 */ SyscallDesc("unused#502", unimplementedFunc), + /* 503 */ SyscallDesc("unused#503", unimplementedFunc), + /* 504 */ SyscallDesc("unused#504", unimplementedFunc), + /* 505 */ SyscallDesc("unused#505", unimplementedFunc), + /* 506 */ SyscallDesc("unused#506", unimplementedFunc), + /* 507 */ SyscallDesc("unused#507", unimplementedFunc), + /* 508 */ SyscallDesc("unused#508", unimplementedFunc), + /* 509 */ SyscallDesc("unused#509", unimplementedFunc), + /* 510 */ SyscallDesc("unused#510", unimplementedFunc), + /* 511 */ SyscallDesc("unused#511", unimplementedFunc), + /* 512 */ SyscallDesc("unused#512", unimplementedFunc), + /* 513 */ SyscallDesc("unused#513", unimplementedFunc), + /* 514 */ SyscallDesc("unused#514", unimplementedFunc), + /* 515 */ SyscallDesc("unused#515", unimplementedFunc), + /* 516 */ SyscallDesc("unused#516", unimplementedFunc), + /* 517 */ SyscallDesc("unused#517", unimplementedFunc), + /* 518 */ SyscallDesc("unused#518", unimplementedFunc), + /* 519 */ SyscallDesc("unused#519", unimplementedFunc), + /* 520 */ SyscallDesc("unused#520", unimplementedFunc), + /* 521 */ SyscallDesc("unused#521", unimplementedFunc), + /* 522 */ SyscallDesc("unused#522", unimplementedFunc), + /* 523 */ SyscallDesc("unused#523", unimplementedFunc), + /* 524 */ SyscallDesc("unused#524", unimplementedFunc), + /* 525 */ SyscallDesc("unused#525", unimplementedFunc), + /* 526 */ SyscallDesc("unused#526", unimplementedFunc), + /* 527 */ SyscallDesc("unused#527", unimplementedFunc), + /* 528 */ SyscallDesc("unused#528", unimplementedFunc), + /* 529 */ SyscallDesc("unused#529", unimplementedFunc), + /* 530 */ SyscallDesc("unused#530", unimplementedFunc), + /* 531 */ SyscallDesc("unused#531", unimplementedFunc), + /* 532 */ SyscallDesc("unused#532", unimplementedFunc), + /* 533 */ SyscallDesc("unused#533", unimplementedFunc), + /* 534 */ SyscallDesc("unused#534", unimplementedFunc), + /* 535 */ SyscallDesc("unused#535", unimplementedFunc), + /* 536 */ SyscallDesc("unused#536", unimplementedFunc), + /* 537 */ SyscallDesc("unused#537", unimplementedFunc), + /* 538 */ SyscallDesc("unused#538", unimplementedFunc), + /* 539 */ SyscallDesc("unused#539", unimplementedFunc), + /* 540 */ SyscallDesc("unused#540", unimplementedFunc), + /* 541 */ SyscallDesc("unused#541", unimplementedFunc), + /* 542 */ SyscallDesc("unused#542", unimplementedFunc), + /* 543 */ SyscallDesc("unused#543", unimplementedFunc), + /* 544 */ SyscallDesc("unused#544", unimplementedFunc), + /* 545 */ SyscallDesc("unused#545", unimplementedFunc), + /* 546 */ SyscallDesc("unused#546", unimplementedFunc), + /* 547 */ SyscallDesc("unused#547", unimplementedFunc), + /* 548 */ SyscallDesc("unused#548", unimplementedFunc), + /* 549 */ SyscallDesc("unused#549", unimplementedFunc), + /* 550 */ SyscallDesc("unused#550", unimplementedFunc), + /* 551 */ SyscallDesc("unused#551", unimplementedFunc), + /* 552 */ SyscallDesc("unused#552", unimplementedFunc), + /* 553 */ SyscallDesc("unused#553", unimplementedFunc), + /* 554 */ SyscallDesc("unused#554", unimplementedFunc), + /* 555 */ SyscallDesc("unused#555", unimplementedFunc), + /* 556 */ SyscallDesc("unused#556", unimplementedFunc), + /* 557 */ SyscallDesc("unused#557", unimplementedFunc), + /* 558 */ SyscallDesc("unused#558", unimplementedFunc), + /* 559 */ SyscallDesc("unused#559", unimplementedFunc), + /* 560 */ SyscallDesc("unused#560", unimplementedFunc), + /* 561 */ SyscallDesc("unused#561", unimplementedFunc), + /* 562 */ SyscallDesc("unused#562", unimplementedFunc), + /* 563 */ SyscallDesc("unused#563", unimplementedFunc), + /* 564 */ SyscallDesc("unused#564", unimplementedFunc), + /* 565 */ SyscallDesc("unused#565", unimplementedFunc), + /* 566 */ SyscallDesc("unused#566", unimplementedFunc), + /* 567 */ SyscallDesc("unused#567", unimplementedFunc), + /* 568 */ SyscallDesc("unused#568", unimplementedFunc), + /* 569 */ SyscallDesc("unused#569", unimplementedFunc), + /* 570 */ SyscallDesc("unused#570", unimplementedFunc), + /* 571 */ SyscallDesc("unused#571", unimplementedFunc), + /* 572 */ SyscallDesc("unused#572", unimplementedFunc), + /* 573 */ SyscallDesc("unused#573", unimplementedFunc), + /* 574 */ SyscallDesc("unused#574", unimplementedFunc), + /* 575 */ SyscallDesc("unused#575", unimplementedFunc), + /* 576 */ SyscallDesc("unused#576", unimplementedFunc), + /* 577 */ SyscallDesc("unused#577", unimplementedFunc), + /* 578 */ SyscallDesc("unused#578", unimplementedFunc), + /* 579 */ SyscallDesc("unused#579", unimplementedFunc), + /* 580 */ SyscallDesc("unused#580", unimplementedFunc), + /* 581 */ SyscallDesc("unused#581", unimplementedFunc), + /* 582 */ SyscallDesc("unused#582", unimplementedFunc), + /* 583 */ SyscallDesc("unused#583", unimplementedFunc), + /* 584 */ SyscallDesc("unused#584", unimplementedFunc), + /* 585 */ SyscallDesc("unused#585", unimplementedFunc), + /* 586 */ SyscallDesc("unused#586", unimplementedFunc), + /* 587 */ SyscallDesc("unused#587", unimplementedFunc), + /* 588 */ SyscallDesc("unused#588", unimplementedFunc), + /* 589 */ SyscallDesc("unused#589", unimplementedFunc), + /* 590 */ SyscallDesc("unused#590", unimplementedFunc), + /* 591 */ SyscallDesc("unused#591", unimplementedFunc), + /* 592 */ SyscallDesc("unused#592", unimplementedFunc), + /* 593 */ SyscallDesc("unused#593", unimplementedFunc), + /* 594 */ SyscallDesc("unused#594", unimplementedFunc), + /* 595 */ SyscallDesc("unused#595", unimplementedFunc), + /* 596 */ SyscallDesc("unused#596", unimplementedFunc), + /* 597 */ SyscallDesc("unused#597", unimplementedFunc), + /* 598 */ SyscallDesc("unused#598", unimplementedFunc), + /* 599 */ SyscallDesc("unused#599", unimplementedFunc), + /* 600 */ SyscallDesc("unused#600", unimplementedFunc), + /* 601 */ SyscallDesc("unused#601", unimplementedFunc), + /* 602 */ SyscallDesc("unused#602", unimplementedFunc), + /* 603 */ SyscallDesc("unused#603", unimplementedFunc), + /* 604 */ SyscallDesc("unused#604", unimplementedFunc), + /* 605 */ SyscallDesc("unused#605", unimplementedFunc), + /* 606 */ SyscallDesc("unused#606", unimplementedFunc), + /* 607 */ SyscallDesc("unused#607", unimplementedFunc), + /* 608 */ SyscallDesc("unused#608", unimplementedFunc), + /* 609 */ SyscallDesc("unused#609", unimplementedFunc), + /* 610 */ SyscallDesc("unused#610", unimplementedFunc), + /* 611 */ SyscallDesc("unused#611", unimplementedFunc), + /* 612 */ SyscallDesc("unused#612", unimplementedFunc), + /* 613 */ SyscallDesc("unused#613", unimplementedFunc), + /* 614 */ SyscallDesc("unused#614", unimplementedFunc), + /* 615 */ SyscallDesc("unused#615", unimplementedFunc), + /* 616 */ SyscallDesc("unused#616", unimplementedFunc), + /* 617 */ SyscallDesc("unused#617", unimplementedFunc), + /* 618 */ SyscallDesc("unused#618", unimplementedFunc), + /* 619 */ SyscallDesc("unused#619", unimplementedFunc), + /* 620 */ SyscallDesc("unused#620", unimplementedFunc), + /* 621 */ SyscallDesc("unused#621", unimplementedFunc), + /* 622 */ SyscallDesc("unused#622", unimplementedFunc), + /* 623 */ SyscallDesc("unused#623", unimplementedFunc), + /* 624 */ SyscallDesc("unused#624", unimplementedFunc), + /* 625 */ SyscallDesc("unused#625", unimplementedFunc), + /* 626 */ SyscallDesc("unused#626", unimplementedFunc), + /* 627 */ SyscallDesc("unused#627", unimplementedFunc), + /* 628 */ SyscallDesc("unused#628", unimplementedFunc), + /* 629 */ SyscallDesc("unused#629", unimplementedFunc), + /* 630 */ SyscallDesc("unused#630", unimplementedFunc), + /* 631 */ SyscallDesc("unused#631", unimplementedFunc), + /* 632 */ SyscallDesc("unused#632", unimplementedFunc), + /* 633 */ SyscallDesc("unused#633", unimplementedFunc), + /* 634 */ SyscallDesc("unused#634", unimplementedFunc), + /* 635 */ SyscallDesc("unused#635", unimplementedFunc), + /* 636 */ SyscallDesc("unused#636", unimplementedFunc), + /* 637 */ SyscallDesc("unused#637", unimplementedFunc), + /* 638 */ SyscallDesc("unused#638", unimplementedFunc), + /* 639 */ SyscallDesc("unused#639", unimplementedFunc), + /* 640 */ SyscallDesc("unused#640", unimplementedFunc), + /* 641 */ SyscallDesc("unused#641", unimplementedFunc), + /* 642 */ SyscallDesc("unused#642", unimplementedFunc), + /* 643 */ SyscallDesc("unused#643", unimplementedFunc), + /* 644 */ SyscallDesc("unused#644", unimplementedFunc), + /* 645 */ SyscallDesc("unused#645", unimplementedFunc), + /* 646 */ SyscallDesc("unused#646", unimplementedFunc), + /* 647 */ SyscallDesc("unused#647", unimplementedFunc), + /* 648 */ SyscallDesc("unused#648", unimplementedFunc), + /* 649 */ SyscallDesc("unused#649", unimplementedFunc), + /* 650 */ SyscallDesc("unused#650", unimplementedFunc), + /* 651 */ SyscallDesc("unused#651", unimplementedFunc), + /* 652 */ SyscallDesc("unused#652", unimplementedFunc), + /* 653 */ SyscallDesc("unused#653", unimplementedFunc), + /* 654 */ SyscallDesc("unused#654", unimplementedFunc), + /* 655 */ SyscallDesc("unused#655", unimplementedFunc), + /* 656 */ SyscallDesc("unused#656", unimplementedFunc), + /* 657 */ SyscallDesc("unused#657", unimplementedFunc), + /* 658 */ SyscallDesc("unused#658", unimplementedFunc), + /* 659 */ SyscallDesc("unused#659", unimplementedFunc), + /* 660 */ SyscallDesc("unused#660", unimplementedFunc), + /* 661 */ SyscallDesc("unused#661", unimplementedFunc), + /* 662 */ SyscallDesc("unused#662", unimplementedFunc), + /* 663 */ SyscallDesc("unused#663", unimplementedFunc), + /* 664 */ SyscallDesc("unused#664", unimplementedFunc), + /* 665 */ SyscallDesc("unused#665", unimplementedFunc), + /* 666 */ SyscallDesc("unused#666", unimplementedFunc), + /* 667 */ SyscallDesc("unused#667", unimplementedFunc), + /* 668 */ SyscallDesc("unused#668", unimplementedFunc), + /* 669 */ SyscallDesc("unused#669", unimplementedFunc), + /* 670 */ SyscallDesc("unused#670", unimplementedFunc), + /* 671 */ SyscallDesc("unused#671", unimplementedFunc), + /* 672 */ SyscallDesc("unused#672", unimplementedFunc), + /* 673 */ SyscallDesc("unused#673", unimplementedFunc), + /* 674 */ SyscallDesc("unused#674", unimplementedFunc), + /* 675 */ SyscallDesc("unused#675", unimplementedFunc), + /* 676 */ SyscallDesc("unused#676", unimplementedFunc), + /* 677 */ SyscallDesc("unused#677", unimplementedFunc), + /* 678 */ SyscallDesc("unused#678", unimplementedFunc), + /* 679 */ SyscallDesc("unused#679", unimplementedFunc), + /* 680 */ SyscallDesc("unused#680", unimplementedFunc), + /* 681 */ SyscallDesc("unused#681", unimplementedFunc), + /* 682 */ SyscallDesc("unused#682", unimplementedFunc), + /* 683 */ SyscallDesc("unused#683", unimplementedFunc), + /* 684 */ SyscallDesc("unused#684", unimplementedFunc), + /* 685 */ SyscallDesc("unused#685", unimplementedFunc), + /* 686 */ SyscallDesc("unused#686", unimplementedFunc), + /* 687 */ SyscallDesc("unused#687", unimplementedFunc), + /* 688 */ SyscallDesc("unused#688", unimplementedFunc), + /* 689 */ SyscallDesc("unused#689", unimplementedFunc), + /* 690 */ SyscallDesc("unused#690", unimplementedFunc), + /* 691 */ SyscallDesc("unused#691", unimplementedFunc), + /* 692 */ SyscallDesc("unused#692", unimplementedFunc), + /* 693 */ SyscallDesc("unused#693", unimplementedFunc), + /* 694 */ SyscallDesc("unused#694", unimplementedFunc), + /* 695 */ SyscallDesc("unused#695", unimplementedFunc), + /* 696 */ SyscallDesc("unused#696", unimplementedFunc), + /* 697 */ SyscallDesc("unused#697", unimplementedFunc), + /* 698 */ SyscallDesc("unused#698", unimplementedFunc), + /* 699 */ SyscallDesc("unused#699", unimplementedFunc), + /* 700 */ SyscallDesc("unused#700", unimplementedFunc), + /* 701 */ SyscallDesc("unused#701", unimplementedFunc), + /* 702 */ SyscallDesc("unused#702", unimplementedFunc), + /* 703 */ SyscallDesc("unused#703", unimplementedFunc), + /* 704 */ SyscallDesc("unused#704", unimplementedFunc), + /* 705 */ SyscallDesc("unused#705", unimplementedFunc), + /* 706 */ SyscallDesc("unused#706", unimplementedFunc), + /* 707 */ SyscallDesc("unused#707", unimplementedFunc), + /* 708 */ SyscallDesc("unused#708", unimplementedFunc), + /* 709 */ SyscallDesc("unused#709", unimplementedFunc), + /* 710 */ SyscallDesc("unused#710", unimplementedFunc), + /* 711 */ SyscallDesc("unused#711", unimplementedFunc), + /* 712 */ SyscallDesc("unused#712", unimplementedFunc), + /* 713 */ SyscallDesc("unused#713", unimplementedFunc), + /* 714 */ SyscallDesc("unused#714", unimplementedFunc), + /* 715 */ SyscallDesc("unused#715", unimplementedFunc), + /* 716 */ SyscallDesc("unused#716", unimplementedFunc), + /* 717 */ SyscallDesc("unused#717", unimplementedFunc), + /* 718 */ SyscallDesc("unused#718", unimplementedFunc), + /* 719 */ SyscallDesc("unused#719", unimplementedFunc), + /* 720 */ SyscallDesc("unused#720", unimplementedFunc), + /* 721 */ SyscallDesc("unused#721", unimplementedFunc), + /* 722 */ SyscallDesc("unused#722", unimplementedFunc), + /* 723 */ SyscallDesc("unused#723", unimplementedFunc), + /* 724 */ SyscallDesc("unused#724", unimplementedFunc), + /* 725 */ SyscallDesc("unused#725", unimplementedFunc), + /* 726 */ SyscallDesc("unused#726", unimplementedFunc), + /* 727 */ SyscallDesc("unused#727", unimplementedFunc), + /* 728 */ SyscallDesc("unused#728", unimplementedFunc), + /* 729 */ SyscallDesc("unused#729", unimplementedFunc), + /* 730 */ SyscallDesc("unused#730", unimplementedFunc), + /* 731 */ SyscallDesc("unused#731", unimplementedFunc), + /* 732 */ SyscallDesc("unused#732", unimplementedFunc), + /* 733 */ SyscallDesc("unused#733", unimplementedFunc), + /* 734 */ SyscallDesc("unused#734", unimplementedFunc), + /* 735 */ SyscallDesc("unused#735", unimplementedFunc), + /* 736 */ SyscallDesc("unused#736", unimplementedFunc), + /* 737 */ SyscallDesc("unused#737", unimplementedFunc), + /* 738 */ SyscallDesc("unused#738", unimplementedFunc), + /* 739 */ SyscallDesc("unused#739", unimplementedFunc), + /* 740 */ SyscallDesc("unused#740", unimplementedFunc), + /* 741 */ SyscallDesc("unused#741", unimplementedFunc), + /* 742 */ SyscallDesc("unused#742", unimplementedFunc), + /* 743 */ SyscallDesc("unused#743", unimplementedFunc), + /* 744 */ SyscallDesc("unused#744", unimplementedFunc), + /* 745 */ SyscallDesc("unused#745", unimplementedFunc), + /* 746 */ SyscallDesc("unused#746", unimplementedFunc), + /* 747 */ SyscallDesc("unused#747", unimplementedFunc), + /* 748 */ SyscallDesc("unused#748", unimplementedFunc), + /* 749 */ SyscallDesc("unused#749", unimplementedFunc), + /* 750 */ SyscallDesc("unused#750", unimplementedFunc), + /* 751 */ SyscallDesc("unused#751", unimplementedFunc), + /* 752 */ SyscallDesc("unused#752", unimplementedFunc), + /* 753 */ SyscallDesc("unused#753", unimplementedFunc), + /* 754 */ SyscallDesc("unused#754", unimplementedFunc), + /* 755 */ SyscallDesc("unused#755", unimplementedFunc), + /* 756 */ SyscallDesc("unused#756", unimplementedFunc), + /* 757 */ SyscallDesc("unused#757", unimplementedFunc), + /* 758 */ SyscallDesc("unused#758", unimplementedFunc), + /* 759 */ SyscallDesc("unused#759", unimplementedFunc), + /* 760 */ SyscallDesc("unused#760", unimplementedFunc), + /* 761 */ SyscallDesc("unused#761", unimplementedFunc), + /* 762 */ SyscallDesc("unused#762", unimplementedFunc), + /* 763 */ SyscallDesc("unused#763", unimplementedFunc), + /* 764 */ SyscallDesc("unused#764", unimplementedFunc), + /* 765 */ SyscallDesc("unused#765", unimplementedFunc), + /* 766 */ SyscallDesc("unused#766", unimplementedFunc), + /* 767 */ SyscallDesc("unused#767", unimplementedFunc), + /* 768 */ SyscallDesc("unused#768", unimplementedFunc), + /* 769 */ SyscallDesc("unused#769", unimplementedFunc), + /* 770 */ SyscallDesc("unused#770", unimplementedFunc), + /* 771 */ SyscallDesc("unused#771", unimplementedFunc), + /* 772 */ SyscallDesc("unused#772", unimplementedFunc), + /* 773 */ SyscallDesc("unused#773", unimplementedFunc), + /* 774 */ SyscallDesc("unused#774", unimplementedFunc), + /* 775 */ SyscallDesc("unused#775", unimplementedFunc), + /* 776 */ SyscallDesc("unused#776", unimplementedFunc), + /* 777 */ SyscallDesc("unused#777", unimplementedFunc), + /* 778 */ SyscallDesc("unused#778", unimplementedFunc), + /* 779 */ SyscallDesc("unused#779", unimplementedFunc), + /* 780 */ SyscallDesc("unused#780", unimplementedFunc), + /* 781 */ SyscallDesc("unused#781", unimplementedFunc), + /* 782 */ SyscallDesc("unused#782", unimplementedFunc), + /* 783 */ SyscallDesc("unused#783", unimplementedFunc), + /* 784 */ SyscallDesc("unused#784", unimplementedFunc), + /* 785 */ SyscallDesc("unused#785", unimplementedFunc), + /* 786 */ SyscallDesc("unused#786", unimplementedFunc), + /* 787 */ SyscallDesc("unused#787", unimplementedFunc), + /* 788 */ SyscallDesc("unused#788", unimplementedFunc), + /* 789 */ SyscallDesc("unused#789", unimplementedFunc), + /* 790 */ SyscallDesc("unused#790", unimplementedFunc), + /* 791 */ SyscallDesc("unused#791", unimplementedFunc), + /* 792 */ SyscallDesc("unused#792", unimplementedFunc), + /* 793 */ SyscallDesc("unused#793", unimplementedFunc), + /* 794 */ SyscallDesc("unused#794", unimplementedFunc), + /* 795 */ SyscallDesc("unused#795", unimplementedFunc), + /* 796 */ SyscallDesc("unused#796", unimplementedFunc), + /* 797 */ SyscallDesc("unused#797", unimplementedFunc), + /* 798 */ SyscallDesc("unused#798", unimplementedFunc), + /* 799 */ SyscallDesc("unused#799", unimplementedFunc), + /* 800 */ SyscallDesc("unused#800", unimplementedFunc), + /* 801 */ SyscallDesc("unused#801", unimplementedFunc), + /* 802 */ SyscallDesc("unused#802", unimplementedFunc), + /* 803 */ SyscallDesc("unused#803", unimplementedFunc), + /* 804 */ SyscallDesc("unused#804", unimplementedFunc), + /* 805 */ SyscallDesc("unused#805", unimplementedFunc), + /* 806 */ SyscallDesc("unused#806", unimplementedFunc), + /* 807 */ SyscallDesc("unused#807", unimplementedFunc), + /* 808 */ SyscallDesc("unused#808", unimplementedFunc), + /* 809 */ SyscallDesc("unused#809", unimplementedFunc), + /* 810 */ SyscallDesc("unused#810", unimplementedFunc), + /* 811 */ SyscallDesc("unused#811", unimplementedFunc), + /* 812 */ SyscallDesc("unused#812", unimplementedFunc), + /* 813 */ SyscallDesc("unused#813", unimplementedFunc), + /* 814 */ SyscallDesc("unused#814", unimplementedFunc), + /* 815 */ SyscallDesc("unused#815", unimplementedFunc), + /* 816 */ SyscallDesc("unused#816", unimplementedFunc), + /* 817 */ SyscallDesc("unused#817", unimplementedFunc), + /* 818 */ SyscallDesc("unused#818", unimplementedFunc), + /* 819 */ SyscallDesc("unused#819", unimplementedFunc), + /* 820 */ SyscallDesc("unused#820", unimplementedFunc), + /* 821 */ SyscallDesc("unused#821", unimplementedFunc), + /* 822 */ SyscallDesc("unused#822", unimplementedFunc), + /* 823 */ SyscallDesc("unused#823", unimplementedFunc), + /* 824 */ SyscallDesc("unused#824", unimplementedFunc), + /* 825 */ SyscallDesc("unused#825", unimplementedFunc), + /* 826 */ SyscallDesc("unused#826", unimplementedFunc), + /* 827 */ SyscallDesc("unused#827", unimplementedFunc), + /* 828 */ SyscallDesc("unused#828", unimplementedFunc), + /* 829 */ SyscallDesc("unused#829", unimplementedFunc), + /* 830 */ SyscallDesc("unused#830", unimplementedFunc), + /* 831 */ SyscallDesc("unused#831", unimplementedFunc), + /* 832 */ SyscallDesc("unused#832", unimplementedFunc), + /* 833 */ SyscallDesc("unused#833", unimplementedFunc), + /* 834 */ SyscallDesc("unused#834", unimplementedFunc), + /* 835 */ SyscallDesc("unused#835", unimplementedFunc), + /* 836 */ SyscallDesc("unused#836", unimplementedFunc), + /* 837 */ SyscallDesc("unused#837", unimplementedFunc), + /* 838 */ SyscallDesc("unused#838", unimplementedFunc), + /* 839 */ SyscallDesc("unused#839", unimplementedFunc), + /* 840 */ SyscallDesc("unused#840", unimplementedFunc), + /* 841 */ SyscallDesc("unused#841", unimplementedFunc), + /* 842 */ SyscallDesc("unused#842", unimplementedFunc), + /* 843 */ SyscallDesc("unused#843", unimplementedFunc), + /* 844 */ SyscallDesc("unused#844", unimplementedFunc), + /* 845 */ SyscallDesc("unused#845", unimplementedFunc), + /* 846 */ SyscallDesc("unused#846", unimplementedFunc), + /* 847 */ SyscallDesc("unused#847", unimplementedFunc), + /* 848 */ SyscallDesc("unused#848", unimplementedFunc), + /* 849 */ SyscallDesc("unused#849", unimplementedFunc), + /* 850 */ SyscallDesc("unused#850", unimplementedFunc), + /* 851 */ SyscallDesc("unused#851", unimplementedFunc), + /* 852 */ SyscallDesc("unused#852", unimplementedFunc), + /* 853 */ SyscallDesc("unused#853", unimplementedFunc), + /* 854 */ SyscallDesc("unused#854", unimplementedFunc), + /* 855 */ SyscallDesc("unused#855", unimplementedFunc), + /* 856 */ SyscallDesc("unused#856", unimplementedFunc), + /* 857 */ SyscallDesc("unused#857", unimplementedFunc), + /* 858 */ SyscallDesc("unused#858", unimplementedFunc), + /* 859 */ SyscallDesc("unused#859", unimplementedFunc), + /* 860 */ SyscallDesc("unused#860", unimplementedFunc), + /* 861 */ SyscallDesc("unused#861", unimplementedFunc), + /* 862 */ SyscallDesc("unused#862", unimplementedFunc), + /* 863 */ SyscallDesc("unused#863", unimplementedFunc), + /* 864 */ SyscallDesc("unused#864", unimplementedFunc), + /* 865 */ SyscallDesc("unused#865", unimplementedFunc), + /* 866 */ SyscallDesc("unused#866", unimplementedFunc), + /* 867 */ SyscallDesc("unused#867", unimplementedFunc), + /* 868 */ SyscallDesc("unused#868", unimplementedFunc), + /* 869 */ SyscallDesc("unused#869", unimplementedFunc), + /* 870 */ SyscallDesc("unused#870", unimplementedFunc), + /* 871 */ SyscallDesc("unused#871", unimplementedFunc), + /* 872 */ SyscallDesc("unused#872", unimplementedFunc), + /* 873 */ SyscallDesc("unused#873", unimplementedFunc), + /* 874 */ SyscallDesc("unused#874", unimplementedFunc), + /* 875 */ SyscallDesc("unused#875", unimplementedFunc), + /* 876 */ SyscallDesc("unused#876", unimplementedFunc), + /* 877 */ SyscallDesc("unused#877", unimplementedFunc), + /* 878 */ SyscallDesc("unused#878", unimplementedFunc), + /* 879 */ SyscallDesc("unused#879", unimplementedFunc), + /* 880 */ SyscallDesc("unused#880", unimplementedFunc), + /* 881 */ SyscallDesc("unused#881", unimplementedFunc), + /* 882 */ SyscallDesc("unused#882", unimplementedFunc), + /* 883 */ SyscallDesc("unused#883", unimplementedFunc), + /* 884 */ SyscallDesc("unused#884", unimplementedFunc), + /* 885 */ SyscallDesc("unused#885", unimplementedFunc), + /* 886 */ SyscallDesc("unused#886", unimplementedFunc), + /* 887 */ SyscallDesc("unused#887", unimplementedFunc), + /* 888 */ SyscallDesc("unused#888", unimplementedFunc), + /* 889 */ SyscallDesc("unused#889", unimplementedFunc), + /* 890 */ SyscallDesc("unused#890", unimplementedFunc), + /* 891 */ SyscallDesc("unused#891", unimplementedFunc), + /* 892 */ SyscallDesc("unused#892", unimplementedFunc), + /* 893 */ SyscallDesc("unused#893", unimplementedFunc), + /* 894 */ SyscallDesc("unused#894", unimplementedFunc), + /* 895 */ SyscallDesc("unused#895", unimplementedFunc), + /* 896 */ SyscallDesc("unused#896", unimplementedFunc), + /* 897 */ SyscallDesc("unused#897", unimplementedFunc), + /* 898 */ SyscallDesc("unused#898", unimplementedFunc), + /* 899 */ SyscallDesc("unused#899", unimplementedFunc), + /* 900 */ SyscallDesc("unused#900", unimplementedFunc), + /* 901 */ SyscallDesc("unused#901", unimplementedFunc), + /* 902 */ SyscallDesc("unused#902", unimplementedFunc), + /* 903 */ SyscallDesc("unused#903", unimplementedFunc), + /* 904 */ SyscallDesc("unused#904", unimplementedFunc), + /* 905 */ SyscallDesc("unused#905", unimplementedFunc), + /* 906 */ SyscallDesc("unused#906", unimplementedFunc), + /* 907 */ SyscallDesc("unused#907", unimplementedFunc), + /* 908 */ SyscallDesc("unused#908", unimplementedFunc), + /* 909 */ SyscallDesc("unused#909", unimplementedFunc), + /* 910 */ SyscallDesc("unused#910", unimplementedFunc), + /* 911 */ SyscallDesc("unused#911", unimplementedFunc), + /* 912 */ SyscallDesc("unused#912", unimplementedFunc), + /* 913 */ SyscallDesc("unused#913", unimplementedFunc), + /* 914 */ SyscallDesc("unused#914", unimplementedFunc), + /* 915 */ SyscallDesc("unused#915", unimplementedFunc), + /* 916 */ SyscallDesc("unused#916", unimplementedFunc), + /* 917 */ SyscallDesc("unused#917", unimplementedFunc), + /* 918 */ SyscallDesc("unused#918", unimplementedFunc), + /* 919 */ SyscallDesc("unused#919", unimplementedFunc), + /* 920 */ SyscallDesc("unused#920", unimplementedFunc), + /* 921 */ SyscallDesc("unused#921", unimplementedFunc), + /* 922 */ SyscallDesc("unused#922", unimplementedFunc), + /* 923 */ SyscallDesc("unused#923", unimplementedFunc), + /* 924 */ SyscallDesc("unused#924", unimplementedFunc), + /* 925 */ SyscallDesc("unused#925", unimplementedFunc), + /* 926 */ SyscallDesc("unused#926", unimplementedFunc), + /* 927 */ SyscallDesc("unused#927", unimplementedFunc), + /* 928 */ SyscallDesc("unused#928", unimplementedFunc), + /* 929 */ SyscallDesc("unused#929", unimplementedFunc), + /* 930 */ SyscallDesc("unused#930", unimplementedFunc), + /* 931 */ SyscallDesc("unused#931", unimplementedFunc), + /* 932 */ SyscallDesc("unused#932", unimplementedFunc), + /* 933 */ SyscallDesc("unused#933", unimplementedFunc), + /* 934 */ SyscallDesc("unused#934", unimplementedFunc), + /* 935 */ SyscallDesc("unused#935", unimplementedFunc), + /* 936 */ SyscallDesc("unused#936", unimplementedFunc), + /* 937 */ SyscallDesc("unused#937", unimplementedFunc), + /* 938 */ SyscallDesc("unused#938", unimplementedFunc), + /* 939 */ SyscallDesc("unused#939", unimplementedFunc), + /* 940 */ SyscallDesc("unused#940", unimplementedFunc), + /* 941 */ SyscallDesc("unused#941", unimplementedFunc), + /* 942 */ SyscallDesc("unused#942", unimplementedFunc), + /* 943 */ SyscallDesc("unused#943", unimplementedFunc), + /* 944 */ SyscallDesc("unused#944", unimplementedFunc), + /* 945 */ SyscallDesc("unused#945", unimplementedFunc), + /* 946 */ SyscallDesc("unused#946", unimplementedFunc), + /* 947 */ SyscallDesc("unused#947", unimplementedFunc), + /* 948 */ SyscallDesc("unused#948", unimplementedFunc), + /* 949 */ SyscallDesc("unused#949", unimplementedFunc), + /* 950 */ SyscallDesc("unused#950", unimplementedFunc), + /* 951 */ SyscallDesc("unused#951", unimplementedFunc), + /* 952 */ SyscallDesc("unused#952", unimplementedFunc), + /* 953 */ SyscallDesc("unused#953", unimplementedFunc), + /* 954 */ SyscallDesc("unused#954", unimplementedFunc), + /* 955 */ SyscallDesc("unused#955", unimplementedFunc), + /* 956 */ SyscallDesc("unused#956", unimplementedFunc), + /* 957 */ SyscallDesc("unused#957", unimplementedFunc), + /* 958 */ SyscallDesc("unused#958", unimplementedFunc), + /* 959 */ SyscallDesc("unused#959", unimplementedFunc), + /* 960 */ SyscallDesc("unused#960", unimplementedFunc), + /* 961 */ SyscallDesc("unused#961", unimplementedFunc), + /* 962 */ SyscallDesc("unused#962", unimplementedFunc), + /* 963 */ SyscallDesc("unused#963", unimplementedFunc), + /* 964 */ SyscallDesc("unused#964", unimplementedFunc), + /* 965 */ SyscallDesc("unused#965", unimplementedFunc), + /* 966 */ SyscallDesc("unused#966", unimplementedFunc), + /* 967 */ SyscallDesc("unused#967", unimplementedFunc), + /* 968 */ SyscallDesc("unused#968", unimplementedFunc), + /* 969 */ SyscallDesc("unused#969", unimplementedFunc), + /* 970 */ SyscallDesc("unused#970", unimplementedFunc), + /* 971 */ SyscallDesc("unused#971", unimplementedFunc), + /* 972 */ SyscallDesc("unused#972", unimplementedFunc), + /* 973 */ SyscallDesc("unused#973", unimplementedFunc), + /* 974 */ SyscallDesc("unused#974", unimplementedFunc), + /* 975 */ SyscallDesc("unused#975", unimplementedFunc), + /* 976 */ SyscallDesc("unused#976", unimplementedFunc), + /* 977 */ SyscallDesc("unused#977", unimplementedFunc), + /* 978 */ SyscallDesc("unused#978", unimplementedFunc), + /* 979 */ SyscallDesc("unused#979", unimplementedFunc), + /* 980 */ SyscallDesc("unused#980", unimplementedFunc), + /* 981 */ SyscallDesc("unused#981", unimplementedFunc), + /* 982 */ SyscallDesc("unused#982", unimplementedFunc), + /* 983 */ SyscallDesc("unused#983", unimplementedFunc), + /* 984 */ SyscallDesc("unused#984", unimplementedFunc), + /* 985 */ SyscallDesc("unused#985", unimplementedFunc), + /* 986 */ SyscallDesc("unused#986", unimplementedFunc), + /* 987 */ SyscallDesc("unused#987", unimplementedFunc), + /* 988 */ SyscallDesc("unused#988", unimplementedFunc), + /* 989 */ SyscallDesc("unused#989", unimplementedFunc), + /* 990 */ SyscallDesc("unused#990", unimplementedFunc), + /* 991 */ SyscallDesc("unused#991", unimplementedFunc), + /* 992 */ SyscallDesc("unused#992", unimplementedFunc), + /* 993 */ SyscallDesc("unused#993", unimplementedFunc), + /* 994 */ SyscallDesc("unused#994", unimplementedFunc), + /* 995 */ SyscallDesc("unused#995", unimplementedFunc), + /* 996 */ SyscallDesc("unused#996", unimplementedFunc), + /* 997 */ SyscallDesc("unused#997", unimplementedFunc), + /* 998 */ SyscallDesc("unused#998", unimplementedFunc), + /* 999 */ SyscallDesc("unused#999", unimplementedFunc), + /* 1000 */ SyscallDesc("unused#1000", unimplementedFunc), + /* 1001 */ SyscallDesc("unused#1001", unimplementedFunc), + /* 1002 */ SyscallDesc("unused#1002", unimplementedFunc), + /* 1003 */ SyscallDesc("unused#1003", unimplementedFunc), + /* 1004 */ SyscallDesc("unused#1004", unimplementedFunc), + /* 1005 */ SyscallDesc("unused#1005", unimplementedFunc), + /* 1006 */ SyscallDesc("unused#1006", unimplementedFunc), + /* 1007 */ SyscallDesc("unused#1007", unimplementedFunc), + /* 1008 */ SyscallDesc("unused#1008", unimplementedFunc), + /* 1009 */ SyscallDesc("unused#1009", unimplementedFunc), + /* 1010 */ SyscallDesc("unused#1010", unimplementedFunc), + /* 1011 */ SyscallDesc("unused#1011", unimplementedFunc), + /* 1012 */ SyscallDesc("unused#1012", unimplementedFunc), + /* 1013 */ SyscallDesc("unused#1013", unimplementedFunc), + /* 1014 */ SyscallDesc("unused#1014", unimplementedFunc), + /* 1015 */ SyscallDesc("unused#1015", unimplementedFunc), + /* 1016 */ SyscallDesc("unused#1016", unimplementedFunc), + /* 1017 */ SyscallDesc("unused#1017", unimplementedFunc), + /* 1018 */ SyscallDesc("unused#1018", unimplementedFunc), + /* 1019 */ SyscallDesc("unused#1019", unimplementedFunc), + /* 1020 */ SyscallDesc("unused#1020", unimplementedFunc), + /* 1021 */ SyscallDesc("unused#1021", unimplementedFunc), + /* 1022 */ SyscallDesc("unused#1022", unimplementedFunc), + /* 1023 */ SyscallDesc("unused#1023", unimplementedFunc), + /* 1024 */ SyscallDesc("open", openFunc<ArmLinux64>), + /* 1025 */ SyscallDesc("link", unimplementedFunc), + /* 1026 */ SyscallDesc("unlink", unlinkFunc), + /* 1027 */ SyscallDesc("mknod", unimplementedFunc), + /* 1028 */ SyscallDesc("chmod", chmodFunc<ArmLinux64>), + /* 1029 */ SyscallDesc("chown", unimplementedFunc), + /* 1030 */ SyscallDesc("mkdir", mkdirFunc), + /* 1031 */ SyscallDesc("rmdir", unimplementedFunc), + /* 1032 */ SyscallDesc("lchown", unimplementedFunc), + /* 1033 */ SyscallDesc("access", unimplementedFunc), + /* 1034 */ SyscallDesc("rename", renameFunc), + /* 1035 */ SyscallDesc("readlink", readlinkFunc), + /* 1036 */ SyscallDesc("symlink", unimplementedFunc), + /* 1037 */ SyscallDesc("utimes", unimplementedFunc), + /* 1038 */ SyscallDesc("stat64", stat64Func<ArmLinux64>), + /* 1039 */ SyscallDesc("lstat64", lstat64Func<ArmLinux64>), + /* 1040 */ SyscallDesc("pipe", pipePseudoFunc), + /* 1041 */ SyscallDesc("dup2", unimplementedFunc), + /* 1042 */ SyscallDesc("epoll_create", unimplementedFunc), + /* 1043 */ SyscallDesc("inotify_init", unimplementedFunc), + /* 1044 */ SyscallDesc("eventfd", unimplementedFunc), + /* 1045 */ SyscallDesc("signalfd", unimplementedFunc), + /* 1046 */ SyscallDesc("sendfile", unimplementedFunc), + /* 1047 */ SyscallDesc("ftruncate", ftruncateFunc), + /* 1048 */ SyscallDesc("truncate", truncateFunc), + /* 1049 */ SyscallDesc("stat", statFunc<ArmLinux64>), + /* 1050 */ SyscallDesc("lstat", unimplementedFunc), + /* 1051 */ SyscallDesc("fstat", fstatFunc<ArmLinux64>), + /* 1052 */ SyscallDesc("fcntl", fcntlFunc), + /* 1053 */ SyscallDesc("fadvise64", unimplementedFunc), + /* 1054 */ SyscallDesc("newfstatat", unimplementedFunc), + /* 1055 */ SyscallDesc("fstatfs", unimplementedFunc), + /* 1056 */ SyscallDesc("statfs", unimplementedFunc), + /* 1057 */ SyscallDesc("lseek", lseekFunc), + /* 1058 */ SyscallDesc("mmap", mmapFunc<ArmLinux64>), + /* 1059 */ SyscallDesc("alarm", unimplementedFunc), + /* 1060 */ SyscallDesc("getpgrp", unimplementedFunc), + /* 1061 */ SyscallDesc("pause", unimplementedFunc), + /* 1062 */ SyscallDesc("time", timeFunc<ArmLinux64>), + /* 1063 */ SyscallDesc("utime", unimplementedFunc), + /* 1064 */ SyscallDesc("creat", unimplementedFunc), + /* 1065 */ SyscallDesc("getdents", unimplementedFunc), + /* 1066 */ SyscallDesc("futimesat", unimplementedFunc), + /* 1067 */ SyscallDesc("select", unimplementedFunc), + /* 1068 */ SyscallDesc("poll", unimplementedFunc), + /* 1069 */ SyscallDesc("epoll_wait", unimplementedFunc), + /* 1070 */ SyscallDesc("ustat", unimplementedFunc), + /* 1071 */ SyscallDesc("vfork", unimplementedFunc), + /* 1072 */ SyscallDesc("oldwait4", unimplementedFunc), + /* 1073 */ SyscallDesc("recv", unimplementedFunc), + /* 1074 */ SyscallDesc("send", unimplementedFunc), + /* 1075 */ SyscallDesc("bdflush", unimplementedFunc), + /* 1076 */ SyscallDesc("umount", unimplementedFunc), + /* 1077 */ SyscallDesc("uselib", unimplementedFunc), + /* 1078 */ SyscallDesc("_sysctl", unimplementedFunc), + /* 1079 */ SyscallDesc("fork", unimplementedFunc) +}; -SyscallDesc ArmLinuxProcess::privSyscallDescs[] = { +static SyscallDesc privSyscallDescs32[] = { /* 1 */ SyscallDesc("breakpoint", unimplementedFunc), /* 2 */ SyscallDesc("cacheflush", unimplementedFunc), /* 3 */ SyscallDesc("usr26", unimplementedFunc), /* 4 */ SyscallDesc("usr32", unimplementedFunc), - /* 5 */ SyscallDesc("set_tls", setTLSFunc) + /* 5 */ SyscallDesc("set_tls", setTLSFunc32) }; -ArmLinuxProcess::ArmLinuxProcess(LiveProcessParams * params, +// Indices 1, 3 and 4 are unallocated. +static SyscallDesc privSyscallDescs64[] = { + /* 1 */ SyscallDesc("unallocated", unimplementedFunc), + /* 2 */ SyscallDesc("cacheflush", unimplementedFunc), + /* 3 */ SyscallDesc("unallocated", unimplementedFunc), + /* 4 */ SyscallDesc("unallocated", unimplementedFunc), + /* 5 */ SyscallDesc("set_tls", setTLSFunc64) +}; + +ArmLinuxProcess32::ArmLinuxProcess32(LiveProcessParams * params, ObjectFile *objFile, ObjectFile::Arch _arch) - : ArmLiveProcess(params, objFile, _arch), - Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc)), - Num_Priv_Syscall_Descs(sizeof(privSyscallDescs) / sizeof(SyscallDesc)) -{ } + : ArmLiveProcess32(params, objFile, _arch) +{ + SyscallTable table; + + table.descs = syscallDescs32; + table.size = sizeof(syscallDescs32) / sizeof(SyscallDesc); + table.base = 0; + syscallTables.push_back(table); + table.base = 0x900000; + syscallTables.push_back(table); -const Addr ArmLinuxProcess::commPage = 0xffff0000; + table.descs = privSyscallDescs32; + table.size = sizeof(privSyscallDescs32) / sizeof(SyscallDesc); + table.base = 0xf0001; + syscallTables.push_back(table); +} + +ArmLinuxProcess64::ArmLinuxProcess64(LiveProcessParams * params, + ObjectFile *objFile, ObjectFile::Arch _arch) + : ArmLiveProcess64(params, objFile, _arch) +{ + SyscallTable table; + + table.descs = syscallDescs64; + table.size = sizeof(syscallDescs64) / sizeof(SyscallDesc); + table.base = 0; + syscallTables.push_back(table); + table.base = 0x900000; + syscallTables.push_back(table); + + table.descs = privSyscallDescs64; + table.size = sizeof(privSyscallDescs64) / sizeof(SyscallDesc); + table.base = 0x1001; + syscallTables.push_back(table); +} + +const Addr ArmLinuxProcess32::commPage = 0xffff0000; SyscallDesc* -ArmLinuxProcess::getDesc(int callnum) +ArmLinuxProcessBits::getLinuxDesc(int callnum) { // Angel SWI syscalls are unsupported in this release - if (callnum == 0x123456) { + if (callnum == 0x123456) panic("Attempt to execute an ANGEL_SWI system call (newlib-related)"); - } else if ((callnum & 0x00f00000) == 0x00900000 || - (callnum & 0xf0000) == 0xf0000) { - callnum &= 0x000fffff; - if ((callnum & 0x0f0000) == 0xf0000) { - callnum -= 0x0f0001; - if (callnum < 0 || callnum > Num_Priv_Syscall_Descs) - return NULL; - return &privSyscallDescs[callnum]; - } + for (unsigned i = 0; i < syscallTables.size(); i++) { + SyscallDesc *desc = syscallTables[i].getDesc(callnum); + if (desc) + return desc; } - // Linux syscalls have to strip off the 0x00900000 + return NULL; +} - if (callnum < 0 || callnum > Num_Syscall_Descs) +SyscallDesc * +ArmLinuxProcessBits::SyscallTable::getDesc(int callnum) const +{ + int offset = callnum - base; + if (offset < 0 || offset >= size) return NULL; + return &descs[offset]; +} + +SyscallDesc* +ArmLinuxProcess32::getDesc(int callnum) +{ + return getLinuxDesc(callnum); +} - return &syscallDescs[callnum]; +SyscallDesc* +ArmLinuxProcess64::getDesc(int callnum) +{ + return getLinuxDesc(callnum); } void -ArmLinuxProcess::initState() +ArmLinuxProcess32::initState() { - ArmLiveProcess::initState(); + ArmLiveProcess32::initState(); allocateMem(commPage, PageBytes); ThreadContext *tc = system->getThreadContext(contextIds[0]); @@ -546,20 +1709,9 @@ ArmLinuxProcess::initState() tc->getMemProxy().writeBlob(commPage + 0x0fe0, get_tls, sizeof(get_tls)); } -ArmISA::IntReg -ArmLinuxProcess::getSyscallArg(ThreadContext *tc, int &i) -{ - // Linux apparently allows more parameter than the ABI says it should. - // This limit may need to be increased even further. - assert(i < 6); - return tc->readIntReg(ArgumentReg0 + i++); -} - void -ArmLinuxProcess::setSyscallArg(ThreadContext *tc, int i, ArmISA::IntReg val) +ArmLinuxProcess64::initState() { - // Linux apparently allows more parameter than the ABI says it should. - // This limit may need to be increased even further. - assert(i < 6); - tc->setIntReg(ArgumentReg0 + i, val); + ArmLiveProcess64::initState(); + // The 64 bit equivalent of the comm page would be set up here. } diff --git a/src/arch/arm/linux/process.hh b/src/arch/arm/linux/process.hh index 7d3a943ed..670739438 100644 --- a/src/arch/arm/linux/process.hh +++ b/src/arch/arm/linux/process.hh @@ -1,4 +1,16 @@ /* +* Copyright (c) 2011-2012 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * * Copyright (c) 2007-2008 The Florida State University * All rights reserved. * @@ -31,39 +43,54 @@ #ifndef __ARM_LINUX_PROCESS_HH__ #define __ARM_LINUX_PROCESS_HH__ +#include <vector> + #include "arch/arm/process.hh" +class ArmLinuxProcessBits +{ + protected: + SyscallDesc* getLinuxDesc(int callnum); + + struct SyscallTable + { + int base; + SyscallDesc *descs; + int size; + + SyscallDesc *getDesc(int offset) const; + }; + + std::vector<SyscallTable> syscallTables; +}; + /// A process with emulated Arm/Linux syscalls. -class ArmLinuxProcess : public ArmLiveProcess +class ArmLinuxProcess32 : public ArmLiveProcess32, public ArmLinuxProcessBits { public: - ArmLinuxProcess(LiveProcessParams * params, ObjectFile *objFile, - ObjectFile::Arch _arch); - - virtual SyscallDesc* getDesc(int callnum); + ArmLinuxProcess32(LiveProcessParams * params, ObjectFile *objFile, + ObjectFile::Arch _arch); void initState(); - ArmISA::IntReg getSyscallArg(ThreadContext *tc, int &i); /// Explicitly import the otherwise hidden getSyscallArg using ArmLiveProcess::getSyscallArg; - void setSyscallArg(ThreadContext *tc, int i, ArmISA::IntReg val); - - /// The target system's hostname. - static const char *hostname; /// A page to hold "kernel" provided functions. The name might be wrong. static const Addr commPage; - /// Array of syscall descriptors, indexed by call number. - static SyscallDesc syscallDescs[]; - - /// Array of "arm private" syscall descriptors. - static SyscallDesc privSyscallDescs[]; + SyscallDesc* getDesc(int callnum); +}; - const int Num_Syscall_Descs; +/// A process with emulated Arm/Linux syscalls. +class ArmLinuxProcess64 : public ArmLiveProcess64, public ArmLinuxProcessBits +{ + public: + ArmLinuxProcess64(LiveProcessParams * params, ObjectFile *objFile, + ObjectFile::Arch _arch); - const int Num_Priv_Syscall_Descs; + void initState(); + SyscallDesc* getDesc(int callnum); }; #endif // __ARM_LINUX_PROCESS_HH__ diff --git a/src/arch/arm/linux/system.cc b/src/arch/arm/linux/system.cc index bc7fd2cb6..216a65899 100644 --- a/src/arch/arm/linux/system.cc +++ b/src/arch/arm/linux/system.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2012 ARM Limited + * Copyright (c) 2010-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -63,7 +63,8 @@ using namespace Linux; LinuxArmSystem::LinuxArmSystem(Params *p) : ArmSystem(p), enableContextSwitchStatsDump(p->enable_context_switch_stats_dump), - kernelPanicEvent(NULL), kernelOopsEvent(NULL) + kernelPanicEvent(NULL), kernelOopsEvent(NULL), + bootReleaseAddr(p->boot_release_addr) { if (p->panic_on_panic) { kernelPanicEvent = addKernelFuncEventOrPanic<PanicPCEvent>( @@ -98,22 +99,30 @@ LinuxArmSystem::LinuxArmSystem(Params *p) secDataPtrAddr = 0; secDataAddr = 0; penReleaseAddr = 0; + kernelSymtab->findAddress("__secondary_data", secDataPtrAddr); kernelSymtab->findAddress("secondary_data", secDataAddr); kernelSymtab->findAddress("pen_release", penReleaseAddr); + kernelSymtab->findAddress("secondary_holding_pen_release", pen64ReleaseAddr); secDataPtrAddr &= ~ULL(0x7F); secDataAddr &= ~ULL(0x7F); penReleaseAddr &= ~ULL(0x7F); + pen64ReleaseAddr &= ~ULL(0x7F); + bootReleaseAddr = (bootReleaseAddr & ~ULL(0x7F)) + loadAddrOffset; + } bool LinuxArmSystem::adderBootUncacheable(Addr a) { Addr block = a & ~ULL(0x7F); + if (block == secDataPtrAddr || block == secDataAddr || - block == penReleaseAddr) + block == penReleaseAddr || pen64ReleaseAddr == block || + block == bootReleaseAddr) return true; + return false; } @@ -145,7 +154,8 @@ LinuxArmSystem::initState() if (kernel_has_fdt_support && dtb_file_specified) { // Kernel supports flattened device tree and dtb file specified. // Using Device Tree Blob to describe system configuration. - inform("Loading DTB file: %s\n", params()->dtb_filename); + inform("Loading DTB file: %s at address %#x\n", params()->dtb_filename, + params()->atags_addr + loadAddrOffset); ObjectFile *dtb_file = createObjectFile(params()->dtb_filename, true); if (!dtb_file) { @@ -165,7 +175,7 @@ LinuxArmSystem::initState() "to DTB file: %s\n", params()->dtb_filename); } - dtb_file->setTextBase(params()->atags_addr); + dtb_file->setTextBase(params()->atags_addr + loadAddrOffset); dtb_file->loadSections(physProxy); delete dtb_file; } else { @@ -215,15 +225,17 @@ LinuxArmSystem::initState() DPRINTF(Loader, "Boot atags was %d bytes in total\n", size << 2); DDUMP(Loader, boot_data, size << 2); - physProxy.writeBlob(params()->atags_addr, boot_data, size << 2); + physProxy.writeBlob(params()->atags_addr + loadAddrOffset, boot_data, + size << 2); delete[] boot_data; } + // Kernel boot requirements to set up r0, r1 and r2 in ARMv7 for (int i = 0; i < threadContexts.size(); i++) { threadContexts[i]->setIntReg(0, 0); threadContexts[i]->setIntReg(1, params()->machine_type); - threadContexts[i]->setIntReg(2, params()->atags_addr); + threadContexts[i]->setIntReg(2, params()->atags_addr + loadAddrOffset); } } diff --git a/src/arch/arm/linux/system.hh b/src/arch/arm/linux/system.hh index 008c64429..4ce6ac49e 100644 --- a/src/arch/arm/linux/system.hh +++ b/src/arch/arm/linux/system.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2012 ARM Limited + * Copyright (c) 2010-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -126,6 +126,8 @@ class LinuxArmSystem : public ArmSystem Addr secDataPtrAddr; Addr secDataAddr; Addr penReleaseAddr; + Addr pen64ReleaseAddr; + Addr bootReleaseAddr; }; class DumpStatsPCEvent : public PCEvent diff --git a/src/arch/arm/locked_mem.hh b/src/arch/arm/locked_mem.hh index f2601f00c..24c78e721 100644 --- a/src/arch/arm/locked_mem.hh +++ b/src/arch/arm/locked_mem.hh @@ -53,6 +53,8 @@ */ #include "arch/arm/miscregs.hh" +#include "arch/arm/isa_traits.hh" +#include "debug/LLSC.hh" #include "mem/packet.hh" #include "mem/request.hh" @@ -62,31 +64,48 @@ template <class XC> inline void handleLockedSnoop(XC *xc, PacketPtr pkt, Addr cacheBlockMask) { + DPRINTF(LLSC,"%s: handleing snoop for address: %#x locked: %d\n", + xc->getCpuPtr()->name(),pkt->getAddr(), + xc->readMiscReg(MISCREG_LOCKFLAG)); if (!xc->readMiscReg(MISCREG_LOCKFLAG)) return; Addr locked_addr = xc->readMiscReg(MISCREG_LOCKADDR) & cacheBlockMask; + // If no caches are attached, the snoop address always needs to be masked Addr snoop_addr = pkt->getAddr() & cacheBlockMask; - if (locked_addr == snoop_addr) + DPRINTF(LLSC,"%s: handleing snoop for address: %#x locked addr: %#x\n", + xc->getCpuPtr()->name(),snoop_addr, locked_addr); + if (locked_addr == snoop_addr) { + DPRINTF(LLSC,"%s: address match, clearing lock and signaling sev\n", + xc->getCpuPtr()->name()); xc->setMiscReg(MISCREG_LOCKFLAG, false); + // Implement ARMv8 WFE/SEV semantics + xc->setMiscReg(MISCREG_SEV_MAILBOX, true); + xc->getCpuPtr()->wakeup(); + } } template <class XC> inline void -handleLockedSnoopHit(XC *xc) +handleLockedRead(XC *xc, Request *req) { + xc->setMiscReg(MISCREG_LOCKADDR, req->getPaddr()); + xc->setMiscReg(MISCREG_LOCKFLAG, true); + DPRINTF(LLSC,"%s: Placing address %#x in monitor\n", xc->getCpuPtr()->name(), + req->getPaddr()); } template <class XC> inline void -handleLockedRead(XC *xc, Request *req) +handleLockedSnoopHit(XC *xc) { - xc->setMiscReg(MISCREG_LOCKADDR, req->getPaddr()); - xc->setMiscReg(MISCREG_LOCKFLAG, true); + DPRINTF(LLSC,"%s: handling snoop lock hit address: %#x\n", + xc->getCpuPtr()->name(), xc->readMiscReg(MISCREG_LOCKADDR)); + xc->setMiscReg(MISCREG_LOCKFLAG, false); + xc->setMiscReg(MISCREG_SEV_MAILBOX, true); } - template <class XC> inline bool handleLockedWrite(XC *xc, Request *req, Addr cacheBlockMask) @@ -94,6 +113,8 @@ handleLockedWrite(XC *xc, Request *req, Addr cacheBlockMask) if (req->isSwap()) return true; + DPRINTF(LLSC,"%s: handling locked write for address %#x in monitor\n", + xc->getCpuPtr()->name(), req->getPaddr()); // Verify that the lock flag is still set and the address // is correct bool lock_flag = xc->readMiscReg(MISCREG_LOCKFLAG); @@ -103,6 +124,8 @@ handleLockedWrite(XC *xc, Request *req, Addr cacheBlockMask) // don't even bother sending to memory system req->setExtraData(0); xc->setMiscReg(MISCREG_LOCKFLAG, false); + DPRINTF(LLSC,"%s: clearing lock flag in handle locked write\n", + xc->getCpuPtr()->name()); // the rest of this code is not architectural; // it's just a debugging aid to help detect // livelock by warning on long sequences of failed diff --git a/src/arch/arm/miscregs.cc b/src/arch/arm/miscregs.cc index 3a64b557a..6fa304938 100644 --- a/src/arch/arm/miscregs.cc +++ b/src/arch/arm/miscregs.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2012 ARM Limited + * Copyright (c) 2010-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -36,11 +36,13 @@ * * Authors: Gabe Black * Ali Saidi + * Giacomo Gabrielli */ #include "arch/arm/isa.hh" #include "arch/arm/miscregs.hh" #include "base/misc.hh" +#include "cpu/thread_context.hh" namespace ArmISA { @@ -50,23 +52,31 @@ decodeCP14Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2) { switch(crn) { case 0: - switch (opc2) { + switch (opc1) { case 0: - switch (crm) { + switch (opc2) { case 0: - return MISCREG_DBGDIDR; - case 1: - return MISCREG_DBGDSCR_INT; - default: - warn("CP14 unimplemented crn[%d], opc1[%d], crm[%d], opc2[%d]", - crn, opc1, crm, opc2); - return NUM_MISCREGS; - } - default: - warn("CP14 unimplemented crn[%d], opc1[%d], crm[%d], opc2[%d]", - crn, opc1, crm, opc2); - return NUM_MISCREGS; + switch (crm) { + case 0: + return MISCREG_DBGDIDR; + case 1: + return MISCREG_DBGDSCRint; + } + break; + } + break; + case 7: + switch (opc2) { + case 0: + switch (crm) { + case 0: + return MISCREG_JIDR; + } + break; + } + break; } + break; case 1: switch (opc1) { case 6: @@ -75,29 +85,1270 @@ decodeCP14Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2) switch (opc2) { case 0: return MISCREG_TEEHBR; - default: - warn("CP14 unimplemented crn[%d], opc1[%d], crm[%d], opc2[%d]", - crn, opc1, crm, opc2); - return NUM_MISCREGS; } - default: - warn("CP14 unimplemented crn[%d], opc1[%d], crm[%d], opc2[%d]", - crn, opc1, crm, opc2); - return NUM_MISCREGS; - } - default: - warn("CP14 unimplemented crn[%d], opc1[%d], crm[%d], opc2[%d]", - crn, opc1, crm, opc2); - return NUM_MISCREGS; + break; + } + break; + case 7: + switch (crm) { + case 0: + switch (opc2) { + case 0: + return MISCREG_JOSCR; + } + break; + } + break; } - default: - warn("CP14 unimplemented crn[%d], opc1[%d], crm[%d], opc2[%d]", - crn, opc1, crm, opc2); - return NUM_MISCREGS; + break; + case 2: + switch (opc1) { + case 7: + switch (crm) { + case 0: + switch (opc2) { + case 0: + return MISCREG_JMCR; + } + break; + } + break; + } + break; } - + // If we get here then it must be a register that we haven't implemented + warn("CP14 unimplemented crn[%d], opc1[%d], crm[%d], opc2[%d]", + crn, opc1, crm, opc2); + return MISCREG_CP14_UNIMPL; } +using namespace std; + +bitset<NUM_MISCREG_INFOS> miscRegInfo[NUM_MISCREGS] = { + // MISCREG_CPSR + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_SPSR + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_SPSR_FIQ + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_SPSR_IRQ + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_SPSR_SVC + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_SPSR_MON + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_SPSR_ABT + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_SPSR_HYP + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_SPSR_UND + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_ELR_HYP + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_FPSID + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_FPSCR + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_MVFR1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_MVFR0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_FPEXC + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + + // Helper registers + // MISCREG_CPSR_MODE + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_CPSR_Q + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_FPSCR_Q + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_FPSCR_EXC + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_LOCKADDR + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_LOCKFLAG + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PRRR_MAIR0 + bitset<NUM_MISCREG_INFOS>(string("0000000000000001101")), + // MISCREG_PRRR_MAIR0_NS + bitset<NUM_MISCREG_INFOS>(string("0000000000000010101")), + // MISCREG_PRRR_MAIR0_S + bitset<NUM_MISCREG_INFOS>(string("0000000000000010101")), + // MISCREG_NMRR_MAIR1 + bitset<NUM_MISCREG_INFOS>(string("0000000000000001101")), + // MISCREG_NMRR_MAIR1_NS + bitset<NUM_MISCREG_INFOS>(string("0000000000000010101")), + // MISCREG_NMRR_MAIR1_S + bitset<NUM_MISCREG_INFOS>(string("0000000000000010101")), + // MISCREG_PMXEVTYPER_PMCCFILTR + bitset<NUM_MISCREG_INFOS>(string("0000000000000000101")), + // MISCREG_SCTLR_RST + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_SEV_MAILBOX + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + + // AArch32 CP14 registers + // MISCREG_DBGDIDR + bitset<NUM_MISCREG_INFOS>(string("0101111111111100001")), + // MISCREG_DBGDSCRint + bitset<NUM_MISCREG_INFOS>(string("0101111111111100001")), + // MISCREG_DBGDCCINT + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGDTRTXint + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGDTRRXint + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGWFAR + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGVCR + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGDTRRXext + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGDSCRext + bitset<NUM_MISCREG_INFOS>(string("1111111111111100010")), + // MISCREG_DBGDTRTXext + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGOSECCR + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGBVR0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGBVR1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGBVR2 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGBVR3 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGBVR4 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGBVR5 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGBCR0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGBCR1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGBCR2 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGBCR3 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGBCR4 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGBCR5 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGWVR0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGWVR1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGWVR2 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGWVR3 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGWCR0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGWCR1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGWCR2 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGWCR3 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGDRAR + bitset<NUM_MISCREG_INFOS>(string("0101111111111100000")), + // MISCREG_DBGBXVR4 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGBXVR5 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGOSLAR + bitset<NUM_MISCREG_INFOS>(string("1010111111111100000")), + // MISCREG_DBGOSLSR + bitset<NUM_MISCREG_INFOS>(string("0101111111111100000")), + // MISCREG_DBGOSDLR + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGPRCR + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGDSAR + bitset<NUM_MISCREG_INFOS>(string("0101111111111100000")), + // MISCREG_DBGCLAIMSET + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGCLAIMCLR + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_DBGAUTHSTATUS + bitset<NUM_MISCREG_INFOS>(string("0101111111111100000")), + // MISCREG_DBGDEVID2 + bitset<NUM_MISCREG_INFOS>(string("0101111111111100000")), + // MISCREG_DBGDEVID1 + bitset<NUM_MISCREG_INFOS>(string("0101111111111100000")), + // MISCREG_DBGDEVID0 + bitset<NUM_MISCREG_INFOS>(string("0101111111111100000")), + // MISCREG_TEECR + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_JIDR + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_TEEHBR + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_JOSCR + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_JMCR + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + + // AArch32 CP15 registers + // MISCREG_MIDR + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_CTR + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_TCMTR + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_TLBTR + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_MPIDR + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_REVIDR + bitset<NUM_MISCREG_INFOS>(string("0101010101000000010")), + // MISCREG_ID_PFR0 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_PFR1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_DFR0 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_AFR0 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_MMFR0 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_MMFR1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_MMFR2 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_MMFR3 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_ISAR0 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_ISAR1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_ISAR2 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_ISAR3 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_ISAR4 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_ISAR5 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_CCSIDR + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_CLIDR + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_AIDR + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_CSSELR + bitset<NUM_MISCREG_INFOS>(string("0000000000000001001")), + // MISCREG_CSSELR_NS + bitset<NUM_MISCREG_INFOS>(string("1100110011000010001")), + // MISCREG_CSSELR_S + bitset<NUM_MISCREG_INFOS>(string("0011001100000010001")), + // MISCREG_VPIDR + bitset<NUM_MISCREG_INFOS>(string("1100110000000000001")), + // MISCREG_VMPIDR + bitset<NUM_MISCREG_INFOS>(string("1100110000000000001")), + // MISCREG_SCTLR + bitset<NUM_MISCREG_INFOS>(string("0000000000000001001")), + // MISCREG_SCTLR_NS + bitset<NUM_MISCREG_INFOS>(string("1100110011000010001")), + // MISCREG_SCTLR_S + bitset<NUM_MISCREG_INFOS>(string("0011001100000010001")), + // MISCREG_ACTLR + bitset<NUM_MISCREG_INFOS>(string("0000000000000001001")), + // MISCREG_ACTLR_NS + bitset<NUM_MISCREG_INFOS>(string("1100110011000010001")), + // MISCREG_ACTLR_S + bitset<NUM_MISCREG_INFOS>(string("0011001100000010001")), + // MISCREG_CPACR + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_SCR + bitset<NUM_MISCREG_INFOS>(string("1111001100000000001")), + // MISCREG_SDER + bitset<NUM_MISCREG_INFOS>(string("1111000000000000001")), + // MISCREG_NSACR + bitset<NUM_MISCREG_INFOS>(string("1111011101000000001")), + // MISCREG_HSCTLR + bitset<NUM_MISCREG_INFOS>(string("1100110000000000001")), + // MISCREG_HACTLR + bitset<NUM_MISCREG_INFOS>(string("1100110000000000001")), + // MISCREG_HCR + bitset<NUM_MISCREG_INFOS>(string("1100110000000000001")), + // MISCREG_HDCR + bitset<NUM_MISCREG_INFOS>(string("1100110000000000001")), + // MISCREG_HCPTR + bitset<NUM_MISCREG_INFOS>(string("1100110000000000001")), + // MISCREG_HSTR + bitset<NUM_MISCREG_INFOS>(string("1100110000000000001")), + // MISCREG_HACR + bitset<NUM_MISCREG_INFOS>(string("1100110000000000010")), + // MISCREG_TTBR0 + bitset<NUM_MISCREG_INFOS>(string("0000000000000001001")), + // MISCREG_TTBR0_NS + bitset<NUM_MISCREG_INFOS>(string("1100110011000010001")), + // MISCREG_TTBR0_S + bitset<NUM_MISCREG_INFOS>(string("0011001100000010001")), + // MISCREG_TTBR1 + bitset<NUM_MISCREG_INFOS>(string("0000000000000001001")), + // MISCREG_TTBR1_NS + bitset<NUM_MISCREG_INFOS>(string("1100110011000010001")), + // MISCREG_TTBR1_S + bitset<NUM_MISCREG_INFOS>(string("0011001100000010001")), + // MISCREG_TTBCR + bitset<NUM_MISCREG_INFOS>(string("0000000000000001001")), + // MISCREG_TTBCR_NS + bitset<NUM_MISCREG_INFOS>(string("1100110011000010001")), + // MISCREG_TTBCR_S + bitset<NUM_MISCREG_INFOS>(string("0011001100000010001")), + // MISCREG_HTCR + bitset<NUM_MISCREG_INFOS>(string("1100110000000000001")), + // MISCREG_VTCR + bitset<NUM_MISCREG_INFOS>(string("1100110000000000001")), + // MISCREG_DACR + bitset<NUM_MISCREG_INFOS>(string("0000000000000001001")), + // MISCREG_DACR_NS + bitset<NUM_MISCREG_INFOS>(string("1100110011000010001")), + // MISCREG_DACR_S + bitset<NUM_MISCREG_INFOS>(string("0011001100000010001")), + // MISCREG_DFSR + bitset<NUM_MISCREG_INFOS>(string("0000000000000001001")), + // MISCREG_DFSR_NS + bitset<NUM_MISCREG_INFOS>(string("1100110011000010001")), + // MISCREG_DFSR_S + bitset<NUM_MISCREG_INFOS>(string("0011001100000010001")), + // MISCREG_IFSR + bitset<NUM_MISCREG_INFOS>(string("0000000000000001001")), + // MISCREG_IFSR_NS + bitset<NUM_MISCREG_INFOS>(string("1100110011000010001")), + // MISCREG_IFSR_S + bitset<NUM_MISCREG_INFOS>(string("0011001100000010001")), + // MISCREG_ADFSR + bitset<NUM_MISCREG_INFOS>(string("0000000000000001010")), + // MISCREG_ADFSR_NS + bitset<NUM_MISCREG_INFOS>(string("1100110011000010010")), + // MISCREG_ADFSR_S + bitset<NUM_MISCREG_INFOS>(string("0011001100000010010")), + // MISCREG_AIFSR + bitset<NUM_MISCREG_INFOS>(string("0000000000000001010")), + // MISCREG_AIFSR_NS + bitset<NUM_MISCREG_INFOS>(string("1100110011000010010")), + // MISCREG_AIFSR_S + bitset<NUM_MISCREG_INFOS>(string("0011001100000010010")), + // MISCREG_HADFSR + bitset<NUM_MISCREG_INFOS>(string("1100110000000000001")), + // MISCREG_HAIFSR + bitset<NUM_MISCREG_INFOS>(string("1100110000000000001")), + // MISCREG_HSR + bitset<NUM_MISCREG_INFOS>(string("1100110000000000001")), + // MISCREG_DFAR + bitset<NUM_MISCREG_INFOS>(string("0000000000000001001")), + // MISCREG_DFAR_NS + bitset<NUM_MISCREG_INFOS>(string("1100110011000010001")), + // MISCREG_DFAR_S + bitset<NUM_MISCREG_INFOS>(string("0011001100000010001")), + // MISCREG_IFAR + bitset<NUM_MISCREG_INFOS>(string("0000000000000001001")), + // MISCREG_IFAR_NS + bitset<NUM_MISCREG_INFOS>(string("1100110011000010001")), + // MISCREG_IFAR_S + bitset<NUM_MISCREG_INFOS>(string("0011001100000010001")), + // MISCREG_HDFAR + bitset<NUM_MISCREG_INFOS>(string("1100110000000000001")), + // MISCREG_HIFAR + bitset<NUM_MISCREG_INFOS>(string("1100110000000000001")), + // MISCREG_HPFAR + bitset<NUM_MISCREG_INFOS>(string("1100110000000000001")), + // MISCREG_ICIALLUIS + bitset<NUM_MISCREG_INFOS>(string("1010101010000000010")), + // MISCREG_BPIALLIS + bitset<NUM_MISCREG_INFOS>(string("1010101010000000010")), + // MISCREG_PAR + bitset<NUM_MISCREG_INFOS>(string("0000000000000001001")), + // MISCREG_PAR_NS + bitset<NUM_MISCREG_INFOS>(string("1100110011000010001")), + // MISCREG_PAR_S + bitset<NUM_MISCREG_INFOS>(string("0011001100000010001")), + // MISCREG_ICIALLU + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_ICIMVAU + bitset<NUM_MISCREG_INFOS>(string("1010101010000000010")), + // MISCREG_CP15ISB + bitset<NUM_MISCREG_INFOS>(string("1010101010101000001")), + // MISCREG_BPIALL + bitset<NUM_MISCREG_INFOS>(string("1010101010000000010")), + // MISCREG_BPIMVA + bitset<NUM_MISCREG_INFOS>(string("1010101010000000010")), + // MISCREG_DCIMVAC + bitset<NUM_MISCREG_INFOS>(string("1010101010000000010")), + // MISCREG_DCISW + bitset<NUM_MISCREG_INFOS>(string("1010101010000000010")), + // MISCREG_ATS1CPR + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_ATS1CPW + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_ATS1CUR + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_ATS1CUW + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_ATS12NSOPR + bitset<NUM_MISCREG_INFOS>(string("1010101000000000001")), + // MISCREG_ATS12NSOPW + bitset<NUM_MISCREG_INFOS>(string("1010101000000000001")), + // MISCREG_ATS12NSOUR + bitset<NUM_MISCREG_INFOS>(string("1010101000000000001")), + // MISCREG_ATS12NSOUW + bitset<NUM_MISCREG_INFOS>(string("1010101000000000001")), + // MISCREG_DCCMVAC + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_DCCSW + bitset<NUM_MISCREG_INFOS>(string("1010101010000000010")), + // MISCREG_CP15DSB + bitset<NUM_MISCREG_INFOS>(string("1010101010101000001")), + // MISCREG_CP15DMB + bitset<NUM_MISCREG_INFOS>(string("1010101010101000001")), + // MISCREG_DCCMVAU + bitset<NUM_MISCREG_INFOS>(string("1010101010000000010")), + // MISCREG_DCCIMVAC + bitset<NUM_MISCREG_INFOS>(string("1010101010000000010")), + // MISCREG_DCCISW + bitset<NUM_MISCREG_INFOS>(string("1010101010000000010")), + // MISCREG_ATS1HR + bitset<NUM_MISCREG_INFOS>(string("1000100000000000001")), + // MISCREG_ATS1HW + bitset<NUM_MISCREG_INFOS>(string("1000100000000000001")), + // MISCREG_TLBIALLIS + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_TLBIMVAIS + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_TLBIASIDIS + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_TLBIMVAAIS + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_TLBIMVALIS + bitset<NUM_MISCREG_INFOS>(string("1010101010000000000")), + // MISCREG_TLBIMVAALIS + bitset<NUM_MISCREG_INFOS>(string("1010101010000000000")), + // MISCREG_ITLBIALL + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_ITLBIMVA + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_ITLBIASID + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_DTLBIALL + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_DTLBIMVA + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_DTLBIASID + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_TLBIALL + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_TLBIMVA + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_TLBIASID + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_TLBIMVAA + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_TLBIMVAL + bitset<NUM_MISCREG_INFOS>(string("1010101010000000000")), + // MISCREG_TLBIMVAAL + bitset<NUM_MISCREG_INFOS>(string("1010101010000000000")), + // MISCREG_TLBIIPAS2IS + bitset<NUM_MISCREG_INFOS>(string("1000100000000000000")), + // MISCREG_TLBIIPAS2LIS + bitset<NUM_MISCREG_INFOS>(string("1000100000000000000")), + // MISCREG_TLBIALLHIS + bitset<NUM_MISCREG_INFOS>(string("1000100000000000001")), + // MISCREG_TLBIMVAHIS + bitset<NUM_MISCREG_INFOS>(string("1000100000000000001")), + // MISCREG_TLBIALLNSNHIS + bitset<NUM_MISCREG_INFOS>(string("1000100000000000001")), + // MISCREG_TLBIMVALHIS + bitset<NUM_MISCREG_INFOS>(string("1000100000000000000")), + // MISCREG_TLBIIPAS2 + bitset<NUM_MISCREG_INFOS>(string("1000100000000000000")), + // MISCREG_TLBIIPAS2L + bitset<NUM_MISCREG_INFOS>(string("1000100000000000000")), + // MISCREG_TLBIALLH + bitset<NUM_MISCREG_INFOS>(string("1000100000000000001")), + // MISCREG_TLBIMVAH + bitset<NUM_MISCREG_INFOS>(string("1000100000000000001")), + // MISCREG_TLBIALLNSNH + bitset<NUM_MISCREG_INFOS>(string("1000100000000000001")), + // MISCREG_TLBIMVALH + bitset<NUM_MISCREG_INFOS>(string("1000100000000000000")), + // MISCREG_PMCR + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMCNTENSET + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMCNTENCLR + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMOVSR + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMSWINC + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMSELR + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMCEID0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMCEID1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMCCNTR + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMXEVTYPER + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMCCFILTR + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMXEVCNTR + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMUSERENR + bitset<NUM_MISCREG_INFOS>(string("1111111111010100001")), + // MISCREG_PMINTENSET + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_PMINTENCLR + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_PMOVSSET + bitset<NUM_MISCREG_INFOS>(string("1111111111111100000")), + // MISCREG_L2CTLR + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_L2ECTLR + bitset<NUM_MISCREG_INFOS>(string("1111111111000000000")), + // MISCREG_PRRR + bitset<NUM_MISCREG_INFOS>(string("0000000000000001001")), + // MISCREG_PRRR_NS + bitset<NUM_MISCREG_INFOS>(string("1100110011000010001")), + // MISCREG_PRRR_S + bitset<NUM_MISCREG_INFOS>(string("0011001100000010001")), + // MISCREG_MAIR0 + bitset<NUM_MISCREG_INFOS>(string("0000000000000001001")), + // MISCREG_MAIR0_NS + bitset<NUM_MISCREG_INFOS>(string("1100110011000010001")), + // MISCREG_MAIR0_S + bitset<NUM_MISCREG_INFOS>(string("0011001100000010001")), + // MISCREG_NMRR + bitset<NUM_MISCREG_INFOS>(string("0000000000000001001")), + // MISCREG_NMRR_NS + bitset<NUM_MISCREG_INFOS>(string("1100110011000010001")), + // MISCREG_NMRR_S + bitset<NUM_MISCREG_INFOS>(string("0011001100000010001")), + // MISCREG_MAIR1 + bitset<NUM_MISCREG_INFOS>(string("0000000000000001001")), + // MISCREG_MAIR1_NS + bitset<NUM_MISCREG_INFOS>(string("1100110011000010001")), + // MISCREG_MAIR1_S + bitset<NUM_MISCREG_INFOS>(string("0011001100000010001")), + // MISCREG_AMAIR0 + bitset<NUM_MISCREG_INFOS>(string("0000000000000001001")), + // MISCREG_AMAIR0_NS + bitset<NUM_MISCREG_INFOS>(string("1100110011000010001")), + // MISCREG_AMAIR0_S + bitset<NUM_MISCREG_INFOS>(string("0011001100000010001")), + // MISCREG_AMAIR1 + bitset<NUM_MISCREG_INFOS>(string("0000000000000001001")), + // MISCREG_AMAIR1_NS + bitset<NUM_MISCREG_INFOS>(string("1100110011000010001")), + // MISCREG_AMAIR1_S + bitset<NUM_MISCREG_INFOS>(string("0011001100000010001")), + // MISCREG_HMAIR0 + bitset<NUM_MISCREG_INFOS>(string("1100110000000000001")), + // MISCREG_HMAIR1 + bitset<NUM_MISCREG_INFOS>(string("1100110000000000001")), + // MISCREG_HAMAIR0 + bitset<NUM_MISCREG_INFOS>(string("1100110000000000010")), + // MISCREG_HAMAIR1 + bitset<NUM_MISCREG_INFOS>(string("1100110000000000010")), + // MISCREG_VBAR + bitset<NUM_MISCREG_INFOS>(string("0000000000000001001")), + // MISCREG_VBAR_NS + bitset<NUM_MISCREG_INFOS>(string("1100110011000010001")), + // MISCREG_VBAR_S + bitset<NUM_MISCREG_INFOS>(string("0011001100000010001")), + // MISCREG_MVBAR + bitset<NUM_MISCREG_INFOS>(string("1111001100000000001")), + // MISCREG_RMR + bitset<NUM_MISCREG_INFOS>(string("1111001100000000000")), + // MISCREG_ISR + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_HVBAR + bitset<NUM_MISCREG_INFOS>(string("1100110000000000001")), + // MISCREG_FCSEIDR + bitset<NUM_MISCREG_INFOS>(string("1111111111000000010")), + // MISCREG_CONTEXTIDR + bitset<NUM_MISCREG_INFOS>(string("0000000000000001001")), + // MISCREG_CONTEXTIDR_NS + bitset<NUM_MISCREG_INFOS>(string("1100110011000010001")), + // MISCREG_CONTEXTIDR_S + bitset<NUM_MISCREG_INFOS>(string("0011001100000010001")), + // MISCREG_TPIDRURW + bitset<NUM_MISCREG_INFOS>(string("0000000000000001001")), + // MISCREG_TPIDRURW_NS + bitset<NUM_MISCREG_INFOS>(string("1100110011111110001")), + // MISCREG_TPIDRURW_S + bitset<NUM_MISCREG_INFOS>(string("0011001100000010001")), + // MISCREG_TPIDRURO + bitset<NUM_MISCREG_INFOS>(string("0000000000000001001")), + // MISCREG_TPIDRURO_NS + bitset<NUM_MISCREG_INFOS>(string("1100110011010110001")), + // MISCREG_TPIDRURO_S + bitset<NUM_MISCREG_INFOS>(string("0011001100000010001")), + // MISCREG_TPIDRPRW + bitset<NUM_MISCREG_INFOS>(string("0000000000000001001")), + // MISCREG_TPIDRPRW_NS + bitset<NUM_MISCREG_INFOS>(string("1100110011000010001")), + // MISCREG_TPIDRPRW_S + bitset<NUM_MISCREG_INFOS>(string("0011001100000010001")), + // MISCREG_HTPIDR + bitset<NUM_MISCREG_INFOS>(string("1100110000000000001")), + // MISCREG_CNTFRQ + bitset<NUM_MISCREG_INFOS>(string("1111010101010100001")), + // MISCREG_CNTKCTL + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_CNTP_TVAL + bitset<NUM_MISCREG_INFOS>(string("0000000000000001001")), + // MISCREG_CNTP_TVAL_NS + bitset<NUM_MISCREG_INFOS>(string("1100110011111110001")), + // MISCREG_CNTP_TVAL_S + bitset<NUM_MISCREG_INFOS>(string("0011001100111110000")), + // MISCREG_CNTP_CTL + bitset<NUM_MISCREG_INFOS>(string("0000000000000001001")), + // MISCREG_CNTP_CTL_NS + bitset<NUM_MISCREG_INFOS>(string("1100110011111110001")), + // MISCREG_CNTP_CTL_S + bitset<NUM_MISCREG_INFOS>(string("0011001100111110000")), + // MISCREG_CNTV_TVAL + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_CNTV_CTL + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_CNTHCTL + bitset<NUM_MISCREG_INFOS>(string("1100110000000000001")), + // MISCREG_CNTHP_TVAL + bitset<NUM_MISCREG_INFOS>(string("1100110000000000001")), + // MISCREG_CNTHP_CTL + bitset<NUM_MISCREG_INFOS>(string("1100110000000000001")), + // MISCREG_IL1DATA0 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000000")), + // MISCREG_IL1DATA1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000000")), + // MISCREG_IL1DATA2 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000000")), + // MISCREG_IL1DATA3 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000000")), + // MISCREG_DL1DATA0 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000000")), + // MISCREG_DL1DATA1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000000")), + // MISCREG_DL1DATA2 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000000")), + // MISCREG_DL1DATA3 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000000")), + // MISCREG_DL1DATA4 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000000")), + // MISCREG_RAMINDEX + bitset<NUM_MISCREG_INFOS>(string("1010101010000000000")), + // MISCREG_L2ACTLR + bitset<NUM_MISCREG_INFOS>(string("1111111111000000000")), + // MISCREG_CBAR + bitset<NUM_MISCREG_INFOS>(string("0101010101000000000")), + // MISCREG_HTTBR + bitset<NUM_MISCREG_INFOS>(string("1100110000000000001")), + // MISCREG_VTTBR + bitset<NUM_MISCREG_INFOS>(string("1100110000000000001")), + // MISCREG_CNTPCT + bitset<NUM_MISCREG_INFOS>(string("0101010101010100001")), + // MISCREG_CNTVCT + bitset<NUM_MISCREG_INFOS>(string("0101010101010100001")), + // MISCREG_CNTP_CVAL + bitset<NUM_MISCREG_INFOS>(string("0000000000000001001")), + // MISCREG_CNTP_CVAL_NS + bitset<NUM_MISCREG_INFOS>(string("1100110011111110000")), + // MISCREG_CNTP_CVAL_S + bitset<NUM_MISCREG_INFOS>(string("0011001100111110000")), + // MISCREG_CNTV_CVAL + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_CNTVOFF + bitset<NUM_MISCREG_INFOS>(string("1100110000000000001")), + // MISCREG_CNTHP_CVAL + bitset<NUM_MISCREG_INFOS>(string("1100110000000000001")), + // MISCREG_CPUMERRSR + bitset<NUM_MISCREG_INFOS>(string("1111111111000000000")), + // MISCREG_L2MERRSR + bitset<NUM_MISCREG_INFOS>(string("1111111111000000000")), + + // AArch64 registers (Op0=2) + // MISCREG_MDCCINT_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_OSDTRRX_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_MDSCR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_OSDTRTX_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_OSECCR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_DBGBVR0_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_DBGBVR1_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_DBGBVR2_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_DBGBVR3_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_DBGBVR4_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_DBGBVR5_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_DBGBCR0_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_DBGBCR1_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_DBGBCR2_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_DBGBCR3_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_DBGBCR4_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_DBGBCR5_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_DBGWVR0_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_DBGWVR1_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_DBGWVR2_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_DBGWVR3_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_DBGWCR0_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_DBGWCR1_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_DBGWCR2_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_DBGWCR3_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_MDCCSR_EL0 + bitset<NUM_MISCREG_INFOS>(string("0101111111111100001")), + // MISCREG_MDDTR_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_MDDTRTX_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_MDDTRRX_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_DBGVCR32_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_MDRAR_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101111111111100001")), + // MISCREG_OSLAR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1010111111111100001")), + // MISCREG_OSLSR_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101111111111100001")), + // MISCREG_OSDLR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_DBGPRCR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_DBGCLAIMSET_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_DBGCLAIMCLR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_DBGAUTHSTATUS_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101111111111100001")), + // MISCREG_TEECR32_EL1 + bitset<NUM_MISCREG_INFOS>(string("0000000000000000001")), + // MISCREG_TEEHBR32_EL1 + bitset<NUM_MISCREG_INFOS>(string("0000000000000000001")), + + // AArch64 registers (Op0=1,3) + // MISCREG_MIDR_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_MPIDR_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_REVIDR_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_PFR0_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_PFR1_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_DFR0_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_AFR0_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_MMFR0_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_MMFR1_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_MMFR2_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_MMFR3_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_ISAR0_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_ISAR1_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_ISAR2_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_ISAR3_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_ISAR4_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_ISAR5_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_MVFR0_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_MVFR1_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_MVFR2_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_AA64PFR0_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_AA64PFR1_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_AA64DFR0_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_AA64DFR1_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_AA64AFR0_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_AA64AFR1_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_AA64ISAR0_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_AA64ISAR1_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_AA64MMFR0_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ID_AA64MMFR1_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_CCSIDR_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_CLIDR_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_AIDR_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_CSSELR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_CTR_EL0 + bitset<NUM_MISCREG_INFOS>(string("0101010101010100001")), + // MISCREG_DCZID_EL0 + bitset<NUM_MISCREG_INFOS>(string("0101010101010100001")), + // MISCREG_VPIDR_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_VMPIDR_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_SCTLR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_ACTLR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_CPACR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_SCTLR_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_ACTLR_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_HCR_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_MDCR_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_CPTR_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_HSTR_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_HACR_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_SCTLR_EL3 + bitset<NUM_MISCREG_INFOS>(string("1111000000000000001")), + // MISCREG_ACTLR_EL3 + bitset<NUM_MISCREG_INFOS>(string("1111000000000000001")), + // MISCREG_SCR_EL3 + bitset<NUM_MISCREG_INFOS>(string("1111000000000000001")), + // MISCREG_SDER32_EL3 + bitset<NUM_MISCREG_INFOS>(string("1111000000000000001")), + // MISCREG_CPTR_EL3 + bitset<NUM_MISCREG_INFOS>(string("1111000000000000001")), + // MISCREG_MDCR_EL3 + bitset<NUM_MISCREG_INFOS>(string("1111000000000000001")), + // MISCREG_TTBR0_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_TTBR1_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_TCR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_TTBR0_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_TCR_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_VTTBR_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_VTCR_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_TTBR0_EL3 + bitset<NUM_MISCREG_INFOS>(string("1111000000000000001")), + // MISCREG_TCR_EL3 + bitset<NUM_MISCREG_INFOS>(string("1111000000000000001")), + // MISCREG_DACR32_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_SPSR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_ELR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_SP_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_SPSEL + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_CURRENTEL + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_NZCV + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_DAIF + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_FPCR + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_FPSR + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_DSPSR_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_DLR_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_SPSR_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_ELR_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_SP_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_SPSR_IRQ_AA64 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_SPSR_ABT_AA64 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_SPSR_UND_AA64 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_SPSR_FIQ_AA64 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_SPSR_EL3 + bitset<NUM_MISCREG_INFOS>(string("1111000000000000001")), + // MISCREG_ELR_EL3 + bitset<NUM_MISCREG_INFOS>(string("1111000000000000001")), + // MISCREG_SP_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111000000000000001")), + // MISCREG_AFSR0_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_AFSR1_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_ESR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_IFSR32_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_AFSR0_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_AFSR1_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_ESR_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_FPEXC32_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_AFSR0_EL3 + bitset<NUM_MISCREG_INFOS>(string("1111000000000000001")), + // MISCREG_AFSR1_EL3 + bitset<NUM_MISCREG_INFOS>(string("1111000000000000001")), + // MISCREG_ESR_EL3 + bitset<NUM_MISCREG_INFOS>(string("1111000000000000001")), + // MISCREG_FAR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_FAR_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_HPFAR_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_FAR_EL3 + bitset<NUM_MISCREG_INFOS>(string("1111000000000000001")), + // MISCREG_IC_IALLUIS + bitset<NUM_MISCREG_INFOS>(string("1010101010000000011")), + // MISCREG_PAR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_IC_IALLU + bitset<NUM_MISCREG_INFOS>(string("1010101010000000011")), + // MISCREG_DC_IVAC_Xt + bitset<NUM_MISCREG_INFOS>(string("1010101010000000011")), + // MISCREG_DC_ISW_Xt + bitset<NUM_MISCREG_INFOS>(string("1010101010000000011")), + // MISCREG_AT_S1E1R_Xt + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_AT_S1E1W_Xt + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_AT_S1E0R_Xt + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_AT_S1E0W_Xt + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_DC_CSW_Xt + bitset<NUM_MISCREG_INFOS>(string("1010101010000000011")), + // MISCREG_DC_CISW_Xt + bitset<NUM_MISCREG_INFOS>(string("1010101010000000011")), + // MISCREG_DC_ZVA_Xt + bitset<NUM_MISCREG_INFOS>(string("1010101010001000011")), + // MISCREG_IC_IVAU_Xt + bitset<NUM_MISCREG_INFOS>(string("1010101010101000001")), + // MISCREG_DC_CVAC_Xt + bitset<NUM_MISCREG_INFOS>(string("1010101010101000011")), + // MISCREG_DC_CVAU_Xt + bitset<NUM_MISCREG_INFOS>(string("1010101010101000011")), + // MISCREG_DC_CIVAC_Xt + bitset<NUM_MISCREG_INFOS>(string("1010101010101000011")), + // MISCREG_AT_S1E2R_Xt + bitset<NUM_MISCREG_INFOS>(string("1000100000000000001")), + // MISCREG_AT_S1E2W_Xt + bitset<NUM_MISCREG_INFOS>(string("1000100000000000001")), + // MISCREG_AT_S12E1R_Xt + bitset<NUM_MISCREG_INFOS>(string("1010100000000000001")), + // MISCREG_AT_S12E1W_Xt + bitset<NUM_MISCREG_INFOS>(string("1010100000000000001")), + // MISCREG_AT_S12E0R_Xt + bitset<NUM_MISCREG_INFOS>(string("1010100000000000001")), + // MISCREG_AT_S12E0W_Xt + bitset<NUM_MISCREG_INFOS>(string("1010100000000000001")), + // MISCREG_AT_S1E3R_Xt + bitset<NUM_MISCREG_INFOS>(string("1010000000000000001")), + // MISCREG_AT_S1E3W_Xt + bitset<NUM_MISCREG_INFOS>(string("1010000000000000001")), + // MISCREG_TLBI_VMALLE1IS + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_TLBI_VAE1IS_Xt + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_TLBI_ASIDE1IS_Xt + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_TLBI_VAAE1IS_Xt + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_TLBI_VALE1IS_Xt + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_TLBI_VAALE1IS_Xt + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_TLBI_VMALLE1 + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_TLBI_VAE1_Xt + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_TLBI_ASIDE1_Xt + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_TLBI_VAAE1_Xt + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_TLBI_VALE1_Xt + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_TLBI_VAALE1_Xt + bitset<NUM_MISCREG_INFOS>(string("1010101010000000001")), + // MISCREG_TLBI_IPAS2E1IS_Xt + bitset<NUM_MISCREG_INFOS>(string("1010100000000000001")), + // MISCREG_TLBI_IPAS2LE1IS_Xt + bitset<NUM_MISCREG_INFOS>(string("1010100000000000001")), + // MISCREG_TLBI_ALLE2IS + bitset<NUM_MISCREG_INFOS>(string("1000100000000000001")), + // MISCREG_TLBI_VAE2IS_Xt + bitset<NUM_MISCREG_INFOS>(string("1000100000000000001")), + // MISCREG_TLBI_ALLE1IS + bitset<NUM_MISCREG_INFOS>(string("1010100000000000001")), + // MISCREG_TLBI_VALE2IS_Xt + bitset<NUM_MISCREG_INFOS>(string("1000100000000000001")), + // MISCREG_TLBI_VMALLS12E1IS + bitset<NUM_MISCREG_INFOS>(string("1010100000000000001")), + // MISCREG_TLBI_IPAS2E1_Xt + bitset<NUM_MISCREG_INFOS>(string("1010100000000000001")), + // MISCREG_TLBI_IPAS2LE1_Xt + bitset<NUM_MISCREG_INFOS>(string("1010100000000000001")), + // MISCREG_TLBI_ALLE2 + bitset<NUM_MISCREG_INFOS>(string("1000100000000000001")), + // MISCREG_TLBI_VAE2_Xt + bitset<NUM_MISCREG_INFOS>(string("1000100000000000001")), + // MISCREG_TLBI_ALLE1 + bitset<NUM_MISCREG_INFOS>(string("1010100000000000001")), + // MISCREG_TLBI_VALE2_Xt + bitset<NUM_MISCREG_INFOS>(string("1000100000000000001")), + // MISCREG_TLBI_VMALLS12E1 + bitset<NUM_MISCREG_INFOS>(string("1010100000000000001")), + // MISCREG_TLBI_ALLE3IS + bitset<NUM_MISCREG_INFOS>(string("1010000000000000001")), + // MISCREG_TLBI_VAE3IS_Xt + bitset<NUM_MISCREG_INFOS>(string("1010000000000000001")), + // MISCREG_TLBI_VALE3IS_Xt + bitset<NUM_MISCREG_INFOS>(string("1010000000000000001")), + // MISCREG_TLBI_ALLE3 + bitset<NUM_MISCREG_INFOS>(string("1010000000000000001")), + // MISCREG_TLBI_VAE3_Xt + bitset<NUM_MISCREG_INFOS>(string("1010000000000000001")), + // MISCREG_TLBI_VALE3_Xt + bitset<NUM_MISCREG_INFOS>(string("1010000000000000001")), + // MISCREG_PMINTENSET_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_PMINTENCLR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_PMCR_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMCNTENSET_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMCNTENCLR_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMOVSCLR_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMSWINC_EL0 + bitset<NUM_MISCREG_INFOS>(string("1010101010111100001")), + // MISCREG_PMSELR_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMCEID0_EL0 + bitset<NUM_MISCREG_INFOS>(string("0101010101111100001")), + // MISCREG_PMCEID1_EL0 + bitset<NUM_MISCREG_INFOS>(string("0101010101111100001")), + // MISCREG_PMCCNTR_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMXEVTYPER_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMCCFILTR_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMXEVCNTR_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMUSERENR_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111010100001")), + // MISCREG_PMOVSSET_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_MAIR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_AMAIR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_MAIR_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_AMAIR_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_MAIR_EL3 + bitset<NUM_MISCREG_INFOS>(string("1111000000000000001")), + // MISCREG_AMAIR_EL3 + bitset<NUM_MISCREG_INFOS>(string("1111000000000000001")), + // MISCREG_L2CTLR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_L2ECTLR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_VBAR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_RVBAR_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_ISR_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_VBAR_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_RVBAR_EL2 + bitset<NUM_MISCREG_INFOS>(string("0101010000000000001")), + // MISCREG_VBAR_EL3 + bitset<NUM_MISCREG_INFOS>(string("1111000000000000001")), + // MISCREG_RVBAR_EL3 + bitset<NUM_MISCREG_INFOS>(string("0101000000000000001")), + // MISCREG_RMR_EL3 + bitset<NUM_MISCREG_INFOS>(string("1111000000000000001")), + // MISCREG_CONTEXTIDR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_TPIDR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_TPIDR_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_TPIDRRO_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111010100001")), + // MISCREG_TPIDR_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_TPIDR_EL3 + bitset<NUM_MISCREG_INFOS>(string("1111000000000000001")), + // MISCREG_CNTKCTL_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_CNTFRQ_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111010101010100001")), + // MISCREG_CNTPCT_EL0 + bitset<NUM_MISCREG_INFOS>(string("0101010101010100001")), + // MISCREG_CNTVCT_EL0 + bitset<NUM_MISCREG_INFOS>(string("0101010101010100001")), + // MISCREG_CNTP_TVAL_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_CNTP_CTL_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_CNTP_CVAL_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_CNTV_TVAL_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_CNTV_CTL_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_CNTV_CVAL_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMEVCNTR0_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMEVCNTR1_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMEVCNTR2_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMEVCNTR3_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMEVCNTR4_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMEVCNTR5_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMEVTYPER0_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMEVTYPER1_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMEVTYPER2_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMEVTYPER3_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMEVTYPER4_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_PMEVTYPER5_EL0 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_CNTVOFF_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_CNTHCTL_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_CNTHP_TVAL_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_CNTHP_CTL_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_CNTHP_CVAL_EL2 + bitset<NUM_MISCREG_INFOS>(string("1111110000000000001")), + // MISCREG_CNTPS_TVAL_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_CNTPS_CTL_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_CNTPS_CVAL_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_IL1DATA0_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_IL1DATA1_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_IL1DATA2_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_IL1DATA3_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_DL1DATA0_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_DL1DATA1_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_DL1DATA2_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_DL1DATA3_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_DL1DATA4_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_L2ACTLR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_CPUACTLR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_CPUECTLR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_CPUMERRSR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_L2MERRSR_EL1 + bitset<NUM_MISCREG_INFOS>(string("1111111111000000001")), + // MISCREG_CBAR_EL1 + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + + // Dummy registers + // MISCREG_NOP + bitset<NUM_MISCREG_INFOS>(string("1111111111111100001")), + // MISCREG_RAZ + bitset<NUM_MISCREG_INFOS>(string("0101010101000000001")), + // MISCREG_CP14_UNIMPL + bitset<NUM_MISCREG_INFOS>(string("0000000000000000010")), + // MISCREG_CP15_UNIMPL + bitset<NUM_MISCREG_INFOS>(string("0000000000000000010")), + // MISCREG_A64_UNIMPL + bitset<NUM_MISCREG_INFOS>(string("0000000000000000010")), + // MISCREG_UNKNOWN + bitset<NUM_MISCREG_INFOS>(string("0000000000000000001")) +}; + MiscRegIndex decodeCP15Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2) { @@ -116,6 +1367,8 @@ decodeCP15Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2) return MISCREG_TLBTR; case 5: return MISCREG_MPIDR; + case 6: + return MISCREG_REVIDR; default: return MISCREG_MIDR; } @@ -180,6 +1433,14 @@ decodeCP15Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2) return MISCREG_CSSELR; } break; + case 4: + if (crm == 0) { + if (opc2 == 0) + return MISCREG_VPIDR; + else if (opc2 == 5) + return MISCREG_VMPIDR; + } + break; } break; case 1: @@ -203,6 +1464,26 @@ decodeCP15Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2) return MISCREG_NSACR; } } + } else if (opc1 == 4) { + if (crm == 0) { + if (opc2 == 0) + return MISCREG_HSCTLR; + else if (opc2 == 1) + return MISCREG_HACTLR; + } else if (crm == 1) { + switch (opc2) { + case 0: + return MISCREG_HCR; + case 1: + return MISCREG_HDCR; + case 2: + return MISCREG_HCPTR; + case 3: + return MISCREG_HSTR; + case 7: + return MISCREG_HACR; + } + } } break; case 2: @@ -215,6 +1496,11 @@ decodeCP15Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2) case 2: return MISCREG_TTBCR; } + } else if (opc1 == 4) { + if (crm == 0 && opc2 == 2) + return MISCREG_HTCR; + else if (crm == 1 && opc2 == 2) + return MISCREG_VTCR; } break; case 3: @@ -237,6 +1523,15 @@ decodeCP15Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2) return MISCREG_AIFSR; } } + } else if (opc1 == 4) { + if (crm == 1) { + if (opc2 == 0) + return MISCREG_HADFSR; + else if (opc2 == 1) + return MISCREG_HAIFSR; + } else if (crm == 2 && opc2 == 0) { + return MISCREG_HSR; + } } break; case 6: @@ -247,6 +1542,15 @@ decodeCP15Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2) case 2: return MISCREG_IFAR; } + } else if (opc1 == 4 && crm == 0) { + switch (opc2) { + case 0: + return MISCREG_HDFAR; + case 2: + return MISCREG_HIFAR; + case 4: + return MISCREG_HPFAR; + } } break; case 7: @@ -294,21 +1598,21 @@ decodeCP15Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2) case 8: switch (opc2) { case 0: - return MISCREG_V2PCWPR; + return MISCREG_ATS1CPR; case 1: - return MISCREG_V2PCWPW; + return MISCREG_ATS1CPW; case 2: - return MISCREG_V2PCWUR; + return MISCREG_ATS1CUR; case 3: - return MISCREG_V2PCWUW; + return MISCREG_ATS1CUW; case 4: - return MISCREG_V2POWPR; + return MISCREG_ATS12NSOPR; case 5: - return MISCREG_V2POWPW; + return MISCREG_ATS12NSOPW; case 6: - return MISCREG_V2POWUR; + return MISCREG_ATS12NSOUR; case 7: - return MISCREG_V2POWUW; + return MISCREG_ATS12NSOUW; } break; case 10: @@ -316,7 +1620,7 @@ decodeCP15Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2) case 1: return MISCREG_DCCMVAC; case 2: - return MISCREG_MCCSW; + return MISCREG_DCCSW; case 4: return MISCREG_CP15DSB; case 5: @@ -341,6 +1645,11 @@ decodeCP15Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2) } break; } + } else if (opc1 == 4 && crm == 8) { + if (opc2 == 0) + return MISCREG_ATS1HR; + else if (opc2 == 1) + return MISCREG_ATS1HW; } break; case 8: @@ -391,6 +1700,26 @@ decodeCP15Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2) } break; } + } else if (opc1 == 4) { + if (crm == 3) { + switch (opc2) { + case 0: + return MISCREG_TLBIALLHIS; + case 1: + return MISCREG_TLBIMVAHIS; + case 4: + return MISCREG_TLBIALLNSNHIS; + } + } else if (crm == 7) { + switch (opc2) { + case 0: + return MISCREG_TLBIALLH; + case 1: + return MISCREG_TLBIMVAH; + case 4: + return MISCREG_TLBIALLNSNH; + } + } } break; case 9: @@ -421,7 +1750,8 @@ decodeCP15Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2) case 0: return MISCREG_PMCCNTR; case 1: - return MISCREG_PMC_OTHER; + // Selector is PMSELR.SEL + return MISCREG_PMXEVTYPER_PMCCFILTR; case 2: return MISCREG_PMXEVCNTR; } @@ -434,6 +1764,8 @@ decodeCP15Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2) return MISCREG_PMINTENSET; case 2: return MISCREG_PMINTENCLR; + case 3: + return MISCREG_PMOVSSET; } break; } @@ -443,28 +1775,45 @@ decodeCP15Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2) switch (opc2) { case 2: // L2CTLR, L2 Control Register return MISCREG_L2CTLR; - default: - warn("Uknown miscregs: crn:%d crm:%d opc1:%d opc2:%d\n", - crn,crm, opc1,opc2); - break; + case 3: + return MISCREG_L2ECTLR; } break; - default: - return MISCREG_L2LATENCY; + break; } } - //Reserved for Branch Predictor, Cache and TCM operations break; case 10: if (opc1 == 0) { // crm 0, 1, 4, and 8, with op2 0 - 7, reserved for TLB lockdown if (crm == 2) { // TEX Remap Registers if (opc2 == 0) { - return MISCREG_PRRR; + // Selector is TTBCR.EAE + return MISCREG_PRRR_MAIR0; } else if (opc2 == 1) { - return MISCREG_NMRR; + // Selector is TTBCR.EAE + return MISCREG_NMRR_MAIR1; + } + } else if (crm == 3) { + if (opc2 == 0) { + return MISCREG_AMAIR0; + } else if (opc2 == 1) { + return MISCREG_AMAIR1; } } + } else if (opc1 == 4) { + // crm 0, 1, 4, and 8, with op2 0 - 7, reserved for TLB lockdown + if (crm == 2) { + if (opc2 == 0) + return MISCREG_HMAIR0; + else if (opc2 == 1) + return MISCREG_HMAIR1; + } else if (crm == 3) { + if (opc2 == 0) + return MISCREG_HAMAIR0; + else if (opc2 == 1) + return MISCREG_HAMAIR1; + } } break; case 11: @@ -498,6 +1847,9 @@ decodeCP15Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2) return MISCREG_ISR; } } + } else if (opc1 == 4) { + if (crm == 0 && opc2 == 0) + return MISCREG_HVBAR; } break; case 13: @@ -505,7 +1857,7 @@ decodeCP15Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2) if (crm == 0) { switch (opc2) { case 0: - return MISCREG_FCEIDR; + return MISCREG_FCSEIDR; case 1: return MISCREG_CONTEXTIDR; case 2: @@ -516,14 +1868,1682 @@ decodeCP15Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2) return MISCREG_TPIDRPRW; } } + } else if (opc1 == 4) { + if (crm == 0 && opc2 == 2) + return MISCREG_HTPIDR; + } + break; + case 14: + if (opc1 == 0) { + switch (crm) { + case 0: + if (opc2 == 0) + return MISCREG_CNTFRQ; + break; + case 1: + if (opc2 == 0) + return MISCREG_CNTKCTL; + break; + case 2: + if (opc2 == 0) + return MISCREG_CNTP_TVAL; + else if (opc2 == 1) + return MISCREG_CNTP_CTL; + break; + case 3: + if (opc2 == 0) + return MISCREG_CNTV_TVAL; + else if (opc2 == 1) + return MISCREG_CNTV_CTL; + break; + } + } else if (opc1 == 4) { + if (crm == 1 && opc2 == 0) { + return MISCREG_CNTHCTL; + } else if (crm == 2) { + if (opc2 == 0) + return MISCREG_CNTHP_TVAL; + else if (opc2 == 1) + return MISCREG_CNTHP_CTL; + } } break; case 15: // Implementation defined - return MISCREG_CRN15; + return MISCREG_CP15_UNIMPL; } // Unrecognized register - return NUM_MISCREGS; + return MISCREG_CP15_UNIMPL; +} + +MiscRegIndex +decodeCP15Reg64(unsigned crm, unsigned opc1) +{ + switch (crm) { + case 2: + switch (opc1) { + case 0: + return MISCREG_TTBR0; + case 1: + return MISCREG_TTBR1; + case 4: + return MISCREG_HTTBR; + case 6: + return MISCREG_VTTBR; + } + break; + case 7: + if (opc1 == 0) + return MISCREG_PAR; + break; + case 14: + switch (opc1) { + case 0: + return MISCREG_CNTPCT; + case 1: + return MISCREG_CNTVCT; + case 2: + return MISCREG_CNTP_CVAL; + case 3: + return MISCREG_CNTV_CVAL; + case 4: + return MISCREG_CNTVOFF; + case 6: + return MISCREG_CNTHP_CVAL; + } + break; + case 15: + if (opc1 == 0) + return MISCREG_CPUMERRSR; + else if (opc1 == 1) + return MISCREG_L2MERRSR; + break; + } + // Unrecognized register + return MISCREG_CP15_UNIMPL; +} + +bool +canReadCoprocReg(MiscRegIndex reg, SCR scr, CPSR cpsr, ThreadContext *tc) +{ + bool secure = !scr.ns; + bool canRead; + + switch (cpsr.mode) { + case MODE_USER: + canRead = secure ? miscRegInfo[reg][MISCREG_USR_S_RD] : + miscRegInfo[reg][MISCREG_USR_NS_RD]; + break; + case MODE_FIQ: + case MODE_IRQ: + case MODE_SVC: + case MODE_ABORT: + case MODE_UNDEFINED: + case MODE_SYSTEM: + canRead = secure ? miscRegInfo[reg][MISCREG_PRI_S_RD] : + miscRegInfo[reg][MISCREG_PRI_NS_RD]; + break; + case MODE_MON: + canRead = secure ? miscRegInfo[reg][MISCREG_MON_NS0_RD] : + miscRegInfo[reg][MISCREG_MON_NS1_RD]; + break; + case MODE_HYP: + canRead = miscRegInfo[reg][MISCREG_HYP_RD]; + break; + default: + panic("Unrecognized mode setting in CPSR.\n"); + } + // can't do permissions checkes on the root of a banked pair of regs + assert(!miscRegInfo[reg][MISCREG_BANKED]); + return canRead; +} + +bool +canWriteCoprocReg(MiscRegIndex reg, SCR scr, CPSR cpsr, ThreadContext *tc) +{ + bool secure = !scr.ns; + bool canWrite; + + switch (cpsr.mode) { + case MODE_USER: + canWrite = secure ? miscRegInfo[reg][MISCREG_USR_S_WR] : + miscRegInfo[reg][MISCREG_USR_NS_WR]; + break; + case MODE_FIQ: + case MODE_IRQ: + case MODE_SVC: + case MODE_ABORT: + case MODE_UNDEFINED: + case MODE_SYSTEM: + canWrite = secure ? miscRegInfo[reg][MISCREG_PRI_S_WR] : + miscRegInfo[reg][MISCREG_PRI_NS_WR]; + break; + case MODE_MON: + canWrite = secure ? miscRegInfo[reg][MISCREG_MON_NS0_WR] : + miscRegInfo[reg][MISCREG_MON_NS1_WR]; + break; + case MODE_HYP: + canWrite = miscRegInfo[reg][MISCREG_HYP_WR]; + break; + default: + panic("Unrecognized mode setting in CPSR.\n"); + } + // can't do permissions checkes on the root of a banked pair of regs + assert(!miscRegInfo[reg][MISCREG_BANKED]); + return canWrite; +} + +int +flattenMiscRegNsBanked(int reg, ThreadContext *tc) +{ + if (miscRegInfo[reg][MISCREG_BANKED]) { + SCR scr = tc->readMiscReg(MISCREG_SCR); + reg += (ArmSystem::haveSecurity(tc) && !scr.ns) ? 2 : 1; + } + return reg; +} + +int +flattenMiscRegNsBanked(int reg, ThreadContext *tc, bool ns) +{ + if (miscRegInfo[reg][MISCREG_BANKED]) { + reg += (ArmSystem::haveSecurity(tc) && !ns) ? 2 : 1; + } + return reg; } + +/** + * If the reg is a child reg of a banked set, then the parent is the last + * banked one in the list. This is messy, and the wish is to eventually have + * the bitmap replaced with a better data structure. the preUnflatten function + * initializes a lookup table to speed up the search for these banked + * registers. + */ + +int unflattenResultMiscReg[NUM_MISCREGS]; + +void +preUnflattenMiscReg() +{ + int reg = -1; + for (int i = 0 ; i < NUM_MISCREGS; i++){ + if (miscRegInfo[i][MISCREG_BANKED]) + reg = i; + if (miscRegInfo[i][MISCREG_BANKED_CHILD]) + unflattenResultMiscReg[i] = reg; + else + unflattenResultMiscReg[i] = i; + // if this assert fails, no parent was found, and something is broken + assert(unflattenResultMiscReg[i] > -1); + } } + +int +unflattenMiscReg(int reg) +{ + return unflattenResultMiscReg[reg]; +} + +bool +canReadAArch64SysReg(MiscRegIndex reg, SCR scr, CPSR cpsr, ThreadContext *tc) +{ + // Check for SP_EL0 access while SPSEL == 0 + if ((reg == MISCREG_SP_EL0) && (tc->readMiscReg(MISCREG_SPSEL) == 0)) + return false; + + // Check for RVBAR access + if (reg == MISCREG_RVBAR_EL1) { + ExceptionLevel highest_el = ArmSystem::highestEL(tc); + if (highest_el == EL2 || highest_el == EL3) + return false; + } + if (reg == MISCREG_RVBAR_EL2) { + ExceptionLevel highest_el = ArmSystem::highestEL(tc); + if (highest_el == EL3) + return false; + } + + bool secure = ArmSystem::haveSecurity(tc) && !scr.ns; + + switch (opModeToEL((OperatingMode) (uint8_t) cpsr.mode)) { + case EL0: + return secure ? miscRegInfo[reg][MISCREG_USR_S_RD] : + miscRegInfo[reg][MISCREG_USR_NS_RD]; + case EL1: + return secure ? miscRegInfo[reg][MISCREG_PRI_S_RD] : + miscRegInfo[reg][MISCREG_PRI_NS_RD]; + // @todo: uncomment this to enable Virtualization + // case EL2: + // return miscRegInfo[reg][MISCREG_HYP_RD]; + case EL3: + return secure ? miscRegInfo[reg][MISCREG_MON_NS0_RD] : + miscRegInfo[reg][MISCREG_MON_NS1_RD]; + default: + panic("Invalid exception level"); + } +} + +bool +canWriteAArch64SysReg(MiscRegIndex reg, SCR scr, CPSR cpsr, ThreadContext *tc) +{ + // Check for SP_EL0 access while SPSEL == 0 + if ((reg == MISCREG_SP_EL0) && (tc->readMiscReg(MISCREG_SPSEL) == 0)) + return false; + ExceptionLevel el = opModeToEL((OperatingMode) (uint8_t) cpsr.mode); + if (reg == MISCREG_DAIF) { + SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR_EL1); + if (el == EL0 && !sctlr.uma) + return false; + } + if (reg == MISCREG_DC_ZVA_Xt) { + SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR_EL1); + if (el == EL0 && !sctlr.dze) + return false; + } + if (reg == MISCREG_DC_CVAC_Xt || reg == MISCREG_DC_CIVAC_Xt) { + SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR_EL1); + if (el == EL0 && !sctlr.uci) + return false; + } + + bool secure = ArmSystem::haveSecurity(tc) && !scr.ns; + + switch (el) { + case EL0: + return secure ? miscRegInfo[reg][MISCREG_USR_S_WR] : + miscRegInfo[reg][MISCREG_USR_NS_WR]; + case EL1: + return secure ? miscRegInfo[reg][MISCREG_PRI_S_WR] : + miscRegInfo[reg][MISCREG_PRI_NS_WR]; + // @todo: uncomment this to enable Virtualization + // case EL2: + // return miscRegInfo[reg][MISCREG_HYP_WR]; + case EL3: + return secure ? miscRegInfo[reg][MISCREG_MON_NS0_WR] : + miscRegInfo[reg][MISCREG_MON_NS1_WR]; + default: + panic("Invalid exception level"); + } +} + +MiscRegIndex +decodeAArch64SysReg(unsigned op0, unsigned op1, + unsigned crn, unsigned crm, + unsigned op2) +{ + switch (op0) { + case 1: + switch (crn) { + case 7: + switch (op1) { + case 0: + switch (crm) { + case 1: + switch (op2) { + case 0: + return MISCREG_IC_IALLUIS; + } + break; + case 5: + switch (op2) { + case 0: + return MISCREG_IC_IALLU; + } + break; + case 6: + switch (op2) { + case 1: + return MISCREG_DC_IVAC_Xt; + case 2: + return MISCREG_DC_ISW_Xt; + } + break; + case 8: + switch (op2) { + case 0: + return MISCREG_AT_S1E1R_Xt; + case 1: + return MISCREG_AT_S1E1W_Xt; + case 2: + return MISCREG_AT_S1E0R_Xt; + case 3: + return MISCREG_AT_S1E0W_Xt; + } + break; + case 10: + switch (op2) { + case 2: + return MISCREG_DC_CSW_Xt; + } + break; + case 14: + switch (op2) { + case 2: + return MISCREG_DC_CISW_Xt; + } + break; + } + break; + case 3: + switch (crm) { + case 4: + switch (op2) { + case 1: + return MISCREG_DC_ZVA_Xt; + } + break; + case 5: + switch (op2) { + case 1: + return MISCREG_IC_IVAU_Xt; + } + break; + case 10: + switch (op2) { + case 1: + return MISCREG_DC_CVAC_Xt; + } + break; + case 11: + switch (op2) { + case 1: + return MISCREG_DC_CVAU_Xt; + } + break; + case 14: + switch (op2) { + case 1: + return MISCREG_DC_CIVAC_Xt; + } + break; + } + break; + case 4: + switch (crm) { + case 8: + switch (op2) { + case 0: + return MISCREG_AT_S1E2R_Xt; + case 1: + return MISCREG_AT_S1E2W_Xt; + case 4: + return MISCREG_AT_S12E1R_Xt; + case 5: + return MISCREG_AT_S12E1W_Xt; + case 6: + return MISCREG_AT_S12E0R_Xt; + case 7: + return MISCREG_AT_S12E0W_Xt; + } + break; + } + break; + case 6: + switch (crm) { + case 8: + switch (op2) { + case 0: + return MISCREG_AT_S1E3R_Xt; + case 1: + return MISCREG_AT_S1E3W_Xt; + } + break; + } + break; + } + break; + case 8: + switch (op1) { + case 0: + switch (crm) { + case 3: + switch (op2) { + case 0: + return MISCREG_TLBI_VMALLE1IS; + case 1: + return MISCREG_TLBI_VAE1IS_Xt; + case 2: + return MISCREG_TLBI_ASIDE1IS_Xt; + case 3: + return MISCREG_TLBI_VAAE1IS_Xt; + case 5: + return MISCREG_TLBI_VALE1IS_Xt; + case 7: + return MISCREG_TLBI_VAALE1IS_Xt; + } + break; + case 7: + switch (op2) { + case 0: + return MISCREG_TLBI_VMALLE1; + case 1: + return MISCREG_TLBI_VAE1_Xt; + case 2: + return MISCREG_TLBI_ASIDE1_Xt; + case 3: + return MISCREG_TLBI_VAAE1_Xt; + case 5: + return MISCREG_TLBI_VALE1_Xt; + case 7: + return MISCREG_TLBI_VAALE1_Xt; + } + break; + } + break; + case 4: + switch (crm) { + case 0: + switch (op2) { + case 1: + return MISCREG_TLBI_IPAS2E1IS_Xt; + case 5: + return MISCREG_TLBI_IPAS2LE1IS_Xt; + } + break; + case 3: + switch (op2) { + case 0: + return MISCREG_TLBI_ALLE2IS; + case 1: + return MISCREG_TLBI_VAE2IS_Xt; + case 4: + return MISCREG_TLBI_ALLE1IS; + case 5: + return MISCREG_TLBI_VALE2IS_Xt; + case 6: + return MISCREG_TLBI_VMALLS12E1IS; + } + break; + case 4: + switch (op2) { + case 1: + return MISCREG_TLBI_IPAS2E1_Xt; + case 5: + return MISCREG_TLBI_IPAS2LE1_Xt; + } + break; + case 7: + switch (op2) { + case 0: + return MISCREG_TLBI_ALLE2; + case 1: + return MISCREG_TLBI_VAE2_Xt; + case 4: + return MISCREG_TLBI_ALLE1; + case 5: + return MISCREG_TLBI_VALE2_Xt; + case 6: + return MISCREG_TLBI_VMALLS12E1; + } + break; + } + break; + case 6: + switch (crm) { + case 3: + switch (op2) { + case 0: + return MISCREG_TLBI_ALLE3IS; + case 1: + return MISCREG_TLBI_VAE3IS_Xt; + case 5: + return MISCREG_TLBI_VALE3IS_Xt; + } + break; + case 7: + switch (op2) { + case 0: + return MISCREG_TLBI_ALLE3; + case 1: + return MISCREG_TLBI_VAE3_Xt; + case 5: + return MISCREG_TLBI_VALE3_Xt; + } + break; + } + break; + } + break; + } + break; + case 2: + switch (crn) { + case 0: + switch (op1) { + case 0: + switch (crm) { + case 0: + switch (op2) { + case 2: + return MISCREG_OSDTRRX_EL1; + case 4: + return MISCREG_DBGBVR0_EL1; + case 5: + return MISCREG_DBGBCR0_EL1; + case 6: + return MISCREG_DBGWVR0_EL1; + case 7: + return MISCREG_DBGWCR0_EL1; + } + break; + case 1: + switch (op2) { + case 4: + return MISCREG_DBGBVR1_EL1; + case 5: + return MISCREG_DBGBCR1_EL1; + case 6: + return MISCREG_DBGWVR1_EL1; + case 7: + return MISCREG_DBGWCR1_EL1; + } + break; + case 2: + switch (op2) { + case 0: + return MISCREG_MDCCINT_EL1; + case 2: + return MISCREG_MDSCR_EL1; + case 4: + return MISCREG_DBGBVR2_EL1; + case 5: + return MISCREG_DBGBCR2_EL1; + case 6: + return MISCREG_DBGWVR2_EL1; + case 7: + return MISCREG_DBGWCR2_EL1; + } + break; + case 3: + switch (op2) { + case 2: + return MISCREG_OSDTRTX_EL1; + case 4: + return MISCREG_DBGBVR3_EL1; + case 5: + return MISCREG_DBGBCR3_EL1; + case 6: + return MISCREG_DBGWVR3_EL1; + case 7: + return MISCREG_DBGWCR3_EL1; + } + break; + case 4: + switch (op2) { + case 4: + return MISCREG_DBGBVR4_EL1; + case 5: + return MISCREG_DBGBCR4_EL1; + } + break; + case 5: + switch (op2) { + case 4: + return MISCREG_DBGBVR5_EL1; + case 5: + return MISCREG_DBGBCR5_EL1; + } + break; + case 6: + switch (op2) { + case 2: + return MISCREG_OSECCR_EL1; + } + break; + } + break; + case 2: + switch (crm) { + case 0: + switch (op2) { + case 0: + return MISCREG_TEECR32_EL1; + } + break; + } + break; + case 3: + switch (crm) { + case 1: + switch (op2) { + case 0: + return MISCREG_MDCCSR_EL0; + } + break; + case 4: + switch (op2) { + case 0: + return MISCREG_MDDTR_EL0; + } + break; + case 5: + switch (op2) { + case 0: + return MISCREG_MDDTRRX_EL0; + } + break; + } + break; + case 4: + switch (crm) { + case 7: + switch (op2) { + case 0: + return MISCREG_DBGVCR32_EL2; + } + break; + } + break; + } + break; + case 1: + switch (op1) { + case 0: + switch (crm) { + case 0: + switch (op2) { + case 0: + return MISCREG_MDRAR_EL1; + case 4: + return MISCREG_OSLAR_EL1; + } + break; + case 1: + switch (op2) { + case 4: + return MISCREG_OSLSR_EL1; + } + break; + case 3: + switch (op2) { + case 4: + return MISCREG_OSDLR_EL1; + } + break; + case 4: + switch (op2) { + case 4: + return MISCREG_DBGPRCR_EL1; + } + break; + } + break; + case 2: + switch (crm) { + case 0: + switch (op2) { + case 0: + return MISCREG_TEEHBR32_EL1; + } + break; + } + break; + } + break; + case 7: + switch (op1) { + case 0: + switch (crm) { + case 8: + switch (op2) { + case 6: + return MISCREG_DBGCLAIMSET_EL1; + } + break; + case 9: + switch (op2) { + case 6: + return MISCREG_DBGCLAIMCLR_EL1; + } + break; + case 14: + switch (op2) { + case 6: + return MISCREG_DBGAUTHSTATUS_EL1; + } + break; + } + break; + } + break; + } + break; + case 3: + switch (crn) { + case 0: + switch (op1) { + case 0: + switch (crm) { + case 0: + switch (op2) { + case 0: + return MISCREG_MIDR_EL1; + case 5: + return MISCREG_MPIDR_EL1; + case 6: + return MISCREG_REVIDR_EL1; + } + break; + case 1: + switch (op2) { + case 0: + return MISCREG_ID_PFR0_EL1; + case 1: + return MISCREG_ID_PFR1_EL1; + case 2: + return MISCREG_ID_DFR0_EL1; + case 3: + return MISCREG_ID_AFR0_EL1; + case 4: + return MISCREG_ID_MMFR0_EL1; + case 5: + return MISCREG_ID_MMFR1_EL1; + case 6: + return MISCREG_ID_MMFR2_EL1; + case 7: + return MISCREG_ID_MMFR3_EL1; + } + break; + case 2: + switch (op2) { + case 0: + return MISCREG_ID_ISAR0_EL1; + case 1: + return MISCREG_ID_ISAR1_EL1; + case 2: + return MISCREG_ID_ISAR2_EL1; + case 3: + return MISCREG_ID_ISAR3_EL1; + case 4: + return MISCREG_ID_ISAR4_EL1; + case 5: + return MISCREG_ID_ISAR5_EL1; + } + break; + case 3: + switch (op2) { + case 0: + return MISCREG_MVFR0_EL1; + case 1: + return MISCREG_MVFR1_EL1; + case 2: + return MISCREG_MVFR2_EL1; + case 3 ... 7: + return MISCREG_RAZ; + } + break; + case 4: + switch (op2) { + case 0: + return MISCREG_ID_AA64PFR0_EL1; + case 1: + return MISCREG_ID_AA64PFR1_EL1; + case 2 ... 7: + return MISCREG_RAZ; + } + break; + case 5: + switch (op2) { + case 0: + return MISCREG_ID_AA64DFR0_EL1; + case 1: + return MISCREG_ID_AA64DFR1_EL1; + case 4: + return MISCREG_ID_AA64AFR0_EL1; + case 5: + return MISCREG_ID_AA64AFR1_EL1; + case 2: + case 3: + case 6: + case 7: + return MISCREG_RAZ; + } + break; + case 6: + switch (op2) { + case 0: + return MISCREG_ID_AA64ISAR0_EL1; + case 1: + return MISCREG_ID_AA64ISAR1_EL1; + case 2 ... 7: + return MISCREG_RAZ; + } + break; + case 7: + switch (op2) { + case 0: + return MISCREG_ID_AA64MMFR0_EL1; + case 1: + return MISCREG_ID_AA64MMFR1_EL1; + case 2 ... 7: + return MISCREG_RAZ; + } + break; + } + break; + case 1: + switch (crm) { + case 0: + switch (op2) { + case 0: + return MISCREG_CCSIDR_EL1; + case 1: + return MISCREG_CLIDR_EL1; + case 7: + return MISCREG_AIDR_EL1; + } + break; + } + break; + case 2: + switch (crm) { + case 0: + switch (op2) { + case 0: + return MISCREG_CSSELR_EL1; + } + break; + } + break; + case 3: + switch (crm) { + case 0: + switch (op2) { + case 1: + return MISCREG_CTR_EL0; + case 7: + return MISCREG_DCZID_EL0; + } + break; + } + break; + case 4: + switch (crm) { + case 0: + switch (op2) { + case 0: + return MISCREG_VPIDR_EL2; + case 5: + return MISCREG_VMPIDR_EL2; + } + break; + } + break; + } + break; + case 1: + switch (op1) { + case 0: + switch (crm) { + case 0: + switch (op2) { + case 0: + return MISCREG_SCTLR_EL1; + case 1: + return MISCREG_ACTLR_EL1; + case 2: + return MISCREG_CPACR_EL1; + } + break; + } + break; + case 4: + switch (crm) { + case 0: + switch (op2) { + case 0: + return MISCREG_SCTLR_EL2; + case 1: + return MISCREG_ACTLR_EL2; + } + break; + case 1: + switch (op2) { + case 0: + return MISCREG_HCR_EL2; + case 1: + return MISCREG_MDCR_EL2; + case 2: + return MISCREG_CPTR_EL2; + case 3: + return MISCREG_HSTR_EL2; + case 7: + return MISCREG_HACR_EL2; + } + break; + } + break; + case 6: + switch (crm) { + case 0: + switch (op2) { + case 0: + return MISCREG_SCTLR_EL3; + case 1: + return MISCREG_ACTLR_EL3; + } + break; + case 1: + switch (op2) { + case 0: + return MISCREG_SCR_EL3; + case 1: + return MISCREG_SDER32_EL3; + case 2: + return MISCREG_CPTR_EL3; + } + break; + case 3: + switch (op2) { + case 1: + return MISCREG_MDCR_EL3; + } + break; + } + break; + } + break; + case 2: + switch (op1) { + case 0: + switch (crm) { + case 0: + switch (op2) { + case 0: + return MISCREG_TTBR0_EL1; + case 1: + return MISCREG_TTBR1_EL1; + case 2: + return MISCREG_TCR_EL1; + } + break; + } + break; + case 4: + switch (crm) { + case 0: + switch (op2) { + case 0: + return MISCREG_TTBR0_EL2; + case 2: + return MISCREG_TCR_EL2; + } + break; + case 1: + switch (op2) { + case 0: + return MISCREG_VTTBR_EL2; + case 2: + return MISCREG_VTCR_EL2; + } + break; + } + break; + case 6: + switch (crm) { + case 0: + switch (op2) { + case 0: + return MISCREG_TTBR0_EL3; + case 2: + return MISCREG_TCR_EL3; + } + break; + } + break; + } + break; + case 3: + switch (op1) { + case 4: + switch (crm) { + case 0: + switch (op2) { + case 0: + return MISCREG_DACR32_EL2; + } + break; + } + break; + } + break; + case 4: + switch (op1) { + case 0: + switch (crm) { + case 0: + switch (op2) { + case 0: + return MISCREG_SPSR_EL1; + case 1: + return MISCREG_ELR_EL1; + } + break; + case 1: + switch (op2) { + case 0: + return MISCREG_SP_EL0; + } + break; + case 2: + switch (op2) { + case 0: + return MISCREG_SPSEL; + case 2: + return MISCREG_CURRENTEL; + } + break; + } + break; + case 3: + switch (crm) { + case 2: + switch (op2) { + case 0: + return MISCREG_NZCV; + case 1: + return MISCREG_DAIF; + } + break; + case 4: + switch (op2) { + case 0: + return MISCREG_FPCR; + case 1: + return MISCREG_FPSR; + } + break; + case 5: + switch (op2) { + case 0: + return MISCREG_DSPSR_EL0; + case 1: + return MISCREG_DLR_EL0; + } + break; + } + break; + case 4: + switch (crm) { + case 0: + switch (op2) { + case 0: + return MISCREG_SPSR_EL2; + case 1: + return MISCREG_ELR_EL2; + } + break; + case 1: + switch (op2) { + case 0: + return MISCREG_SP_EL1; + } + break; + case 3: + switch (op2) { + case 0: + return MISCREG_SPSR_IRQ_AA64; + case 1: + return MISCREG_SPSR_ABT_AA64; + case 2: + return MISCREG_SPSR_UND_AA64; + case 3: + return MISCREG_SPSR_FIQ_AA64; + } + break; + } + break; + case 6: + switch (crm) { + case 0: + switch (op2) { + case 0: + return MISCREG_SPSR_EL3; + case 1: + return MISCREG_ELR_EL3; + } + break; + case 1: + switch (op2) { + case 0: + return MISCREG_SP_EL2; + } + break; + } + break; + } + break; + case 5: + switch (op1) { + case 0: + switch (crm) { + case 1: + switch (op2) { + case 0: + return MISCREG_AFSR0_EL1; + case 1: + return MISCREG_AFSR1_EL1; + } + break; + case 2: + switch (op2) { + case 0: + return MISCREG_ESR_EL1; + } + break; + } + break; + case 4: + switch (crm) { + case 0: + switch (op2) { + case 1: + return MISCREG_IFSR32_EL2; + } + break; + case 1: + switch (op2) { + case 0: + return MISCREG_AFSR0_EL2; + case 1: + return MISCREG_AFSR1_EL2; + } + break; + case 2: + switch (op2) { + case 0: + return MISCREG_ESR_EL2; + } + break; + case 3: + switch (op2) { + case 0: + return MISCREG_FPEXC32_EL2; + } + break; + } + break; + case 6: + switch (crm) { + case 1: + switch (op2) { + case 0: + return MISCREG_AFSR0_EL3; + case 1: + return MISCREG_AFSR1_EL3; + } + break; + case 2: + switch (op2) { + case 0: + return MISCREG_ESR_EL3; + } + break; + } + break; + } + break; + case 6: + switch (op1) { + case 0: + switch (crm) { + case 0: + switch (op2) { + case 0: + return MISCREG_FAR_EL1; + } + break; + } + break; + case 4: + switch (crm) { + case 0: + switch (op2) { + case 0: + return MISCREG_FAR_EL2; + case 4: + return MISCREG_HPFAR_EL2; + } + break; + } + break; + case 6: + switch (crm) { + case 0: + switch (op2) { + case 0: + return MISCREG_FAR_EL3; + } + break; + } + break; + } + break; + case 7: + switch (op1) { + case 0: + switch (crm) { + case 4: + switch (op2) { + case 0: + return MISCREG_PAR_EL1; + } + break; + } + break; + } + break; + case 9: + switch (op1) { + case 0: + switch (crm) { + case 14: + switch (op2) { + case 1: + return MISCREG_PMINTENSET_EL1; + case 2: + return MISCREG_PMINTENCLR_EL1; + } + break; + } + break; + case 3: + switch (crm) { + case 12: + switch (op2) { + case 0: + return MISCREG_PMCR_EL0; + case 1: + return MISCREG_PMCNTENSET_EL0; + case 2: + return MISCREG_PMCNTENCLR_EL0; + case 3: + return MISCREG_PMOVSCLR_EL0; + case 4: + return MISCREG_PMSWINC_EL0; + case 5: + return MISCREG_PMSELR_EL0; + case 6: + return MISCREG_PMCEID0_EL0; + case 7: + return MISCREG_PMCEID1_EL0; + } + break; + case 13: + switch (op2) { + case 0: + return MISCREG_PMCCNTR_EL0; + case 1: + return MISCREG_PMCCFILTR_EL0; + case 2: + return MISCREG_PMXEVCNTR_EL0; + } + break; + case 14: + switch (op2) { + case 0: + return MISCREG_PMUSERENR_EL0; + case 3: + return MISCREG_PMOVSSET_EL0; + } + break; + } + break; + } + break; + case 10: + switch (op1) { + case 0: + switch (crm) { + case 2: + switch (op2) { + case 0: + return MISCREG_MAIR_EL1; + } + break; + case 3: + switch (op2) { + case 0: + return MISCREG_AMAIR_EL1; + } + break; + } + break; + case 4: + switch (crm) { + case 2: + switch (op2) { + case 0: + return MISCREG_MAIR_EL2; + } + break; + case 3: + switch (op2) { + case 0: + return MISCREG_AMAIR_EL2; + } + break; + } + break; + case 6: + switch (crm) { + case 2: + switch (op2) { + case 0: + return MISCREG_MAIR_EL3; + } + break; + case 3: + switch (op2) { + case 0: + return MISCREG_AMAIR_EL3; + } + break; + } + break; + } + break; + case 11: + switch (op1) { + case 1: + switch (crm) { + case 0: + switch (op2) { + case 2: + return MISCREG_L2CTLR_EL1; + case 3: + return MISCREG_L2ECTLR_EL1; + } + break; + } + break; + } + break; + case 12: + switch (op1) { + case 0: + switch (crm) { + case 0: + switch (op2) { + case 0: + return MISCREG_VBAR_EL1; + case 1: + return MISCREG_RVBAR_EL1; + } + break; + case 1: + switch (op2) { + case 0: + return MISCREG_ISR_EL1; + } + break; + } + break; + case 4: + switch (crm) { + case 0: + switch (op2) { + case 0: + return MISCREG_VBAR_EL2; + case 1: + return MISCREG_RVBAR_EL2; + } + break; + } + break; + case 6: + switch (crm) { + case 0: + switch (op2) { + case 0: + return MISCREG_VBAR_EL3; + case 1: + return MISCREG_RVBAR_EL3; + case 2: + return MISCREG_RMR_EL3; + } + break; + } + break; + } + break; + case 13: + switch (op1) { + case 0: + switch (crm) { + case 0: + switch (op2) { + case 1: + return MISCREG_CONTEXTIDR_EL1; + case 4: + return MISCREG_TPIDR_EL1; + } + break; + } + break; + case 3: + switch (crm) { + case 0: + switch (op2) { + case 2: + return MISCREG_TPIDR_EL0; + case 3: + return MISCREG_TPIDRRO_EL0; + } + break; + } + break; + case 4: + switch (crm) { + case 0: + switch (op2) { + case 2: + return MISCREG_TPIDR_EL2; + } + break; + } + break; + case 6: + switch (crm) { + case 0: + switch (op2) { + case 2: + return MISCREG_TPIDR_EL3; + } + break; + } + break; + } + break; + case 14: + switch (op1) { + case 0: + switch (crm) { + case 1: + switch (op2) { + case 0: + return MISCREG_CNTKCTL_EL1; + } + break; + } + break; + case 3: + switch (crm) { + case 0: + switch (op2) { + case 0: + return MISCREG_CNTFRQ_EL0; + case 1: + return MISCREG_CNTPCT_EL0; + case 2: + return MISCREG_CNTVCT_EL0; + } + break; + case 2: + switch (op2) { + case 0: + return MISCREG_CNTP_TVAL_EL0; + case 1: + return MISCREG_CNTP_CTL_EL0; + case 2: + return MISCREG_CNTP_CVAL_EL0; + } + break; + case 3: + switch (op2) { + case 0: + return MISCREG_CNTV_TVAL_EL0; + case 1: + return MISCREG_CNTV_CTL_EL0; + case 2: + return MISCREG_CNTV_CVAL_EL0; + } + break; + case 8: + switch (op2) { + case 0: + return MISCREG_PMEVCNTR0_EL0; + case 1: + return MISCREG_PMEVCNTR1_EL0; + case 2: + return MISCREG_PMEVCNTR2_EL0; + case 3: + return MISCREG_PMEVCNTR3_EL0; + case 4: + return MISCREG_PMEVCNTR4_EL0; + case 5: + return MISCREG_PMEVCNTR5_EL0; + } + break; + case 12: + switch (op2) { + case 0: + return MISCREG_PMEVTYPER0_EL0; + case 1: + return MISCREG_PMEVTYPER1_EL0; + case 2: + return MISCREG_PMEVTYPER2_EL0; + case 3: + return MISCREG_PMEVTYPER3_EL0; + case 4: + return MISCREG_PMEVTYPER4_EL0; + case 5: + return MISCREG_PMEVTYPER5_EL0; + } + break; + } + break; + case 4: + switch (crm) { + case 0: + switch (op2) { + case 3: + return MISCREG_CNTVOFF_EL2; + } + break; + case 1: + switch (op2) { + case 0: + return MISCREG_CNTHCTL_EL2; + } + break; + case 2: + switch (op2) { + case 0: + return MISCREG_CNTHP_TVAL_EL2; + case 1: + return MISCREG_CNTHP_CTL_EL2; + case 2: + return MISCREG_CNTHP_CVAL_EL2; + } + break; + } + break; + case 7: + switch (crm) { + case 2: + switch (op2) { + case 0: + return MISCREG_CNTPS_TVAL_EL1; + case 1: + return MISCREG_CNTPS_CTL_EL1; + case 2: + return MISCREG_CNTPS_CVAL_EL1; + } + break; + } + break; + } + break; + case 15: + switch (op1) { + case 0: + switch (crm) { + case 0: + switch (op2) { + case 0: + return MISCREG_IL1DATA0_EL1; + case 1: + return MISCREG_IL1DATA1_EL1; + case 2: + return MISCREG_IL1DATA2_EL1; + case 3: + return MISCREG_IL1DATA3_EL1; + } + break; + case 1: + switch (op2) { + case 0: + return MISCREG_DL1DATA0_EL1; + case 1: + return MISCREG_DL1DATA1_EL1; + case 2: + return MISCREG_DL1DATA2_EL1; + case 3: + return MISCREG_DL1DATA3_EL1; + case 4: + return MISCREG_DL1DATA4_EL1; + } + break; + } + break; + case 1: + switch (crm) { + case 0: + switch (op2) { + case 0: + return MISCREG_L2ACTLR_EL1; + } + break; + case 2: + switch (op2) { + case 0: + return MISCREG_CPUACTLR_EL1; + case 1: + return MISCREG_CPUECTLR_EL1; + case 2: + return MISCREG_CPUMERRSR_EL1; + case 3: + return MISCREG_L2MERRSR_EL1; + } + break; + case 3: + switch (op2) { + case 0: + return MISCREG_CBAR_EL1; + + } + break; + } + break; + } + break; + } + break; + } + + return MISCREG_UNKNOWN; +} + +} // namespace ArmISA diff --git a/src/arch/arm/miscregs.hh b/src/arch/arm/miscregs.hh index 13234ddf5..c447dcd27 100644 --- a/src/arch/arm/miscregs.hh +++ b/src/arch/arm/miscregs.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2012 ARM Limited + * Copyright (c) 2010-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -38,13 +38,19 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Gabe Black + * Giacomo Gabrielli */ #ifndef __ARCH_ARM_MISCREGS_HH__ #define __ARCH_ARM_MISCREGS_HH__ +#include <bitset> + #include "base/bitunion.hh" #include "base/compiler.hh" +class ThreadContext; + + namespace ArmISA { enum ConditionCode { @@ -67,284 +73,1330 @@ namespace ArmISA }; enum MiscRegIndex { - MISCREG_CPSR = 0, - MISCREG_CPSR_Q, - MISCREG_SPSR, - MISCREG_SPSR_FIQ, - MISCREG_SPSR_IRQ, - MISCREG_SPSR_SVC, - MISCREG_SPSR_MON, - MISCREG_SPSR_UND, - MISCREG_SPSR_ABT, - MISCREG_FPSR, - MISCREG_FPSID, - MISCREG_FPSCR, - MISCREG_FPSCR_QC, // Cumulative saturation flag - MISCREG_FPSCR_EXC, // Cumulative FP exception flags - MISCREG_FPEXC, - MISCREG_MVFR0, - MISCREG_MVFR1, - MISCREG_SCTLR_RST, - MISCREG_SEV_MAILBOX, - - // CP14 registers - MISCREG_CP14_START, - MISCREG_DBGDIDR = MISCREG_CP14_START, - MISCREG_DBGDSCR_INT, - MISCREG_DBGDTRRX_INT, - MISCREG_DBGTRTX_INT, - MISCREG_DBGWFAR, - MISCREG_DBGVCR, - MISCREG_DBGECR, - MISCREG_DBGDSCCR, - MISCREG_DBGSMCR, - MISCREG_DBGDTRRX_EXT, - MISCREG_DBGDSCR_EXT, - MISCREG_DBGDTRTX_EXT, - MISCREG_DBGDRCR, - MISCREG_DBGBVR, - MISCREG_DBGBCR, - MISCREG_DBGBVR_M, - MISCREG_DBGBCR_M, - MISCREG_DBGDRAR, - MISCREG_DBGBXVR_M, - MISCREG_DBGOSLAR, - MISCREG_DBGOSSRR, - MISCREG_DBGOSDLR, - MISCREG_DBGPRCR, - MISCREG_DBGPRSR, - MISCREG_DBGDSAR, - MISCREG_DBGITCTRL, - MISCREG_DBGCLAIMSET, - MISCREG_DBGCLAIMCLR, - MISCREG_DBGAUTHSTATUS, - MISCREG_DBGDEVID2, - MISCREG_DBGDEVID1, - MISCREG_DBGDEVID, - MISCREG_TEEHBR, - - // CP15 registers - MISCREG_CP15_START, - MISCREG_SCTLR = MISCREG_CP15_START, - MISCREG_DCCISW, - MISCREG_DCCIMVAC, - MISCREG_DCCMVAC, - MISCREG_CONTEXTIDR, - MISCREG_TPIDRURW, - MISCREG_TPIDRURO, - MISCREG_TPIDRPRW, - MISCREG_CP15ISB, - MISCREG_CP15DSB, - MISCREG_CP15DMB, - MISCREG_CPACR, - MISCREG_CLIDR, - MISCREG_CCSIDR, - MISCREG_CSSELR, - MISCREG_ICIALLUIS, - MISCREG_ICIALLU, - MISCREG_ICIMVAU, - MISCREG_BPIMVA, - MISCREG_BPIALLIS, - MISCREG_BPIALL, - MISCREG_MIDR, - MISCREG_TTBR0, - MISCREG_TTBR1, - MISCREG_TLBTR, - MISCREG_DACR, - MISCREG_TLBIALLIS, - MISCREG_TLBIMVAIS, - MISCREG_TLBIASIDIS, - MISCREG_TLBIMVAAIS, - MISCREG_ITLBIALL, - MISCREG_ITLBIMVA, - MISCREG_ITLBIASID, - MISCREG_DTLBIALL, - MISCREG_DTLBIMVA, - MISCREG_DTLBIASID, - MISCREG_TLBIALL, - MISCREG_TLBIMVA, - MISCREG_TLBIASID, - MISCREG_TLBIMVAA, - MISCREG_DFSR, - MISCREG_IFSR, - MISCREG_DFAR, - MISCREG_IFAR, - MISCREG_MPIDR, - MISCREG_PRRR, - MISCREG_NMRR, - MISCREG_TTBCR, - MISCREG_ID_PFR0, - MISCREG_CTR, - MISCREG_SCR, - MISCREG_SDER, - MISCREG_PAR, - MISCREG_V2PCWPR, - MISCREG_V2PCWPW, - MISCREG_V2PCWUR, - MISCREG_V2PCWUW, - MISCREG_V2POWPR, - MISCREG_V2POWPW, - MISCREG_V2POWUR, - MISCREG_V2POWUW, - MISCREG_ID_MMFR0, - MISCREG_ID_MMFR2, - MISCREG_ID_MMFR3, - MISCREG_ACTLR, - MISCREG_PMCR, - MISCREG_PMCCNTR, - MISCREG_PMCNTENSET, - MISCREG_PMCNTENCLR, - MISCREG_PMOVSR, - MISCREG_PMSWINC, - MISCREG_PMSELR, - MISCREG_PMCEID0, - MISCREG_PMCEID1, - MISCREG_PMC_OTHER, - MISCREG_PMXEVCNTR, - MISCREG_PMUSERENR, - MISCREG_PMINTENSET, - MISCREG_PMINTENCLR, - MISCREG_ID_ISAR0, - MISCREG_ID_ISAR1, - MISCREG_ID_ISAR2, - MISCREG_ID_ISAR3, - MISCREG_ID_ISAR4, - MISCREG_ID_ISAR5, - MISCREG_LOCKFLAG, - MISCREG_LOCKADDR, - MISCREG_ID_PFR1, - MISCREG_L2CTLR, - MISCREG_CP15_UNIMP_START, - MISCREG_TCMTR = MISCREG_CP15_UNIMP_START, - MISCREG_ID_DFR0, - MISCREG_ID_AFR0, - MISCREG_ID_MMFR1, - MISCREG_AIDR, - MISCREG_ADFSR, - MISCREG_AIFSR, - MISCREG_DCIMVAC, - MISCREG_DCISW, - MISCREG_MCCSW, - MISCREG_DCCMVAU, - MISCREG_NSACR, - MISCREG_VBAR, - MISCREG_MVBAR, - MISCREG_ISR, - MISCREG_FCEIDR, - MISCREG_L2LATENCY, - MISCREG_CRN15, - - - MISCREG_CP15_END, - - // Dummy indices - MISCREG_NOP = MISCREG_CP15_END, - MISCREG_RAZ, - - NUM_MISCREGS + MISCREG_CPSR = 0, // 0 + MISCREG_SPSR, // 1 + MISCREG_SPSR_FIQ, // 2 + MISCREG_SPSR_IRQ, // 3 + MISCREG_SPSR_SVC, // 4 + MISCREG_SPSR_MON, // 5 + MISCREG_SPSR_ABT, // 6 + MISCREG_SPSR_HYP, // 7 + MISCREG_SPSR_UND, // 8 + MISCREG_ELR_HYP, // 9 + MISCREG_FPSID, // 10 + MISCREG_FPSCR, // 11 + MISCREG_MVFR1, // 12 + MISCREG_MVFR0, // 13 + MISCREG_FPEXC, // 14 + + // Helper registers + MISCREG_CPSR_MODE, // 15 + MISCREG_CPSR_Q, // 16 + MISCREG_FPSCR_EXC, // 17 + MISCREG_FPSCR_QC, // 18 + MISCREG_LOCKADDR, // 19 + MISCREG_LOCKFLAG, // 20 + MISCREG_PRRR_MAIR0, // 21 + MISCREG_PRRR_MAIR0_NS, // 22 + MISCREG_PRRR_MAIR0_S, // 23 + MISCREG_NMRR_MAIR1, // 24 + MISCREG_NMRR_MAIR1_NS, // 25 + MISCREG_NMRR_MAIR1_S, // 26 + MISCREG_PMXEVTYPER_PMCCFILTR, // 27 + MISCREG_SCTLR_RST, // 28 + MISCREG_SEV_MAILBOX, // 29 + + // AArch32 CP14 registers (debug/trace/ThumbEE/Jazelle control) + MISCREG_DBGDIDR, // 30 + MISCREG_DBGDSCRint, // 31 + MISCREG_DBGDCCINT, // 32 + MISCREG_DBGDTRTXint, // 33 + MISCREG_DBGDTRRXint, // 34 + MISCREG_DBGWFAR, // 35 + MISCREG_DBGVCR, // 36 + MISCREG_DBGDTRRXext, // 37 + MISCREG_DBGDSCRext, // 38 + MISCREG_DBGDTRTXext, // 39 + MISCREG_DBGOSECCR, // 40 + MISCREG_DBGBVR0, // 41 + MISCREG_DBGBVR1, // 42 + MISCREG_DBGBVR2, // 43 + MISCREG_DBGBVR3, // 44 + MISCREG_DBGBVR4, // 45 + MISCREG_DBGBVR5, // 46 + MISCREG_DBGBCR0, // 47 + MISCREG_DBGBCR1, // 48 + MISCREG_DBGBCR2, // 49 + MISCREG_DBGBCR3, // 50 + MISCREG_DBGBCR4, // 51 + MISCREG_DBGBCR5, // 52 + MISCREG_DBGWVR0, // 53 + MISCREG_DBGWVR1, // 54 + MISCREG_DBGWVR2, // 55 + MISCREG_DBGWVR3, // 56 + MISCREG_DBGWCR0, // 57 + MISCREG_DBGWCR1, // 58 + MISCREG_DBGWCR2, // 59 + MISCREG_DBGWCR3, // 60 + MISCREG_DBGDRAR, // 61 + MISCREG_DBGBXVR4, // 62 + MISCREG_DBGBXVR5, // 63 + MISCREG_DBGOSLAR, // 64 + MISCREG_DBGOSLSR, // 65 + MISCREG_DBGOSDLR, // 66 + MISCREG_DBGPRCR, // 67 + MISCREG_DBGDSAR, // 68 + MISCREG_DBGCLAIMSET, // 69 + MISCREG_DBGCLAIMCLR, // 70 + MISCREG_DBGAUTHSTATUS, // 71 + MISCREG_DBGDEVID2, // 72 + MISCREG_DBGDEVID1, // 73 + MISCREG_DBGDEVID0, // 74 + MISCREG_TEECR, // 75 + MISCREG_JIDR, // 76 + MISCREG_TEEHBR, // 77 + MISCREG_JOSCR, // 78 + MISCREG_JMCR, // 79 + + // AArch32 CP15 registers (system control) + MISCREG_MIDR, // 80 + MISCREG_CTR, // 81 + MISCREG_TCMTR, // 82 + MISCREG_TLBTR, // 83 + MISCREG_MPIDR, // 84 + MISCREG_REVIDR, // 85 + MISCREG_ID_PFR0, // 86 + MISCREG_ID_PFR1, // 87 + MISCREG_ID_DFR0, // 88 + MISCREG_ID_AFR0, // 89 + MISCREG_ID_MMFR0, // 90 + MISCREG_ID_MMFR1, // 91 + MISCREG_ID_MMFR2, // 92 + MISCREG_ID_MMFR3, // 93 + MISCREG_ID_ISAR0, // 94 + MISCREG_ID_ISAR1, // 95 + MISCREG_ID_ISAR2, // 96 + MISCREG_ID_ISAR3, // 97 + MISCREG_ID_ISAR4, // 98 + MISCREG_ID_ISAR5, // 99 + MISCREG_CCSIDR, // 100 + MISCREG_CLIDR, // 101 + MISCREG_AIDR, // 102 + MISCREG_CSSELR, // 103 + MISCREG_CSSELR_NS, // 104 + MISCREG_CSSELR_S, // 105 + MISCREG_VPIDR, // 106 + MISCREG_VMPIDR, // 107 + MISCREG_SCTLR, // 108 + MISCREG_SCTLR_NS, // 109 + MISCREG_SCTLR_S, // 110 + MISCREG_ACTLR, // 111 + MISCREG_ACTLR_NS, // 112 + MISCREG_ACTLR_S, // 113 + MISCREG_CPACR, // 114 + MISCREG_SCR, // 115 + MISCREG_SDER, // 116 + MISCREG_NSACR, // 117 + MISCREG_HSCTLR, // 118 + MISCREG_HACTLR, // 119 + MISCREG_HCR, // 120 + MISCREG_HDCR, // 121 + MISCREG_HCPTR, // 122 + MISCREG_HSTR, // 123 + MISCREG_HACR, // 124 + MISCREG_TTBR0, // 125 + MISCREG_TTBR0_NS, // 126 + MISCREG_TTBR0_S, // 127 + MISCREG_TTBR1, // 128 + MISCREG_TTBR1_NS, // 129 + MISCREG_TTBR1_S, // 130 + MISCREG_TTBCR, // 131 + MISCREG_TTBCR_NS, // 132 + MISCREG_TTBCR_S, // 133 + MISCREG_HTCR, // 134 + MISCREG_VTCR, // 135 + MISCREG_DACR, // 136 + MISCREG_DACR_NS, // 137 + MISCREG_DACR_S, // 138 + MISCREG_DFSR, // 139 + MISCREG_DFSR_NS, // 140 + MISCREG_DFSR_S, // 141 + MISCREG_IFSR, // 142 + MISCREG_IFSR_NS, // 143 + MISCREG_IFSR_S, // 144 + MISCREG_ADFSR, // 145 + MISCREG_ADFSR_NS, // 146 + MISCREG_ADFSR_S, // 147 + MISCREG_AIFSR, // 148 + MISCREG_AIFSR_NS, // 149 + MISCREG_AIFSR_S, // 150 + MISCREG_HADFSR, // 151 + MISCREG_HAIFSR, // 152 + MISCREG_HSR, // 153 + MISCREG_DFAR, // 154 + MISCREG_DFAR_NS, // 155 + MISCREG_DFAR_S, // 156 + MISCREG_IFAR, // 157 + MISCREG_IFAR_NS, // 158 + MISCREG_IFAR_S, // 159 + MISCREG_HDFAR, // 160 + MISCREG_HIFAR, // 161 + MISCREG_HPFAR, // 162 + MISCREG_ICIALLUIS, // 163 + MISCREG_BPIALLIS, // 164 + MISCREG_PAR, // 165 + MISCREG_PAR_NS, // 166 + MISCREG_PAR_S, // 167 + MISCREG_ICIALLU, // 168 + MISCREG_ICIMVAU, // 169 + MISCREG_CP15ISB, // 170 + MISCREG_BPIALL, // 171 + MISCREG_BPIMVA, // 172 + MISCREG_DCIMVAC, // 173 + MISCREG_DCISW, // 174 + MISCREG_ATS1CPR, // 175 + MISCREG_ATS1CPW, // 176 + MISCREG_ATS1CUR, // 177 + MISCREG_ATS1CUW, // 178 + MISCREG_ATS12NSOPR, // 179 + MISCREG_ATS12NSOPW, // 180 + MISCREG_ATS12NSOUR, // 181 + MISCREG_ATS12NSOUW, // 182 + MISCREG_DCCMVAC, // 183 + MISCREG_DCCSW, // 184 + MISCREG_CP15DSB, // 185 + MISCREG_CP15DMB, // 186 + MISCREG_DCCMVAU, // 187 + MISCREG_DCCIMVAC, // 188 + MISCREG_DCCISW, // 189 + MISCREG_ATS1HR, // 190 + MISCREG_ATS1HW, // 191 + MISCREG_TLBIALLIS, // 192 + MISCREG_TLBIMVAIS, // 193 + MISCREG_TLBIASIDIS, // 194 + MISCREG_TLBIMVAAIS, // 195 + MISCREG_TLBIMVALIS, // 196 + MISCREG_TLBIMVAALIS, // 197 + MISCREG_ITLBIALL, // 198 + MISCREG_ITLBIMVA, // 199 + MISCREG_ITLBIASID, // 200 + MISCREG_DTLBIALL, // 201 + MISCREG_DTLBIMVA, // 202 + MISCREG_DTLBIASID, // 203 + MISCREG_TLBIALL, // 204 + MISCREG_TLBIMVA, // 205 + MISCREG_TLBIASID, // 206 + MISCREG_TLBIMVAA, // 207 + MISCREG_TLBIMVAL, // 208 + MISCREG_TLBIMVAAL, // 209 + MISCREG_TLBIIPAS2IS, // 210 + MISCREG_TLBIIPAS2LIS, // 211 + MISCREG_TLBIALLHIS, // 212 + MISCREG_TLBIMVAHIS, // 213 + MISCREG_TLBIALLNSNHIS, // 214 + MISCREG_TLBIMVALHIS, // 215 + MISCREG_TLBIIPAS2, // 216 + MISCREG_TLBIIPAS2L, // 217 + MISCREG_TLBIALLH, // 218 + MISCREG_TLBIMVAH, // 219 + MISCREG_TLBIALLNSNH, // 220 + MISCREG_TLBIMVALH, // 221 + MISCREG_PMCR, // 222 + MISCREG_PMCNTENSET, // 223 + MISCREG_PMCNTENCLR, // 224 + MISCREG_PMOVSR, // 225 + MISCREG_PMSWINC, // 226 + MISCREG_PMSELR, // 227 + MISCREG_PMCEID0, // 228 + MISCREG_PMCEID1, // 229 + MISCREG_PMCCNTR, // 230 + MISCREG_PMXEVTYPER, // 231 + MISCREG_PMCCFILTR, // 232 + MISCREG_PMXEVCNTR, // 233 + MISCREG_PMUSERENR, // 234 + MISCREG_PMINTENSET, // 235 + MISCREG_PMINTENCLR, // 236 + MISCREG_PMOVSSET, // 237 + MISCREG_L2CTLR, // 238 + MISCREG_L2ECTLR, // 239 + MISCREG_PRRR, // 240 + MISCREG_PRRR_NS, // 241 + MISCREG_PRRR_S, // 242 + MISCREG_MAIR0, // 243 + MISCREG_MAIR0_NS, // 244 + MISCREG_MAIR0_S, // 245 + MISCREG_NMRR, // 246 + MISCREG_NMRR_NS, // 247 + MISCREG_NMRR_S, // 248 + MISCREG_MAIR1, // 249 + MISCREG_MAIR1_NS, // 250 + MISCREG_MAIR1_S, // 251 + MISCREG_AMAIR0, // 252 + MISCREG_AMAIR0_NS, // 253 + MISCREG_AMAIR0_S, // 254 + MISCREG_AMAIR1, // 255 + MISCREG_AMAIR1_NS, // 256 + MISCREG_AMAIR1_S, // 257 + MISCREG_HMAIR0, // 258 + MISCREG_HMAIR1, // 259 + MISCREG_HAMAIR0, // 260 + MISCREG_HAMAIR1, // 261 + MISCREG_VBAR, // 262 + MISCREG_VBAR_NS, // 263 + MISCREG_VBAR_S, // 264 + MISCREG_MVBAR, // 265 + MISCREG_RMR, // 266 + MISCREG_ISR, // 267 + MISCREG_HVBAR, // 268 + MISCREG_FCSEIDR, // 269 + MISCREG_CONTEXTIDR, // 270 + MISCREG_CONTEXTIDR_NS, // 271 + MISCREG_CONTEXTIDR_S, // 272 + MISCREG_TPIDRURW, // 273 + MISCREG_TPIDRURW_NS, // 274 + MISCREG_TPIDRURW_S, // 275 + MISCREG_TPIDRURO, // 276 + MISCREG_TPIDRURO_NS, // 277 + MISCREG_TPIDRURO_S, // 278 + MISCREG_TPIDRPRW, // 279 + MISCREG_TPIDRPRW_NS, // 280 + MISCREG_TPIDRPRW_S, // 281 + MISCREG_HTPIDR, // 282 + MISCREG_CNTFRQ, // 283 + MISCREG_CNTKCTL, // 284 + MISCREG_CNTP_TVAL, // 285 + MISCREG_CNTP_TVAL_NS, // 286 + MISCREG_CNTP_TVAL_S, // 287 + MISCREG_CNTP_CTL, // 288 + MISCREG_CNTP_CTL_NS, // 289 + MISCREG_CNTP_CTL_S, // 290 + MISCREG_CNTV_TVAL, // 291 + MISCREG_CNTV_CTL, // 292 + MISCREG_CNTHCTL, // 293 + MISCREG_CNTHP_TVAL, // 294 + MISCREG_CNTHP_CTL, // 295 + MISCREG_IL1DATA0, // 296 + MISCREG_IL1DATA1, // 297 + MISCREG_IL1DATA2, // 298 + MISCREG_IL1DATA3, // 299 + MISCREG_DL1DATA0, // 300 + MISCREG_DL1DATA1, // 301 + MISCREG_DL1DATA2, // 302 + MISCREG_DL1DATA3, // 303 + MISCREG_DL1DATA4, // 304 + MISCREG_RAMINDEX, // 305 + MISCREG_L2ACTLR, // 306 + MISCREG_CBAR, // 307 + MISCREG_HTTBR, // 308 + MISCREG_VTTBR, // 309 + MISCREG_CNTPCT, // 310 + MISCREG_CNTVCT, // 311 + MISCREG_CNTP_CVAL, // 312 + MISCREG_CNTP_CVAL_NS, // 313 + MISCREG_CNTP_CVAL_S, // 314 + MISCREG_CNTV_CVAL, // 315 + MISCREG_CNTVOFF, // 316 + MISCREG_CNTHP_CVAL, // 317 + MISCREG_CPUMERRSR, // 318 + MISCREG_L2MERRSR, // 319 + + // AArch64 registers (Op0=2) + MISCREG_MDCCINT_EL1, // 320 + MISCREG_OSDTRRX_EL1, // 321 + MISCREG_MDSCR_EL1, // 322 + MISCREG_OSDTRTX_EL1, // 323 + MISCREG_OSECCR_EL1, // 324 + MISCREG_DBGBVR0_EL1, // 325 + MISCREG_DBGBVR1_EL1, // 326 + MISCREG_DBGBVR2_EL1, // 327 + MISCREG_DBGBVR3_EL1, // 328 + MISCREG_DBGBVR4_EL1, // 329 + MISCREG_DBGBVR5_EL1, // 330 + MISCREG_DBGBCR0_EL1, // 331 + MISCREG_DBGBCR1_EL1, // 332 + MISCREG_DBGBCR2_EL1, // 333 + MISCREG_DBGBCR3_EL1, // 334 + MISCREG_DBGBCR4_EL1, // 335 + MISCREG_DBGBCR5_EL1, // 336 + MISCREG_DBGWVR0_EL1, // 337 + MISCREG_DBGWVR1_EL1, // 338 + MISCREG_DBGWVR2_EL1, // 339 + MISCREG_DBGWVR3_EL1, // 340 + MISCREG_DBGWCR0_EL1, // 341 + MISCREG_DBGWCR1_EL1, // 342 + MISCREG_DBGWCR2_EL1, // 343 + MISCREG_DBGWCR3_EL1, // 344 + MISCREG_MDCCSR_EL0, // 345 + MISCREG_MDDTR_EL0, // 346 + MISCREG_MDDTRTX_EL0, // 347 + MISCREG_MDDTRRX_EL0, // 348 + MISCREG_DBGVCR32_EL2, // 349 + MISCREG_MDRAR_EL1, // 350 + MISCREG_OSLAR_EL1, // 351 + MISCREG_OSLSR_EL1, // 352 + MISCREG_OSDLR_EL1, // 353 + MISCREG_DBGPRCR_EL1, // 354 + MISCREG_DBGCLAIMSET_EL1, // 355 + MISCREG_DBGCLAIMCLR_EL1, // 356 + MISCREG_DBGAUTHSTATUS_EL1, // 357 + MISCREG_TEECR32_EL1, // 358 + MISCREG_TEEHBR32_EL1, // 359 + + // AArch64 registers (Op0=1,3) + MISCREG_MIDR_EL1, // 360 + MISCREG_MPIDR_EL1, // 361 + MISCREG_REVIDR_EL1, // 362 + MISCREG_ID_PFR0_EL1, // 363 + MISCREG_ID_PFR1_EL1, // 364 + MISCREG_ID_DFR0_EL1, // 365 + MISCREG_ID_AFR0_EL1, // 366 + MISCREG_ID_MMFR0_EL1, // 367 + MISCREG_ID_MMFR1_EL1, // 368 + MISCREG_ID_MMFR2_EL1, // 369 + MISCREG_ID_MMFR3_EL1, // 370 + MISCREG_ID_ISAR0_EL1, // 371 + MISCREG_ID_ISAR1_EL1, // 372 + MISCREG_ID_ISAR2_EL1, // 373 + MISCREG_ID_ISAR3_EL1, // 374 + MISCREG_ID_ISAR4_EL1, // 375 + MISCREG_ID_ISAR5_EL1, // 376 + MISCREG_MVFR0_EL1, // 377 + MISCREG_MVFR1_EL1, // 378 + MISCREG_MVFR2_EL1, // 379 + MISCREG_ID_AA64PFR0_EL1, // 380 + MISCREG_ID_AA64PFR1_EL1, // 381 + MISCREG_ID_AA64DFR0_EL1, // 382 + MISCREG_ID_AA64DFR1_EL1, // 383 + MISCREG_ID_AA64AFR0_EL1, // 384 + MISCREG_ID_AA64AFR1_EL1, // 385 + MISCREG_ID_AA64ISAR0_EL1, // 386 + MISCREG_ID_AA64ISAR1_EL1, // 387 + MISCREG_ID_AA64MMFR0_EL1, // 388 + MISCREG_ID_AA64MMFR1_EL1, // 389 + MISCREG_CCSIDR_EL1, // 390 + MISCREG_CLIDR_EL1, // 391 + MISCREG_AIDR_EL1, // 392 + MISCREG_CSSELR_EL1, // 393 + MISCREG_CTR_EL0, // 394 + MISCREG_DCZID_EL0, // 395 + MISCREG_VPIDR_EL2, // 396 + MISCREG_VMPIDR_EL2, // 397 + MISCREG_SCTLR_EL1, // 398 + MISCREG_ACTLR_EL1, // 399 + MISCREG_CPACR_EL1, // 400 + MISCREG_SCTLR_EL2, // 401 + MISCREG_ACTLR_EL2, // 402 + MISCREG_HCR_EL2, // 403 + MISCREG_MDCR_EL2, // 404 + MISCREG_CPTR_EL2, // 405 + MISCREG_HSTR_EL2, // 406 + MISCREG_HACR_EL2, // 407 + MISCREG_SCTLR_EL3, // 408 + MISCREG_ACTLR_EL3, // 409 + MISCREG_SCR_EL3, // 410 + MISCREG_SDER32_EL3, // 411 + MISCREG_CPTR_EL3, // 412 + MISCREG_MDCR_EL3, // 413 + MISCREG_TTBR0_EL1, // 414 + MISCREG_TTBR1_EL1, // 415 + MISCREG_TCR_EL1, // 416 + MISCREG_TTBR0_EL2, // 417 + MISCREG_TCR_EL2, // 418 + MISCREG_VTTBR_EL2, // 419 + MISCREG_VTCR_EL2, // 420 + MISCREG_TTBR0_EL3, // 421 + MISCREG_TCR_EL3, // 422 + MISCREG_DACR32_EL2, // 423 + MISCREG_SPSR_EL1, // 424 + MISCREG_ELR_EL1, // 425 + MISCREG_SP_EL0, // 426 + MISCREG_SPSEL, // 427 + MISCREG_CURRENTEL, // 428 + MISCREG_NZCV, // 429 + MISCREG_DAIF, // 430 + MISCREG_FPCR, // 431 + MISCREG_FPSR, // 432 + MISCREG_DSPSR_EL0, // 433 + MISCREG_DLR_EL0, // 434 + MISCREG_SPSR_EL2, // 435 + MISCREG_ELR_EL2, // 436 + MISCREG_SP_EL1, // 437 + MISCREG_SPSR_IRQ_AA64, // 438 + MISCREG_SPSR_ABT_AA64, // 439 + MISCREG_SPSR_UND_AA64, // 440 + MISCREG_SPSR_FIQ_AA64, // 441 + MISCREG_SPSR_EL3, // 442 + MISCREG_ELR_EL3, // 443 + MISCREG_SP_EL2, // 444 + MISCREG_AFSR0_EL1, // 445 + MISCREG_AFSR1_EL1, // 446 + MISCREG_ESR_EL1, // 447 + MISCREG_IFSR32_EL2, // 448 + MISCREG_AFSR0_EL2, // 449 + MISCREG_AFSR1_EL2, // 450 + MISCREG_ESR_EL2, // 451 + MISCREG_FPEXC32_EL2, // 452 + MISCREG_AFSR0_EL3, // 453 + MISCREG_AFSR1_EL3, // 454 + MISCREG_ESR_EL3, // 455 + MISCREG_FAR_EL1, // 456 + MISCREG_FAR_EL2, // 457 + MISCREG_HPFAR_EL2, // 458 + MISCREG_FAR_EL3, // 459 + MISCREG_IC_IALLUIS, // 460 + MISCREG_PAR_EL1, // 461 + MISCREG_IC_IALLU, // 462 + MISCREG_DC_IVAC_Xt, // 463 + MISCREG_DC_ISW_Xt, // 464 + MISCREG_AT_S1E1R_Xt, // 465 + MISCREG_AT_S1E1W_Xt, // 466 + MISCREG_AT_S1E0R_Xt, // 467 + MISCREG_AT_S1E0W_Xt, // 468 + MISCREG_DC_CSW_Xt, // 469 + MISCREG_DC_CISW_Xt, // 470 + MISCREG_DC_ZVA_Xt, // 471 + MISCREG_IC_IVAU_Xt, // 472 + MISCREG_DC_CVAC_Xt, // 473 + MISCREG_DC_CVAU_Xt, // 474 + MISCREG_DC_CIVAC_Xt, // 475 + MISCREG_AT_S1E2R_Xt, // 476 + MISCREG_AT_S1E2W_Xt, // 477 + MISCREG_AT_S12E1R_Xt, // 478 + MISCREG_AT_S12E1W_Xt, // 479 + MISCREG_AT_S12E0R_Xt, // 480 + MISCREG_AT_S12E0W_Xt, // 481 + MISCREG_AT_S1E3R_Xt, // 482 + MISCREG_AT_S1E3W_Xt, // 483 + MISCREG_TLBI_VMALLE1IS, // 484 + MISCREG_TLBI_VAE1IS_Xt, // 485 + MISCREG_TLBI_ASIDE1IS_Xt, // 486 + MISCREG_TLBI_VAAE1IS_Xt, // 487 + MISCREG_TLBI_VALE1IS_Xt, // 488 + MISCREG_TLBI_VAALE1IS_Xt, // 489 + MISCREG_TLBI_VMALLE1, // 490 + MISCREG_TLBI_VAE1_Xt, // 491 + MISCREG_TLBI_ASIDE1_Xt, // 492 + MISCREG_TLBI_VAAE1_Xt, // 493 + MISCREG_TLBI_VALE1_Xt, // 494 + MISCREG_TLBI_VAALE1_Xt, // 495 + MISCREG_TLBI_IPAS2E1IS_Xt, // 496 + MISCREG_TLBI_IPAS2LE1IS_Xt, // 497 + MISCREG_TLBI_ALLE2IS, // 498 + MISCREG_TLBI_VAE2IS_Xt, // 499 + MISCREG_TLBI_ALLE1IS, // 500 + MISCREG_TLBI_VALE2IS_Xt, // 501 + MISCREG_TLBI_VMALLS12E1IS, // 502 + MISCREG_TLBI_IPAS2E1_Xt, // 503 + MISCREG_TLBI_IPAS2LE1_Xt, // 504 + MISCREG_TLBI_ALLE2, // 505 + MISCREG_TLBI_VAE2_Xt, // 506 + MISCREG_TLBI_ALLE1, // 507 + MISCREG_TLBI_VALE2_Xt, // 508 + MISCREG_TLBI_VMALLS12E1, // 509 + MISCREG_TLBI_ALLE3IS, // 510 + MISCREG_TLBI_VAE3IS_Xt, // 511 + MISCREG_TLBI_VALE3IS_Xt, // 512 + MISCREG_TLBI_ALLE3, // 513 + MISCREG_TLBI_VAE3_Xt, // 514 + MISCREG_TLBI_VALE3_Xt, // 515 + MISCREG_PMINTENSET_EL1, // 516 + MISCREG_PMINTENCLR_EL1, // 517 + MISCREG_PMCR_EL0, // 518 + MISCREG_PMCNTENSET_EL0, // 519 + MISCREG_PMCNTENCLR_EL0, // 520 + MISCREG_PMOVSCLR_EL0, // 521 + MISCREG_PMSWINC_EL0, // 522 + MISCREG_PMSELR_EL0, // 523 + MISCREG_PMCEID0_EL0, // 524 + MISCREG_PMCEID1_EL0, // 525 + MISCREG_PMCCNTR_EL0, // 526 + MISCREG_PMXEVTYPER_EL0, // 527 + MISCREG_PMCCFILTR_EL0, // 528 + MISCREG_PMXEVCNTR_EL0, // 529 + MISCREG_PMUSERENR_EL0, // 530 + MISCREG_PMOVSSET_EL0, // 531 + MISCREG_MAIR_EL1, // 532 + MISCREG_AMAIR_EL1, // 533 + MISCREG_MAIR_EL2, // 534 + MISCREG_AMAIR_EL2, // 535 + MISCREG_MAIR_EL3, // 536 + MISCREG_AMAIR_EL3, // 537 + MISCREG_L2CTLR_EL1, // 538 + MISCREG_L2ECTLR_EL1, // 539 + MISCREG_VBAR_EL1, // 540 + MISCREG_RVBAR_EL1, // 541 + MISCREG_ISR_EL1, // 542 + MISCREG_VBAR_EL2, // 543 + MISCREG_RVBAR_EL2, // 544 + MISCREG_VBAR_EL3, // 545 + MISCREG_RVBAR_EL3, // 546 + MISCREG_RMR_EL3, // 547 + MISCREG_CONTEXTIDR_EL1, // 548 + MISCREG_TPIDR_EL1, // 549 + MISCREG_TPIDR_EL0, // 550 + MISCREG_TPIDRRO_EL0, // 551 + MISCREG_TPIDR_EL2, // 552 + MISCREG_TPIDR_EL3, // 553 + MISCREG_CNTKCTL_EL1, // 554 + MISCREG_CNTFRQ_EL0, // 555 + MISCREG_CNTPCT_EL0, // 556 + MISCREG_CNTVCT_EL0, // 557 + MISCREG_CNTP_TVAL_EL0, // 558 + MISCREG_CNTP_CTL_EL0, // 559 + MISCREG_CNTP_CVAL_EL0, // 560 + MISCREG_CNTV_TVAL_EL0, // 561 + MISCREG_CNTV_CTL_EL0, // 562 + MISCREG_CNTV_CVAL_EL0, // 563 + MISCREG_PMEVCNTR0_EL0, // 564 + MISCREG_PMEVCNTR1_EL0, // 565 + MISCREG_PMEVCNTR2_EL0, // 566 + MISCREG_PMEVCNTR3_EL0, // 567 + MISCREG_PMEVCNTR4_EL0, // 568 + MISCREG_PMEVCNTR5_EL0, // 569 + MISCREG_PMEVTYPER0_EL0, // 570 + MISCREG_PMEVTYPER1_EL0, // 571 + MISCREG_PMEVTYPER2_EL0, // 572 + MISCREG_PMEVTYPER3_EL0, // 573 + MISCREG_PMEVTYPER4_EL0, // 574 + MISCREG_PMEVTYPER5_EL0, // 575 + MISCREG_CNTVOFF_EL2, // 576 + MISCREG_CNTHCTL_EL2, // 577 + MISCREG_CNTHP_TVAL_EL2, // 578 + MISCREG_CNTHP_CTL_EL2, // 579 + MISCREG_CNTHP_CVAL_EL2, // 580 + MISCREG_CNTPS_TVAL_EL1, // 581 + MISCREG_CNTPS_CTL_EL1, // 582 + MISCREG_CNTPS_CVAL_EL1, // 583 + MISCREG_IL1DATA0_EL1, // 584 + MISCREG_IL1DATA1_EL1, // 585 + MISCREG_IL1DATA2_EL1, // 586 + MISCREG_IL1DATA3_EL1, // 587 + MISCREG_DL1DATA0_EL1, // 588 + MISCREG_DL1DATA1_EL1, // 589 + MISCREG_DL1DATA2_EL1, // 590 + MISCREG_DL1DATA3_EL1, // 591 + MISCREG_DL1DATA4_EL1, // 592 + MISCREG_L2ACTLR_EL1, // 593 + MISCREG_CPUACTLR_EL1, // 594 + MISCREG_CPUECTLR_EL1, // 595 + MISCREG_CPUMERRSR_EL1, // 596 + MISCREG_L2MERRSR_EL1, // 597 + MISCREG_CBAR_EL1, // 598 + + // Dummy registers + MISCREG_NOP, // 599 + MISCREG_RAZ, // 600 + MISCREG_CP14_UNIMPL, // 601 + MISCREG_CP15_UNIMPL, // 602 + MISCREG_A64_UNIMPL, // 603 + MISCREG_UNKNOWN, // 604 + + NUM_MISCREGS // 605 }; + enum MiscRegInfo { + MISCREG_IMPLEMENTED, + MISCREG_WARN_NOT_FAIL, // If MISCREG_IMPLEMENTED is deasserted, it + // tells whether the instruction should raise a + // warning or fail + MISCREG_MUTEX, // True if the register corresponds to a pair of + // mutually exclusive registers + MISCREG_BANKED, // True if the register is banked between the two + // security states, and this is the parent node of the + // two banked registers + MISCREG_BANKED_CHILD, // The entry is one of the child registers that + // forms a banked set of regs (along with the + // other child regs) + + // Access permissions + // User mode + MISCREG_USR_NS_RD, + MISCREG_USR_NS_WR, + MISCREG_USR_S_RD, + MISCREG_USR_S_WR, + // Privileged modes other than hypervisor or monitor + MISCREG_PRI_NS_RD, + MISCREG_PRI_NS_WR, + MISCREG_PRI_S_RD, + MISCREG_PRI_S_WR, + // Hypervisor mode + MISCREG_HYP_RD, + MISCREG_HYP_WR, + // Monitor mode, SCR.NS == 0 + MISCREG_MON_NS0_RD, + MISCREG_MON_NS0_WR, + // Monitor mode, SCR.NS == 1 + MISCREG_MON_NS1_RD, + MISCREG_MON_NS1_WR, + + NUM_MISCREG_INFOS + }; + + extern std::bitset<NUM_MISCREG_INFOS> miscRegInfo[NUM_MISCREGS]; + + // Decodes 32-bit CP14 registers accessible through MCR/MRC instructions MiscRegIndex decodeCP14Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2); + MiscRegIndex decodeAArch64SysReg(unsigned op0, unsigned op1, + unsigned crn, unsigned crm, + unsigned op2); + // Whether a particular AArch64 system register is -always- read only. + bool aarch64SysRegReadOnly(MiscRegIndex miscReg); + // Decodes 32-bit CP15 registers accessible through MCR/MRC instructions MiscRegIndex decodeCP15Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2); + // Decodes 64-bit CP15 registers accessible through MCRR/MRRC instructions + MiscRegIndex decodeCP15Reg64(unsigned crm, unsigned opc1); + const char * const miscRegName[] = { - "cpsr", "cpsr_q", "spsr", "spsr_fiq", "spsr_irq", "spsr_svc", - "spsr_mon", "spsr_und", "spsr_abt", - "fpsr", "fpsid", "fpscr", "fpscr_qc", "fpscr_exc", "fpexc", - "mvfr0", "mvfr1", - "sctlr_rst", "sev_mailbox", - "DBGDIDR", - "DBGDSCR_INT", - "DBGDTRRX_INT", - "DBGTRTX_INT", - "DBGWFAR", - "DBGVCR", - "DBGECR", - "DBGDSCCR", - "DBGSMCR", - "DBGDTRRX_EXT", - "DBGDSCR_EXT", - "DBGDTRTX_EXT", - "DBGDRCR", - "DBGBVR", - "DBGBCR", - "DBGBVR_M", - "DBGBCR_M", - "DBGDRAR", - "DBGBXVR_M", - "DBGOSLAR", - "DBGOSSRR", - "DBGOSDLR", - "DBGPRCR", - "DBGPRSR", - "DBGDSAR", - "DBGITCTRL", - "DBGCLAIMSET", - "DBGCLAIMCLR", - "DBGAUTHSTATUS", - "DBGDEVID2", - "DBGDEVID1", - "DBGDEVID", - "TEEHBR", - "sctlr", "dccisw", "dccimvac", "dccmvac", - "contextidr", "tpidrurw", "tpidruro", "tpidrprw", - "cp15isb", "cp15dsb", "cp15dmb", "cpacr", - "clidr", "ccsidr", "csselr", - "icialluis", "iciallu", "icimvau", - "bpimva", "bpiallis", "bpiall", - "midr", "ttbr0", "ttbr1", "tlbtr", "dacr", - "tlbiallis", "tlbimvais", "tlbiasidis", "tlbimvaais", - "itlbiall", "itlbimva", "itlbiasid", - "dtlbiall", "dtlbimva", "dtlbiasid", - "tlbiall", "tlbimva", "tlbiasid", "tlbimvaa", - "dfsr", "ifsr", "dfar", "ifar", "mpidr", - "prrr", "nmrr", "ttbcr", "id_pfr0", "ctr", - "scr", "sder", "par", - "v2pcwpr", "v2pcwpw", "v2pcwur", "v2pcwuw", - "v2powpr", "v2powpw", "v2powur", "v2powuw", - "id_mmfr0", "id_mmfr2", "id_mmfr3", "actlr", "pmcr", "pmccntr", - "pmcntenset", "pmcntenclr", "pmovsr", - "pmswinc", "pmselr", "pmceid0", - "pmceid1", "pmc_other", "pmxevcntr", - "pmuserenr", "pmintenset", "pmintenclr", - "id_isar0", "id_isar1", "id_isar2", "id_isar3", "id_isar4", "id_isar5", - "lockflag", "lockaddr", "id_pfr1", - "l2ctlr", - // Unimplemented below + "cpsr", + "spsr", + "spsr_fiq", + "spsr_irq", + "spsr_svc", + "spsr_mon", + "spsr_abt", + "spsr_hyp", + "spsr_und", + "elr_hyp", + "fpsid", + "fpscr", + "mvfr1", + "mvfr0", + "fpexc", + + // Helper registers + "cpsr_mode", + "cpsr_q", + "fpscr_exc", + "fpscr_qc", + "lockaddr", + "lockflag", + "prrr_mair0", + "prrr_mair0_ns", + "prrr_mair0_s", + "nmrr_mair1", + "nmrr_mair1_ns", + "nmrr_mair1_s", + "pmxevtyper_pmccfiltr", + "sctlr_rst", + "sev_mailbox", + + // AArch32 CP14 registers + "dbgdidr", + "dbgdscrint", + "dbgdccint", + "dbgdtrtxint", + "dbgdtrrxint", + "dbgwfar", + "dbgvcr", + "dbgdtrrxext", + "dbgdscrext", + "dbgdtrtxext", + "dbgoseccr", + "dbgbvr0", + "dbgbvr1", + "dbgbvr2", + "dbgbvr3", + "dbgbvr4", + "dbgbvr5", + "dbgbcr0", + "dbgbcr1", + "dbgbcr2", + "dbgbcr3", + "dbgbcr4", + "dbgbcr5", + "dbgwvr0", + "dbgwvr1", + "dbgwvr2", + "dbgwvr3", + "dbgwcr0", + "dbgwcr1", + "dbgwcr2", + "dbgwcr3", + "dbgdrar", + "dbgbxvr4", + "dbgbxvr5", + "dbgoslar", + "dbgoslsr", + "dbgosdlr", + "dbgprcr", + "dbgdsar", + "dbgclaimset", + "dbgclaimclr", + "dbgauthstatus", + "dbgdevid2", + "dbgdevid1", + "dbgdevid0", + "teecr", + "jidr", + "teehbr", + "joscr", + "jmcr", + + // AArch32 CP15 registers + "midr", + "ctr", "tcmtr", - "id_dfr0", "id_afr0", + "tlbtr", + "mpidr", + "revidr", + "id_pfr0", + "id_pfr1", + "id_dfr0", + "id_afr0", + "id_mmfr0", "id_mmfr1", - "aidr", "adfsr", "aifsr", - "dcimvac", "dcisw", "mccsw", - "dccmvau", + "id_mmfr2", + "id_mmfr3", + "id_isar0", + "id_isar1", + "id_isar2", + "id_isar3", + "id_isar4", + "id_isar5", + "ccsidr", + "clidr", + "aidr", + "csselr", + "csselr_ns", + "csselr_s", + "vpidr", + "vmpidr", + "sctlr", + "sctlr_ns", + "sctlr_s", + "actlr", + "actlr_ns", + "actlr_s", + "cpacr", + "scr", + "sder", "nsacr", - "vbar", "mvbar", "isr", "fceidr", "l2latency", - "crn15", - "nop", "raz" + "hsctlr", + "hactlr", + "hcr", + "hdcr", + "hcptr", + "hstr", + "hacr", + "ttbr0", + "ttbr0_ns", + "ttbr0_s", + "ttbr1", + "ttbr1_ns", + "ttbr1_s", + "ttbcr", + "ttbcr_ns", + "ttbcr_s", + "htcr", + "vtcr", + "dacr", + "dacr_ns", + "dacr_s", + "dfsr", + "dfsr_ns", + "dfsr_s", + "ifsr", + "ifsr_ns", + "ifsr_s", + "adfsr", + "adfsr_ns", + "adfsr_s", + "aifsr", + "aifsr_ns", + "aifsr_s", + "hadfsr", + "haifsr", + "hsr", + "dfar", + "dfar_ns", + "dfar_s", + "ifar", + "ifar_ns", + "ifar_s", + "hdfar", + "hifar", + "hpfar", + "icialluis", + "bpiallis", + "par", + "par_ns", + "par_s", + "iciallu", + "icimvau", + "cp15isb", + "bpiall", + "bpimva", + "dcimvac", + "dcisw", + "ats1cpr", + "ats1cpw", + "ats1cur", + "ats1cuw", + "ats12nsopr", + "ats12nsopw", + "ats12nsour", + "ats12nsouw", + "dccmvac", + "dccsw", + "cp15dsb", + "cp15dmb", + "dccmvau", + "dccimvac", + "dccisw", + "ats1hr", + "ats1hw", + "tlbiallis", + "tlbimvais", + "tlbiasidis", + "tlbimvaais", + "tlbimvalis", + "tlbimvaalis", + "itlbiall", + "itlbimva", + "itlbiasid", + "dtlbiall", + "dtlbimva", + "dtlbiasid", + "tlbiall", + "tlbimva", + "tlbiasid", + "tlbimvaa", + "tlbimval", + "tlbimvaal", + "tlbiipas2is", + "tlbiipas2lis", + "tlbiallhis", + "tlbimvahis", + "tlbiallnsnhis", + "tlbimvalhis", + "tlbiipas2", + "tlbiipas2l", + "tlbiallh", + "tlbimvah", + "tlbiallnsnh", + "tlbimvalh", + "pmcr", + "pmcntenset", + "pmcntenclr", + "pmovsr", + "pmswinc", + "pmselr", + "pmceid0", + "pmceid1", + "pmccntr", + "pmxevtyper", + "pmccfiltr", + "pmxevcntr", + "pmuserenr", + "pmintenset", + "pmintenclr", + "pmovsset", + "l2ctlr", + "l2ectlr", + "prrr", + "prrr_ns", + "prrr_s", + "mair0", + "mair0_ns", + "mair0_s", + "nmrr", + "nmrr_ns", + "nmrr_s", + "mair1", + "mair1_ns", + "mair1_s", + "amair0", + "amair0_ns", + "amair0_s", + "amair1", + "amair1_ns", + "amair1_s", + "hmair0", + "hmair1", + "hamair0", + "hamair1", + "vbar", + "vbar_ns", + "vbar_s", + "mvbar", + "rmr", + "isr", + "hvbar", + "fcseidr", + "contextidr", + "contextidr_ns", + "contextidr_s", + "tpidrurw", + "tpidrurw_ns", + "tpidrurw_s", + "tpidruro", + "tpidruro_ns", + "tpidruro_s", + "tpidrprw", + "tpidrprw_ns", + "tpidrprw_s", + "htpidr", + "cntfrq", + "cntkctl", + "cntp_tval", + "cntp_tval_ns", + "cntp_tval_s", + "cntp_ctl", + "cntp_ctl_ns", + "cntp_ctl_s", + "cntv_tval", + "cntv_ctl", + "cnthctl", + "cnthp_tval", + "cnthp_ctl", + "il1data0", + "il1data1", + "il1data2", + "il1data3", + "dl1data0", + "dl1data1", + "dl1data2", + "dl1data3", + "dl1data4", + "ramindex", + "l2actlr", + "cbar", + "httbr", + "vttbr", + "cntpct", + "cntvct", + "cntp_cval", + "cntp_cval_ns", + "cntp_cval_s", + "cntv_cval", + "cntvoff", + "cnthp_cval", + "cpumerrsr", + "l2merrsr", + + // AArch64 registers (Op0=2) + "mdccint_el1", + "osdtrrx_el1", + "mdscr_el1", + "osdtrtx_el1", + "oseccr_el1", + "dbgbvr0_el1", + "dbgbvr1_el1", + "dbgbvr2_el1", + "dbgbvr3_el1", + "dbgbvr4_el1", + "dbgbvr5_el1", + "dbgbcr0_el1", + "dbgbcr1_el1", + "dbgbcr2_el1", + "dbgbcr3_el1", + "dbgbcr4_el1", + "dbgbcr5_el1", + "dbgwvr0_el1", + "dbgwvr1_el1", + "dbgwvr2_el1", + "dbgwvr3_el1", + "dbgwcr0_el1", + "dbgwcr1_el1", + "dbgwcr2_el1", + "dbgwcr3_el1", + "mdccsr_el0", + "mddtr_el0", + "mddtrtx_el0", + "mddtrrx_el0", + "dbgvcr32_el2", + "mdrar_el1", + "oslar_el1", + "oslsr_el1", + "osdlr_el1", + "dbgprcr_el1", + "dbgclaimset_el1", + "dbgclaimclr_el1", + "dbgauthstatus_el1", + "teecr32_el1", + "teehbr32_el1", + + // AArch64 registers (Op0=1,3) + "midr_el1", + "mpidr_el1", + "revidr_el1", + "id_pfr0_el1", + "id_pfr1_el1", + "id_dfr0_el1", + "id_afr0_el1", + "id_mmfr0_el1", + "id_mmfr1_el1", + "id_mmfr2_el1", + "id_mmfr3_el1", + "id_isar0_el1", + "id_isar1_el1", + "id_isar2_el1", + "id_isar3_el1", + "id_isar4_el1", + "id_isar5_el1", + "mvfr0_el1", + "mvfr1_el1", + "mvfr2_el1", + "id_aa64pfr0_el1", + "id_aa64pfr1_el1", + "id_aa64dfr0_el1", + "id_aa64dfr1_el1", + "id_aa64afr0_el1", + "id_aa64afr1_el1", + "id_aa64isar0_el1", + "id_aa64isar1_el1", + "id_aa64mmfr0_el1", + "id_aa64mmfr1_el1", + "ccsidr_el1", + "clidr_el1", + "aidr_el1", + "csselr_el1", + "ctr_el0", + "dczid_el0", + "vpidr_el2", + "vmpidr_el2", + "sctlr_el1", + "actlr_el1", + "cpacr_el1", + "sctlr_el2", + "actlr_el2", + "hcr_el2", + "mdcr_el2", + "cptr_el2", + "hstr_el2", + "hacr_el2", + "sctlr_el3", + "actlr_el3", + "scr_el3", + "sder32_el3", + "cptr_el3", + "mdcr_el3", + "ttbr0_el1", + "ttbr1_el1", + "tcr_el1", + "ttbr0_el2", + "tcr_el2", + "vttbr_el2", + "vtcr_el2", + "ttbr0_el3", + "tcr_el3", + "dacr32_el2", + "spsr_el1", + "elr_el1", + "sp_el0", + "spsel", + "currentel", + "nzcv", + "daif", + "fpcr", + "fpsr", + "dspsr_el0", + "dlr_el0", + "spsr_el2", + "elr_el2", + "sp_el1", + "spsr_irq_aa64", + "spsr_abt_aa64", + "spsr_und_aa64", + "spsr_fiq_aa64", + "spsr_el3", + "elr_el3", + "sp_el2", + "afsr0_el1", + "afsr1_el1", + "esr_el1", + "ifsr32_el2", + "afsr0_el2", + "afsr1_el2", + "esr_el2", + "fpexc32_el2", + "afsr0_el3", + "afsr1_el3", + "esr_el3", + "far_el1", + "far_el2", + "hpfar_el2", + "far_el3", + "ic_ialluis", + "par_el1", + "ic_iallu", + "dc_ivac_xt", + "dc_isw_xt", + "at_s1e1r_xt", + "at_s1e1w_xt", + "at_s1e0r_xt", + "at_s1e0w_xt", + "dc_csw_xt", + "dc_cisw_xt", + "dc_zva_xt", + "ic_ivau_xt", + "dc_cvac_xt", + "dc_cvau_xt", + "dc_civac_xt", + "at_s1e2r_xt", + "at_s1e2w_xt", + "at_s12e1r_xt", + "at_s12e1w_xt", + "at_s12e0r_xt", + "at_s12e0w_xt", + "at_s1e3r_xt", + "at_s1e3w_xt", + "tlbi_vmalle1is", + "tlbi_vae1is_xt", + "tlbi_aside1is_xt", + "tlbi_vaae1is_xt", + "tlbi_vale1is_xt", + "tlbi_vaale1is_xt", + "tlbi_vmalle1", + "tlbi_vae1_xt", + "tlbi_aside1_xt", + "tlbi_vaae1_xt", + "tlbi_vale1_xt", + "tlbi_vaale1_xt", + "tlbi_ipas2e1is_xt", + "tlbi_ipas2le1is_xt", + "tlbi_alle2is", + "tlbi_vae2is_xt", + "tlbi_alle1is", + "tlbi_vale2is_xt", + "tlbi_vmalls12e1is", + "tlbi_ipas2e1_xt", + "tlbi_ipas2le1_xt", + "tlbi_alle2", + "tlbi_vae2_xt", + "tlbi_alle1", + "tlbi_vale2_xt", + "tlbi_vmalls12e1", + "tlbi_alle3is", + "tlbi_vae3is_xt", + "tlbi_vale3is_xt", + "tlbi_alle3", + "tlbi_vae3_xt", + "tlbi_vale3_xt", + "pmintenset_el1", + "pmintenclr_el1", + "pmcr_el0", + "pmcntenset_el0", + "pmcntenclr_el0", + "pmovsclr_el0", + "pmswinc_el0", + "pmselr_el0", + "pmceid0_el0", + "pmceid1_el0", + "pmccntr_el0", + "pmxevtyper_el0", + "pmccfiltr_el0", + "pmxevcntr_el0", + "pmuserenr_el0", + "pmovsset_el0", + "mair_el1", + "amair_el1", + "mair_el2", + "amair_el2", + "mair_el3", + "amair_el3", + "l2ctlr_el1", + "l2ectlr_el1", + "vbar_el1", + "rvbar_el1", + "isr_el1", + "vbar_el2", + "rvbar_el2", + "vbar_el3", + "rvbar_el3", + "rmr_el3", + "contextidr_el1", + "tpidr_el1", + "tpidr_el0", + "tpidrro_el0", + "tpidr_el2", + "tpidr_el3", + "cntkctl_el1", + "cntfrq_el0", + "cntpct_el0", + "cntvct_el0", + "cntp_tval_el0", + "cntp_ctl_el0", + "cntp_cval_el0", + "cntv_tval_el0", + "cntv_ctl_el0", + "cntv_cval_el0", + "pmevcntr0_el0", + "pmevcntr1_el0", + "pmevcntr2_el0", + "pmevcntr3_el0", + "pmevcntr4_el0", + "pmevcntr5_el0", + "pmevtyper0_el0", + "pmevtyper1_el0", + "pmevtyper2_el0", + "pmevtyper3_el0", + "pmevtyper4_el0", + "pmevtyper5_el0", + "cntvoff_el2", + "cnthctl_el2", + "cnthp_tval_el2", + "cnthp_ctl_el2", + "cnthp_cval_el2", + "cntps_tval_el1", + "cntps_ctl_el1", + "cntps_cval_el1", + "il1data0_el1", + "il1data1_el1", + "il1data2_el1", + "il1data3_el1", + "dl1data0_el1", + "dl1data1_el1", + "dl1data2_el1", + "dl1data3_el1", + "dl1data4_el1", + "l2actlr_el1", + "cpuactlr_el1", + "cpuectlr_el1", + "cpumerrsr_el1", + "l2merrsr_el1", + "cbar_el1", + + // Dummy registers + "nop", + "raz", + "cp14_unimpl", + "cp15_unimpl", + "a64_unimpl", + "unknown" }; static_assert(sizeof(miscRegName) / sizeof(*miscRegName) == NUM_MISCREGS, "The miscRegName array and NUM_MISCREGS are inconsistent."); BitUnion32(CPSR) - Bitfield<31,30> nz; + Bitfield<31, 30> nz; Bitfield<29> c; Bitfield<28> v; Bitfield<27> q; - Bitfield<26,25> it1; + Bitfield<26, 25> it1; Bitfield<24> j; + Bitfield<23, 22> res0_23_22; + Bitfield<21> ss; // AArch64 + Bitfield<20> il; // AArch64 Bitfield<19, 16> ge; - Bitfield<15,10> it2; + Bitfield<15, 10> it2; + Bitfield<9> d; // AArch64 Bitfield<9> e; Bitfield<8> a; Bitfield<7> i; Bitfield<6> f; + Bitfield<9, 6> daif; // AArch64 Bitfield<5> t; + Bitfield<4> width; // AArch64 + Bitfield<3, 2> el; // AArch64 Bitfield<4, 0> mode; + Bitfield<0> sp; // AArch64 EndBitUnion(CPSR) // This mask selects bits of the CPSR that actually go in the CondCodes @@ -352,32 +1404,190 @@ namespace ArmISA static const uint32_t CondCodesMask = 0xF00F0000; static const uint32_t CpsrMaskQ = 0x08000000; + BitUnion32(HDCR) + Bitfield<11> tdra; + Bitfield<10> tdosa; + Bitfield<9> tda; + Bitfield<8> tde; + Bitfield<7> hpme; + Bitfield<6> tpm; + Bitfield<5> tpmcr; + Bitfield<4, 0> hpmn; + EndBitUnion(HDCR) + + BitUnion32(HCPTR) + Bitfield<31> tcpac; + Bitfield<20> tta; + Bitfield<15> tase; + Bitfield<13> tcp13; + Bitfield<12> tcp12; + Bitfield<11> tcp11; + Bitfield<10> tcp10; + Bitfield<10> tfp; // AArch64 + Bitfield<9> tcp9; + Bitfield<8> tcp8; + Bitfield<7> tcp7; + Bitfield<6> tcp6; + Bitfield<5> tcp5; + Bitfield<4> tcp4; + Bitfield<3> tcp3; + Bitfield<2> tcp2; + Bitfield<1> tcp1; + Bitfield<0> tcp0; + EndBitUnion(HCPTR) + + BitUnion32(HSTR) + Bitfield<17> tjdbx; + Bitfield<16> ttee; + Bitfield<15> t15; + Bitfield<13> t13; + Bitfield<12> t12; + Bitfield<11> t11; + Bitfield<10> t10; + Bitfield<9> t9; + Bitfield<8> t8; + Bitfield<7> t7; + Bitfield<6> t6; + Bitfield<5> t5; + Bitfield<4> t4; + Bitfield<3> t3; + Bitfield<2> t2; + Bitfield<1> t1; + Bitfield<0> t0; + EndBitUnion(HSTR) + + BitUnion64(HCR) + Bitfield<33> id; // AArch64 + Bitfield<32> cd; // AArch64 + Bitfield<31> rw; // AArch64 + Bitfield<30> trvm; // AArch64 + Bitfield<29> hcd; // AArch64 + Bitfield<28> tdz; // AArch64 + + Bitfield<27> tge; + Bitfield<26> tvm; + Bitfield<25> ttlb; + Bitfield<24> tpu; + Bitfield<23> tpc; + Bitfield<22> tsw; + Bitfield<21> tac; + Bitfield<21> tacr; // AArch64 + Bitfield<20> tidcp; + Bitfield<19> tsc; + Bitfield<18> tid3; + Bitfield<17> tid2; + Bitfield<16> tid1; + Bitfield<15> tid0; + Bitfield<14> twe; + Bitfield<13> twi; + Bitfield<12> dc; + Bitfield<11, 10> bsu; + Bitfield<9> fb; + Bitfield<8> va; + Bitfield<8> vse; // AArch64 + Bitfield<7> vi; + Bitfield<6> vf; + Bitfield<5> amo; + Bitfield<4> imo; + Bitfield<3> fmo; + Bitfield<2> ptw; + Bitfield<1> swio; + Bitfield<0> vm; + EndBitUnion(HCR) + + BitUnion32(NSACR) + Bitfield<20> nstrcdis; + Bitfield<19> rfr; + Bitfield<15> nsasedis; + Bitfield<14> nsd32dis; + Bitfield<13> cp13; + Bitfield<12> cp12; + Bitfield<11> cp11; + Bitfield<10> cp10; + Bitfield<9> cp9; + Bitfield<8> cp8; + Bitfield<7> cp7; + Bitfield<6> cp6; + Bitfield<5> cp5; + Bitfield<4> cp4; + Bitfield<3> cp3; + Bitfield<2> cp2; + Bitfield<1> cp1; + Bitfield<0> cp0; + EndBitUnion(NSACR) + + BitUnion32(SCR) + Bitfield<13> twe; + Bitfield<12> twi; + Bitfield<11> st; // AArch64 + Bitfield<10> rw; // AArch64 + Bitfield<9> sif; + Bitfield<8> hce; + Bitfield<7> scd; + Bitfield<7> smd; // AArch64 + Bitfield<6> nEt; + Bitfield<5> aw; + Bitfield<4> fw; + Bitfield<3> ea; + Bitfield<2> fiq; + Bitfield<1> irq; + Bitfield<0> ns; + EndBitUnion(SCR) + BitUnion32(SCTLR) - Bitfield<31> ie; // Instruction endianness - Bitfield<30> te; // Thumb Exception Enable - Bitfield<29> afe; // Access flag enable - Bitfield<28> tre; // TEX Remap bit - Bitfield<27> nmfi;// Non-maskable fast interrupts enable - Bitfield<25> ee; // Exception Endianness bit - Bitfield<24> ve; // Interrupt vectors enable - Bitfield<23> xp; // Extended page table enable bit - Bitfield<22> u; // Alignment (now unused) - Bitfield<21> fi; // Fast interrupts configuration enable - Bitfield<19> dz; // Divide by Zero fault enable bit - Bitfield<18> rao2;// Read as one - Bitfield<17> br; // Background region bit - Bitfield<16> rao3;// Read as one - Bitfield<14> rr; // Round robin cache replacement - Bitfield<13> v; // Base address for exception vectors - Bitfield<12> i; // instruction cache enable - Bitfield<11> z; // branch prediction enable bit - Bitfield<10> sw; // Enable swp/swpb - Bitfield<9,8> rs; // deprecated protection bits - Bitfield<6,3> rao4;// Read as one - Bitfield<7> b; // Endianness support (unused) - Bitfield<2> c; // Cache enable bit - Bitfield<1> a; // Alignment fault checking - Bitfield<0> m; // MMU enable bit + Bitfield<30> te; // Thumb Exception Enable (AArch32 only) + Bitfield<29> afe; // Access flag enable (AArch32 only) + Bitfield<28> tre; // TEX remap enable (AArch32 only) + Bitfield<27> nmfi; // Non-maskable FIQ support (ARMv7 only) + Bitfield<26> uci; // Enable EL0 access to DC CVAU, DC CIVAC, + // DC CVAC and IC IVAU instructions + // (AArch64 SCTLR_EL1 only) + Bitfield<25> ee; // Exception Endianness + Bitfield<24> ve; // Interrupt Vectors Enable (ARMv7 only) + Bitfield<24> e0e; // Endianness of explicit data accesses at EL0 + // (AArch64 SCTLR_EL1 only) + Bitfield<23> xp; // Extended page table enable (dropped in ARMv7) + Bitfield<22> u; // Alignment (dropped in ARMv7) + Bitfield<21> fi; // Fast interrupts configuration enable + // (ARMv7 only) + Bitfield<20> uwxn; // Unprivileged write permission implies EL1 XN + // (AArch32 only) + Bitfield<19> dz; // Divide by Zero fault enable + // (dropped in ARMv7) + Bitfield<19> wxn; // Write permission implies XN + Bitfield<18> ntwe; // Not trap WFE + // (ARMv8 AArch32 and AArch64 SCTLR_EL1 only) + Bitfield<18> rao2; // Read as one + Bitfield<16> ntwi; // Not trap WFI + // (ARMv8 AArch32 and AArch64 SCTLR_EL1 only) + Bitfield<16> rao3; // Read as one + Bitfield<15> uct; // Enable EL0 access to CTR_EL0 + // (AArch64 SCTLR_EL1 only) + Bitfield<14> rr; // Round Robin select (ARMv7 only) + Bitfield<14> dze; // Enable EL0 access to DC ZVA + // (AArch64 SCTLR_EL1 only) + Bitfield<13> v; // Vectors bit (AArch32 only) + Bitfield<12> i; // Instruction cache enable + Bitfield<11> z; // Branch prediction enable (ARMv7 only) + Bitfield<10> sw; // SWP/SWPB enable (ARMv7 only) + Bitfield<9, 8> rs; // Deprecated protection bits (dropped in ARMv7) + Bitfield<9> uma; // User mask access (AArch64 SCTLR_EL1 only) + Bitfield<8> sed; // SETEND disable + // (ARMv8 AArch32 and AArch64 SCTLR_EL1 only) + Bitfield<7> b; // Endianness support (dropped in ARMv7) + Bitfield<7> itd; // IT disable + // (ARMv8 AArch32 and AArch64 SCTLR_EL1 only) + Bitfield<6, 3> rao4; // Read as one + Bitfield<6> thee; // ThumbEE enable + // (ARMv8 AArch32 and AArch64 SCTLR_EL1 only) + Bitfield<5> cp15ben; // CP15 barrier enable + // (AArch32 and AArch64 SCTLR_EL1 only) + Bitfield<4> sa0; // Stack Alignment Check Enable for EL0 + // (AArch64 SCTLR_EL1 only) + Bitfield<3> sa; // Stack Alignment Check Enable (AArch64 only) + Bitfield<2> c; // Cache enable + Bitfield<1> a; // Alignment check enable + Bitfield<0> m; // MMU enable EndBitUnion(SCTLR) BitUnion32(CPACR) @@ -392,20 +1602,25 @@ namespace ArmISA Bitfield<17, 16> cp8; Bitfield<19, 18> cp9; Bitfield<21, 20> cp10; + Bitfield<21, 20> fpen; // AArch64 Bitfield<23, 22> cp11; Bitfield<25, 24> cp12; Bitfield<27, 26> cp13; Bitfield<29, 28> rsvd; + Bitfield<28> tta; // AArch64 Bitfield<30> d32dis; Bitfield<31> asedis; EndBitUnion(CPACR) BitUnion32(FSR) Bitfield<3, 0> fsLow; + Bitfield<5, 0> status; // LPAE Bitfield<7, 4> domain; + Bitfield<9> lpae; Bitfield<10> fsHigh; Bitfield<11> wnr; Bitfield<12> ext; + Bitfield<13> cm; // LPAE EndBitUnion(FSR) BitUnion32(FPSCR) @@ -470,6 +1685,52 @@ namespace ArmISA Bitfield<31, 28> raz; EndBitUnion(MVFR1) + BitUnion64(TTBCR) + // Short-descriptor translation table format + Bitfield<2, 0> n; + Bitfield<4> pd0; + Bitfield<5> pd1; + // Long-descriptor translation table format + Bitfield<5, 0> t0sz; + Bitfield<7> epd0; + Bitfield<9, 8> irgn0; + Bitfield<11, 10> orgn0; + Bitfield<13, 12> sh0; + Bitfield<14> tg0; + Bitfield<21, 16> t1sz; + Bitfield<22> a1; + Bitfield<23> epd1; + Bitfield<25, 24> irgn1; + Bitfield<27, 26> orgn1; + Bitfield<29, 28> sh1; + Bitfield<30> tg1; + Bitfield<34, 32> ips; + Bitfield<36> as; + Bitfield<37> tbi0; + Bitfield<38> tbi1; + // Common + Bitfield<31> eae; + // TCR_EL2/3 (AArch64) + Bitfield<18, 16> ps; + Bitfield<20> tbi; + EndBitUnion(TTBCR) + + BitUnion32(HTCR) + Bitfield<2, 0> t0sz; + Bitfield<9, 8> irgn0; + Bitfield<11, 10> orgn0; + Bitfield<13, 12> sh0; + EndBitUnion(HTCR) + + BitUnion32(VTCR_t) + Bitfield<3, 0> t0sz; + Bitfield<4> s; + Bitfield<7, 6> sl0; + Bitfield<9, 8> irgn0; + Bitfield<11, 10> orgn0; + Bitfield<13, 12> sh0; + EndBitUnion(VTCR_t) + BitUnion32(PRRR) Bitfield<1,0> tr0; Bitfield<3,2> tr1; @@ -544,6 +1805,72 @@ namespace ArmISA Bitfield<28> raz_28; Bitfield<31,29> format; EndBitUnion(CTR) + + BitUnion32(PMSELR) + Bitfield<4, 0> sel; + EndBitUnion(PMSELR) + + BitUnion64(PAR) + // 64-bit format + Bitfield<63, 56> attr; + Bitfield<39, 12> pa; + Bitfield<11> lpae; + Bitfield<9> ns; + Bitfield<8, 7> sh; + Bitfield<0> f; + EndBitUnion(PAR) + + BitUnion32(ESR) + Bitfield<31, 26> ec; + Bitfield<25> il; + Bitfield<15, 0> imm16; + EndBitUnion(ESR) + + BitUnion32(CPTR) + Bitfield<31> tcpac; + Bitfield<20> tta; + Bitfield<13, 12> res1_13_12_el2; + Bitfield<10> tfp; + Bitfield<9, 0> res1_9_0_el2; + EndBitUnion(CPTR) + + + // Checks read access permissions to coproc. registers + bool canReadCoprocReg(MiscRegIndex reg, SCR scr, CPSR cpsr, + ThreadContext *tc); + + // Checks write access permissions to coproc. registers + bool canWriteCoprocReg(MiscRegIndex reg, SCR scr, CPSR cpsr, + ThreadContext *tc); + + // Checks read access permissions to AArch64 system registers + bool canReadAArch64SysReg(MiscRegIndex reg, SCR scr, CPSR cpsr, + ThreadContext *tc); + + // Checks write access permissions to AArch64 system registers + bool canWriteAArch64SysReg(MiscRegIndex reg, SCR scr, CPSR cpsr, + ThreadContext *tc); + + // Uses just the scr.ns bit to pre flatten the misc regs. This is useful + // for MCR/MRC instructions + int + flattenMiscRegNsBanked(int reg, ThreadContext *tc); + + // Flattens a misc reg index using the specified security state. This is + // used for opperations (eg address translations) where the security + // state of the register access may differ from the current state of the + // processor + int + flattenMiscRegNsBanked(int reg, ThreadContext *tc, bool ns); + + // Takes a misc reg index and returns the root reg if its one of a set of + // banked registers + void + preUnflattenMiscReg(); + + int + unflattenMiscReg(int reg); + } #endif // __ARCH_ARM_MISCREGS_HH__ diff --git a/src/arch/arm/nativetrace.cc b/src/arch/arm/nativetrace.cc index 21dff8b7c..9ba3fa84a 100644 --- a/src/arch/arm/nativetrace.cc +++ b/src/arch/arm/nativetrace.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010-2011 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -124,7 +124,7 @@ Trace::ArmNativeTrace::ThreadState::update(ThreadContext *tc) newState[STATE_CPSR] = cpsr; changed[STATE_CPSR] = (newState[STATE_CPSR] != oldState[STATE_CPSR]); - for (int i = 0; i < NumFloatArchRegs; i += 2) { + for (int i = 0; i < NumFloatV7ArchRegs; i += 2) { newState[STATE_F0 + (i >> 1)] = static_cast<uint64_t>(tc->readFloatRegBits(i + 1)) << 32 | tc->readFloatRegBits(i); diff --git a/src/arch/arm/pagetable.hh b/src/arch/arm/pagetable.hh index 898ab3191..591ec9807 100644 --- a/src/arch/arm/pagetable.hh +++ b/src/arch/arm/pagetable.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010, 2012-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -43,6 +43,8 @@ #ifndef __ARCH_ARM_PAGETABLE_H__ #define __ARCH_ARM_PAGETABLE_H__ +#include <cstdint> + #include "arch/arm/isa_traits.hh" #include "arch/arm/utility.hh" #include "arch/arm/vtophys.hh" @@ -71,69 +73,107 @@ struct PTE }; +// Lookup level +enum LookupLevel { + L0 = 0, // AArch64 only + L1, + L2, + L3, + MAX_LOOKUP_LEVELS +}; + // ITB/DTB table entry struct TlbEntry { public: - enum MemoryType { + enum class MemoryType : std::uint8_t { StronglyOrdered, Device, Normal }; - enum DomainType { - DomainNoAccess = 0, - DomainClient, - DomainReserved, - DomainManager + + enum class DomainType : std::uint8_t { + NoAccess = 0, + Client, + Reserved, + Manager }; // Matching variables Addr pfn; Addr size; // Size of this entry, == Type of TLB Rec Addr vpn; // Virtual Page Number - uint32_t asid; // Address Space Identifier + uint64_t attributes; // Memory attributes formatted for PAR + + LookupLevel lookupLevel; // Lookup level where the descriptor was fetched + // from. Used to set the FSR for faults + // occurring while the long desc. format is in + // use (AArch32 w/ LPAE and AArch64) + + uint16_t asid; // Address Space Identifier + uint8_t vmid; // Virtual machine Identifier uint8_t N; // Number of bits in pagesize + uint8_t innerAttrs; + uint8_t outerAttrs; + uint8_t ap; // Access permissions bits + uint8_t hap; // Hyp access permissions bits + DomainType domain; // Access Domain + + MemoryType mtype; + + // True if the long descriptor format is used for this entry (LPAE only) + bool longDescFormat; // @todo use this in the update attribute bethod + + bool isHyp; bool global; bool valid; + // True if the entry targets the non-secure physical address space + bool ns; + // True if the entry was brought in from a non-secure page table + bool nstid; + // Exception level on insert, AARCH64 EL0&1, AARCH32 -> el=1 + uint8_t el; + // Type of memory bool nonCacheable; // Can we wrap this in mtype? - bool sNp; // Section descriptor // Memory Attributes - MemoryType mtype; - uint8_t innerAttrs; - uint8_t outerAttrs; bool shareable; - uint32_t attributes; // Memory attributes formatted for PAR - + bool outerShareable; // Access permissions bool xn; // Execute Never - uint8_t ap; // Access permissions bits - uint8_t domain; // Access Domain + bool pxn; // Privileged Execute Never (LPAE only) //Construct an entry that maps to physical address addr for SE mode - TlbEntry(Addr _asn, Addr _vaddr, Addr _paddr) + TlbEntry(Addr _asn, Addr _vaddr, Addr _paddr) : + pfn(_paddr >> PageShift), size(PageBytes - 1), vpn(_vaddr >> PageShift), + attributes(0), lookupLevel(L1), asid(_asn), vmid(0), N(0), + innerAttrs(0), outerAttrs(0), ap(0), hap(0x3), + domain(DomainType::Client), mtype(MemoryType::StronglyOrdered), + longDescFormat(false), isHyp(false), global(false), valid(true), + ns(true), nstid(true), el(0), nonCacheable(false), shareable(false), + outerShareable(false), xn(0), pxn(0) { - pfn = _paddr >> PageShift; - size = PageBytes - 1; - asid = _asn; - global = false; - valid = true; + // no restrictions by default, hap = 0x3 - vpn = _vaddr >> PageShift; + // @todo Check the memory type + } - nonCacheable = sNp = false; + TlbEntry() : + pfn(0), size(0), vpn(0), attributes(0), lookupLevel(L1), asid(0), + vmid(0), N(0), innerAttrs(0), outerAttrs(0), ap(0), hap(0x3), + domain(DomainType::Client), mtype(MemoryType::StronglyOrdered), + longDescFormat(false), isHyp(false), global(false), valid(true), + ns(true), nstid(true), el(0), nonCacheable(false), + shareable(false), outerShareable(false), xn(0), pxn(0) + { + // no restrictions by default, hap = 0x3 - xn = 0; - ap = 0; // ??? - domain = DomainClient; //??? + // @todo Check the memory type } - TlbEntry() - {} - void updateVaddr(Addr new_vaddr) { @@ -141,67 +181,165 @@ struct TlbEntry } Addr - pageStart() + pageStart() const { return pfn << PageShift; } bool - match(Addr va, uint8_t cid) + match(Addr va, uint8_t _vmid, bool hypLookUp, bool secure_lookup, + uint8_t target_el) const + { + return match(va, 0, _vmid, hypLookUp, secure_lookup, true, target_el); + } + + bool + match(Addr va, uint16_t asn, uint8_t _vmid, bool hypLookUp, + bool secure_lookup, bool ignore_asn, uint8_t target_el) const { + bool match = false; Addr v = vpn << N; - if (valid && va >= v && va <= v + size && (global || cid == asid)) - return true; - return false; + + if (valid && va >= v && va <= v + size && (secure_lookup == !nstid) && + (hypLookUp == isHyp)) + { + if (target_el == 2 || target_el == 3) + match = (el == target_el); + else + match = (el == 0) || (el == 1); + if (match && !ignore_asn) { + match = global || (asn == asid); + } + if (match && nstid) { + match = isHyp || (_vmid == vmid); + } + } + return match; } Addr - pAddr(Addr va) + pAddr(Addr va) const { return (pfn << N) | (va & size); } void + updateAttributes() + { + uint64_t mask; + uint64_t newBits; + + // chec bit 11 to determine if its currently LPAE or VMSA format. + if ( attributes & (1 << 11) ) { + newBits = ((outerShareable ? 0x2 : + shareable ? 0x3 : 0) << 7); + mask = 0x180; + } else { + /** Formatting for Physical Address Register (PAR) + * Only including lower bits (TLB info here) + * PAR (32-bit format): + * PA [31:12] + * LPAE [11] (Large Physical Address Extension) + * TLB info [10:1] + * NOS [10] (Not Outer Sharable) + * NS [9] (Non-Secure) + * -- [8] (Implementation Defined) + * SH [7] (Sharable) + * Inner[6:4](Inner memory attributes) + * Outer[3:2](Outer memory attributes) + * SS [1] (SuperSection) + * F [0] (Fault, Fault Status in [6:1] if faulted) + */ + newBits = ((outerShareable ? 0:1) << 10) | + ((shareable ? 1:0) << 7) | + (innerAttrs << 4) | + (outerAttrs << 2); + // TODO: Supersection bit + mask = 0x4FC; + } + // common bits + newBits |= ns << 9; // NS bit + mask |= 1 << 9; + // add in the new bits + attributes &= ~mask; + attributes |= newBits; + } + + void + setAttributes(bool lpae) + { + attributes = lpae ? (1 << 11) : 0; + updateAttributes(); + } + + std::string + print() const + { + return csprintf("%#x, asn %d vmn %d hyp %d ppn %#x size: %#x ap:%d " + "ns:%d nstid:%d g:%d el:%d", vpn << N, asid, vmid, + isHyp, pfn << N, size, ap, ns, nstid, global, el); + } + + void serialize(std::ostream &os) { + SERIALIZE_SCALAR(longDescFormat); SERIALIZE_SCALAR(pfn); SERIALIZE_SCALAR(size); SERIALIZE_SCALAR(vpn); SERIALIZE_SCALAR(asid); + SERIALIZE_SCALAR(vmid); + SERIALIZE_SCALAR(isHyp); SERIALIZE_SCALAR(N); SERIALIZE_SCALAR(global); SERIALIZE_SCALAR(valid); + SERIALIZE_SCALAR(ns); + SERIALIZE_SCALAR(nstid); SERIALIZE_SCALAR(nonCacheable); - SERIALIZE_SCALAR(sNp); + SERIALIZE_ENUM(lookupLevel); SERIALIZE_ENUM(mtype); SERIALIZE_SCALAR(innerAttrs); SERIALIZE_SCALAR(outerAttrs); SERIALIZE_SCALAR(shareable); + SERIALIZE_SCALAR(outerShareable); SERIALIZE_SCALAR(attributes); SERIALIZE_SCALAR(xn); + SERIALIZE_SCALAR(pxn); SERIALIZE_SCALAR(ap); - SERIALIZE_SCALAR(domain); + SERIALIZE_SCALAR(hap); + uint8_t domain_ = static_cast<uint8_t>(domain); + paramOut(os, "domain", domain_); } void unserialize(Checkpoint *cp, const std::string §ion) { + UNSERIALIZE_SCALAR(longDescFormat); UNSERIALIZE_SCALAR(pfn); UNSERIALIZE_SCALAR(size); UNSERIALIZE_SCALAR(vpn); UNSERIALIZE_SCALAR(asid); + UNSERIALIZE_SCALAR(vmid); + UNSERIALIZE_SCALAR(isHyp); UNSERIALIZE_SCALAR(N); UNSERIALIZE_SCALAR(global); UNSERIALIZE_SCALAR(valid); + UNSERIALIZE_SCALAR(ns); + UNSERIALIZE_SCALAR(nstid); UNSERIALIZE_SCALAR(nonCacheable); - UNSERIALIZE_SCALAR(sNp); + UNSERIALIZE_ENUM(lookupLevel); UNSERIALIZE_ENUM(mtype); UNSERIALIZE_SCALAR(innerAttrs); UNSERIALIZE_SCALAR(outerAttrs); UNSERIALIZE_SCALAR(shareable); + UNSERIALIZE_SCALAR(outerShareable); UNSERIALIZE_SCALAR(attributes); UNSERIALIZE_SCALAR(xn); + UNSERIALIZE_SCALAR(pxn); UNSERIALIZE_SCALAR(ap); - UNSERIALIZE_SCALAR(domain); + UNSERIALIZE_SCALAR(hap); + uint8_t domain_; + paramIn(cp, section, "domain", domain_); + domain = static_cast<DomainType>(domain_); } }; diff --git a/src/arch/arm/process.cc b/src/arch/arm/process.cc index 37999c905..dd23a5e21 100644 --- a/src/arch/arm/process.cc +++ b/src/arch/arm/process.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010, 2012 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -61,6 +61,12 @@ ArmLiveProcess::ArmLiveProcess(LiveProcessParams *params, ObjectFile *objFile, ObjectFile::Arch _arch) : LiveProcess(params, objFile), arch(_arch) { +} + +ArmLiveProcess32::ArmLiveProcess32(LiveProcessParams *params, + ObjectFile *objFile, ObjectFile::Arch _arch) + : ArmLiveProcess(params, objFile, _arch) +{ stack_base = 0xbf000000L; // Set pointer for next thread stack. Reserve 8M for main stack. @@ -74,11 +80,28 @@ ArmLiveProcess::ArmLiveProcess(LiveProcessParams *params, ObjectFile *objFile, mmap_start = mmap_end = 0x40000000L; } +ArmLiveProcess64::ArmLiveProcess64(LiveProcessParams *params, + ObjectFile *objFile, ObjectFile::Arch _arch) + : ArmLiveProcess(params, objFile, _arch) +{ + stack_base = 0x7fffff0000L; + + // Set pointer for next thread stack. Reserve 8M for main stack. + next_thread_stack_base = stack_base - (8 * 1024 * 1024); + + // Set up break point (Top of Heap) + brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize(); + brk_point = roundUp(brk_point, VMPageSize); + + // Set up region for mmaps. For now, start at bottom of kuseg space. + mmap_start = mmap_end = 0x4000000000L; +} + void -ArmLiveProcess::initState() +ArmLiveProcess32::initState() { LiveProcess::initState(); - argsInit(MachineBytes, VMPageSize); + argsInit<uint32_t>(VMPageSize, INTREG_SP); for (int i = 0; i < contextIds.size(); i++) { ThreadContext * tc = system->getThreadContext(contextIds[i]); CPACR cpacr = tc->readMiscReg(MISCREG_CPACR); @@ -94,9 +117,34 @@ ArmLiveProcess::initState() } void -ArmLiveProcess::argsInit(int intSize, int pageSize) +ArmLiveProcess64::initState() { - typedef AuxVector<uint32_t> auxv_t; + LiveProcess::initState(); + argsInit<uint64_t>(VMPageSize, INTREG_SP0); + for (int i = 0; i < contextIds.size(); i++) { + ThreadContext * tc = system->getThreadContext(contextIds[i]); + CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); + cpsr.mode = MODE_EL0T; + tc->setMiscReg(MISCREG_CPSR, cpsr); + CPACR cpacr = tc->readMiscReg(MISCREG_CPACR_EL1); + // Enable the floating point coprocessors. + cpacr.cp10 = 0x3; + cpacr.cp11 = 0x3; + tc->setMiscReg(MISCREG_CPACR_EL1, cpacr); + // Generically enable floating point support. + FPEXC fpexc = tc->readMiscReg(MISCREG_FPEXC); + fpexc.en = 1; + tc->setMiscReg(MISCREG_FPEXC, fpexc); + } +} + +template <class IntType> +void +ArmLiveProcess::argsInit(int pageSize, IntRegIndex spIndex) +{ + int intSize = sizeof(IntType); + + typedef AuxVector<IntType> auxv_t; std::vector<auxv_t> auxv; string filename; @@ -133,7 +181,7 @@ ArmLiveProcess::argsInit(int intSize, int pageSize) //Auxilliary vectors are loaded only for elf formatted executables. ElfObject * elfObject = dynamic_cast<ElfObject *>(objFile); if (elfObject) { - uint32_t features = + IntType features = Arm_Swp | Arm_Half | Arm_Thumb | @@ -253,16 +301,16 @@ ArmLiveProcess::argsInit(int intSize, int pageSize) allocateMem(roundDown(stack_min, pageSize), roundUp(stack_size, pageSize)); // map out initial stack contents - uint32_t sentry_base = stack_base - sentry_size; - uint32_t aux_data_base = sentry_base - aux_data_size; - uint32_t env_data_base = aux_data_base - env_data_size; - uint32_t arg_data_base = env_data_base - arg_data_size; - uint32_t platform_base = arg_data_base - platform_size; - uint32_t aux_random_base = platform_base - aux_random_size; - uint32_t auxv_array_base = aux_random_base - aux_array_size - aux_padding; - uint32_t envp_array_base = auxv_array_base - envp_array_size; - uint32_t argv_array_base = envp_array_base - argv_array_size; - uint32_t argc_base = argv_array_base - argc_size; + IntType sentry_base = stack_base - sentry_size; + IntType aux_data_base = sentry_base - aux_data_size; + IntType env_data_base = aux_data_base - env_data_size; + IntType arg_data_base = env_data_base - arg_data_size; + IntType platform_base = arg_data_base - platform_size; + IntType aux_random_base = platform_base - aux_random_size; + IntType auxv_array_base = aux_random_base - aux_array_size - aux_padding; + IntType envp_array_base = auxv_array_base - envp_array_size; + IntType argv_array_base = envp_array_base - argv_array_size; + IntType argc_base = argv_array_base - argc_size; DPRINTF(Stack, "The addresses of items on the initial stack:\n"); DPRINTF(Stack, "0x%x - aux data\n", aux_data_base); @@ -279,11 +327,11 @@ ArmLiveProcess::argsInit(int intSize, int pageSize) // write contents to stack // figure out argc - uint32_t argc = argv.size(); - uint32_t guestArgc = ArmISA::htog(argc); + IntType argc = argv.size(); + IntType guestArgc = ArmISA::htog(argc); //Write out the sentry void * - uint32_t sentry_NULL = 0; + IntType sentry_NULL = 0; initVirtMem.writeBlob(sentry_base, (uint8_t*)&sentry_NULL, sentry_size); @@ -302,8 +350,7 @@ ArmLiveProcess::argsInit(int intSize, int pageSize) } //Copy the aux stuff - for(int x = 0; x < auxv.size(); x++) - { + for (int x = 0; x < auxv.size(); x++) { initVirtMem.writeBlob(auxv_array_base + x * 2 * intSize, (uint8_t*)&(auxv[x].a_type), intSize); initVirtMem.writeBlob(auxv_array_base + (x * 2 + 1) * intSize, @@ -321,7 +368,7 @@ ArmLiveProcess::argsInit(int intSize, int pageSize) ThreadContext *tc = system->getThreadContext(contextIds[0]); //Set the stack pointer register - tc->setIntReg(StackPointerReg, stack_min); + tc->setIntReg(spIndex, stack_min); //A pointer to a function to run when the program exits. We'll set this //to zero explicitly to make sure this isn't used. tc->setIntReg(ArgumentReg0, 0); @@ -342,6 +389,8 @@ ArmLiveProcess::argsInit(int intSize, int pageSize) PCState pc; pc.thumb(arch == ObjectFile::Thumb); pc.nextThumb(pc.thumb()); + pc.aarch64(arch == ObjectFile::Arm64); + pc.nextAArch64(pc.aarch64()); pc.set(objFile->entryPoint() & ~mask(1)); tc->pcState(pc); @@ -350,14 +399,21 @@ ArmLiveProcess::argsInit(int intSize, int pageSize) } ArmISA::IntReg -ArmLiveProcess::getSyscallArg(ThreadContext *tc, int &i) +ArmLiveProcess32::getSyscallArg(ThreadContext *tc, int &i) { assert(i < 6); return tc->readIntReg(ArgumentReg0 + i++); } -uint64_t -ArmLiveProcess::getSyscallArg(ThreadContext *tc, int &i, int width) +ArmISA::IntReg +ArmLiveProcess64::getSyscallArg(ThreadContext *tc, int &i) +{ + assert(i < 8); + return tc->readIntReg(ArgumentReg0 + i++); +} + +ArmISA::IntReg +ArmLiveProcess32::getSyscallArg(ThreadContext *tc, int &i, int width) { assert(width == 32 || width == 64); if (width == 32) @@ -375,17 +431,37 @@ ArmLiveProcess::getSyscallArg(ThreadContext *tc, int &i, int width) return val; } +ArmISA::IntReg +ArmLiveProcess64::getSyscallArg(ThreadContext *tc, int &i, int width) +{ + return getSyscallArg(tc, i); +} + + +void +ArmLiveProcess32::setSyscallArg(ThreadContext *tc, int i, ArmISA::IntReg val) +{ + assert(i < 6); + tc->setIntReg(ArgumentReg0 + i, val); +} void -ArmLiveProcess::setSyscallArg(ThreadContext *tc, +ArmLiveProcess64::setSyscallArg(ThreadContext *tc, int i, ArmISA::IntReg val) { - assert(i < 4); + assert(i < 8); tc->setIntReg(ArgumentReg0 + i, val); } void -ArmLiveProcess::setSyscallReturn(ThreadContext *tc, +ArmLiveProcess32::setSyscallReturn(ThreadContext *tc, + SyscallReturn return_value) +{ + tc->setIntReg(ReturnValueReg, return_value.value()); +} + +void +ArmLiveProcess64::setSyscallReturn(ThreadContext *tc, SyscallReturn return_value) { tc->setIntReg(ReturnValueReg, return_value.value()); diff --git a/src/arch/arm/process.hh b/src/arch/arm/process.hh index f8d821037..34ce1dd02 100644 --- a/src/arch/arm/process.hh +++ b/src/arch/arm/process.hh @@ -1,4 +1,16 @@ /* +* Copyright (c) 2012 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * * Copyright (c) 2007-2008 The Florida State University * All rights reserved. * @@ -34,6 +46,7 @@ #include <string> #include <vector> +#include "arch/arm/intregs.hh" #include "base/loader/object_file.hh" #include "sim/process.hh" @@ -47,11 +60,37 @@ class ArmLiveProcess : public LiveProcess ObjectFile::Arch arch; ArmLiveProcess(LiveProcessParams * params, ObjectFile *objFile, ObjectFile::Arch _arch); + template<class IntType> + void argsInit(int pageSize, ArmISA::IntRegIndex spIndex); +}; + +class ArmLiveProcess32 : public ArmLiveProcess +{ + protected: + ObjectFile::Arch arch; + ArmLiveProcess32(LiveProcessParams * params, ObjectFile *objFile, + ObjectFile::Arch _arch); + + void initState(); + + public: + + ArmISA::IntReg getSyscallArg(ThreadContext *tc, int &i, int width); + ArmISA::IntReg getSyscallArg(ThreadContext *tc, int &i); + void setSyscallArg(ThreadContext *tc, int i, ArmISA::IntReg val); + void setSyscallReturn(ThreadContext *tc, SyscallReturn return_value); +}; + +class ArmLiveProcess64 : public ArmLiveProcess +{ + protected: + ObjectFile::Arch arch; + ArmLiveProcess64(LiveProcessParams * params, ObjectFile *objFile, + ObjectFile::Arch _arch); void initState(); public: - void argsInit(int intSize, int pageSize); ArmISA::IntReg getSyscallArg(ThreadContext *tc, int &i, int width); ArmISA::IntReg getSyscallArg(ThreadContext *tc, int &i); diff --git a/src/arch/arm/registers.hh b/src/arch/arm/registers.hh index b9033fd5b..09041f306 100644 --- a/src/arch/arm/registers.hh +++ b/src/arch/arm/registers.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010-2011 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -74,11 +74,12 @@ typedef uint8_t CCReg; // Constants Related to the number of registers const int NumIntArchRegs = NUM_ARCH_INTREGS; // The number of single precision floating point registers -const int NumFloatArchRegs = 64; -const int NumFloatSpecialRegs = 8; +const int NumFloatV7ArchRegs = 64; +const int NumFloatV8ArchRegs = 128; +const int NumFloatSpecialRegs = 32; const int NumIntRegs = NUM_INTREGS; -const int NumFloatRegs = NumFloatArchRegs + NumFloatSpecialRegs; +const int NumFloatRegs = NumFloatV8ArchRegs + NumFloatSpecialRegs; const int NumCCRegs = 0; const int NumMiscRegs = NUM_MISCREGS; @@ -89,6 +90,7 @@ const int ReturnValueReg = 0; const int ReturnValueReg1 = 1; const int ReturnValueReg2 = 2; const int NumArgumentRegs = 4; +const int NumArgumentRegs64 = 8; const int ArgumentReg0 = 0; const int ArgumentReg1 = 1; const int ArgumentReg2 = 2; diff --git a/src/arch/arm/remote_gdb.cc b/src/arch/arm/remote_gdb.cc index 4078630d6..74c3c7ff3 100644 --- a/src/arch/arm/remote_gdb.cc +++ b/src/arch/arm/remote_gdb.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010, 2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -138,6 +138,7 @@ #include "arch/arm/pagetable.hh" #include "arch/arm/registers.hh" #include "arch/arm/remote_gdb.hh" +#include "arch/arm/system.hh" #include "arch/arm/utility.hh" #include "arch/arm/vtophys.hh" #include "base/intmath.hh" @@ -159,7 +160,7 @@ using namespace std; using namespace ArmISA; RemoteGDB::RemoteGDB(System *_system, ThreadContext *tc) - : BaseRemoteGDB(_system, tc, NUMREGS) + : BaseRemoteGDB(_system, tc, MAX_NUMREGS) { } @@ -204,45 +205,65 @@ RemoteGDB::getregs() memset(gdbregs.regs, 0, gdbregs.bytes()); - // R0-R15 supervisor mode - // arm registers are 32 bits wide, gdb registers are 64 bits wide - // two arm registers are packed into one gdb register (little endian) - gdbregs.regs[REG_R0 + 0] = context->readIntReg(INTREG_R1) << 32 | - context->readIntReg(INTREG_R0); - gdbregs.regs[REG_R0 + 1] = context->readIntReg(INTREG_R3) << 32 | - context->readIntReg(INTREG_R2); - gdbregs.regs[REG_R0 + 2] = context->readIntReg(INTREG_R5) << 32 | - context->readIntReg(INTREG_R4); - gdbregs.regs[REG_R0 + 3] = context->readIntReg(INTREG_R7) << 32 | - context->readIntReg(INTREG_R6); - gdbregs.regs[REG_R0 + 4] = context->readIntReg(INTREG_R9) << 32 | - context->readIntReg(INTREG_R8); - gdbregs.regs[REG_R0 + 5] = context->readIntReg(INTREG_R11) << 32| - context->readIntReg(INTREG_R10); - gdbregs.regs[REG_R0 + 6] = context->readIntReg(INTREG_SP) << 32 | - context->readIntReg(INTREG_R12); - gdbregs.regs[REG_R0 + 7] = context->pcState().pc() << 32 | - context->readIntReg(INTREG_LR); - - // CPSR - gdbregs.regs[REG_CPSR] = context->readMiscRegNoEffect(MISCREG_CPSR); - - // vfpv3/neon floating point registers (32 double or 64 float) - - gdbregs.regs[REG_F0] = - static_cast<uint64_t>(context->readFloatRegBits(0)) << 32 | - gdbregs.regs[REG_CPSR]; - - for (int i = 1; i < (NumFloatArchRegs>>1); ++i) { - gdbregs.regs[i + REG_F0] = - static_cast<uint64_t>(context->readFloatRegBits(2*i)) << 32 | - context->readFloatRegBits(2*i-1); + if (inAArch64(context)) { // AArch64 + // x0-x31 + for (int i = 0; i < 32; ++i) { + gdbregs.regs[REG_X0 + i] = context->readIntReg(INTREG_X0 + i); + } + // pc + gdbregs.regs[REG_PC_64] = context->pcState().pc(); + // cpsr + gdbregs.regs[REG_CPSR_64] = context->readMiscRegNoEffect(MISCREG_CPSR); + // v0-v31 + for (int i = 0; i < 32; ++i) { + gdbregs.regs[REG_V0 + 2 * i] = static_cast<uint64_t>( + context->readFloatRegBits(i * 4 + 3)) << 32 | + context->readFloatRegBits(i * 4 + 2); + gdbregs.regs[REG_V0 + 2 * i + 1] = static_cast<uint64_t>( + context->readFloatRegBits(i * 4 + 1)) << 32 | + context->readFloatRegBits(i * 4 + 0); + } + } else { // AArch32 + // R0-R15 supervisor mode + // arm registers are 32 bits wide, gdb registers are 64 bits wide two + // arm registers are packed into one gdb register (little endian) + gdbregs.regs[REG_R0 + 0] = context->readIntReg(INTREG_R1) << 32 | + context->readIntReg(INTREG_R0); + gdbregs.regs[REG_R0 + 1] = context->readIntReg(INTREG_R3) << 32 | + context->readIntReg(INTREG_R2); + gdbregs.regs[REG_R0 + 2] = context->readIntReg(INTREG_R5) << 32 | + context->readIntReg(INTREG_R4); + gdbregs.regs[REG_R0 + 3] = context->readIntReg(INTREG_R7) << 32 | + context->readIntReg(INTREG_R6); + gdbregs.regs[REG_R0 + 4] = context->readIntReg(INTREG_R9) << 32 | + context->readIntReg(INTREG_R8); + gdbregs.regs[REG_R0 + 5] = context->readIntReg(INTREG_R11) << 32| + context->readIntReg(INTREG_R10); + gdbregs.regs[REG_R0 + 6] = context->readIntReg(INTREG_SP) << 32 | + context->readIntReg(INTREG_R12); + gdbregs.regs[REG_R0 + 7] = context->pcState().pc() << 32 | + context->readIntReg(INTREG_LR); + + // CPSR + gdbregs.regs[REG_CPSR] = context->readMiscRegNoEffect(MISCREG_CPSR); + + // vfpv3/neon floating point registers (32 double or 64 float) + + gdbregs.regs[REG_F0] = + static_cast<uint64_t>(context->readFloatRegBits(0)) << 32 | + gdbregs.regs[REG_CPSR]; + + for (int i = 1; i < (NumFloatV7ArchRegs>>1); ++i) { + gdbregs.regs[i + REG_F0] = + static_cast<uint64_t>(context->readFloatRegBits(2*i)) << 32 | + context->readFloatRegBits(2*i-1); + } + + // FPSCR + gdbregs.regs[REG_FPSCR] = static_cast<uint64_t>( + context->readMiscRegNoEffect(MISCREG_FPSCR)) << 32 | + context->readFloatRegBits(NumFloatV7ArchRegs - 1); } - - // FPSCR - gdbregs.regs[REG_FPSCR] = - static_cast<uint64_t>(context->readMiscRegNoEffect(MISCREG_FPSCR)) << 32 | - context->readFloatRegBits(NumFloatArchRegs - 1); } /* @@ -254,46 +275,66 @@ RemoteGDB::setregs() { DPRINTF(GDBAcc, "setregs in remotegdb \n"); + if (inAArch64(context)) { // AArch64 + // x0-x31 + for (int i = 0; i < 32; ++i) { + context->setIntReg(INTREG_X0 + i, gdbregs.regs[REG_X0 + i]); + } + // pc + context->pcState(gdbregs.regs[REG_PC_64]); + // cpsr + context->setMiscRegNoEffect(MISCREG_CPSR, gdbregs.regs[REG_CPSR_64]); + // v0-v31 + for (int i = 0; i < 32; ++i) { + context->setFloatRegBits(i * 4 + 3, + gdbregs.regs[REG_V0 + 2 * i] >> 32); + context->setFloatRegBits(i * 4 + 2, + gdbregs.regs[REG_V0 + 2 * i]); + context->setFloatRegBits(i * 4 + 1, + gdbregs.regs[REG_V0 + 2 * i + 1] >> 32); + context->setFloatRegBits(i * 4 + 0, + gdbregs.regs[REG_V0 + 2 * i + 1]); + } + } else { // AArch32 + // R0-R15 supervisor mode + // arm registers are 32 bits wide, gdb registers are 64 bits wide + // two arm registers are packed into one gdb register (little endian) + context->setIntReg(INTREG_R0 , bits(gdbregs.regs[REG_R0 + 0], 31, 0)); + context->setIntReg(INTREG_R1 , bits(gdbregs.regs[REG_R0 + 0], 63, 32)); + context->setIntReg(INTREG_R2 , bits(gdbregs.regs[REG_R0 + 1], 31, 0)); + context->setIntReg(INTREG_R3 , bits(gdbregs.regs[REG_R0 + 1], 63, 32)); + context->setIntReg(INTREG_R4 , bits(gdbregs.regs[REG_R0 + 2], 31, 0)); + context->setIntReg(INTREG_R5 , bits(gdbregs.regs[REG_R0 + 2], 63, 32)); + context->setIntReg(INTREG_R6 , bits(gdbregs.regs[REG_R0 + 3], 31, 0)); + context->setIntReg(INTREG_R7 , bits(gdbregs.regs[REG_R0 + 3], 63, 32)); + context->setIntReg(INTREG_R8 , bits(gdbregs.regs[REG_R0 + 4], 31, 0)); + context->setIntReg(INTREG_R9 , bits(gdbregs.regs[REG_R0 + 4], 63, 32)); + context->setIntReg(INTREG_R10, bits(gdbregs.regs[REG_R0 + 5], 31, 0)); + context->setIntReg(INTREG_R11, bits(gdbregs.regs[REG_R0 + 5], 63, 32)); + context->setIntReg(INTREG_R12, bits(gdbregs.regs[REG_R0 + 6], 31, 0)); + context->setIntReg(INTREG_SP , bits(gdbregs.regs[REG_R0 + 6], 63, 32)); + context->setIntReg(INTREG_LR , bits(gdbregs.regs[REG_R0 + 7], 31, 0)); + context->pcState(bits(gdbregs.regs[REG_R0 + 7], 63, 32)); + + //CPSR + context->setMiscRegNoEffect(MISCREG_CPSR, gdbregs.regs[REG_CPSR]); + + //vfpv3/neon floating point registers (32 double or 64 float) + context->setFloatRegBits(0, gdbregs.regs[REG_F0]>>32); + + for (int i = 1; i < NumFloatV7ArchRegs; ++i) { + if (i%2) { + int j = (i+1)/2; + context->setFloatRegBits(i, bits(gdbregs.regs[j + REG_F0], 31, 0)); + } else { + int j = i/2; + context->setFloatRegBits(i, gdbregs.regs[j + REG_F0]>>32); + } + } - // R0-R15 supervisor mode - // arm registers are 32 bits wide, gdb registers are 64 bits wide - // two arm registers are packed into one gdb register (little endian) - context->setIntReg(INTREG_R0 , bits(gdbregs.regs[REG_R0 + 0], 31, 0)); - context->setIntReg(INTREG_R1 , bits(gdbregs.regs[REG_R0 + 0], 63, 32)); - context->setIntReg(INTREG_R2 , bits(gdbregs.regs[REG_R0 + 1], 31, 0)); - context->setIntReg(INTREG_R3 , bits(gdbregs.regs[REG_R0 + 1], 63, 32)); - context->setIntReg(INTREG_R4 , bits(gdbregs.regs[REG_R0 + 2], 31, 0)); - context->setIntReg(INTREG_R5 , bits(gdbregs.regs[REG_R0 + 2], 63, 32)); - context->setIntReg(INTREG_R6 , bits(gdbregs.regs[REG_R0 + 3], 31, 0)); - context->setIntReg(INTREG_R7 , bits(gdbregs.regs[REG_R0 + 3], 63, 32)); - context->setIntReg(INTREG_R8 , bits(gdbregs.regs[REG_R0 + 4], 31, 0)); - context->setIntReg(INTREG_R9 , bits(gdbregs.regs[REG_R0 + 4], 63, 32)); - context->setIntReg(INTREG_R10, bits(gdbregs.regs[REG_R0 + 5], 31, 0)); - context->setIntReg(INTREG_R11, bits(gdbregs.regs[REG_R0 + 5], 63, 32)); - context->setIntReg(INTREG_R12, bits(gdbregs.regs[REG_R0 + 6], 31, 0)); - context->setIntReg(INTREG_SP , bits(gdbregs.regs[REG_R0 + 6], 63, 32)); - context->setIntReg(INTREG_LR , bits(gdbregs.regs[REG_R0 + 7], 31, 0)); - context->pcState(bits(gdbregs.regs[REG_R0 + 7], 63, 32)); - - //CPSR - context->setMiscRegNoEffect(MISCREG_CPSR, gdbregs.regs[REG_CPSR]); - - //vfpv3/neon floating point registers (32 double or 64 float) - context->setFloatRegBits(0, gdbregs.regs[REG_F0]>>32); - - for (int i = 1; i < NumFloatArchRegs; ++i) { - if(i%2){ - int j = (i+1)/2; - context->setFloatRegBits(i, bits(gdbregs.regs[j + REG_F0], 31, 0)); - } - else{ - int j = i/2; - context->setFloatRegBits(i, gdbregs.regs[j + REG_F0]>>32); - } + //FPSCR + context->setMiscReg(MISCREG_FPSCR, gdbregs.regs[REG_FPSCR]>>32); } - - //FPSCR - context->setMiscReg(MISCREG_FPSCR, gdbregs.regs[REG_FPSCR]>>32); } void diff --git a/src/arch/arm/remote_gdb.hh b/src/arch/arm/remote_gdb.hh index b75d921fb..a6b2b9d35 100644 --- a/src/arch/arm/remote_gdb.hh +++ b/src/arch/arm/remote_gdb.hh @@ -1,4 +1,16 @@ /* + * Copyright (c) 2013 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * * Copyright (c) 2002-2005 The Regents of The University of Michigan * Copyright (c) 2007-2008 The Florida State University * All rights reserved. @@ -40,13 +52,24 @@ class ThreadContext; namespace ArmISA { -// registers for arm with vfpv3/neon + +// AArch32 registers with vfpv3/neon const int NUMREGS = 41; /* r0-r15, cpsr, d0-d31, fpscr */ const int REG_R0 = 0; const int REG_F0 = 8; const int REG_CPSR = 8; /* bit 512 to bit 543 */ const int REG_FPSCR = 40; /* bit 2592 to bit 2623 */ +// AArch64 registers +const int NUMREGS_64 = 98; // x0-x31, pc, cpsr (64-bit GPRs) + // v0-v31 (128-bit FPRs) +const int REG_X0 = 0; +const int REG_PC_64 = 32; +const int REG_CPSR_64 = 33; +const int REG_V0 = 34; + +const int MAX_NUMREGS = NUMREGS_64; + class RemoteGDB : public BaseRemoteGDB { diff --git a/src/arch/arm/stage2_lookup.cc b/src/arch/arm/stage2_lookup.cc new file mode 100755 index 000000000..1299ade68 --- /dev/null +++ b/src/arch/arm/stage2_lookup.cc @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2010-2013 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + * Giacomo Gabrielli + */ + +#include "arch/arm/faults.hh" +#include "arch/arm/stage2_lookup.hh" +#include "arch/arm/system.hh" +#include "arch/arm/table_walker.hh" +#include "arch/arm/tlb.hh" +#include "cpu/base.hh" +#include "cpu/thread_context.hh" +#include "debug/Checkpoint.hh" +#include "debug/TLB.hh" +#include "debug/TLBVerbose.hh" +#include "sim/system.hh" + +using namespace ArmISA; + +Fault +Stage2LookUp::getTe(ThreadContext *tc, TlbEntry *destTe) + +{ + fault = stage2Tlb->getTE(&stage2Te, &req, tc, mode, this, timing, + functional, false, tranType); + // Call finish if we're done already + if ((fault != NoFault) || (stage2Te != NULL)) { + mergeTe(&req, mode); + *destTe = stage1Te; + } + return fault; +} + +void +Stage2LookUp::mergeTe(RequestPtr req, BaseTLB::Mode mode) +{ + // Since we directly requested the table entry (which we need later on to + // merge the attributes) then we've skipped some stage 2 permissinos + // checking. So call translate on stage 2 to do the checking. As the entry + // is now in the TLB this should always hit the cache. + if (fault == NoFault) { + fault = stage2Tlb->checkPermissions(stage2Te, req, mode); + } + + // Check again that we haven't got a fault + if (fault == NoFault) { + assert(stage2Te != NULL); + + // Now we have the table entries for both stages of translation + // merge them and insert the result into the stage 1 TLB. See + // CombineS1S2Desc() in pseudocode + stage1Te.N = stage2Te->N; + stage1Te.nonCacheable |= stage2Te->nonCacheable; + stage1Te.xn |= stage2Te->xn; + + if (stage1Te.size > stage2Te->size) { + // Size mismatch also implies vpn mismatch (this is shifted by + // sizebits!). + stage1Te.vpn = s1Req->getVaddr() / (stage2Te->size+1); + stage1Te.pfn = stage2Te->pfn; + stage1Te.size = stage2Te->size; + } else if (stage1Te.size < stage2Te->size) { + // Guest 4K could well be section-backed by host hugepage! In this + // case a 4K entry is added but pfn needs to be adjusted. New PFN = + // offset into section PFN given by stage2 IPA treated as a stage1 + // page size. + stage1Te.pfn = (stage2Te->pfn * ((stage2Te->size+1) / (stage1Te.size+1))) + + (stage2Te->vpn / (stage1Te.size+1)); + // Size remains smaller of the two. + } else { + // Matching sizes + stage1Te.pfn = stage2Te->pfn; + } + + if (stage2Te->mtype == TlbEntry::MemoryType::StronglyOrdered || + stage1Te.mtype == TlbEntry::MemoryType::StronglyOrdered) { + stage1Te.mtype = TlbEntry::MemoryType::StronglyOrdered; + } else if (stage2Te->mtype == TlbEntry::MemoryType::Device || + stage1Te.mtype == TlbEntry::MemoryType::Device) { + stage1Te.mtype = TlbEntry::MemoryType::Device; + } else { + stage1Te.mtype = TlbEntry::MemoryType::Normal; + } + + if (stage1Te.mtype == TlbEntry::MemoryType::Normal) { + + if (stage2Te->innerAttrs == 0 || + stage1Te.innerAttrs == 0) { + // either encoding Non-cacheable + stage1Te.innerAttrs = 0; + } else if (stage2Te->innerAttrs == 2 || + stage1Te.innerAttrs == 2) { + // either encoding Write-Through cacheable + stage1Te.innerAttrs = 2; + } else { + // both encodings Write-Back + stage1Te.innerAttrs = 3; + } + + if (stage2Te->outerAttrs == 0 || + stage1Te.outerAttrs == 0) { + // either encoding Non-cacheable + stage1Te.outerAttrs = 0; + } else if (stage2Te->outerAttrs == 2 || + stage1Te.outerAttrs == 2) { + // either encoding Write-Through cacheable + stage1Te.outerAttrs = 2; + } else { + // both encodings Write-Back + stage1Te.outerAttrs = 3; + } + + stage1Te.shareable |= stage2Te->shareable; + stage1Te.outerShareable |= stage2Te->outerShareable; + if (stage1Te.innerAttrs == 0 && + stage1Te.outerAttrs == 0) { + // something Non-cacheable at each level is outer shareable + stage1Te.shareable = true; + stage1Te.outerShareable = true; + } + } else { + stage1Te.shareable = true; + stage1Te.outerShareable = true; + } + stage1Te.updateAttributes(); + } + + // if there's a fault annotate it, + if (fault != NoFault) { + // If the second stage of translation generated a fault add the + // details of the original stage 1 virtual address + reinterpret_cast<ArmFault *>(fault.get())->annotate(ArmFault::OVA, + s1Req->getVaddr()); + } + complete = true; +} + +void +Stage2LookUp::finish(Fault _fault, RequestPtr req, + ThreadContext *tc, BaseTLB::Mode mode) +{ + fault = _fault; + // if we haven't got the table entry get it now + if ((fault == NoFault) && (stage2Te == NULL)) { + fault = stage2Tlb->getTE(&stage2Te, req, tc, mode, this, + timing, functional, false, tranType); + } + + // Now we have the stage 2 table entry we need to merge it with the stage + // 1 entry we were given at the start + mergeTe(req, mode); + + if (fault != NoFault) { + transState->finish(fault, req, tc, mode); + } else if (timing) { + // Now notify the original stage 1 translation that we finally have + // a result + stage1Tlb->translateComplete(s1Req, tc, transState, mode, tranType, true); + } + // if we have been asked to delete ourselfs do it now + if (selfDelete) { + delete this; + } +} + diff --git a/src/arch/arm/stage2_lookup.hh b/src/arch/arm/stage2_lookup.hh new file mode 100755 index 000000000..3a1228f46 --- /dev/null +++ b/src/arch/arm/stage2_lookup.hh @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2010-2013 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + * Giacomo Gabrielli + */ + +#ifndef __ARCH_ARM_STAGE2_LOOKUP_HH__ +#define __ARCH_ARM_STAGE2_LOOKUP_HH__ + +#include <list> + +#include "arch/arm/system.hh" +#include "arch/arm/table_walker.hh" +#include "arch/arm/tlb.hh" +#include "mem/request.hh" +#include "sim/tlb.hh" + +class ThreadContext; + +namespace ArmISA { +class Translation; +class TLB; + + +class Stage2LookUp : public BaseTLB::Translation +{ + private: + TLB *stage1Tlb; + TLB *stage2Tlb; + TlbEntry stage1Te; + RequestPtr s1Req; + TLB::Translation *transState; + BaseTLB::Mode mode; + bool timing; + bool functional; + TLB::ArmTranslationType tranType; + TlbEntry *stage2Te; + Request req; + Fault fault; + bool complete; + bool selfDelete; + + public: + Stage2LookUp(TLB *s1Tlb, TLB *s2Tlb, TlbEntry s1Te, RequestPtr _req, + TLB::Translation *_transState, BaseTLB::Mode _mode, bool _timing, + bool _functional, TLB::ArmTranslationType _tranType) : + stage1Tlb(s1Tlb), stage2Tlb(s2Tlb), stage1Te(s1Te), s1Req(_req), + transState(_transState), mode(_mode), timing(_timing), + functional(_functional), tranType(_tranType), fault(NoFault), + complete(false), selfDelete(false) + { + req.setVirt(0, s1Te.pAddr(s1Req->getVaddr()), s1Req->getSize(), + s1Req->getFlags(), s1Req->masterId(), 0); + } + + Fault getTe(ThreadContext *tc, TlbEntry *destTe); + + void mergeTe(RequestPtr req, BaseTLB::Mode mode); + + void setSelfDelete() { selfDelete = true; } + + bool isComplete() const { return complete; } + + void markDelayed() {} + + void finish(Fault fault, RequestPtr req, ThreadContext *tc, + BaseTLB::Mode mode); +}; + + +} // namespace ArmISA + +#endif //__ARCH_ARM_STAGE2_LOOKUP_HH__ + diff --git a/src/arch/arm/stage2_mmu.cc b/src/arch/arm/stage2_mmu.cc new file mode 100755 index 000000000..01451548c --- /dev/null +++ b/src/arch/arm/stage2_mmu.cc @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2012-2013 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Thomas Grocutt + */ + +#include "arch/arm/faults.hh" +#include "arch/arm/stage2_mmu.hh" +#include "arch/arm/system.hh" +#include "arch/arm/tlb.hh" +#include "cpu/base.hh" +#include "cpu/thread_context.hh" +#include "debug/Checkpoint.hh" +#include "debug/TLB.hh" +#include "debug/TLBVerbose.hh" + +using namespace ArmISA; + +Stage2MMU::Stage2MMU(const Params *p) + : SimObject(p), _stage1Tlb(p->tlb), _stage2Tlb(p->stage2_tlb) +{ + stage1Tlb()->setMMU(this); + stage2Tlb()->setMMU(this); +} + +Fault +Stage2MMU::readDataUntimed(ThreadContext *tc, Addr oVAddr, Addr descAddr, + uint8_t *data, int numBytes, Request::Flags flags, int masterId, + bool isFunctional) +{ + Fault fault; + + // translate to physical address using the second stage MMU + Request req = Request(); + req.setVirt(0, descAddr, numBytes, flags | Request::PT_WALK, masterId, 0); + if (isFunctional) { + fault = stage2Tlb()->translateFunctional(&req, tc, BaseTLB::Read); + } else { + fault = stage2Tlb()->translateAtomic(&req, tc, BaseTLB::Read); + } + + // Now do the access. + if (fault == NoFault && !req.getFlags().isSet(Request::NO_ACCESS)) { + Packet pkt = Packet(&req, MemCmd::ReadReq); + pkt.dataStatic(data); + if (isFunctional) { + stage1Tlb()->getWalkerPort().sendFunctional(&pkt); + } else { + stage1Tlb()->getWalkerPort().sendAtomic(&pkt); + } + assert(!pkt.isError()); + } + + // If there was a fault annotate it with the flag saying the foult occured + // while doing a translation for a stage 1 page table walk. + if (fault != NoFault) { + ArmFault *armFault = reinterpret_cast<ArmFault *>(fault.get()); + armFault->annotate(ArmFault::S1PTW, true); + armFault->annotate(ArmFault::OVA, oVAddr); + } + return fault; +} + +Fault +Stage2MMU::readDataTimed(ThreadContext *tc, Addr descAddr, + Stage2Translation *translation, int numBytes, Request::Flags flags, + int masterId) +{ + Fault fault; + // translate to physical address using the second stage MMU + translation->setVirt(descAddr, numBytes, flags | Request::PT_WALK, masterId); + fault = translation->translateTiming(tc); + return fault; +} + +Stage2MMU::Stage2Translation::Stage2Translation(Stage2MMU &_parent, + uint8_t *_data, Event *_event, Addr _oVAddr) + : data(_data), event(_event), parent(_parent), oVAddr(_oVAddr), + fault(NoFault) +{ +} + +void +Stage2MMU::Stage2Translation::finish(Fault _fault, RequestPtr req, ThreadContext *tc, + BaseTLB::Mode mode) +{ + fault = _fault; + + // If there was a fault annotate it with the flag saying the foult occured + // while doing a translation for a stage 1 page table walk. + if (fault != NoFault) { + ArmFault *armFault = reinterpret_cast<ArmFault *>(fault.get()); + armFault->annotate(ArmFault::S1PTW, true); + armFault->annotate(ArmFault::OVA, oVAddr); + } + + if (_fault == NoFault && !req->getFlags().isSet(Request::NO_ACCESS)) { + DmaPort& port = parent.stage1Tlb()->getWalkerPort(); + port.dmaAction(MemCmd::ReadReq, req->getPaddr(), numBytes, + event, data, tc->getCpuPtr()->clockPeriod(), + req->getFlags()); + } else { + // We can't do the DMA access as there's been a problem, so tell the + // event we're done + event->process(); + } +} + +ArmISA::Stage2MMU * +ArmStage2MMUParams::create() +{ + return new ArmISA::Stage2MMU(this); +} diff --git a/src/arch/arm/stage2_mmu.hh b/src/arch/arm/stage2_mmu.hh new file mode 100755 index 000000000..d1812c4ed --- /dev/null +++ b/src/arch/arm/stage2_mmu.hh @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2012-2013 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Thomas Grocutt + */ + +#ifndef __ARCH_ARM_STAGE2_MMU_HH__ +#define __ARCH_ARM_STAGE2_MMU_HH__ + +#include "arch/arm/faults.hh" +#include "arch/arm/tlb.hh" +#include "mem/request.hh" +#include "params/ArmStage2MMU.hh" +#include "sim/eventq.hh" + +namespace ArmISA { + +class Stage2MMU : public SimObject +{ + private: + TLB *_stage1Tlb; + /** The TLB that will cache the stage 2 look ups. */ + TLB *_stage2Tlb; + + public: + /** This translation class is used to trigger the data fetch once a timing + translation returns the translated physical address */ + class Stage2Translation : public BaseTLB::Translation + { + private: + uint8_t *data; + int numBytes; + Request req; + Event *event; + Stage2MMU &parent; + Addr oVAddr; + + public: + Fault fault; + + Stage2Translation(Stage2MMU &_parent, uint8_t *_data, Event *_event, + Addr _oVAddr); + + void + markDelayed() {} + + void + finish(Fault fault, RequestPtr req, ThreadContext *tc, + BaseTLB::Mode mode); + + void setVirt(Addr vaddr, int size, Request::Flags flags, int masterId) + { + numBytes = size; + req.setVirt(0, vaddr, size, flags, masterId, 0); + } + + Fault translateTiming(ThreadContext *tc) + { + return (parent.stage2Tlb()->translateTiming(&req, tc, this, BaseTLB::Read)); + } + }; + + typedef ArmStage2MMUParams Params; + Stage2MMU(const Params *p); + + Fault readDataUntimed(ThreadContext *tc, Addr oVAddr, Addr descAddr, + uint8_t *data, int numBytes, Request::Flags flags, int masterId, + bool isFunctional); + Fault readDataTimed(ThreadContext *tc, Addr descAddr, + Stage2Translation *translation, int numBytes, Request::Flags flags, + int masterId); + + TLB* stage1Tlb() const { return _stage1Tlb; } + TLB* stage2Tlb() const { return _stage2Tlb; } +}; + + + +} // namespace ArmISA + +#endif //__ARCH_ARM_STAGE2_MMU_HH__ + diff --git a/src/arch/arm/system.cc b/src/arch/arm/system.cc index b09784b64..00d9d7613 100644 --- a/src/arch/arm/system.cc +++ b/src/arch/arm/system.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010, 2012-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -48,19 +48,46 @@ #include "cpu/thread_context.hh" #include "mem/physical.hh" #include "mem/fs_translating_port_proxy.hh" +#include "sim/full_system.hh" using namespace std; using namespace Linux; ArmSystem::ArmSystem(Params *p) - : System(p), bootldr(NULL), multiProc(p->multi_proc) + : System(p), bootldr(NULL), _haveSecurity(p->have_security), + _haveLPAE(p->have_lpae), + _haveVirtualization(p->have_virtualization), + _haveGenericTimer(p->have_generic_timer), + _highestELIs64(p->highest_el_is_64), + _resetAddr64(p->reset_addr_64), + _physAddrRange64(p->phys_addr_range_64), + _haveLargeAsid64(p->have_large_asid_64), + multiProc(p->multi_proc) { + // Check if the physical address range is valid + if (_highestELIs64 && ( + _physAddrRange64 < 32 || + _physAddrRange64 > 48 || + (_physAddrRange64 % 4 != 0 && _physAddrRange64 != 42))) { + fatal("Invalid physical address range (%d)\n", _physAddrRange64); + } + if (p->boot_loader != "") { bootldr = createObjectFile(p->boot_loader); if (!bootldr) fatal("Could not read bootloader: %s\n", p->boot_loader); + if ((bootldr->getArch() == ObjectFile::Arm64) && !_highestELIs64) { + warn("Highest ARM exception-level set to AArch32 but bootloader " + "is for AArch64. Assuming you wanted these to match.\n"); + _highestELIs64 = true; + } else if ((bootldr->getArch() == ObjectFile::Arm) && _highestELIs64) { + warn("Highest ARM exception-level set to AArch64 but bootloader " + "is for AArch32. Assuming you wanted these to match.\n"); + _highestELIs64 = false; + } + bootldr->loadGlobalSymbols(debugSymbolTable); } @@ -81,11 +108,21 @@ ArmSystem::initState() if (bootldr) { bootldr->loadSections(physProxy); - uint8_t jump_to_bl[] = + uint8_t jump_to_bl_32[] = + { + 0x07, 0xf0, 0xa0, 0xe1 // branch to r7 in aarch32 + }; + + uint8_t jump_to_bl_64[] = { - 0x07, 0xf0, 0xa0, 0xe1 // branch to r7 + 0xe0, 0x00, 0x1f, 0xd6 // instruction "br x7" in aarch64 }; - physProxy.writeBlob(0x0, jump_to_bl, sizeof(jump_to_bl)); + + // write the jump to branch table into address 0 + if (!_highestELIs64) + physProxy.writeBlob(0x0, jump_to_bl_32, sizeof(jump_to_bl_32)); + else + physProxy.writeBlob(0x0, jump_to_bl_64, sizeof(jump_to_bl_64)); inform("Using bootloader at address %#x\n", bootldr->entryPoint()); @@ -96,24 +133,116 @@ ArmSystem::initState() fatal("gic_cpu_addr && flags_addr must be set with bootloader\n"); for (int i = 0; i < threadContexts.size(); i++) { - threadContexts[i]->setIntReg(3, kernelEntry & loadAddrMask); + if (!_highestELIs64) + threadContexts[i]->setIntReg(3, (kernelEntry & loadAddrMask) + + loadAddrOffset); threadContexts[i]->setIntReg(4, params()->gic_cpu_addr); threadContexts[i]->setIntReg(5, params()->flags_addr); threadContexts[i]->setIntReg(7, bootldr->entryPoint()); } + inform("Using kernel entry physical address at %#x\n", + (kernelEntry & loadAddrMask) + loadAddrOffset); } else { // Set the initial PC to be at start of the kernel code - threadContexts[0]->pcState(kernelEntry & loadAddrMask); + if (!_highestELIs64) + threadContexts[0]->pcState((kernelEntry & loadAddrMask) + + loadAddrOffset); + } +} + +GenericTimer::ArchTimer * +ArmSystem::getArchTimer(int cpu_id) const +{ + if (_genericTimer) { + return _genericTimer->getArchTimer(cpu_id); } + return NULL; } +GenericTimer::SystemCounter * +ArmSystem::getSystemCounter() const +{ + if (_genericTimer) { + return _genericTimer->getSystemCounter(); + } + return NULL; +} + +bool +ArmSystem::haveSecurity(ThreadContext *tc) +{ + if (!FullSystem) + return false; + + ArmSystem *a_sys = dynamic_cast<ArmSystem *>(tc->getSystemPtr()); + assert(a_sys); + return a_sys->haveSecurity(); +} + + ArmSystem::~ArmSystem() { if (debugPrintkEvent) delete debugPrintkEvent; } +bool +ArmSystem::haveLPAE(ThreadContext *tc) +{ + if (!FullSystem) + return false; + ArmSystem *a_sys = dynamic_cast<ArmSystem *>(tc->getSystemPtr()); + assert(a_sys); + return a_sys->haveLPAE(); +} + +bool +ArmSystem::haveVirtualization(ThreadContext *tc) +{ + if (!FullSystem) + return false; + + ArmSystem *a_sys = dynamic_cast<ArmSystem *>(tc->getSystemPtr()); + assert(a_sys); + return a_sys->haveVirtualization(); +} + +bool +ArmSystem::highestELIs64(ThreadContext *tc) +{ + return dynamic_cast<ArmSystem *>(tc->getSystemPtr())->highestELIs64(); +} + +ExceptionLevel +ArmSystem::highestEL(ThreadContext *tc) +{ + return dynamic_cast<ArmSystem *>(tc->getSystemPtr())->highestEL(); +} + +Addr +ArmSystem::resetAddr64(ThreadContext *tc) +{ + return dynamic_cast<ArmSystem *>(tc->getSystemPtr())->resetAddr64(); +} + +uint8_t +ArmSystem::physAddrRange(ThreadContext *tc) +{ + return dynamic_cast<ArmSystem *>(tc->getSystemPtr())->physAddrRange(); +} + +Addr +ArmSystem::physAddrMask(ThreadContext *tc) +{ + return dynamic_cast<ArmSystem *>(tc->getSystemPtr())->physAddrMask(); +} + +bool +ArmSystem::haveLargeAsid64(ThreadContext *tc) +{ + return dynamic_cast<ArmSystem *>(tc->getSystemPtr())->haveLargeAsid64(); +} ArmSystem * ArmSystemParams::create() { diff --git a/src/arch/arm/system.hh b/src/arch/arm/system.hh index 3135c5da1..f906dc2d2 100644 --- a/src/arch/arm/system.hh +++ b/src/arch/arm/system.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010, 2012-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -46,11 +46,14 @@ #include <string> #include <vector> +#include "dev/arm/generic_timer.hh" #include "kern/linux/events.hh" #include "params/ArmSystem.hh" #include "sim/sim_object.hh" #include "sim/system.hh" +class ThreadContext; + class ArmSystem : public System { protected: @@ -65,6 +68,54 @@ class ArmSystem : public System */ ObjectFile *bootldr; + /** + * True if this system implements the Security Extensions + */ + const bool _haveSecurity; + + /** + * True if this system implements the Large Physical Address Extension + */ + const bool _haveLPAE; + + /** + * True if this system implements the virtualization Extensions + */ + const bool _haveVirtualization; + + /** + * True if this system implements the Generic Timer extension + */ + const bool _haveGenericTimer; + + /** + * Pointer to the Generic Timer wrapper. + */ + GenericTimer *_genericTimer; + + /** + * True if the register width of the highest implemented exception level is + * 64 bits (ARMv8) + */ + bool _highestELIs64; + + /** + * Reset address if the highest implemented exception level is 64 bits + * (ARMv8) + */ + const Addr _resetAddr64; + + /** + * Supported physical address range in bits if the highest implemented + * exception level is 64 bits (ARMv8) + */ + const uint8_t _physAddrRange64; + + /** + * True if ASID is 16 bits in AArch64 (ARMv8) + */ + const bool _haveLargeAsid64; + public: typedef ArmSystemParams Params; const Params * @@ -101,6 +152,120 @@ class ArmSystem : public System /** true if this a multiprocessor system */ bool multiProc; + + /** Returns true if this system implements the Security Extensions */ + bool haveSecurity() const { return _haveSecurity; } + + /** Returns true if this system implements the Large Physical Address + * Extension */ + bool haveLPAE() const { return _haveLPAE; } + + /** Returns true if this system implements the virtualization + * Extensions + */ + bool haveVirtualization() const { return _haveVirtualization; } + + /** Returns true if this system implements the Generic Timer extension. */ + bool haveGenericTimer() const { return _haveGenericTimer; } + + /** Sets the pointer to the Generic Timer. */ + void setGenericTimer(GenericTimer *generic_timer) + { + _genericTimer = generic_timer; + } + + /** Returns a pointer to the system counter. */ + GenericTimer::SystemCounter *getSystemCounter() const; + + /** Returns a pointer to the appropriate architected timer. */ + GenericTimer::ArchTimer *getArchTimer(int cpu_id) const; + + /** Returns true if the register width of the highest implemented exception + * level is 64 bits (ARMv8) */ + bool highestELIs64() const { return _highestELIs64; } + + /** Returns the highest implemented exception level */ + ExceptionLevel highestEL() const + { + if (_haveSecurity) + return EL3; + // @todo: uncomment this to enable Virtualization + // if (_haveVirtualization) + // return EL2; + return EL1; + } + + /** Returns the reset address if the highest implemented exception level is + * 64 bits (ARMv8) */ + Addr resetAddr64() const { return _resetAddr64; } + + /** Returns true if ASID is 16 bits in AArch64 (ARMv8) */ + bool haveLargeAsid64() const { return _haveLargeAsid64; } + + /** Returns the supported physical address range in bits if the highest + * implemented exception level is 64 bits (ARMv8) */ + uint8_t physAddrRange64() const { return _physAddrRange64; } + + /** Returns the supported physical address range in bits */ + uint8_t physAddrRange() const + { + if (_highestELIs64) + return _physAddrRange64; + if (_haveLPAE) + return 40; + return 32; + } + + /** Returns the physical address mask */ + Addr physAddrMask() const + { + return mask(physAddrRange()); + } + + /** Returns true if the system of a specific thread context implements the + * Security Extensions + */ + static bool haveSecurity(ThreadContext *tc); + + /** Returns true if the system of a specific thread context implements the + * virtualization Extensions + */ + static bool haveVirtualization(ThreadContext *tc); + + /** Returns true if the system of a specific thread context implements the + * Large Physical Address Extension + */ + static bool haveLPAE(ThreadContext *tc); + + /** Returns true if the register width of the highest implemented exception + * level for the system of a specific thread context is 64 bits (ARMv8) + */ + static bool highestELIs64(ThreadContext *tc); + + /** Returns the highest implemented exception level for the system of a + * specific thread context + */ + static ExceptionLevel highestEL(ThreadContext *tc); + + /** Returns the reset address if the highest implemented exception level for + * the system of a specific thread context is 64 bits (ARMv8) + */ + static Addr resetAddr64(ThreadContext *tc); + + /** Returns the supported physical address range in bits for the system of a + * specific thread context + */ + static uint8_t physAddrRange(ThreadContext *tc); + + /** Returns the physical address mask for the system of a specific thread + * context + */ + static Addr physAddrMask(ThreadContext *tc); + + /** Returns true if ASID is 16 bits for the system of a specific thread + * context while in AArch64 (ARMv8) */ + static bool haveLargeAsid64(ThreadContext *tc); + }; #endif diff --git a/src/arch/arm/table_walker.cc b/src/arch/arm/table_walker.cc index d419fdec5..7eda13b3e 100644 --- a/src/arch/arm/table_walker.cc +++ b/src/arch/arm/table_walker.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010, 2012-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -35,9 +35,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Ali Saidi + * Giacomo Gabrielli */ #include "arch/arm/faults.hh" +#include "arch/arm/stage2_mmu.hh" +#include "arch/arm/system.hh" #include "arch/arm/table_walker.hh" #include "arch/arm/tlb.hh" #include "cpu/base.hh" @@ -51,13 +54,33 @@ using namespace ArmISA; TableWalker::TableWalker(const Params *p) - : MemObject(p), port(this, params()->sys), drainManager(NULL), - tlb(NULL), currState(NULL), pending(false), - masterId(p->sys->getMasterId(name())), + : MemObject(p), port(this, p->sys), drainManager(NULL), + stage2Mmu(NULL), isStage2(p->is_stage2), tlb(NULL), + currState(NULL), pending(false), masterId(p->sys->getMasterId(name())), numSquashable(p->num_squash_per_cycle), - doL1DescEvent(this), doL2DescEvent(this), doProcessEvent(this) + doL1DescEvent(this), doL2DescEvent(this), + doL0LongDescEvent(this), doL1LongDescEvent(this), doL2LongDescEvent(this), + doL3LongDescEvent(this), + doProcessEvent(this) { sctlr = 0; + + // Cache system-level properties + if (FullSystem) { + armSys = dynamic_cast<ArmSystem *>(p->sys); + assert(armSys); + haveSecurity = armSys->haveSecurity(); + _haveLPAE = armSys->haveLPAE(); + _haveVirtualization = armSys->haveVirtualization(); + physAddrRange = armSys->physAddrRange(); + _haveLargeAsid64 = armSys->haveLargeAsid64(); + } else { + armSys = NULL; + haveSecurity = _haveLPAE = _haveVirtualization = false; + _haveLargeAsid64 = false; + physAddrRange = 32; + } + } TableWalker::~TableWalker() @@ -65,10 +88,14 @@ TableWalker::~TableWalker() ; } +TableWalker::WalkerState::WalkerState() : stage2Tran(NULL), l2Desc(l1Desc) +{ +} + void TableWalker::completeDrain() { - if (drainManager && stateQueueL1.empty() && stateQueueL2.empty() && + if (drainManager && stateQueues[L1].empty() && stateQueues[L2].empty() && pendingQueue.empty()) { setDrainState(Drainable::Drained); DPRINTF(Drain, "TableWalker done draining, processing drain event\n"); @@ -82,21 +109,28 @@ TableWalker::drain(DrainManager *dm) { unsigned int count = port.drain(dm); - if (stateQueueL1.empty() && stateQueueL2.empty() && - pendingQueue.empty()) { - setDrainState(Drainable::Drained); - DPRINTF(Drain, "TableWalker free, no need to drain\n"); + bool state_queues_not_empty = false; - // table walker is drained, but its ports may still need to be drained - return count; - } else { + for (int i = 0; i < MAX_LOOKUP_LEVELS; ++i) { + if (!stateQueues[i].empty()) { + state_queues_not_empty = true; + break; + } + } + + if (state_queues_not_empty || pendingQueue.size()) { drainManager = dm; setDrainState(Drainable::Draining); DPRINTF(Drain, "TableWalker not drained\n"); // return port drain count plus the table walker itself needs to drain return count + 1; + } else { + setDrainState(Drainable::Drained); + DPRINTF(Drain, "TableWalker free, no need to drain\n"); + // table walker is drained, but its ports may still need to be drained + return count; } } @@ -120,10 +154,13 @@ TableWalker::getMasterPort(const std::string &if_name, PortID idx) } Fault -TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode _mode, - TLB::Translation *_trans, bool _timing, bool _functional) +TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint16_t _asid, + uint8_t _vmid, bool _isHyp, TLB::Mode _mode, + TLB::Translation *_trans, bool _timing, bool _functional, + bool secure, TLB::ArmTranslationType tranType) { assert(!(_functional && _timing)); + if (!currState) { // For atomic mode, a new WalkerState instance should be only created // once per TLB. For timing mode, a new instance is generated for every @@ -139,41 +176,113 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode _ // misprediction, in which case nothing will happen or we'll use // this fault to re-execute the faulting instruction which should clean // up everything. - if (currState->vaddr == _req->getVaddr()) { + if (currState->vaddr_tainted == _req->getVaddr()) { return new ReExec; } - panic("currState should always be empty in timing mode!\n"); } currState->tc = _tc; + currState->aarch64 = opModeIs64(currOpMode(_tc)); + currState->el = currEL(_tc); currState->transState = _trans; currState->req = _req; currState->fault = NoFault; - currState->contextId = _cid; + currState->asid = _asid; + currState->vmid = _vmid; + currState->isHyp = _isHyp; currState->timing = _timing; currState->functional = _functional; currState->mode = _mode; + currState->tranType = tranType; + currState->isSecure = secure; + currState->physAddrRange = physAddrRange; /** @todo These should be cached or grabbed from cached copies in the TLB, all these miscreg reads are expensive */ - currState->vaddr = currState->req->getVaddr(); - currState->sctlr = currState->tc->readMiscReg(MISCREG_SCTLR); + currState->vaddr_tainted = currState->req->getVaddr(); + if (currState->aarch64) + currState->vaddr = purifyTaggedAddr(currState->vaddr_tainted, + currState->tc, currState->el); + else + currState->vaddr = currState->vaddr_tainted; + + if (currState->aarch64) { + switch (currState->el) { + case EL0: + case EL1: + currState->sctlr = currState->tc->readMiscReg(MISCREG_SCTLR_EL1); + currState->ttbcr = currState->tc->readMiscReg(MISCREG_TCR_EL1); + break; + // @todo: uncomment this to enable Virtualization + // case EL2: + // assert(haveVirtualization); + // currState->sctlr = currState->tc->readMiscReg(MISCREG_SCTLR_EL2); + // currState->ttbcr = currState->tc->readMiscReg(MISCREG_TCR_EL2); + // break; + case EL3: + assert(haveSecurity); + currState->sctlr = currState->tc->readMiscReg(MISCREG_SCTLR_EL3); + currState->ttbcr = currState->tc->readMiscReg(MISCREG_TCR_EL3); + break; + default: + panic("Invalid exception level"); + break; + } + } else { + currState->sctlr = currState->tc->readMiscReg(flattenMiscRegNsBanked( + MISCREG_SCTLR, currState->tc, !currState->isSecure)); + currState->ttbcr = currState->tc->readMiscReg(flattenMiscRegNsBanked( + MISCREG_TTBCR, currState->tc, !currState->isSecure)); + currState->htcr = currState->tc->readMiscReg(MISCREG_HTCR); + currState->hcr = currState->tc->readMiscReg(MISCREG_HCR); + currState->vtcr = currState->tc->readMiscReg(MISCREG_VTCR); + } sctlr = currState->sctlr; - currState->N = currState->tc->readMiscReg(MISCREG_TTBCR); currState->isFetch = (currState->mode == TLB::Execute); currState->isWrite = (currState->mode == TLB::Write); + // We only do a second stage of translation if we're not secure, or in + // hyp mode, the second stage MMU is enabled, and this table walker + // instance is the first stage. + currState->doingStage2 = false; + // @todo: for now disable this in AArch64 (HCR is not set) + currState->stage2Req = !currState->aarch64 && currState->hcr.vm && + !isStage2 && !currState->isSecure && !currState->isHyp; + + bool long_desc_format = currState->aarch64 || + (_haveLPAE && currState->ttbcr.eae) || + _isHyp || isStage2; + + if (long_desc_format) { + // Helper variables used for hierarchical permissions + currState->secureLookup = currState->isSecure; + currState->rwTable = true; + currState->userTable = true; + currState->xnTable = false; + currState->pxnTable = false; + } - if (!currState->timing) - return processWalk(); + if (!currState->timing) { + if (currState->aarch64) + return processWalkAArch64(); + else if (long_desc_format) + return processWalkLPAE(); + else + return processWalk(); + } if (pending || pendingQueue.size()) { pendingQueue.push_back(currState); currState = NULL; } else { pending = true; - return processWalk(); + if (currState->aarch64) + return processWalkAArch64(); + else if (long_desc_format) + return processWalkLPAE(); + else + return processWalk(); } return NoFault; @@ -186,8 +295,17 @@ TableWalker::processWalkWrapper() assert(pendingQueue.size()); currState = pendingQueue.front(); + ExceptionLevel target_el = EL0; + if (currState->aarch64) + target_el = currEL(currState->tc); + else + target_el = EL1; + // Check if a previous walk filled this request already - TlbEntry* te = tlb->lookup(currState->vaddr, currState->contextId, true); + // @TODO Should this always be the TLB or should we look in the stage2 TLB? + TlbEntry* te = tlb->lookup(currState->vaddr, currState->asid, + currState->vmid, currState->isHyp, currState->isSecure, true, false, + target_el); // Check if we still need to have a walk for this request. If the requesting // instruction has been squashed, or a previous walk has filled the TLB with @@ -198,7 +316,12 @@ TableWalker::processWalkWrapper() // We've got a valid request, lets process it pending = true; pendingQueue.pop_front(); - processWalk(); + if (currState->aarch64) + processWalkAArch64(); + else if ((_haveLPAE && currState->ttbcr.eae) || currState->isHyp || isStage2) + processWalkLPAE(); + else + processWalk(); return; } @@ -212,7 +335,8 @@ TableWalker::processWalkWrapper() pendingQueue.pop_front(); num_squashed++; - DPRINTF(TLB, "Squashing table walk for address %#x\n", currState->vaddr); + DPRINTF(TLB, "Squashing table walk for address %#x\n", + currState->vaddr_tainted); if (currState->transState->squashed()) { // finish the translation which will delete the translation object @@ -220,8 +344,9 @@ TableWalker::processWalkWrapper() currState->req, currState->tc, currState->mode); } else { // translate the request now that we know it will work - currState->fault = tlb->translateTiming(currState->req, currState->tc, - currState->transState, currState->mode); + tlb->translateTiming(currState->req, currState->tc, + currState->transState, currState->mode); + } // delete the current request @@ -230,7 +355,9 @@ TableWalker::processWalkWrapper() // peak at the next one if (pendingQueue.size()) { currState = pendingQueue.front(); - te = tlb->lookup(currState->vaddr, currState->contextId, true); + te = tlb->lookup(currState->vaddr, currState->asid, + currState->vmid, currState->isHyp, currState->isSecure, true, + false, target_el); } else { // Terminate the loop, nothing more to do currState = NULL; @@ -249,32 +376,62 @@ TableWalker::processWalk() Addr ttbr = 0; // If translation isn't enabled, we shouldn't be here - assert(currState->sctlr.m); + assert(currState->sctlr.m || isStage2); - DPRINTF(TLB, "Begining table walk for address %#x, TTBCR: %#x, bits:%#x\n", - currState->vaddr, currState->N, mbits(currState->vaddr, 31, - 32-currState->N)); + DPRINTF(TLB, "Beginning table walk for address %#x, TTBCR: %#x, bits:%#x\n", + currState->vaddr_tainted, currState->ttbcr, mbits(currState->vaddr, 31, + 32 - currState->ttbcr.n)); - if (currState->N == 0 || !mbits(currState->vaddr, 31, 32-currState->N)) { + if (currState->ttbcr.n == 0 || !mbits(currState->vaddr, 31, + 32 - currState->ttbcr.n)) { DPRINTF(TLB, " - Selecting TTBR0\n"); - ttbr = currState->tc->readMiscReg(MISCREG_TTBR0); + // Check if table walk is allowed when Security Extensions are enabled + if (haveSecurity && currState->ttbcr.pd0) { + if (currState->isFetch) + return new PrefetchAbort(currState->vaddr_tainted, + ArmFault::TranslationLL + L1, + isStage2, + ArmFault::VmsaTran); + else + return new DataAbort(currState->vaddr_tainted, + TlbEntry::DomainType::NoAccess, currState->isWrite, + ArmFault::TranslationLL + L1, isStage2, + ArmFault::VmsaTran); + } + ttbr = currState->tc->readMiscReg(flattenMiscRegNsBanked( + MISCREG_TTBR0, currState->tc, !currState->isSecure)); } else { DPRINTF(TLB, " - Selecting TTBR1\n"); - ttbr = currState->tc->readMiscReg(MISCREG_TTBR1); - currState->N = 0; + // Check if table walk is allowed when Security Extensions are enabled + if (haveSecurity && currState->ttbcr.pd1) { + if (currState->isFetch) + return new PrefetchAbort(currState->vaddr_tainted, + ArmFault::TranslationLL + L1, + isStage2, + ArmFault::VmsaTran); + else + return new DataAbort(currState->vaddr_tainted, + TlbEntry::DomainType::NoAccess, currState->isWrite, + ArmFault::TranslationLL + L1, isStage2, + ArmFault::VmsaTran); + } + ttbr = currState->tc->readMiscReg(flattenMiscRegNsBanked( + MISCREG_TTBR1, currState->tc, !currState->isSecure)); + currState->ttbcr.n = 0; } - Addr l1desc_addr = mbits(ttbr, 31, 14-currState->N) | - (bits(currState->vaddr,31-currState->N,20) << 2); - DPRINTF(TLB, " - Descriptor at address %#x\n", l1desc_addr); - + Addr l1desc_addr = mbits(ttbr, 31, 14 - currState->ttbcr.n) | + (bits(currState->vaddr, 31 - currState->ttbcr.n, 20) << 2); + DPRINTF(TLB, " - Descriptor at address %#x (%s)\n", l1desc_addr, + currState->isSecure ? "s" : "ns"); // Trickbox address check Fault f; - f = tlb->walkTrickBoxCheck(l1desc_addr, currState->vaddr, sizeof(uint32_t), - currState->isFetch, currState->isWrite, 0, true); + f = tlb->walkTrickBoxCheck(l1desc_addr, currState->isSecure, + currState->vaddr, sizeof(uint32_t), currState->isFetch, + currState->isWrite, TlbEntry::DomainType::NoAccess, L1); if (f) { - DPRINTF(TLB, "Trickbox check caused fault on %#x\n", currState->vaddr); + DPRINTF(TLB, "Trickbox check caused fault on %#x\n", currState->vaddr_tainted); if (currState->timing) { pending = false; nextWalk(currState->tc); @@ -291,28 +448,422 @@ TableWalker::processWalk() flag = Request::UNCACHEABLE; } + bool delayed; + delayed = fetchDescriptor(l1desc_addr, (uint8_t*)&currState->l1Desc.data, + sizeof(uint32_t), flag, L1, &doL1DescEvent, + &TableWalker::doL1Descriptor); + if (!delayed) { + f = currState->fault; + } + + return f; +} + +Fault +TableWalker::processWalkLPAE() +{ + Addr ttbr, ttbr0_max, ttbr1_min, desc_addr; + int tsz, n; + LookupLevel start_lookup_level = L1; + + DPRINTF(TLB, "Beginning table walk for address %#x, TTBCR: %#x\n", + currState->vaddr_tainted, currState->ttbcr); + + Request::Flags flag = 0; + if (currState->isSecure) + flag.set(Request::SECURE); + + // work out which base address register to use, if in hyp mode we always + // use HTTBR + if (isStage2) { + DPRINTF(TLB, " - Selecting VTTBR (long-desc.)\n"); + ttbr = currState->tc->readMiscReg(MISCREG_VTTBR); + tsz = sext<4>(currState->vtcr.t0sz); + start_lookup_level = currState->vtcr.sl0 ? L1 : L2; + } else if (currState->isHyp) { + DPRINTF(TLB, " - Selecting HTTBR (long-desc.)\n"); + ttbr = currState->tc->readMiscReg(MISCREG_HTTBR); + tsz = currState->htcr.t0sz; + } else { + assert(_haveLPAE && currState->ttbcr.eae); + + // Determine boundaries of TTBR0/1 regions + if (currState->ttbcr.t0sz) + ttbr0_max = (1ULL << (32 - currState->ttbcr.t0sz)) - 1; + else if (currState->ttbcr.t1sz) + ttbr0_max = (1ULL << 32) - + (1ULL << (32 - currState->ttbcr.t1sz)) - 1; + else + ttbr0_max = (1ULL << 32) - 1; + if (currState->ttbcr.t1sz) + ttbr1_min = (1ULL << 32) - (1ULL << (32 - currState->ttbcr.t1sz)); + else + ttbr1_min = (1ULL << (32 - currState->ttbcr.t0sz)); + + // The following code snippet selects the appropriate translation table base + // address (TTBR0 or TTBR1) and the appropriate starting lookup level + // depending on the address range supported by the translation table (ARM + // ARM issue C B3.6.4) + if (currState->vaddr <= ttbr0_max) { + DPRINTF(TLB, " - Selecting TTBR0 (long-desc.)\n"); + // Check if table walk is allowed + if (currState->ttbcr.epd0) { + if (currState->isFetch) + return new PrefetchAbort(currState->vaddr_tainted, + ArmFault::TranslationLL + L1, + isStage2, + ArmFault::LpaeTran); + else + return new DataAbort(currState->vaddr_tainted, + TlbEntry::DomainType::NoAccess, + currState->isWrite, + ArmFault::TranslationLL + L1, + isStage2, + ArmFault::LpaeTran); + } + ttbr = currState->tc->readMiscReg(flattenMiscRegNsBanked( + MISCREG_TTBR0, currState->tc, !currState->isSecure)); + tsz = currState->ttbcr.t0sz; + if (ttbr0_max < (1ULL << 30)) // Upper limit < 1 GB + start_lookup_level = L2; + } else if (currState->vaddr >= ttbr1_min) { + DPRINTF(TLB, " - Selecting TTBR1 (long-desc.)\n"); + // Check if table walk is allowed + if (currState->ttbcr.epd1) { + if (currState->isFetch) + return new PrefetchAbort(currState->vaddr_tainted, + ArmFault::TranslationLL + L1, + isStage2, + ArmFault::LpaeTran); + else + return new DataAbort(currState->vaddr_tainted, + TlbEntry::DomainType::NoAccess, + currState->isWrite, + ArmFault::TranslationLL + L1, + isStage2, + ArmFault::LpaeTran); + } + ttbr = currState->tc->readMiscReg(flattenMiscRegNsBanked( + MISCREG_TTBR1, currState->tc, !currState->isSecure)); + tsz = currState->ttbcr.t1sz; + if (ttbr1_min >= (1ULL << 31) + (1ULL << 30)) // Lower limit >= 3 GB + start_lookup_level = L2; + } else { + // Out of boundaries -> translation fault + if (currState->isFetch) + return new PrefetchAbort(currState->vaddr_tainted, + ArmFault::TranslationLL + L1, + isStage2, + ArmFault::LpaeTran); + else + return new DataAbort(currState->vaddr_tainted, + TlbEntry::DomainType::NoAccess, + currState->isWrite, ArmFault::TranslationLL + L1, + isStage2, ArmFault::LpaeTran); + } + + } + + // Perform lookup (ARM ARM issue C B3.6.6) + if (start_lookup_level == L1) { + n = 5 - tsz; + desc_addr = mbits(ttbr, 39, n) | + (bits(currState->vaddr, n + 26, 30) << 3); + DPRINTF(TLB, " - Descriptor at address %#x (%s) (long-desc.)\n", + desc_addr, currState->isSecure ? "s" : "ns"); + } else { + // Skip first-level lookup + n = (tsz >= 2 ? 14 - tsz : 12); + desc_addr = mbits(ttbr, 39, n) | + (bits(currState->vaddr, n + 17, 21) << 3); + DPRINTF(TLB, " - Descriptor at address %#x (%s) (long-desc.)\n", + desc_addr, currState->isSecure ? "s" : "ns"); + } + + // Trickbox address check + Fault f = tlb->walkTrickBoxCheck(desc_addr, currState->isSecure, + currState->vaddr, sizeof(uint64_t), currState->isFetch, + currState->isWrite, TlbEntry::DomainType::NoAccess, + start_lookup_level); + if (f) { + DPRINTF(TLB, "Trickbox check caused fault on %#x\n", currState->vaddr_tainted); + if (currState->timing) { + pending = false; + nextWalk(currState->tc); + currState = NULL; + } else { + currState->tc = NULL; + currState->req = NULL; + } + return f; + } + + if (currState->sctlr.c == 0) { + flag = Request::UNCACHEABLE; + } + + if (currState->isSecure) + flag.set(Request::SECURE); + + currState->longDesc.lookupLevel = start_lookup_level; + currState->longDesc.aarch64 = false; + currState->longDesc.largeGrain = false; + currState->longDesc.grainSize = 12; + + Event *event = start_lookup_level == L1 ? (Event *) &doL1LongDescEvent + : (Event *) &doL2LongDescEvent; + + bool delayed = fetchDescriptor(desc_addr, (uint8_t*)&currState->longDesc.data, + sizeof(uint64_t), flag, start_lookup_level, + event, &TableWalker::doLongDescriptor); + if (!delayed) { + f = currState->fault; + } + + return f; +} + +unsigned +TableWalker::adjustTableSizeAArch64(unsigned tsz) +{ + if (tsz < 25) + return 25; + if (tsz > 48) + return 48; + return tsz; +} + +bool +TableWalker::checkAddrSizeFaultAArch64(Addr addr, int currPhysAddrRange) +{ + return (currPhysAddrRange != MaxPhysAddrRange && + bits(addr, MaxPhysAddrRange - 1, currPhysAddrRange)); +} + +Fault +TableWalker::processWalkAArch64() +{ + assert(currState->aarch64); + + DPRINTF(TLB, "Beginning table walk for address %#llx, TTBCR: %#llx\n", + currState->vaddr_tainted, currState->ttbcr); + + // Determine TTBR, table size, granule size and phys. address range + Addr ttbr = 0; + int tsz = 0, ps = 0; + bool large_grain = false; + bool fault = false; + switch (currState->el) { + case EL0: + case EL1: + switch (bits(currState->vaddr, 63,48)) { + case 0: + DPRINTF(TLB, " - Selecting TTBR0 (AArch64)\n"); + ttbr = currState->tc->readMiscReg(MISCREG_TTBR0_EL1); + tsz = adjustTableSizeAArch64(64 - currState->ttbcr.t0sz); + large_grain = currState->ttbcr.tg0; + if (bits(currState->vaddr, 63, tsz) != 0x0 || + currState->ttbcr.epd0) + fault = true; + break; + case 0xffff: + DPRINTF(TLB, " - Selecting TTBR1 (AArch64)\n"); + ttbr = currState->tc->readMiscReg(MISCREG_TTBR1_EL1); + tsz = adjustTableSizeAArch64(64 - currState->ttbcr.t1sz); + large_grain = currState->ttbcr.tg1; + if (bits(currState->vaddr, 63, tsz) != mask(64-tsz) || + currState->ttbcr.epd1) + fault = true; + break; + default: + // top two bytes must be all 0s or all 1s, else invalid addr + fault = true; + } + ps = currState->ttbcr.ips; + break; + case EL2: + case EL3: + switch(bits(currState->vaddr, 63,48)) { + case 0: + DPRINTF(TLB, " - Selecting TTBR0 (AArch64)\n"); + if (currState->el == EL2) + ttbr = currState->tc->readMiscReg(MISCREG_TTBR0_EL2); + else + ttbr = currState->tc->readMiscReg(MISCREG_TTBR0_EL3); + tsz = adjustTableSizeAArch64(64 - currState->ttbcr.t0sz); + large_grain = currState->ttbcr.tg0; + break; + default: + // invalid addr if top two bytes are not all 0s + fault = true; + } + ps = currState->ttbcr.ps; + break; + } + + if (fault) { + Fault f; + if (currState->isFetch) + f = new PrefetchAbort(currState->vaddr_tainted, + ArmFault::TranslationLL + L0, isStage2, + ArmFault::LpaeTran); + else + f = new DataAbort(currState->vaddr_tainted, + TlbEntry::DomainType::NoAccess, + currState->isWrite, + ArmFault::TranslationLL + L0, + isStage2, ArmFault::LpaeTran); + + if (currState->timing) { + pending = false; + nextWalk(currState->tc); + currState = NULL; + } else { + currState->tc = NULL; + currState->req = NULL; + } + return f; + + } + + // Determine starting lookup level + LookupLevel start_lookup_level; + int grain_size, stride; + if (large_grain) { // 64 KB granule + grain_size = 16; + stride = grain_size - 3; + if (tsz > grain_size + 2 * stride) + start_lookup_level = L1; + else if (tsz > grain_size + stride) + start_lookup_level = L2; + else + start_lookup_level = L3; + } else { // 4 KB granule + grain_size = 12; + stride = grain_size - 3; + if (tsz > grain_size + 3 * stride) + start_lookup_level = L0; + else if (tsz > grain_size + 2 * stride) + start_lookup_level = L1; + else + start_lookup_level = L2; + } + + // Determine table base address + int base_addr_lo = 3 + tsz - stride * (3 - start_lookup_level) - + grain_size; + Addr base_addr = mbits(ttbr, 47, base_addr_lo); + + // Determine physical address size and raise an Address Size Fault if + // necessary + int pa_range = decodePhysAddrRange64(ps); + // Clamp to lower limit + if (pa_range > physAddrRange) + currState->physAddrRange = physAddrRange; + else + currState->physAddrRange = pa_range; + if (checkAddrSizeFaultAArch64(base_addr, currState->physAddrRange)) { + DPRINTF(TLB, "Address size fault before any lookup\n"); + Fault f; + if (currState->isFetch) + f = new PrefetchAbort(currState->vaddr_tainted, + ArmFault::AddressSizeLL + start_lookup_level, + isStage2, + ArmFault::LpaeTran); + else + f = new DataAbort(currState->vaddr_tainted, + TlbEntry::DomainType::NoAccess, + currState->isWrite, + ArmFault::AddressSizeLL + start_lookup_level, + isStage2, + ArmFault::LpaeTran); + + + if (currState->timing) { + pending = false; + nextWalk(currState->tc); + currState = NULL; + } else { + currState->tc = NULL; + currState->req = NULL; + } + return f; + + } + + // Determine descriptor address + Addr desc_addr = base_addr | + (bits(currState->vaddr, tsz - 1, + stride * (3 - start_lookup_level) + grain_size) << 3); + + // Trickbox address check + Fault f = tlb->walkTrickBoxCheck(desc_addr, currState->isSecure, + currState->vaddr, sizeof(uint64_t), currState->isFetch, + currState->isWrite, TlbEntry::DomainType::NoAccess, + start_lookup_level); + if (f) { + DPRINTF(TLB, "Trickbox check caused fault on %#x\n", currState->vaddr_tainted); + if (currState->timing) { + pending = false; + nextWalk(currState->tc); + currState = NULL; + } else { + currState->tc = NULL; + currState->req = NULL; + } + return f; + } + + Request::Flags flag = 0; + if (currState->sctlr.c == 0) { + flag = Request::UNCACHEABLE; + } + + currState->longDesc.lookupLevel = start_lookup_level; + currState->longDesc.aarch64 = true; + currState->longDesc.largeGrain = large_grain; + currState->longDesc.grainSize = grain_size; + if (currState->timing) { - port.dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t), - &doL1DescEvent, (uint8_t*)&currState->l1Desc.data, + Event *event; + switch (start_lookup_level) { + case L0: + event = (Event *) &doL0LongDescEvent; + break; + case L1: + event = (Event *) &doL1LongDescEvent; + break; + case L2: + event = (Event *) &doL2LongDescEvent; + break; + case L3: + event = (Event *) &doL3LongDescEvent; + break; + default: + panic("Invalid table lookup level"); + break; + } + port.dmaAction(MemCmd::ReadReq, desc_addr, sizeof(uint64_t), event, + (uint8_t*) &currState->longDesc.data, currState->tc->getCpuPtr()->clockPeriod(), flag); - DPRINTF(TLBVerbose, "Adding to walker fifo: queue size before " - "adding: %d\n", - stateQueueL1.size()); - stateQueueL1.push_back(currState); + DPRINTF(TLBVerbose, + "Adding to walker fifo: queue size before adding: %d\n", + stateQueues[start_lookup_level].size()); + stateQueues[start_lookup_level].push_back(currState); currState = NULL; } else if (!currState->functional) { - port.dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t), - NULL, (uint8_t*)&currState->l1Desc.data, + port.dmaAction(MemCmd::ReadReq, desc_addr, sizeof(uint64_t), + NULL, (uint8_t*) &currState->longDesc.data, currState->tc->getCpuPtr()->clockPeriod(), flag); - doL1Descriptor(); + doLongDescriptor(); f = currState->fault; } else { - RequestPtr req = new Request(l1desc_addr, sizeof(uint32_t), flag, masterId); - req->taskId(ContextSwitchTaskId::DMA); + RequestPtr req = new Request(desc_addr, sizeof(uint64_t), flag, + masterId); PacketPtr pkt = new Packet(req, MemCmd::ReadReq); - pkt->dataStatic((uint8_t*)&currState->l1Desc.data); + pkt->dataStatic((uint8_t*) &currState->longDesc.data); port.sendFunctional(pkt); - doL1Descriptor(); + doLongDescriptor(); delete req; delete pkt; f = currState->fault; @@ -330,38 +881,38 @@ TableWalker::memAttrs(ThreadContext *tc, TlbEntry &te, SCTLR sctlr, DPRINTF(TLBVerbose, "memAttrs texcb:%d s:%d\n", texcb, s); te.shareable = false; // default value te.nonCacheable = false; - bool outer_shareable = false; + te.outerShareable = false; if (sctlr.tre == 0 || ((sctlr.tre == 1) && (sctlr.m == 0))) { switch(texcb) { case 0: // Stongly-ordered te.nonCacheable = true; - te.mtype = TlbEntry::StronglyOrdered; + te.mtype = TlbEntry::MemoryType::StronglyOrdered; te.shareable = true; te.innerAttrs = 1; te.outerAttrs = 0; break; case 1: // Shareable Device te.nonCacheable = true; - te.mtype = TlbEntry::Device; + te.mtype = TlbEntry::MemoryType::Device; te.shareable = true; te.innerAttrs = 3; te.outerAttrs = 0; break; case 2: // Outer and Inner Write-Through, no Write-Allocate - te.mtype = TlbEntry::Normal; + te.mtype = TlbEntry::MemoryType::Normal; te.shareable = s; te.innerAttrs = 6; te.outerAttrs = bits(texcb, 1, 0); break; case 3: // Outer and Inner Write-Back, no Write-Allocate - te.mtype = TlbEntry::Normal; + te.mtype = TlbEntry::MemoryType::Normal; te.shareable = s; te.innerAttrs = 7; te.outerAttrs = bits(texcb, 1, 0); break; case 4: // Outer and Inner Non-cacheable te.nonCacheable = true; - te.mtype = TlbEntry::Normal; + te.mtype = TlbEntry::MemoryType::Normal; te.shareable = s; te.innerAttrs = 0; te.outerAttrs = bits(texcb, 1, 0); @@ -373,14 +924,14 @@ TableWalker::memAttrs(ThreadContext *tc, TlbEntry &te, SCTLR sctlr, panic("Implementation-defined texcb value!\n"); break; case 7: // Outer and Inner Write-Back, Write-Allocate - te.mtype = TlbEntry::Normal; + te.mtype = TlbEntry::MemoryType::Normal; te.shareable = s; te.innerAttrs = 5; te.outerAttrs = 1; break; case 8: // Non-shareable Device te.nonCacheable = true; - te.mtype = TlbEntry::Device; + te.mtype = TlbEntry::MemoryType::Device; te.shareable = false; te.innerAttrs = 3; te.outerAttrs = 0; @@ -389,7 +940,7 @@ TableWalker::memAttrs(ThreadContext *tc, TlbEntry &te, SCTLR sctlr, panic("Reserved texcb value!\n"); break; case 16 ... 31: // Cacheable Memory - te.mtype = TlbEntry::Normal; + te.mtype = TlbEntry::MemoryType::Normal; te.shareable = s; if (bits(texcb, 1,0) == 0 || bits(texcb, 3,2) == 0) te.nonCacheable = true; @@ -401,8 +952,10 @@ TableWalker::memAttrs(ThreadContext *tc, TlbEntry &te, SCTLR sctlr, } } else { assert(tc); - PRRR prrr = tc->readMiscReg(MISCREG_PRRR); - NMRR nmrr = tc->readMiscReg(MISCREG_NMRR); + PRRR prrr = tc->readMiscReg(flattenMiscRegNsBanked(MISCREG_PRRR, + currState->tc, !currState->isSecure)); + NMRR nmrr = tc->readMiscReg(flattenMiscRegNsBanked(MISCREG_NMRR, + currState->tc, !currState->isSecure)); DPRINTF(TLBVerbose, "memAttrs PRRR:%08x NMRR:%08x\n", prrr, nmrr); uint8_t curr_tr = 0, curr_ir = 0, curr_or = 0; switch(bits(texcb, 2,0)) { @@ -410,37 +963,37 @@ TableWalker::memAttrs(ThreadContext *tc, TlbEntry &te, SCTLR sctlr, curr_tr = prrr.tr0; curr_ir = nmrr.ir0; curr_or = nmrr.or0; - outer_shareable = (prrr.nos0 == 0); + te.outerShareable = (prrr.nos0 == 0); break; case 1: curr_tr = prrr.tr1; curr_ir = nmrr.ir1; curr_or = nmrr.or1; - outer_shareable = (prrr.nos1 == 0); + te.outerShareable = (prrr.nos1 == 0); break; case 2: curr_tr = prrr.tr2; curr_ir = nmrr.ir2; curr_or = nmrr.or2; - outer_shareable = (prrr.nos2 == 0); + te.outerShareable = (prrr.nos2 == 0); break; case 3: curr_tr = prrr.tr3; curr_ir = nmrr.ir3; curr_or = nmrr.or3; - outer_shareable = (prrr.nos3 == 0); + te.outerShareable = (prrr.nos3 == 0); break; case 4: curr_tr = prrr.tr4; curr_ir = nmrr.ir4; curr_or = nmrr.or4; - outer_shareable = (prrr.nos4 == 0); + te.outerShareable = (prrr.nos4 == 0); break; case 5: curr_tr = prrr.tr5; curr_ir = nmrr.ir5; curr_or = nmrr.or5; - outer_shareable = (prrr.nos5 == 0); + te.outerShareable = (prrr.nos5 == 0); break; case 6: panic("Imp defined type\n"); @@ -448,14 +1001,14 @@ TableWalker::memAttrs(ThreadContext *tc, TlbEntry &te, SCTLR sctlr, curr_tr = prrr.tr7; curr_ir = nmrr.ir7; curr_or = nmrr.or7; - outer_shareable = (prrr.nos7 == 0); + te.outerShareable = (prrr.nos7 == 0); break; } switch(curr_tr) { case 0: DPRINTF(TLBVerbose, "StronglyOrdered\n"); - te.mtype = TlbEntry::StronglyOrdered; + te.mtype = TlbEntry::MemoryType::StronglyOrdered; te.nonCacheable = true; te.innerAttrs = 1; te.outerAttrs = 0; @@ -464,7 +1017,7 @@ TableWalker::memAttrs(ThreadContext *tc, TlbEntry &te, SCTLR sctlr, case 1: DPRINTF(TLBVerbose, "Device ds1:%d ds0:%d s:%d\n", prrr.ds1, prrr.ds0, s); - te.mtype = TlbEntry::Device; + te.mtype = TlbEntry::MemoryType::Device; te.nonCacheable = true; te.innerAttrs = 3; te.outerAttrs = 0; @@ -476,7 +1029,7 @@ TableWalker::memAttrs(ThreadContext *tc, TlbEntry &te, SCTLR sctlr, case 2: DPRINTF(TLBVerbose, "Normal ns1:%d ns0:%d s:%d\n", prrr.ns1, prrr.ns0, s); - te.mtype = TlbEntry::Normal; + te.mtype = TlbEntry::MemoryType::Normal; if (prrr.ns1 && s) te.shareable = true; if (prrr.ns0 && !s) @@ -486,7 +1039,7 @@ TableWalker::memAttrs(ThreadContext *tc, TlbEntry &te, SCTLR sctlr, panic("Reserved type"); } - if (te.mtype == TlbEntry::Normal){ + if (te.mtype == TlbEntry::MemoryType::Normal){ switch(curr_ir) { case 0: te.nonCacheable = true; @@ -523,40 +1076,192 @@ TableWalker::memAttrs(ThreadContext *tc, TlbEntry &te, SCTLR sctlr, DPRINTF(TLBVerbose, "memAttrs: shareable: %d, innerAttrs: %d, \ outerAttrs: %d\n", te.shareable, te.innerAttrs, te.outerAttrs); + te.setAttributes(false); +} + +void +TableWalker::memAttrsLPAE(ThreadContext *tc, TlbEntry &te, + LongDescriptor &lDescriptor) +{ + assert(_haveLPAE); + + uint8_t attr; + uint8_t sh = lDescriptor.sh(); + // Different format and source of attributes if this is a stage 2 + // translation + if (isStage2) { + attr = lDescriptor.memAttr(); + uint8_t attr_3_2 = (attr >> 2) & 0x3; + uint8_t attr_1_0 = attr & 0x3; + + DPRINTF(TLBVerbose, "memAttrsLPAE MemAttr:%#x sh:%#x\n", attr, sh); + + if (attr_3_2 == 0) { + te.mtype = attr_1_0 == 0 ? TlbEntry::MemoryType::StronglyOrdered + : TlbEntry::MemoryType::Device; + te.outerAttrs = 0; + te.innerAttrs = attr_1_0 == 0 ? 1 : 3; + te.nonCacheable = true; + } else { + te.mtype = TlbEntry::MemoryType::Normal; + te.outerAttrs = attr_3_2 == 1 ? 0 : + attr_3_2 == 2 ? 2 : 1; + te.innerAttrs = attr_1_0 == 1 ? 0 : + attr_1_0 == 2 ? 6 : 5; + te.nonCacheable = (attr_3_2 == 1) || (attr_1_0 == 1); + } + } else { + uint8_t attrIndx = lDescriptor.attrIndx(); + + // LPAE always uses remapping of memory attributes, irrespective of the + // value of SCTLR.TRE + int reg = attrIndx & 0x4 ? MISCREG_MAIR1 : MISCREG_MAIR0; + reg = flattenMiscRegNsBanked(reg, currState->tc, !currState->isSecure); + uint32_t mair = currState->tc->readMiscReg(reg); + attr = (mair >> (8 * (attrIndx % 4))) & 0xff; + uint8_t attr_7_4 = bits(attr, 7, 4); + uint8_t attr_3_0 = bits(attr, 3, 0); + DPRINTF(TLBVerbose, "memAttrsLPAE AttrIndx:%#x sh:%#x, attr %#x\n", attrIndx, sh, attr); + + // Note: the memory subsystem only cares about the 'cacheable' memory + // attribute. The other attributes are only used to fill the PAR register + // accordingly to provide the illusion of full support + te.nonCacheable = false; + + switch (attr_7_4) { + case 0x0: + // Strongly-ordered or Device memory + if (attr_3_0 == 0x0) + te.mtype = TlbEntry::MemoryType::StronglyOrdered; + else if (attr_3_0 == 0x4) + te.mtype = TlbEntry::MemoryType::Device; + else + panic("Unpredictable behavior\n"); + te.nonCacheable = true; + te.outerAttrs = 0; + break; + case 0x4: + // Normal memory, Outer Non-cacheable + te.mtype = TlbEntry::MemoryType::Normal; + te.outerAttrs = 0; + if (attr_3_0 == 0x4) + // Inner Non-cacheable + te.nonCacheable = true; + else if (attr_3_0 < 0x8) + panic("Unpredictable behavior\n"); + break; + case 0x8: + case 0x9: + case 0xa: + case 0xb: + case 0xc: + case 0xd: + case 0xe: + case 0xf: + if (attr_7_4 & 0x4) { + te.outerAttrs = (attr_7_4 & 1) ? 1 : 3; + } else { + te.outerAttrs = 0x2; + } + // Normal memory, Outer Cacheable + te.mtype = TlbEntry::MemoryType::Normal; + if (attr_3_0 != 0x4 && attr_3_0 < 0x8) + panic("Unpredictable behavior\n"); + break; + default: + panic("Unpredictable behavior\n"); + break; + } + + switch (attr_3_0) { + case 0x0: + te.innerAttrs = 0x1; + break; + case 0x4: + te.innerAttrs = attr_7_4 == 0 ? 0x3 : 0; + break; + case 0x8: + case 0x9: + case 0xA: + case 0xB: + te.innerAttrs = 6; + break; + case 0xC: + case 0xD: + case 0xE: + case 0xF: + te.innerAttrs = attr_3_0 & 1 ? 0x5 : 0x7; + break; + default: + panic("Unpredictable behavior\n"); + break; + } + } + + te.outerShareable = sh == 2; + te.shareable = (sh & 0x2) ? true : false; + te.setAttributes(true); + te.attributes |= (uint64_t) attr << 56; +} - /** Formatting for Physical Address Register (PAR) - * Only including lower bits (TLB info here) - * PAR: - * PA [31:12] - * Reserved [11] - * TLB info [10:1] - * NOS [10] (Not Outer Sharable) - * NS [9] (Non-Secure) - * -- [8] (Implementation Defined) - * SH [7] (Sharable) - * Inner[6:4](Inner memory attributes) - * Outer[3:2](Outer memory attributes) - * SS [1] (SuperSection) - * F [0] (Fault, Fault Status in [6:1] if faulted) - */ - te.attributes = ( - ((outer_shareable ? 0:1) << 10) | - // TODO: NS Bit - ((te.shareable ? 1:0) << 7) | - (te.innerAttrs << 4) | - (te.outerAttrs << 2) - // TODO: Supersection bit - // TODO: Fault bit - ); +void +TableWalker::memAttrsAArch64(ThreadContext *tc, TlbEntry &te, uint8_t attrIndx, + uint8_t sh) +{ + DPRINTF(TLBVerbose, "memAttrsAArch64 AttrIndx:%#x sh:%#x\n", attrIndx, sh); + + // Select MAIR + uint64_t mair; + switch (currState->el) { + case EL0: + case EL1: + mair = tc->readMiscReg(MISCREG_MAIR_EL1); + break; + case EL2: + mair = tc->readMiscReg(MISCREG_MAIR_EL2); + break; + case EL3: + mair = tc->readMiscReg(MISCREG_MAIR_EL3); + break; + default: + panic("Invalid exception level"); + break; + } + + // Select attributes + uint8_t attr = bits(mair, 8 * attrIndx + 7, 8 * attrIndx); + uint8_t attr_lo = bits(attr, 3, 0); + uint8_t attr_hi = bits(attr, 7, 4); + // Memory type + te.mtype = attr_hi == 0 ? TlbEntry::MemoryType::Device : TlbEntry::MemoryType::Normal; + // Cacheability + te.nonCacheable = false; + if (te.mtype == TlbEntry::MemoryType::Device || // Device memory + attr_hi == 0x8 || // Normal memory, Outer Non-cacheable + attr_lo == 0x8) { // Normal memory, Inner Non-cacheable + te.nonCacheable = true; + } + + te.shareable = sh == 2; + te.outerShareable = (sh & 0x2) ? true : false; + // Attributes formatted according to the 64-bit PAR + te.attributes = ((uint64_t) attr << 56) | + (1 << 11) | // LPAE bit + (te.ns << 9) | // NS bit + (sh << 7); } void TableWalker::doL1Descriptor() { + if (currState->fault != NoFault) { + return; + } + DPRINTF(TLB, "L1 descriptor for %#x is %#x\n", - currState->vaddr, currState->l1Desc.data); + currState->vaddr_tainted, currState->l1Desc.data); TlbEntry te; switch (currState->l1Desc.type()) { @@ -569,11 +1274,17 @@ TableWalker::doL1Descriptor() DPRINTF(TLB, "L1 Descriptor Reserved/Ignore, causing fault\n"); if (currState->isFetch) currState->fault = - new PrefetchAbort(currState->vaddr, ArmFault::Translation0); + new PrefetchAbort(currState->vaddr_tainted, + ArmFault::TranslationLL + L1, + isStage2, + ArmFault::VmsaTran); else currState->fault = - new DataAbort(currState->vaddr, 0, currState->isWrite, - ArmFault::Translation0); + new DataAbort(currState->vaddr_tainted, + TlbEntry::DomainType::NoAccess, + currState->isWrite, + ArmFault::TranslationLL + L1, isStage2, + ArmFault::VmsaTran); return; case L1Descriptor::Section: if (currState->sctlr.afe && bits(currState->l1Desc.ap(), 0) == 0) { @@ -582,85 +1293,251 @@ TableWalker::doL1Descriptor() * AccessFlag0 */ - currState->fault = new DataAbort(currState->vaddr, - currState->l1Desc.domain(), currState->isWrite, - ArmFault::AccessFlag0); + currState->fault = new DataAbort(currState->vaddr_tainted, + currState->l1Desc.domain(), + currState->isWrite, + ArmFault::AccessFlagLL + L1, + isStage2, + ArmFault::VmsaTran); } if (currState->l1Desc.supersection()) { panic("Haven't implemented supersections\n"); } - te.N = 20; - te.pfn = currState->l1Desc.pfn(); - te.size = (1<<te.N) - 1; - te.global = !currState->l1Desc.global(); - te.valid = true; - te.vpn = currState->vaddr >> te.N; - te.sNp = true; - te.xn = currState->l1Desc.xn(); - te.ap = currState->l1Desc.ap(); - te.domain = currState->l1Desc.domain(); - te.asid = currState->contextId; - memAttrs(currState->tc, te, currState->sctlr, - currState->l1Desc.texcb(), currState->l1Desc.shareable()); - - DPRINTF(TLB, "Inserting Section Descriptor into TLB\n"); - DPRINTF(TLB, " - N:%d pfn:%#x size: %#x global:%d valid: %d\n", - te.N, te.pfn, te.size, te.global, te.valid); - DPRINTF(TLB, " - vpn:%#x sNp: %d xn:%d ap:%d domain: %d asid:%d nc:%d\n", - te.vpn, te.sNp, te.xn, te.ap, te.domain, te.asid, - te.nonCacheable); - DPRINTF(TLB, " - domain from l1 desc: %d data: %#x bits:%d\n", - currState->l1Desc.domain(), currState->l1Desc.data, - (currState->l1Desc.data >> 5) & 0xF ); + insertTableEntry(currState->l1Desc, false); + return; + case L1Descriptor::PageTable: + { + Addr l2desc_addr; + l2desc_addr = currState->l1Desc.l2Addr() | + (bits(currState->vaddr, 19, 12) << 2); + DPRINTF(TLB, "L1 descriptor points to page table at: %#x (%s)\n", + l2desc_addr, currState->isSecure ? "s" : "ns"); + + // Trickbox address check + currState->fault = tlb->walkTrickBoxCheck( + l2desc_addr, currState->isSecure, currState->vaddr, + sizeof(uint32_t), currState->isFetch, currState->isWrite, + currState->l1Desc.domain(), L2); + + if (currState->fault) { + if (!currState->timing) { + currState->tc = NULL; + currState->req = NULL; + } + return; + } + + Request::Flags flag = 0; + if (currState->isSecure) + flag.set(Request::SECURE); + + bool delayed; + delayed = fetchDescriptor(l2desc_addr, + (uint8_t*)&currState->l2Desc.data, + sizeof(uint32_t), flag, -1, &doL2DescEvent, + &TableWalker::doL2Descriptor); + if (delayed) { + currState->delayed = true; + } + return; + } + default: + panic("A new type in a 2 bit field?\n"); + } +} + +void +TableWalker::doLongDescriptor() +{ + if (currState->fault != NoFault) { + return; + } + + DPRINTF(TLB, "L%d descriptor for %#llx is %#llx (%s)\n", + currState->longDesc.lookupLevel, currState->vaddr_tainted, + currState->longDesc.data, + currState->aarch64 ? "AArch64" : "long-desc."); + + if ((currState->longDesc.type() == LongDescriptor::Block) || + (currState->longDesc.type() == LongDescriptor::Page)) { + DPRINTF(TLBVerbose, "Analyzing L%d descriptor: %#llx, pxn: %d, " + "xn: %d, ap: %d, af: %d, type: %d\n", + currState->longDesc.lookupLevel, + currState->longDesc.data, + currState->longDesc.pxn(), + currState->longDesc.xn(), + currState->longDesc.ap(), + currState->longDesc.af(), + currState->longDesc.type()); + } else { + DPRINTF(TLBVerbose, "Analyzing L%d descriptor: %#llx, type: %d\n", + currState->longDesc.lookupLevel, + currState->longDesc.data, + currState->longDesc.type()); + } + + TlbEntry te; + + switch (currState->longDesc.type()) { + case LongDescriptor::Invalid: if (!currState->timing) { currState->tc = NULL; currState->req = NULL; } - tlb->insert(currState->vaddr, te); + DPRINTF(TLB, "L%d descriptor Invalid, causing fault type %d\n", + currState->longDesc.lookupLevel, + ArmFault::TranslationLL + currState->longDesc.lookupLevel); + if (currState->isFetch) + currState->fault = new PrefetchAbort( + currState->vaddr_tainted, + ArmFault::TranslationLL + currState->longDesc.lookupLevel, + isStage2, + ArmFault::LpaeTran); + else + currState->fault = new DataAbort( + currState->vaddr_tainted, + TlbEntry::DomainType::NoAccess, + currState->isWrite, + ArmFault::TranslationLL + currState->longDesc.lookupLevel, + isStage2, + ArmFault::LpaeTran); return; - case L1Descriptor::PageTable: - Addr l2desc_addr; - l2desc_addr = currState->l1Desc.l2Addr() | - (bits(currState->vaddr, 19,12) << 2); - DPRINTF(TLB, "L1 descriptor points to page table at: %#x\n", - l2desc_addr); - - // Trickbox address check - currState->fault = tlb->walkTrickBoxCheck(l2desc_addr, currState->vaddr, - sizeof(uint32_t), currState->isFetch, currState->isWrite, - currState->l1Desc.domain(), false); - - if (currState->fault) { - if (!currState->timing) { - currState->tc = NULL; - currState->req = NULL; + case LongDescriptor::Block: + case LongDescriptor::Page: + { + bool fault = false; + bool aff = false; + // Check for address size fault + if (checkAddrSizeFaultAArch64( + mbits(currState->longDesc.data, MaxPhysAddrRange - 1, + currState->longDesc.offsetBits()), + currState->physAddrRange)) { + fault = true; + DPRINTF(TLB, "L%d descriptor causing Address Size Fault\n", + currState->longDesc.lookupLevel); + // Check for access fault + } else if (currState->longDesc.af() == 0) { + fault = true; + DPRINTF(TLB, "L%d descriptor causing Access Fault\n", + currState->longDesc.lookupLevel); + aff = true; + } + if (fault) { + if (currState->isFetch) + currState->fault = new PrefetchAbort( + currState->vaddr_tainted, + (aff ? ArmFault::AccessFlagLL : ArmFault::AddressSizeLL) + + currState->longDesc.lookupLevel, + isStage2, + ArmFault::LpaeTran); + else + currState->fault = new DataAbort( + currState->vaddr_tainted, + TlbEntry::DomainType::NoAccess, currState->isWrite, + (aff ? ArmFault::AccessFlagLL : ArmFault::AddressSizeLL) + + currState->longDesc.lookupLevel, + isStage2, + ArmFault::LpaeTran); + } else { + insertTableEntry(currState->longDesc, true); } - return; } + return; + case LongDescriptor::Table: + { + // Set hierarchical permission flags + currState->secureLookup = currState->secureLookup && + currState->longDesc.secureTable(); + currState->rwTable = currState->rwTable && + currState->longDesc.rwTable(); + currState->userTable = currState->userTable && + currState->longDesc.userTable(); + currState->xnTable = currState->xnTable || + currState->longDesc.xnTable(); + currState->pxnTable = currState->pxnTable || + currState->longDesc.pxnTable(); + + // Set up next level lookup + Addr next_desc_addr = currState->longDesc.nextDescAddr( + currState->vaddr); + + DPRINTF(TLB, "L%d descriptor points to L%d descriptor at: %#x (%s)\n", + currState->longDesc.lookupLevel, + currState->longDesc.lookupLevel + 1, + next_desc_addr, + currState->secureLookup ? "s" : "ns"); + + // Check for address size fault + if (currState->aarch64 && checkAddrSizeFaultAArch64( + next_desc_addr, currState->physAddrRange)) { + DPRINTF(TLB, "L%d descriptor causing Address Size Fault\n", + currState->longDesc.lookupLevel); + if (currState->isFetch) + currState->fault = new PrefetchAbort( + currState->vaddr_tainted, + ArmFault::AddressSizeLL + + currState->longDesc.lookupLevel, + isStage2, + ArmFault::LpaeTran); + else + currState->fault = new DataAbort( + currState->vaddr_tainted, + TlbEntry::DomainType::NoAccess, currState->isWrite, + ArmFault::AddressSizeLL + + currState->longDesc.lookupLevel, + isStage2, + ArmFault::LpaeTran); + return; + } + // Trickbox address check + currState->fault = tlb->walkTrickBoxCheck( + next_desc_addr, currState->vaddr, + currState->vaddr, sizeof(uint64_t), + currState->isFetch, currState->isWrite, + TlbEntry::DomainType::Client, + toLookupLevel(currState->longDesc.lookupLevel +1)); + + if (currState->fault) { + if (!currState->timing) { + currState->tc = NULL; + currState->req = NULL; + } + return; + } - if (currState->timing) { - currState->delayed = true; - port.dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t), - &doL2DescEvent, (uint8_t*)&currState->l2Desc.data, - currState->tc->getCpuPtr()->clockPeriod()); - } else if (!currState->functional) { - port.dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t), - NULL, (uint8_t*)&currState->l2Desc.data, - currState->tc->getCpuPtr()->clockPeriod()); - doL2Descriptor(); - } else { - RequestPtr req = new Request(l2desc_addr, sizeof(uint32_t), 0, - masterId); - req->taskId(ContextSwitchTaskId::DMA); - PacketPtr pkt = new Packet(req, MemCmd::ReadReq); - pkt->dataStatic((uint8_t*)&currState->l2Desc.data); - port.sendFunctional(pkt); - doL2Descriptor(); - delete req; - delete pkt; + Request::Flags flag = 0; + if (currState->secureLookup) + flag.set(Request::SECURE); + + currState->longDesc.lookupLevel = + (LookupLevel) (currState->longDesc.lookupLevel + 1); + Event *event = NULL; + switch (currState->longDesc.lookupLevel) { + case L1: + assert(currState->aarch64); + event = &doL1LongDescEvent; + break; + case L2: + event = &doL2LongDescEvent; + break; + case L3: + event = &doL3LongDescEvent; + break; + default: + panic("Wrong lookup level in table walk\n"); + break; + } + + bool delayed; + delayed = fetchDescriptor(next_desc_addr, (uint8_t*)&currState->longDesc.data, + sizeof(uint64_t), flag, -1, event, + &TableWalker::doLongDescriptor); + if (delayed) { + currState->delayed = true; + } } return; default: @@ -671,8 +1548,12 @@ TableWalker::doL1Descriptor() void TableWalker::doL2Descriptor() { + if (currState->fault != NoFault) { + return; + } + DPRINTF(TLB, "L2 descriptor for %#x is %#x\n", - currState->vaddr, currState->l2Desc.data); + currState->vaddr_tainted, currState->l2Desc.data); TlbEntry te; if (currState->l2Desc.invalid()) { @@ -683,11 +1564,16 @@ TableWalker::doL2Descriptor() } if (currState->isFetch) currState->fault = - new PrefetchAbort(currState->vaddr, ArmFault::Translation1); + new PrefetchAbort(currState->vaddr_tainted, + ArmFault::TranslationLL + L2, + isStage2, + ArmFault::VmsaTran); else currState->fault = - new DataAbort(currState->vaddr, currState->l1Desc.domain(), - currState->isWrite, ArmFault::Translation1); + new DataAbort(currState->vaddr_tainted, currState->l1Desc.domain(), + currState->isWrite, ArmFault::TranslationLL + L2, + isStage2, + ArmFault::VmsaTran); return; } @@ -695,53 +1581,38 @@ TableWalker::doL2Descriptor() /** @todo: check sctlr.ha (bit[17]) if Hardware Access Flag is enabled * if set, do l2.Desc.setAp0() instead of generating AccessFlag0 */ + DPRINTF(TLB, "Generating access fault at L2, afe: %d, ap: %d\n", + currState->sctlr.afe, currState->l2Desc.ap()); currState->fault = - new DataAbort(currState->vaddr, 0, currState->isWrite, - ArmFault::AccessFlag1); - + new DataAbort(currState->vaddr_tainted, + TlbEntry::DomainType::NoAccess, currState->isWrite, + ArmFault::AccessFlagLL + L2, isStage2, + ArmFault::VmsaTran); } - if (currState->l2Desc.large()) { - te.N = 16; - te.pfn = currState->l2Desc.pfn(); - } else { - te.N = 12; - te.pfn = currState->l2Desc.pfn(); - } - - te.valid = true; - te.size = (1 << te.N) - 1; - te.asid = currState->contextId; - te.sNp = false; - te.vpn = currState->vaddr >> te.N; - te.global = currState->l2Desc.global(); - te.xn = currState->l2Desc.xn(); - te.ap = currState->l2Desc.ap(); - te.domain = currState->l1Desc.domain(); - memAttrs(currState->tc, te, currState->sctlr, currState->l2Desc.texcb(), - currState->l2Desc.shareable()); - - if (!currState->timing) { - currState->tc = NULL; - currState->req = NULL; - } - tlb->insert(currState->vaddr, te); + insertTableEntry(currState->l2Desc, false); } void TableWalker::doL1DescriptorWrapper() { - currState = stateQueueL1.front(); + currState = stateQueues[L1].front(); currState->delayed = false; + // if there's a stage2 translation object we don't need it any more + if (currState->stage2Tran) { + delete currState->stage2Tran; + currState->stage2Tran = NULL; + } + DPRINTF(TLBVerbose, "L1 Desc object host addr: %p\n",&currState->l1Desc.data); DPRINTF(TLBVerbose, "L1 Desc object data: %08x\n",currState->l1Desc.data); - DPRINTF(TLBVerbose, "calling doL1Descriptor for vaddr:%#x\n", currState->vaddr); + DPRINTF(TLBVerbose, "calling doL1Descriptor for vaddr:%#x\n", currState->vaddr_tainted); doL1Descriptor(); - stateQueueL1.pop_front(); + stateQueues[L1].pop_front(); completeDrain(); // Check if fault was generated if (currState->fault != NoFault) { @@ -758,9 +1629,12 @@ TableWalker::doL1DescriptorWrapper() } else if (!currState->delayed) { // delay is not set so there is no L2 to do - DPRINTF(TLBVerbose, "calling translateTiming again\n"); - currState->fault = tlb->translateTiming(currState->req, currState->tc, - currState->transState, currState->mode); + // Don't finish the translation if a stage 2 look up is underway + if (!currState->doingStage2) { + DPRINTF(TLBVerbose, "calling translateTiming again\n"); + currState->fault = tlb->translateTiming(currState->req, currState->tc, + currState->transState, currState->mode); + } pending = false; nextWalk(currState->tc); @@ -771,7 +1645,7 @@ TableWalker::doL1DescriptorWrapper() delete currState; } else { // need to do L2 descriptor - stateQueueL2.push_back(currState); + stateQueues[L2].push_back(currState); } currState = NULL; } @@ -779,11 +1653,16 @@ TableWalker::doL1DescriptorWrapper() void TableWalker::doL2DescriptorWrapper() { - currState = stateQueueL2.front(); + currState = stateQueues[L2].front(); assert(currState->delayed); + // if there's a stage2 translation object we don't need it any more + if (currState->stage2Tran) { + delete currState->stage2Tran; + currState->stage2Tran = NULL; + } DPRINTF(TLBVerbose, "calling doL2Descriptor for vaddr:%#x\n", - currState->vaddr); + currState->vaddr_tainted); doL2Descriptor(); // Check if fault was generated @@ -792,13 +1671,16 @@ TableWalker::doL2DescriptorWrapper() currState->tc, currState->mode); } else { - DPRINTF(TLBVerbose, "calling translateTiming again\n"); - currState->fault = tlb->translateTiming(currState->req, currState->tc, - currState->transState, currState->mode); + // Don't finish the translation if a stage 2 look up is underway + if (!currState->doingStage2) { + DPRINTF(TLBVerbose, "calling translateTiming again\n"); + currState->fault = tlb->translateTiming(currState->req, + currState->tc, currState->transState, currState->mode); + } } - stateQueueL2.pop_front(); + stateQueues[L2].pop_front(); completeDrain(); pending = false; nextWalk(currState->tc); @@ -812,13 +1694,234 @@ TableWalker::doL2DescriptorWrapper() } void +TableWalker::doL0LongDescriptorWrapper() +{ + doLongDescriptorWrapper(L0); +} + +void +TableWalker::doL1LongDescriptorWrapper() +{ + doLongDescriptorWrapper(L1); +} + +void +TableWalker::doL2LongDescriptorWrapper() +{ + doLongDescriptorWrapper(L2); +} + +void +TableWalker::doL3LongDescriptorWrapper() +{ + doLongDescriptorWrapper(L3); +} + +void +TableWalker::doLongDescriptorWrapper(LookupLevel curr_lookup_level) +{ + currState = stateQueues[curr_lookup_level].front(); + assert(curr_lookup_level == currState->longDesc.lookupLevel); + currState->delayed = false; + + // if there's a stage2 translation object we don't need it any more + if (currState->stage2Tran) { + delete currState->stage2Tran; + currState->stage2Tran = NULL; + } + + DPRINTF(TLBVerbose, "calling doLongDescriptor for vaddr:%#x\n", + currState->vaddr_tainted); + doLongDescriptor(); + + stateQueues[curr_lookup_level].pop_front(); + + if (currState->fault != NoFault) { + // A fault was generated + currState->transState->finish(currState->fault, currState->req, + currState->tc, currState->mode); + + pending = false; + nextWalk(currState->tc); + + currState->req = NULL; + currState->tc = NULL; + currState->delayed = false; + delete currState; + } else if (!currState->delayed) { + // No additional lookups required + // Don't finish the translation if a stage 2 look up is underway + if (!currState->doingStage2) { + DPRINTF(TLBVerbose, "calling translateTiming again\n"); + currState->fault = tlb->translateTiming(currState->req, currState->tc, + currState->transState, + currState->mode); + } + + pending = false; + nextWalk(currState->tc); + + currState->req = NULL; + currState->tc = NULL; + currState->delayed = false; + delete currState; + } else { + if (curr_lookup_level >= MAX_LOOKUP_LEVELS - 1) + panic("Max. number of lookups already reached in table walk\n"); + // Need to perform additional lookups + stateQueues[currState->longDesc.lookupLevel].push_back(currState); + } + currState = NULL; +} + + +void TableWalker::nextWalk(ThreadContext *tc) { if (pendingQueue.size()) schedule(doProcessEvent, clockEdge(Cycles(1))); } +bool +TableWalker::fetchDescriptor(Addr descAddr, uint8_t *data, int numBytes, + Request::Flags flags, int queueIndex, Event *event, + void (TableWalker::*doDescriptor)()) +{ + bool isTiming = currState->timing; + + // do the requests for the page table descriptors have to go through the + // second stage MMU + if (currState->stage2Req) { + Fault fault; + flags = flags | TLB::MustBeOne; + + if (isTiming) { + Stage2MMU::Stage2Translation *tran = new + Stage2MMU::Stage2Translation(*stage2Mmu, data, event, + currState->vaddr); + currState->stage2Tran = tran; + stage2Mmu->readDataTimed(currState->tc, descAddr, tran, numBytes, + flags, masterId); + fault = tran->fault; + } else { + fault = stage2Mmu->readDataUntimed(currState->tc, + currState->vaddr, descAddr, data, numBytes, flags, masterId, + currState->functional); + } + + if (fault != NoFault) { + currState->fault = fault; + } + if (isTiming) { + if (queueIndex >= 0) { + DPRINTF(TLBVerbose, "Adding to walker fifo: queue size before adding: %d\n", + stateQueues[queueIndex].size()); + stateQueues[queueIndex].push_back(currState); + currState = NULL; + } + } else { + (this->*doDescriptor)(); + } + } else { + if (isTiming) { + port.dmaAction(MemCmd::ReadReq, descAddr, numBytes, event, data, + currState->tc->getCpuPtr()->clockPeriod(), flags); + if (queueIndex >= 0) { + DPRINTF(TLBVerbose, "Adding to walker fifo: queue size before adding: %d\n", + stateQueues[queueIndex].size()); + stateQueues[queueIndex].push_back(currState); + currState = NULL; + } + } else if (!currState->functional) { + port.dmaAction(MemCmd::ReadReq, descAddr, numBytes, NULL, data, + currState->tc->getCpuPtr()->clockPeriod(), flags); + (this->*doDescriptor)(); + } else { + RequestPtr req = new Request(descAddr, numBytes, flags, masterId); + req->taskId(ContextSwitchTaskId::DMA); + PacketPtr pkt = new Packet(req, MemCmd::ReadReq); + pkt->dataStatic(data); + port.sendFunctional(pkt); + (this->*doDescriptor)(); + delete req; + delete pkt; + } + } + return (isTiming); +} + +void +TableWalker::insertTableEntry(DescriptorBase &descriptor, bool longDescriptor) +{ + TlbEntry te; + // Create and fill a new page table entry + te.valid = true; + te.longDescFormat = longDescriptor; + te.isHyp = currState->isHyp; + te.asid = currState->asid; + te.vmid = currState->vmid; + te.N = descriptor.offsetBits(); + te.vpn = currState->vaddr >> te.N; + te.size = (1<<te.N) - 1; + te.pfn = descriptor.pfn(); + te.domain = descriptor.domain(); + te.lookupLevel = descriptor.lookupLevel; + te.ns = !descriptor.secure(haveSecurity, currState) || isStage2; + te.nstid = !currState->isSecure; + te.xn = descriptor.xn(); + if (currState->aarch64) + te.el = currState->el; + else + te.el = 1; + + // ASID has no meaning for stage 2 TLB entries, so mark all stage 2 entries + // as global + te.global = descriptor.global(currState) || isStage2; + if (longDescriptor) { + LongDescriptor lDescriptor = + dynamic_cast<LongDescriptor &>(descriptor); + + te.xn |= currState->xnTable; + te.pxn = currState->pxnTable || lDescriptor.pxn(); + if (isStage2) { + // this is actually the HAP field, but its stored in the same bit + // possitions as the AP field in a stage 1 translation. + te.hap = lDescriptor.ap(); + } else { + te.ap = ((!currState->rwTable || descriptor.ap() >> 1) << 1) | + (currState->userTable && (descriptor.ap() & 0x1)); + } + if (currState->aarch64) + memAttrsAArch64(currState->tc, te, currState->longDesc.attrIndx(), + currState->longDesc.sh()); + else + memAttrsLPAE(currState->tc, te, lDescriptor); + } else { + te.ap = descriptor.ap(); + memAttrs(currState->tc, te, currState->sctlr, descriptor.texcb(), + descriptor.shareable()); + } + + // Debug output + DPRINTF(TLB, descriptor.dbgHeader().c_str()); + DPRINTF(TLB, " - N:%d pfn:%#x size:%#x global:%d valid:%d\n", + te.N, te.pfn, te.size, te.global, te.valid); + DPRINTF(TLB, " - vpn:%#x xn:%d pxn:%d ap:%d domain:%d asid:%d " + "vmid:%d hyp:%d nc:%d ns:%d\n", te.vpn, te.xn, te.pxn, + te.ap, static_cast<uint8_t>(te.domain), te.asid, te.vmid, te.isHyp, + te.nonCacheable, te.ns); + DPRINTF(TLB, " - domain from L%d desc:%d data:%#x\n", + descriptor.lookupLevel, static_cast<uint8_t>(descriptor.domain()), + descriptor.getRawData()); + + // Insert the entry into the TLB + tlb->insert(currState->vaddr, te); + if (!currState->timing) { + currState->tc = NULL; + currState->req = NULL; + } +} ArmISA::TableWalker * ArmTableWalkerParams::create() @@ -826,3 +1929,17 @@ ArmTableWalkerParams::create() return new ArmISA::TableWalker(this); } +LookupLevel +TableWalker::toLookupLevel(uint8_t lookup_level_as_int) +{ + switch (lookup_level_as_int) { + case L1: + return L1; + case L2: + return L2; + case L3: + return L3; + default: + panic("Invalid lookup level conversion"); + } +} diff --git a/src/arch/arm/table_walker.hh b/src/arch/arm/table_walker.hh index 23464f56d..4753fe6a0 100644 --- a/src/arch/arm/table_walker.hh +++ b/src/arch/arm/table_walker.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2012 ARM Limited + * Copyright (c) 2010-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -35,6 +35,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Ali Saidi + * Giacomo Gabrielli */ #ifndef __ARCH_ARM_TABLE_WALKER_HH__ @@ -43,6 +44,7 @@ #include <list> #include "arch/arm/miscregs.hh" +#include "arch/arm/system.hh" #include "arch/arm/tlb.hh" #include "dev/dma_device.hh" #include "mem/mem_object.hh" @@ -56,11 +58,39 @@ class ThreadContext; namespace ArmISA { class Translation; class TLB; +class Stage2MMU; class TableWalker : public MemObject { public: - struct L1Descriptor { + class WalkerState; + + class DescriptorBase { + public: + /** Current lookup level for this descriptor */ + LookupLevel lookupLevel; + + virtual Addr pfn() const = 0; + virtual TlbEntry::DomainType domain() const = 0; + virtual bool xn() const = 0; + virtual uint8_t ap() const = 0; + virtual bool global(WalkerState *currState) const = 0; + virtual uint8_t offsetBits() const = 0; + virtual bool secure(bool have_security, WalkerState *currState) const = 0; + virtual std::string dbgHeader() const = 0; + virtual uint64_t getRawData() const = 0; + virtual uint8_t texcb() const + { + panic("texcb() not implemented for this class\n"); + } + virtual bool shareable() const + { + panic("shareable() not implemented for this class\n"); + } + }; + + class L1Descriptor : public DescriptorBase { + public: /** Type of page table entry ARM DDI 0406B: B3-8*/ enum EntryType { Ignore, @@ -76,6 +106,27 @@ class TableWalker : public MemObject * written back to memory */ bool _dirty; + /** Default ctor */ + L1Descriptor() + { + lookupLevel = L1; + } + + virtual uint64_t getRawData() const + { + return (data); + } + + virtual std::string dbgHeader() const + { + return "Inserting Section Descriptor into TLB\n"; + } + + virtual uint8_t offsetBits() const + { + return 20; + } + EntryType type() const { return (EntryType)(data & 0x3); @@ -112,9 +163,9 @@ class TableWalker : public MemObject } /** Is the translation global (no asid used)? */ - bool global() const + bool global(WalkerState *currState) const { - return bits(data, 17); + return !bits(data, 17); } /** Is the translation not allow execution? */ @@ -130,9 +181,9 @@ class TableWalker : public MemObject } /** Domain Client/Manager: ARM DDI 0406B: B3-31 */ - uint8_t domain() const + TlbEntry::DomainType domain() const { - return bits(data, 8, 5); + return static_cast<TlbEntry::DomainType>(bits(data, 8, 5)); } /** Address of L2 descriptor if it exists */ @@ -171,18 +222,70 @@ class TableWalker : public MemObject { return _dirty; } + + /** + * Returns true if this entry targets the secure physical address + * map. + */ + bool secure(bool have_security, WalkerState *currState) const + { + if (have_security) { + if (type() == PageTable) + return !bits(data, 3); + else + return !bits(data, 19); + } + return false; + } }; /** Level 2 page table descriptor */ - struct L2Descriptor { - + class L2Descriptor : public DescriptorBase { + public: /** The raw bits of the entry. */ - uint32_t data; + uint32_t data; + L1Descriptor *l1Parent; /** This entry has been modified (access flag set) and needs to be * written back to memory */ bool _dirty; + /** Default ctor */ + L2Descriptor() + { + lookupLevel = L2; + } + + L2Descriptor(L1Descriptor &parent) : l1Parent(&parent) + { + lookupLevel = L2; + } + + virtual uint64_t getRawData() const + { + return (data); + } + + virtual std::string dbgHeader() const + { + return "Inserting L2 Descriptor into TLB\n"; + } + + virtual TlbEntry::DomainType domain() const + { + return l1Parent->domain(); + } + + bool secure(bool have_security, WalkerState *currState) const + { + return l1Parent->secure(have_security, currState); + } + + virtual uint8_t offsetBits() const + { + return large() ? 16 : 12; + } + /** Is the entry invalid */ bool invalid() const { @@ -202,7 +305,7 @@ class TableWalker : public MemObject } /** Is the translation global (no asid used)? */ - bool global() const + bool global(WalkerState *currState) const { return !bits(data, 11); } @@ -259,49 +362,329 @@ class TableWalker : public MemObject }; - protected: + /** Long-descriptor format (LPAE) */ + class LongDescriptor : public DescriptorBase { + public: + /** Descriptor type */ + enum EntryType { + Invalid, + Table, + Block, + Page + }; - /** - * A snooping DMA port that currently does nothing besides - * extending the DMA port to accept snoops without complaining. - */ - class SnoopingDmaPort : public DmaPort - { + /** The raw bits of the entry */ + uint64_t data; - protected: + /** This entry has been modified (access flag set) and needs to be + * written back to memory */ + bool _dirty; - virtual void recvTimingSnoopReq(PacketPtr pkt) - { } + virtual uint64_t getRawData() const + { + return (data); + } - virtual Tick recvAtomicSnoop(PacketPtr pkt) - { return 0; } + virtual std::string dbgHeader() const + { + if (type() == LongDescriptor::Page) { + assert(lookupLevel == L3); + return "Inserting Page descriptor into TLB\n"; + } else { + assert(lookupLevel < L3); + return "Inserting Block descriptor into TLB\n"; + } + } - virtual void recvFunctionalSnoop(PacketPtr pkt) - { } + /** + * Returns true if this entry targets the secure physical address + * map. + */ + bool secure(bool have_security, WalkerState *currState) const + { + assert(type() == Block || type() == Page); + return have_security && (currState->secureLookup && !bits(data, 5)); + } - virtual bool isSnooping() const { return true; } + /** True if the current lookup is performed in AArch64 state */ + bool aarch64; - public: + /** True if the granule size is 64 KB (AArch64 only) */ + bool largeGrain; - /** - * A snooping DMA port merely calls the construtor of the DMA - * port. - */ - SnoopingDmaPort(MemObject *dev, System *s) : - DmaPort(dev, s) - { } + /** Width of the granule size in bits */ + int grainSize; + + /** Return the descriptor type */ + EntryType type() const + { + switch (bits(data, 1, 0)) { + case 0x1: + // In AArch64 blocks are not allowed at L0 for the 4 KB granule + // and at L1 for the 64 KB granule + if (largeGrain) + return lookupLevel == L2 ? Block : Invalid; + return lookupLevel == L0 || lookupLevel == L3 ? Invalid : Block; + case 0x3: + return lookupLevel == L3 ? Page : Table; + default: + return Invalid; + } + } + + /** Return the bit width of the page/block offset */ + uint8_t offsetBits() const + { + assert(type() == Block || type() == Page); + if (largeGrain) { + if (type() == Block) + return 29 /* 512 MB */; + return 16 /* 64 KB */; // type() == Page + } else { + if (type() == Block) + return lookupLevel == L1 ? 30 /* 1 GB */ : 21 /* 2 MB */; + return 12 /* 4 KB */; // type() == Page + } + } + + /** Return the physical frame, bits shifted right */ + Addr pfn() const + { + if (aarch64) + return bits(data, 47, offsetBits()); + return bits(data, 39, offsetBits()); + } + + /** Return the complete physical address given a VA */ + Addr paddr(Addr va) const + { + int n = offsetBits(); + if (aarch64) + return mbits(data, 47, n) | mbits(va, n - 1, 0); + return mbits(data, 39, n) | mbits(va, n - 1, 0); + } + + /** Return the physical address of the entry */ + Addr paddr() const + { + if (aarch64) + return mbits(data, 47, offsetBits()); + return mbits(data, 39, offsetBits()); + } + + /** Return the address of the next page table */ + Addr nextTableAddr() const + { + assert(type() == Table); + if (aarch64) + return mbits(data, 47, grainSize); + else + return mbits(data, 39, 12); + } + + /** Return the address of the next descriptor */ + Addr nextDescAddr(Addr va) const + { + assert(type() == Table); + Addr pa = 0; + if (aarch64) { + int stride = grainSize - 3; + int va_lo = stride * (3 - (lookupLevel + 1)) + grainSize; + int va_hi = va_lo + stride - 1; + pa = nextTableAddr() | (bits(va, va_hi, va_lo) << 3); + } else { + if (lookupLevel == L1) + pa = nextTableAddr() | (bits(va, 29, 21) << 3); + else // lookupLevel == L2 + pa = nextTableAddr() | (bits(va, 20, 12) << 3); + } + return pa; + } + + /** Is execution allowed on this mapping? */ + bool xn() const + { + assert(type() == Block || type() == Page); + return bits(data, 54); + } + + /** Is privileged execution allowed on this mapping? (LPAE only) */ + bool pxn() const + { + assert(type() == Block || type() == Page); + return bits(data, 53); + } + + /** Contiguous hint bit. */ + bool contiguousHint() const + { + assert(type() == Block || type() == Page); + return bits(data, 52); + } + + /** Is the translation global (no asid used)? */ + bool global(WalkerState *currState) const + { + assert(currState && (type() == Block || type() == Page)); + if (!currState->aarch64 && (currState->isSecure && + !currState->secureLookup)) { + return false; // ARM ARM issue C B3.6.3 + } else if (currState->aarch64) { + if (currState->el == EL2 || currState->el == EL3) { + return true; // By default translations are treated as global + // in AArch64 EL2 and EL3 + } else if (currState->isSecure && !currState->secureLookup) { + return false; + } + } + return !bits(data, 11); + } + + /** Returns true if the access flag (AF) is set. */ + bool af() const + { + assert(type() == Block || type() == Page); + return bits(data, 10); + } + + /** 2-bit shareability field */ + uint8_t sh() const + { + assert(type() == Block || type() == Page); + return bits(data, 9, 8); + } + + /** 2-bit access protection flags */ + uint8_t ap() const + { + assert(type() == Block || type() == Page); + // Long descriptors only support the AP[2:1] scheme + return bits(data, 7, 6); + } + + /** Read/write access protection flag */ + bool rw() const + { + assert(type() == Block || type() == Page); + return !bits(data, 7); + } + + /** User/privileged level access protection flag */ + bool user() const + { + assert(type() == Block || type() == Page); + return bits(data, 6); + } + + /** Return the AP bits as compatible with the AP[2:0] format. Utility + * function used to simplify the code in the TLB for performing + * permission checks. */ + static uint8_t ap(bool rw, bool user) + { + return ((!rw) << 2) | (user << 1); + } + + TlbEntry::DomainType domain() const + { + // Long-desc. format only supports Client domain + assert(type() == Block || type() == Page); + return TlbEntry::DomainType::Client; + } + + /** Attribute index */ + uint8_t attrIndx() const + { + assert(type() == Block || type() == Page); + return bits(data, 4, 2); + } + + /** Memory attributes, only used by stage 2 translations */ + uint8_t memAttr() const + { + assert(type() == Block || type() == Page); + return bits(data, 5, 2); + } + + /** Set access flag that this entry has been touched. Mark the entry as + * requiring a writeback, in the future. */ + void setAf() + { + data |= 1 << 10; + _dirty = true; + } + + /** This entry needs to be written back to memory */ + bool dirty() const + { + return _dirty; + } + + /** Whether the subsequent levels of lookup are secure */ + bool secureTable() const + { + assert(type() == Table); + return !bits(data, 63); + } + + /** Two bit access protection flags for subsequent levels of lookup */ + uint8_t apTable() const + { + assert(type() == Table); + return bits(data, 62, 61); + } + + /** R/W protection flag for subsequent levels of lookup */ + uint8_t rwTable() const + { + assert(type() == Table); + return !bits(data, 62); + } + + /** User/privileged mode protection flag for subsequent levels of + * lookup */ + uint8_t userTable() const + { + assert(type() == Table); + return !bits(data, 61); + } + + /** Is execution allowed on subsequent lookup levels? */ + bool xnTable() const + { + assert(type() == Table); + return bits(data, 60); + } + + /** Is privileged execution allowed on subsequent lookup levels? */ + bool pxnTable() const + { + assert(type() == Table); + return bits(data, 59); + } }; - struct WalkerState //: public SimObject + class WalkerState { + public: /** Thread context that we're doing the walk for */ ThreadContext *tc; + /** If the access is performed in AArch64 state */ + bool aarch64; + + /** Current exception level */ + ExceptionLevel el; + + /** Current physical address range in bits */ + int physAddrRange; + /** Request that is currently being serviced */ RequestPtr req; - /** Context ID that we're servicing the request under */ - uint8_t contextId; + /** ASID that we're servicing the request under */ + uint16_t asid; + uint8_t vmid; + bool isHyp; /** Translation state for delayed requests */ TLB::Translation *transState; @@ -309,14 +692,32 @@ class TableWalker : public MemObject /** The fault that we are going to return */ Fault fault; - /** The virtual address that is being translated */ + /** The virtual address that is being translated with tagging removed.*/ Addr vaddr; + /** The virtual address that is being translated */ + Addr vaddr_tainted; + /** Cached copy of the sctlr as it existed when translation began */ SCTLR sctlr; - /** Width of the base address held in TTRB0 */ - uint32_t N; + /** Cached copy of the scr as it existed when translation began */ + SCR scr; + + /** Cached copy of the cpsr as it existed when translation began */ + CPSR cpsr; + + /** Cached copy of the ttbcr as it existed when translation began. */ + TTBCR ttbcr; + + /** Cached copy of the htcr as it existed when translation began. */ + HTCR htcr; + + /** Cached copy of the htcr as it existed when translation began. */ + HCR hcr; + + /** Cached copy of the vtcr as it existed when translation began. */ + VTCR_t vtcr; /** If the access is a write */ bool isWrite; @@ -324,6 +725,28 @@ class TableWalker : public MemObject /** If the access is a fetch (for execution, and no-exec) must be checked?*/ bool isFetch; + /** If the access comes from the secure state. */ + bool isSecure; + + /** Helper variables used to implement hierarchical access permissions + * when the long-desc. format is used (LPAE only) */ + bool secureLookup; + bool rwTable; + bool userTable; + bool xnTable; + bool pxnTable; + + /** Flag indicating if a second stage of lookup is required */ + bool stage2Req; + + /** Indicates whether the translation has been passed onto the second + * stage mmu, and no more work is required from the first stage. + */ + bool doingStage2; + + /** A pointer to the stage 2 translation that's in progress */ + TLB::Translation *stage2Tran; + /** If the mode is timing or atomic */ bool timing; @@ -333,10 +756,18 @@ class TableWalker : public MemObject /** Save mode for use in delayed response */ BaseTLB::Mode mode; + /** The translation type that has been requested */ + TLB::ArmTranslationType tranType; + + /** Short-format descriptors */ L1Descriptor l1Desc; L2Descriptor l2Desc; - /** Whether L1/L2 descriptor response is delayed in timing mode */ + /** Long-format descriptor (LPAE and AArch64) */ + LongDescriptor longDesc; + + /** Whether the response is delayed in timing mode due to additional + * lookups */ bool delayed; TableWalker *tableWalker; @@ -344,16 +775,48 @@ class TableWalker : public MemObject void doL1Descriptor(); void doL2Descriptor(); - std::string name() const {return tableWalker->name();} + void doLongDescriptor(); + + WalkerState(); + + std::string name() const { return tableWalker->name(); } }; + protected: + + /** + * A snooping DMA port that currently does nothing besides + * extending the DMA port to accept snoops without complaining. + */ + class SnoopingDmaPort : public DmaPort + { - /** Queue of requests that need processing first level translation */ - std::list<WalkerState *> stateQueueL1; + protected: - /** Queue of requests that have passed first level translation and - * require an additional level. */ - std::list<WalkerState *> stateQueueL2; + virtual void recvTimingSnoopReq(PacketPtr pkt) + { } + + virtual Tick recvAtomicSnoop(PacketPtr pkt) + { return 0; } + + virtual void recvFunctionalSnoop(PacketPtr pkt) + { } + + virtual bool isSnooping() const { return true; } + + public: + + /** + * A snooping DMA port merely calls the construtor of the DMA + * port. + */ + SnoopingDmaPort(MemObject *dev, System *s) : + DmaPort(dev, s) + { } + }; + + /** Queues of requests for all the different lookup levels */ + std::list<WalkerState *> stateQueues[MAX_LOOKUP_LEVELS]; /** Queue of requests that have passed are waiting because the walker is * currently busy. */ @@ -366,6 +829,12 @@ class TableWalker : public MemObject /** If we're draining keep the drain event around until we're drained */ DrainManager *drainManager; + /** The MMU to forward second stage look upts to */ + Stage2MMU *stage2Mmu; + + /** Indicates whether this table walker is part of the stage 2 mmu */ + const bool isStage2; + /** TLB that is initiating these table walks */ TLB *tlb; @@ -384,8 +853,16 @@ class TableWalker : public MemObject * removed from the pendingQueue per cycle. */ unsigned numSquashable; + /** Cached copies of system-level properties */ + bool haveSecurity; + bool _haveLPAE; + bool _haveVirtualization; + uint8_t physAddrRange; + bool _haveLargeAsid64; + ArmSystem *armSys; + public: - typedef ArmTableWalkerParams Params; + typedef ArmTableWalkerParams Params; TableWalker(const Params *p); virtual ~TableWalker(); @@ -395,38 +872,90 @@ class TableWalker : public MemObject return dynamic_cast<const Params *>(_params); } + bool haveLPAE() const { return _haveLPAE; } + bool haveVirtualization() const { return _haveVirtualization; } + bool haveLargeAsid64() const { return _haveLargeAsid64; } /** Checks if all state is cleared and if so, completes drain */ void completeDrain(); unsigned int drain(DrainManager *dm); - void drainResume(); + virtual void drainResume(); virtual BaseMasterPort& getMasterPort(const std::string &if_name, PortID idx = InvalidPortID); - Fault walk(RequestPtr req, ThreadContext *tc, uint8_t cid, TLB::Mode mode, - TLB::Translation *_trans, bool timing, bool functional = false); + /** + * Allow the MMU (overseeing both stage 1 and stage 2 TLBs) to + * access the table walker port through the TLB so that it can + * orchestrate staged translations. + * + * @return Our DMA port + */ + DmaPort& getWalkerPort() { return port; } + + Fault walk(RequestPtr req, ThreadContext *tc, uint16_t asid, uint8_t _vmid, + bool _isHyp, TLB::Mode mode, TLB::Translation *_trans, + bool timing, bool functional, bool secure, + TLB::ArmTranslationType tranType); void setTlb(TLB *_tlb) { tlb = _tlb; } + TLB* getTlb() { return tlb; } + void setMMU(Stage2MMU *m) { stage2Mmu = m; } void memAttrs(ThreadContext *tc, TlbEntry &te, SCTLR sctlr, uint8_t texcb, bool s); + void memAttrsLPAE(ThreadContext *tc, TlbEntry &te, + LongDescriptor &lDescriptor); + void memAttrsAArch64(ThreadContext *tc, TlbEntry &te, uint8_t attrIndx, + uint8_t sh); + + static LookupLevel toLookupLevel(uint8_t lookup_level_as_int); private: void doL1Descriptor(); void doL1DescriptorWrapper(); - EventWrapper<TableWalker, &TableWalker::doL1DescriptorWrapper> doL1DescEvent; + EventWrapper<TableWalker, + &TableWalker::doL1DescriptorWrapper> doL1DescEvent; void doL2Descriptor(); void doL2DescriptorWrapper(); - EventWrapper<TableWalker, &TableWalker::doL2DescriptorWrapper> doL2DescEvent; + EventWrapper<TableWalker, + &TableWalker::doL2DescriptorWrapper> doL2DescEvent; + + void doLongDescriptor(); + + void doL0LongDescriptorWrapper(); + EventWrapper<TableWalker, + &TableWalker::doL0LongDescriptorWrapper> doL0LongDescEvent; + void doL1LongDescriptorWrapper(); + EventWrapper<TableWalker, + &TableWalker::doL1LongDescriptorWrapper> doL1LongDescEvent; + void doL2LongDescriptorWrapper(); + EventWrapper<TableWalker, + &TableWalker::doL2LongDescriptorWrapper> doL2LongDescEvent; + void doL3LongDescriptorWrapper(); + EventWrapper<TableWalker, + &TableWalker::doL3LongDescriptorWrapper> doL3LongDescEvent; + + void doLongDescriptorWrapper(LookupLevel curr_lookup_level); + + bool fetchDescriptor(Addr descAddr, uint8_t *data, int numBytes, + Request::Flags flags, int queueIndex, Event *event, + void (TableWalker::*doDescriptor)()); + + void insertTableEntry(DescriptorBase &descriptor, bool longDescriptor); Fault processWalk(); + Fault processWalkLPAE(); + static unsigned adjustTableSizeAArch64(unsigned tsz); + /// Returns true if the address exceeds the range permitted by the + /// system-wide setting or by the TCR_ELx IPS/PS setting + static bool checkAddrSizeFaultAArch64(Addr addr, int currPhysAddrRange); + Fault processWalkAArch64(); void processWalkWrapper(); EventWrapper<TableWalker, &TableWalker::processWalkWrapper> doProcessEvent; void nextWalk(ThreadContext *tc); }; - } // namespace ArmISA #endif //__ARCH_ARM_TABLE_WALKER_HH__ diff --git a/src/arch/arm/tlb.cc b/src/arch/arm/tlb.cc index 805898576..037f7490e 100644 --- a/src/arch/arm/tlb.cc +++ b/src/arch/arm/tlb.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2012 ARM Limited + * Copyright (c) 2010-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -49,6 +49,8 @@ #include "arch/arm/pagetable.hh" #include "arch/arm/system.hh" #include "arch/arm/table_walker.hh" +#include "arch/arm/stage2_lookup.hh" +#include "arch/arm/stage2_mmu.hh" #include "arch/arm/tlb.hh" #include "arch/arm/utility.hh" #include "base/inifile.hh" @@ -67,28 +69,51 @@ using namespace std; using namespace ArmISA; -TLB::TLB(const Params *p) - : BaseTLB(p), size(p->size) , tableWalker(p->walker), - rangeMRU(1), bootUncacheability(false), miscRegValid(false) +TLB::TLB(const ArmTLBParams *p) + : BaseTLB(p), table(new TlbEntry[p->size]), size(p->size), + isStage2(p->is_stage2), tableWalker(p->walker), stage2Tlb(NULL), + stage2Mmu(NULL), rangeMRU(1), bootUncacheability(false), + miscRegValid(false), curTranType(NormalTran) { - table = new TlbEntry[size]; - memset(table, 0, sizeof(TlbEntry) * size); - tableWalker->setTlb(this); + + // Cache system-level properties + haveLPAE = tableWalker->haveLPAE(); + haveVirtualization = tableWalker->haveVirtualization(); + haveLargeAsid64 = tableWalker->haveLargeAsid64(); } TLB::~TLB() { - if (table) - delete [] table; + delete[] table; +} + +void +TLB::init() +{ + if (stage2Mmu && !isStage2) + stage2Tlb = stage2Mmu->stage2Tlb(); +} + +void +TLB::setMMU(Stage2MMU *m) +{ + stage2Mmu = m; + tableWalker->setMMU(m); } bool TLB::translateFunctional(ThreadContext *tc, Addr va, Addr &pa) { - if (!miscRegValid) - updateMiscReg(tc); - TlbEntry *e = lookup(va, contextId, true); + updateMiscReg(tc); + + if (directToStage2) { + assert(stage2Tlb); + return stage2Tlb->translateFunctional(tc, va, pa); + } + + TlbEntry *e = lookup(va, asid, vmid, isHyp, isSecure, true, false, + aarch64 ? aarch64EL : EL1); if (!e) return false; pa = e->pAddr(va); @@ -102,22 +127,24 @@ TLB::finalizePhysical(RequestPtr req, ThreadContext *tc, Mode mode) const } TlbEntry* -TLB::lookup(Addr va, uint8_t cid, bool functional) +TLB::lookup(Addr va, uint16_t asn, uint8_t vmid, bool hyp, bool secure, + bool functional, bool ignore_asn, uint8_t target_el) { TlbEntry *retval = NULL; - // Maitaining LRU array - + // Maintaining LRU array int x = 0; while (retval == NULL && x < size) { - if (table[x].match(va, cid)) { - - // We only move the hit entry ahead when the position is higher than rangeMRU + if ((!ignore_asn && table[x].match(va, asn, vmid, hyp, secure, false, + target_el)) || + (ignore_asn && table[x].match(va, vmid, hyp, secure, target_el))) { + // We only move the hit entry ahead when the position is higher + // than rangeMRU if (x > rangeMRU && !functional) { TlbEntry tmp_entry = table[x]; for(int i = x; i > 0; i--) - table[i] = table[i-1]; + table[i] = table[i - 1]; table[0] = tmp_entry; retval = &table[0]; } else { @@ -125,14 +152,19 @@ TLB::lookup(Addr va, uint8_t cid, bool functional) } break; } - x++; + ++x; } - DPRINTF(TLBVerbose, "Lookup %#x, cid %#x -> %s ppn %#x size: %#x pa: %#x ap:%d\n", - va, cid, retval ? "hit" : "miss", retval ? retval->pfn : 0, - retval ? retval->size : 0, retval ? retval->pAddr(va) : 0, - retval ? retval->ap : 0); - ; + DPRINTF(TLBVerbose, "Lookup %#x, asn %#x -> %s vmn 0x%x hyp %d secure %d " + "ppn %#x size: %#x pa: %#x ap:%d ns:%d nstid:%d g:%d asid: %d " + "el: %d\n", + va, asn, retval ? "hit" : "miss", vmid, hyp, secure, + retval ? retval->pfn : 0, retval ? retval->size : 0, + retval ? retval->pAddr(va) : 0, retval ? retval->ap : 0, + retval ? retval->ns : 0, retval ? retval->nstid : 0, + retval ? retval->global : 0, retval ? retval->asid : 0, + retval ? retval->el : 0, retval ? retval->el : 0); + return retval; } @@ -141,122 +173,176 @@ void TLB::insert(Addr addr, TlbEntry &entry) { DPRINTF(TLB, "Inserting entry into TLB with pfn:%#x size:%#x vpn: %#x" - " asid:%d N:%d global:%d valid:%d nc:%d sNp:%d xn:%d ap:%#x" - " domain:%#x\n", entry.pfn, entry.size, entry.vpn, entry.asid, - entry.N, entry.global, entry.valid, entry.nonCacheable, entry.sNp, - entry.xn, entry.ap, entry.domain); - - if (table[size-1].valid) - DPRINTF(TLB, " - Replacing Valid entry %#x, asn %d ppn %#x size: %#x ap:%d\n", + " asid:%d vmid:%d N:%d global:%d valid:%d nc:%d xn:%d" + " ap:%#x domain:%#x ns:%d nstid:%d isHyp:%d\n", entry.pfn, + entry.size, entry.vpn, entry.asid, entry.vmid, entry.N, + entry.global, entry.valid, entry.nonCacheable, entry.xn, + entry.ap, static_cast<uint8_t>(entry.domain), entry.ns, entry.nstid, + entry.isHyp); + + if (table[size - 1].valid) + DPRINTF(TLB, " - Replacing Valid entry %#x, asn %d vmn %d ppn %#x " + "size: %#x ap:%d ns:%d nstid:%d g:%d isHyp:%d el: %d\n", table[size-1].vpn << table[size-1].N, table[size-1].asid, - table[size-1].pfn << table[size-1].N, table[size-1].size, - table[size-1].ap); + table[size-1].vmid, table[size-1].pfn << table[size-1].N, + table[size-1].size, table[size-1].ap, table[size-1].ns, + table[size-1].nstid, table[size-1].global, table[size-1].isHyp, + table[size-1].el); //inserting to MRU position and evicting the LRU one - for(int i = size-1; i > 0; i--) - table[i] = table[i-1]; + for (int i = size - 1; i > 0; --i) + table[i] = table[i-1]; table[0] = entry; inserts++; } void -TLB::printTlb() +TLB::printTlb() const { int x = 0; TlbEntry *te; DPRINTF(TLB, "Current TLB contents:\n"); while (x < size) { - te = &table[x]; - if (te->valid) - DPRINTF(TLB, " * %#x, asn %d ppn %#x size: %#x ap:%d\n", - te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap); - x++; + te = &table[x]; + if (te->valid) + DPRINTF(TLB, " * %s\n", te->print()); + ++x; } } - void -TLB::flushAll() +TLB::flushAllSecurity(bool secure_lookup, uint8_t target_el, bool ignore_el) { - DPRINTF(TLB, "Flushing all TLB entries\n"); + DPRINTF(TLB, "Flushing all TLB entries (%s lookup)\n", + (secure_lookup ? "secure" : "non-secure")); int x = 0; TlbEntry *te; while (x < size) { - te = &table[x]; - if (te->valid) { - DPRINTF(TLB, " - %#x, asn %d ppn %#x size: %#x ap:%d\n", - te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap); - flushedEntries++; - } - x++; - } + te = &table[x]; + if (te->valid && secure_lookup == !te->nstid && + (te->vmid == vmid || secure_lookup) && + checkELMatch(target_el, te->el, ignore_el)) { - memset(table, 0, sizeof(TlbEntry) * size); + DPRINTF(TLB, " - %s\n", te->print()); + te->valid = false; + flushedEntries++; + } + ++x; + } flushTlb++; -} + // If there's a second stage TLB (and we're not it) then flush it as well + // if we're currently in hyp mode + if (!isStage2 && isHyp) { + stage2Tlb->flushAllSecurity(secure_lookup, true); + } +} void -TLB::flushMvaAsid(Addr mva, uint64_t asn) +TLB::flushAllNs(bool hyp, uint8_t target_el, bool ignore_el) { - DPRINTF(TLB, "Flushing mva %#x asid: %#x\n", mva, asn); + DPRINTF(TLB, "Flushing all NS TLB entries (%s lookup)\n", + (hyp ? "hyp" : "non-hyp")); + int x = 0; TlbEntry *te; + while (x < size) { + te = &table[x]; + if (te->valid && te->nstid && te->isHyp == hyp && + checkELMatch(target_el, te->el, ignore_el)) { - te = lookup(mva, asn); - while (te != NULL) { - DPRINTF(TLB, " - %#x, asn %d ppn %#x size: %#x ap:%d\n", - te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap); - te->valid = false; - flushedEntries++; - te = lookup(mva,asn); + DPRINTF(TLB, " - %s\n", te->print()); + flushedEntries++; + te->valid = false; + } + ++x; + } + + flushTlb++; + + // If there's a second stage TLB (and we're not it) then flush it as well + if (!isStage2 && !hyp) { + stage2Tlb->flushAllNs(false, true); } +} + +void +TLB::flushMvaAsid(Addr mva, uint64_t asn, bool secure_lookup, uint8_t target_el) +{ + DPRINTF(TLB, "Flushing TLB entries with mva: %#x, asid: %#x " + "(%s lookup)\n", mva, asn, (secure_lookup ? + "secure" : "non-secure")); + _flushMva(mva, asn, secure_lookup, false, false, target_el); flushTlbMvaAsid++; } void -TLB::flushAsid(uint64_t asn) +TLB::flushAsid(uint64_t asn, bool secure_lookup, uint8_t target_el) { - DPRINTF(TLB, "Flushing all entries with asid: %#x\n", asn); + DPRINTF(TLB, "Flushing TLB entries with asid: %#x (%s lookup)\n", asn, + (secure_lookup ? "secure" : "non-secure")); - int x = 0; + int x = 0 ; TlbEntry *te; while (x < size) { te = &table[x]; - if (te->asid == asn) { + if (te->valid && te->asid == asn && secure_lookup == !te->nstid && + (te->vmid == vmid || secure_lookup) && + checkELMatch(target_el, te->el, false)) { + te->valid = false; - DPRINTF(TLB, " - %#x, asn %d ppn %#x size: %#x ap:%d\n", - te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap); + DPRINTF(TLB, " - %s\n", te->print()); flushedEntries++; } - x++; + ++x; } flushTlbAsid++; } void -TLB::flushMva(Addr mva) +TLB::flushMva(Addr mva, bool secure_lookup, bool hyp, uint8_t target_el) { - DPRINTF(TLB, "Flushing all entries with mva: %#x\n", mva); + DPRINTF(TLB, "Flushing TLB entries with mva: %#x (%s lookup)\n", mva, + (secure_lookup ? "secure" : "non-secure")); + _flushMva(mva, 0xbeef, secure_lookup, hyp, true, target_el); + flushTlbMva++; +} - int x = 0; +void +TLB::_flushMva(Addr mva, uint64_t asn, bool secure_lookup, bool hyp, + bool ignore_asn, uint8_t target_el) +{ TlbEntry *te; - - while (x < size) { - te = &table[x]; - Addr v = te->vpn << te->N; - if (mva >= v && mva < v + te->size) { + // D5.7.2: Sign-extend address to 64 bits + mva = sext<56>(mva); + te = lookup(mva, asn, vmid, hyp, secure_lookup, false, ignore_asn, + target_el); + while (te != NULL) { + if (secure_lookup == !te->nstid) { + DPRINTF(TLB, " - %s\n", te->print()); te->valid = false; - DPRINTF(TLB, " - %#x, asn %d ppn %#x size: %#x ap:%d\n", - te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap); flushedEntries++; } - x++; + te = lookup(mva, asn, vmid, hyp, secure_lookup, false, ignore_asn, + target_el); } - flushTlbMva++; +} + +bool +TLB::checkELMatch(uint8_t target_el, uint8_t tentry_el, bool ignore_el) +{ + bool elMatch = true; + if (!ignore_el) { + if (target_el == 2 || target_el == 3) { + elMatch = (tentry_el == target_el); + } else { + elMatch = (tentry_el == 0) || (tentry_el == 1); + } + } + return elMatch; } void @@ -273,6 +359,10 @@ TLB::serialize(ostream &os) DPRINTF(Checkpoint, "Serializing Arm TLB\n"); SERIALIZE_SCALAR(_attr); + SERIALIZE_SCALAR(haveLPAE); + SERIALIZE_SCALAR(directToStage2); + SERIALIZE_SCALAR(stage2Req); + SERIALIZE_SCALAR(bootUncacheability); int num_entries = size; SERIALIZE_SCALAR(num_entries); @@ -288,6 +378,11 @@ TLB::unserialize(Checkpoint *cp, const string §ion) DPRINTF(Checkpoint, "Unserializing Arm TLB\n"); UNSERIALIZE_SCALAR(_attr); + UNSERIALIZE_SCALAR(haveLPAE); + UNSERIALIZE_SCALAR(directToStage2); + UNSERIALIZE_SCALAR(stage2Req); + UNSERIALIZE_SCALAR(bootUncacheability); + int num_entries; UNSERIALIZE_SCALAR(num_entries); for(int i = 0; i < min(size, num_entries); i++){ @@ -413,11 +508,15 @@ TLB::regStats() Fault TLB::translateSe(RequestPtr req, ThreadContext *tc, Mode mode, - Translation *translation, bool &delay, bool timing) + Translation *translation, bool &delay, bool timing) { - if (!miscRegValid) - updateMiscReg(tc); - Addr vaddr = req->getVaddr(); + updateMiscReg(tc); + Addr vaddr_tainted = req->getVaddr(); + Addr vaddr = 0; + if (aarch64) + vaddr = purifyTaggedAddr(vaddr_tainted, tc, aarch64EL); + else + vaddr = vaddr_tainted; uint32_t flags = req->getFlags(); bool is_fetch = (mode == Execute); @@ -426,8 +525,12 @@ TLB::translateSe(RequestPtr req, ThreadContext *tc, Mode mode, if (!is_fetch) { assert(flags & MustBeOne); if (sctlr.a || !(flags & AllowUnaligned)) { - if (vaddr & flags & AlignmentMask) { - return new DataAbort(vaddr, 0, is_write, ArmFault::AlignmentFault); + if (vaddr & mask(flags & AlignmentMask)) { + // LPAE is always disabled in SE mode + return new DataAbort(vaddr_tainted, + TlbEntry::DomainType::NoAccess, is_write, + ArmFault::AlignmentFault, isStage2, + ArmFault::VmsaTran); } } } @@ -436,56 +539,411 @@ TLB::translateSe(RequestPtr req, ThreadContext *tc, Mode mode, Process *p = tc->getProcessPtr(); if (!p->pTable->translate(vaddr, paddr)) - return Fault(new GenericPageTableFault(vaddr)); + return Fault(new GenericPageTableFault(vaddr_tainted)); req->setPaddr(paddr); return NoFault; } Fault -TLB::trickBoxCheck(RequestPtr req, Mode mode, uint8_t domain, bool sNp) +TLB::trickBoxCheck(RequestPtr req, Mode mode, TlbEntry::DomainType domain) { return NoFault; } Fault -TLB::walkTrickBoxCheck(Addr pa, Addr va, Addr sz, bool is_exec, - bool is_write, uint8_t domain, bool sNp) +TLB::walkTrickBoxCheck(Addr pa, bool is_secure, Addr va, Addr sz, bool is_exec, + bool is_write, TlbEntry::DomainType domain, LookupLevel lookup_level) +{ + return NoFault; +} + +Fault +TLB::checkPermissions(TlbEntry *te, RequestPtr req, Mode mode) +{ + Addr vaddr = req->getVaddr(); // 32-bit don't have to purify + uint32_t flags = req->getFlags(); + bool is_fetch = (mode == Execute); + bool is_write = (mode == Write); + bool is_priv = isPriv && !(flags & UserMode); + + // Get the translation type from the actuall table entry + ArmFault::TranMethod tranMethod = te->longDescFormat ? ArmFault::LpaeTran + : ArmFault::VmsaTran; + + // If this is the second stage of translation and the request is for a + // stage 1 page table walk then we need to check the HCR.PTW bit. This + // allows us to generate a fault if the request targets an area marked + // as a device or strongly ordered. + if (isStage2 && req->isPTWalk() && hcr.ptw && + (te->mtype != TlbEntry::MemoryType::Normal)) { + return new DataAbort(vaddr, te->domain, is_write, + ArmFault::PermissionLL + te->lookupLevel, + isStage2, tranMethod); + } + + // Generate an alignment fault for unaligned data accesses to device or + // strongly ordered memory + if (!is_fetch) { + if (te->mtype != TlbEntry::MemoryType::Normal) { + if (vaddr & mask(flags & AlignmentMask)) { + alignFaults++; + return new DataAbort(vaddr, TlbEntry::DomainType::NoAccess, is_write, + ArmFault::AlignmentFault, isStage2, + tranMethod); + } + } + } + + if (te->nonCacheable) { + // Prevent prefetching from I/O devices. + if (req->isPrefetch()) { + // Here we can safely use the fault status for the short + // desc. format in all cases + return new PrefetchAbort(vaddr, ArmFault::PrefetchUncacheable, + isStage2, tranMethod); + } + } + + if (!te->longDescFormat) { + switch ((dacr >> (static_cast<uint8_t>(te->domain) * 2)) & 0x3) { + case 0: + domainFaults++; + DPRINTF(TLB, "TLB Fault: Data abort on domain. DACR: %#x" + " domain: %#x write:%d\n", dacr, + static_cast<uint8_t>(te->domain), is_write); + if (is_fetch) + return new PrefetchAbort(vaddr, + ArmFault::DomainLL + te->lookupLevel, + isStage2, tranMethod); + else + return new DataAbort(vaddr, te->domain, is_write, + ArmFault::DomainLL + te->lookupLevel, + isStage2, tranMethod); + case 1: + // Continue with permissions check + break; + case 2: + panic("UNPRED domain\n"); + case 3: + return NoFault; + } + } + + // The 'ap' variable is AP[2:0] or {AP[2,1],1b'0}, i.e. always three bits + uint8_t ap = te->longDescFormat ? te->ap << 1 : te->ap; + uint8_t hap = te->hap; + + if (sctlr.afe == 1 || te->longDescFormat) + ap |= 1; + + bool abt; + bool isWritable = true; + // If this is a stage 2 access (eg for reading stage 1 page table entries) + // then don't perform the AP permissions check, we stil do the HAP check + // below. + if (isStage2) { + abt = false; + } else { + switch (ap) { + case 0: + DPRINTF(TLB, "Access permissions 0, checking rs:%#x\n", + (int)sctlr.rs); + if (!sctlr.xp) { + switch ((int)sctlr.rs) { + case 2: + abt = is_write; + break; + case 1: + abt = is_write || !is_priv; + break; + case 0: + case 3: + default: + abt = true; + break; + } + } else { + abt = true; + } + break; + case 1: + abt = !is_priv; + break; + case 2: + abt = !is_priv && is_write; + isWritable = is_priv; + break; + case 3: + abt = false; + break; + case 4: + panic("UNPRED premissions\n"); + case 5: + abt = !is_priv || is_write; + isWritable = false; + break; + case 6: + case 7: + abt = is_write; + isWritable = false; + break; + default: + panic("Unknown permissions %#x\n", ap); + } + } + + bool hapAbt = is_write ? !(hap & 2) : !(hap & 1); + bool xn = te->xn || (isWritable && sctlr.wxn) || + (ap == 3 && sctlr.uwxn && is_priv); + if (is_fetch && (abt || xn || + (te->longDescFormat && te->pxn && !is_priv) || + (isSecure && te->ns && scr.sif))) { + permsFaults++; + DPRINTF(TLB, "TLB Fault: Prefetch abort on permission check. AP:%d " + "priv:%d write:%d ns:%d sif:%d sctlr.afe: %d \n", + ap, is_priv, is_write, te->ns, scr.sif,sctlr.afe); + return new PrefetchAbort(vaddr, + ArmFault::PermissionLL + te->lookupLevel, + isStage2, tranMethod); + } else if (abt | hapAbt) { + permsFaults++; + DPRINTF(TLB, "TLB Fault: Data abort on permission check. AP:%d priv:%d" + " write:%d\n", ap, is_priv, is_write); + return new DataAbort(vaddr, te->domain, is_write, + ArmFault::PermissionLL + te->lookupLevel, + isStage2 | !abt, tranMethod); + } + return NoFault; +} + + +Fault +TLB::checkPermissions64(TlbEntry *te, RequestPtr req, Mode mode, + ThreadContext *tc) { + assert(aarch64); + + Addr vaddr_tainted = req->getVaddr(); + Addr vaddr = purifyTaggedAddr(vaddr_tainted, tc, aarch64EL); + + uint32_t flags = req->getFlags(); + bool is_fetch = (mode == Execute); + bool is_write = (mode == Write); + bool is_priv M5_VAR_USED = isPriv && !(flags & UserMode); + + updateMiscReg(tc, curTranType); + + // If this is the second stage of translation and the request is for a + // stage 1 page table walk then we need to check the HCR.PTW bit. This + // allows us to generate a fault if the request targets an area marked + // as a device or strongly ordered. + if (isStage2 && req->isPTWalk() && hcr.ptw && + (te->mtype != TlbEntry::MemoryType::Normal)) { + return new DataAbort(vaddr_tainted, te->domain, is_write, + ArmFault::PermissionLL + te->lookupLevel, + isStage2, ArmFault::LpaeTran); + } + + // Generate an alignment fault for unaligned accesses to device or + // strongly ordered memory + if (!is_fetch) { + if (te->mtype != TlbEntry::MemoryType::Normal) { + if (vaddr & mask(flags & AlignmentMask)) { + alignFaults++; + return new DataAbort(vaddr_tainted, + TlbEntry::DomainType::NoAccess, is_write, + ArmFault::AlignmentFault, isStage2, + ArmFault::LpaeTran); + } + } + } + + if (te->nonCacheable) { + // Prevent prefetching from I/O devices. + if (req->isPrefetch()) { + // Here we can safely use the fault status for the short + // desc. format in all cases + return new PrefetchAbort(vaddr_tainted, + ArmFault::PrefetchUncacheable, + isStage2, ArmFault::LpaeTran); + } + } + + uint8_t ap = 0x3 & (te->ap); // 2-bit access protection field + bool grant = false; + + uint8_t xn = te->xn; + uint8_t pxn = te->pxn; + bool r = !is_write && !is_fetch; + bool w = is_write; + bool x = is_fetch; + DPRINTF(TLBVerbose, "Checking permissions: ap:%d, xn:%d, pxn:%d, r:%d, " + "w:%d, x:%d\n", ap, xn, pxn, r, w, x); + + if (isStage2) { + panic("Virtualization in AArch64 state is not supported yet"); + } else { + switch (aarch64EL) { + case EL0: + { + uint8_t perm = (ap << 2) | (xn << 1) | pxn; + switch (perm) { + case 0: + case 1: + case 8: + case 9: + grant = x; + break; + case 4: + case 5: + grant = r || w || (x && !sctlr.wxn); + break; + case 6: + case 7: + grant = r || w; + break; + case 12: + case 13: + grant = r || x; + break; + case 14: + case 15: + grant = r; + break; + default: + grant = false; + } + } + break; + case EL1: + { + uint8_t perm = (ap << 2) | (xn << 1) | pxn; + switch (perm) { + case 0: + case 2: + grant = r || w || (x && !sctlr.wxn); + break; + case 1: + case 3: + case 4: + case 5: + case 6: + case 7: + // regions that are writeable at EL0 should not be + // executable at EL1 + grant = r || w; + break; + case 8: + case 10: + case 12: + case 14: + grant = r || x; + break; + case 9: + case 11: + case 13: + case 15: + grant = r; + break; + default: + grant = false; + } + } + break; + case EL2: + case EL3: + { + uint8_t perm = (ap & 0x2) | xn; + switch (perm) { + case 0: + grant = r || w || (x && !sctlr.wxn) ; + break; + case 1: + grant = r || w; + break; + case 2: + grant = r || x; + break; + case 3: + grant = r; + break; + default: + grant = false; + } + } + break; + } + } + + if (!grant) { + if (is_fetch) { + permsFaults++; + DPRINTF(TLB, "TLB Fault: Prefetch abort on permission check. " + "AP:%d priv:%d write:%d ns:%d sif:%d " + "sctlr.afe: %d\n", + ap, is_priv, is_write, te->ns, scr.sif, sctlr.afe); + // Use PC value instead of vaddr because vaddr might be aligned to + // cache line and should not be the address reported in FAR + return new PrefetchAbort(req->getPC(), + ArmFault::PermissionLL + te->lookupLevel, + isStage2, ArmFault::LpaeTran); + } else { + permsFaults++; + DPRINTF(TLB, "TLB Fault: Data abort on permission check. AP:%d " + "priv:%d write:%d\n", ap, is_priv, is_write); + return new DataAbort(vaddr_tainted, te->domain, is_write, + ArmFault::PermissionLL + te->lookupLevel, + isStage2, ArmFault::LpaeTran); + } + } + return NoFault; } Fault TLB::translateFs(RequestPtr req, ThreadContext *tc, Mode mode, - Translation *translation, bool &delay, bool timing, bool functional) + Translation *translation, bool &delay, bool timing, + TLB::ArmTranslationType tranType, bool functional) { // No such thing as a functional timing access assert(!(timing && functional)); - if (!miscRegValid) { - updateMiscReg(tc); - DPRINTF(TLBVerbose, "TLB variables changed!\n"); - } + updateMiscReg(tc, tranType); - Addr vaddr = req->getVaddr(); + Addr vaddr_tainted = req->getVaddr(); + Addr vaddr = 0; + if (aarch64) + vaddr = purifyTaggedAddr(vaddr_tainted, tc, aarch64EL); + else + vaddr = vaddr_tainted; uint32_t flags = req->getFlags(); - bool is_fetch = (mode == Execute); - bool is_write = (mode == Write); - bool is_priv = isPriv && !(flags & UserMode); + bool is_fetch = (mode == Execute); + bool is_write = (mode == Write); + bool long_desc_format = aarch64 || (haveLPAE && ttbcr.eae); + ArmFault::TranMethod tranMethod = long_desc_format ? ArmFault::LpaeTran + : ArmFault::VmsaTran; + + req->setAsid(asid); - req->setAsid(contextId.asid); - if (is_priv) - req->setFlags(Request::PRIVILEGED); + DPRINTF(TLBVerbose, "CPSR is priv:%d UserMode:%d secure:%d S1S2NsTran:%d\n", + isPriv, flags & UserMode, isSecure, tranType & S1S2NsTran); - req->taskId(tc->getCpuPtr()->taskId()); + DPRINTF(TLB, "translateFs addr %#x, mode %d, st2 %d, scr %#x sctlr %#x " + "flags %#x tranType 0x%x\n", vaddr_tainted, mode, isStage2, + scr, sctlr, flags, tranType); + + // Generate an alignment fault for unaligned PC + if (aarch64 && is_fetch && (req->getPC() & mask(2))) { + return new PCAlignmentFault(req->getPC()); + } - DPRINTF(TLBVerbose, "CPSR is priv:%d UserMode:%d\n", - isPriv, flags & UserMode); // If this is a clrex instruction, provide a PA of 0 with no fault // This will force the monitor to set the tracked address to 0 // a bit of a hack but this effectively clrears this processors monitor if (flags & Request::CLEAR_LL){ + // @todo: check implications of security extensions req->setPaddr(0); req->setFlags(Request::UNCACHEABLE); req->setFlags(Request::CLEAR_LL); @@ -498,209 +956,139 @@ TLB::translateFs(RequestPtr req, ThreadContext *tc, Mode mode, if (!is_fetch) { assert(flags & MustBeOne); if (sctlr.a || !(flags & AllowUnaligned)) { - if (vaddr & flags & AlignmentMask) { + if (vaddr & mask(flags & AlignmentMask)) { alignFaults++; - return new DataAbort(vaddr, 0, is_write, ArmFault::AlignmentFault); + return new DataAbort(vaddr_tainted, + TlbEntry::DomainType::NoAccess, is_write, + ArmFault::AlignmentFault, isStage2, + tranMethod); } } } - Fault fault; + // If guest MMU is off or hcr.vm=0 go straight to stage2 + if ((isStage2 && !hcr.vm) || (!isStage2 && !sctlr.m)) { - if (!sctlr.m) { req->setPaddr(vaddr); - if (sctlr.tre == 0) { + // When the MMU is off the security attribute corresponds to the + // security state of the processor + if (isSecure) + req->setFlags(Request::SECURE); + + // @todo: double check this (ARM ARM issue C B3.2.1) + if (long_desc_format || sctlr.tre == 0) { req->setFlags(Request::UNCACHEABLE); } else { if (nmrr.ir0 == 0 || nmrr.or0 == 0 || prrr.tr0 != 0x2) - req->setFlags(Request::UNCACHEABLE); + req->setFlags(Request::UNCACHEABLE); } // Set memory attributes TlbEntry temp_te; - tableWalker->memAttrs(tc, temp_te, sctlr, 0, 1); - temp_te.shareable = true; + temp_te.ns = !isSecure; + if (isStage2 || hcr.dc == 0 || isSecure || + (isHyp && !(tranType & S1CTran))) { + + temp_te.mtype = is_fetch ? TlbEntry::MemoryType::Normal + : TlbEntry::MemoryType::StronglyOrdered; + temp_te.innerAttrs = 0x0; + temp_te.outerAttrs = 0x0; + temp_te.shareable = true; + temp_te.outerShareable = true; + } else { + temp_te.mtype = TlbEntry::MemoryType::Normal; + temp_te.innerAttrs = 0x3; + temp_te.outerAttrs = 0x3; + temp_te.shareable = false; + temp_te.outerShareable = false; + } + temp_te.setAttributes(long_desc_format); DPRINTF(TLBVerbose, "(No MMU) setting memory attributes: shareable:\ - %d, innerAttrs: %d, outerAttrs: %d\n", temp_te.shareable, - temp_te.innerAttrs, temp_te.outerAttrs); + %d, innerAttrs: %d, outerAttrs: %d, isStage2: %d\n", + temp_te.shareable, temp_te.innerAttrs, temp_te.outerAttrs, + isStage2); setAttr(temp_te.attributes); - return trickBoxCheck(req, mode, 0, false); + return trickBoxCheck(req, mode, TlbEntry::DomainType::NoAccess); } - DPRINTF(TLBVerbose, "Translating vaddr=%#x context=%d\n", vaddr, contextId); + DPRINTF(TLBVerbose, "Translating %s=%#x context=%d\n", + isStage2 ? "IPA" : "VA", vaddr_tainted, asid); // Translation enabled - TlbEntry *te = lookup(vaddr, contextId); - if (te == NULL) { - if (req->isPrefetch()){ - //if the request is a prefetch don't attempt to fill the TLB - //or go any further with the memory access - prefetchFaults++; - return new PrefetchAbort(vaddr, ArmFault::PrefetchTLBMiss); - } - - if (is_fetch) - instMisses++; - else if (is_write) - writeMisses++; - else - readMisses++; + TlbEntry *te = NULL; + TlbEntry mergeTe; + Fault fault = getResultTe(&te, req, tc, mode, translation, timing, + functional, &mergeTe); + // only proceed if we have a valid table entry + if ((te == NULL) && (fault == NoFault)) delay = true; - // start translation table walk, pass variables rather than - // re-retreaving in table walker for speed - DPRINTF(TLB, "TLB Miss: Starting hardware table walker for %#x(%d)\n", - vaddr, contextId); - fault = tableWalker->walk(req, tc, contextId, mode, translation, - timing, functional); - if (timing && fault == NoFault) { - delay = true; - // for timing mode, return and wait for table walk - return fault; + // If we have the table entry transfer some of the attributes to the + // request that triggered the translation + if (te != NULL) { + // Set memory attributes + DPRINTF(TLBVerbose, + "Setting memory attributes: shareable: %d, innerAttrs: %d, \ + outerAttrs: %d, mtype: %d, isStage2: %d\n", + te->shareable, te->innerAttrs, te->outerAttrs, + static_cast<uint8_t>(te->mtype), isStage2); + setAttr(te->attributes); + if (te->nonCacheable) { + req->setFlags(Request::UNCACHEABLE); } - if (fault) - return fault; - - te = lookup(vaddr, contextId); - if (!te) - printTlb(); - assert(te); - } else { - if (is_fetch) - instHits++; - else if (is_write) - writeHits++; - else - readHits++; - } - - // Set memory attributes - DPRINTF(TLBVerbose, - "Setting memory attributes: shareable: %d, innerAttrs: %d, \ - outerAttrs: %d\n", - te->shareable, te->innerAttrs, te->outerAttrs); - setAttr(te->attributes); - if (te->nonCacheable) { - req->setFlags(Request::UNCACHEABLE); - // Prevent prefetching from I/O devices. - if (req->isPrefetch()) { - return new PrefetchAbort(vaddr, ArmFault::PrefetchUncacheable); + if (!bootUncacheability && + ((ArmSystem*)tc->getSystemPtr())->adderBootUncacheable(vaddr)) { + req->setFlags(Request::UNCACHEABLE); } - } - - if (!bootUncacheability && - ((ArmSystem*)tc->getSystemPtr())->adderBootUncacheable(vaddr)) - req->setFlags(Request::UNCACHEABLE); - switch ( (dacr >> (te->domain * 2)) & 0x3) { - case 0: - domainFaults++; - DPRINTF(TLB, "TLB Fault: Data abort on domain. DACR: %#x domain: %#x" - " write:%d sNp:%d\n", dacr, te->domain, is_write, te->sNp); - if (is_fetch) - return new PrefetchAbort(vaddr, - (te->sNp ? ArmFault::Domain0 : ArmFault::Domain1)); - else - return new DataAbort(vaddr, te->domain, is_write, - (te->sNp ? ArmFault::Domain0 : ArmFault::Domain1)); - case 1: - // Continue with permissions check - break; - case 2: - panic("UNPRED domain\n"); - case 3: req->setPaddr(te->pAddr(vaddr)); - fault = trickBoxCheck(req, mode, te->domain, te->sNp); - if (fault) - return fault; - return NoFault; - } - - uint8_t ap = te->ap; - - if (sctlr.afe == 1) - ap |= 1; - - bool abt; + if (isSecure && !te->ns) { + req->setFlags(Request::SECURE); + } + if ((!is_fetch) && (vaddr & mask(flags & AlignmentMask)) && + (te->mtype != TlbEntry::MemoryType::Normal)) { + // Unaligned accesses to Device memory should always cause an + // abort regardless of sctlr.a + alignFaults++; + return new DataAbort(vaddr_tainted, + TlbEntry::DomainType::NoAccess, is_write, + ArmFault::AlignmentFault, isStage2, + tranMethod); + } - /* if (!sctlr.xp) - ap &= 0x3; -*/ - switch (ap) { - case 0: - DPRINTF(TLB, "Access permissions 0, checking rs:%#x\n", (int)sctlr.rs); - if (!sctlr.xp) { - switch ((int)sctlr.rs) { - case 2: - abt = is_write; - break; - case 1: - abt = is_write || !is_priv; - break; - case 0: - case 3: - default: - abt = true; - break; - } - } else { - abt = true; + // Check for a trickbox generated address fault + if (fault == NoFault) { + fault = trickBoxCheck(req, mode, te->domain); } - break; - case 1: - abt = !is_priv; - break; - case 2: - abt = !is_priv && is_write; - break; - case 3: - abt = false; - break; - case 4: - panic("UNPRED premissions\n"); - case 5: - abt = !is_priv || is_write; - break; - case 6: - case 7: - abt = is_write; - break; - default: - panic("Unknown permissions\n"); - } - if ((is_fetch) && (abt || te->xn)) { - permsFaults++; - DPRINTF(TLB, "TLB Fault: Prefetch abort on permission check. AP:%d priv:%d" - " write:%d sNp:%d\n", ap, is_priv, is_write, te->sNp); - return new PrefetchAbort(vaddr, - (te->sNp ? ArmFault::Permission0 : - ArmFault::Permission1)); - } else if (abt) { - permsFaults++; - DPRINTF(TLB, "TLB Fault: Data abort on permission check. AP:%d priv:%d" - " write:%d sNp:%d\n", ap, is_priv, is_write, te->sNp); - return new DataAbort(vaddr, te->domain, is_write, - (te->sNp ? ArmFault::Permission0 : - ArmFault::Permission1)); } - req->setPaddr(te->pAddr(vaddr)); - // Check for a trickbox generated address fault - fault = trickBoxCheck(req, mode, te->domain, te->sNp); - if (fault) - return fault; + // Generate Illegal Inst Set State fault if IL bit is set in CPSR + if (fault == NoFault) { + CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); + if (aarch64 && is_fetch && cpsr.il == 1) { + return new IllegalInstSetStateFault(); + } + } - return NoFault; + return fault; } Fault -TLB::translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode) +TLB::translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode, + TLB::ArmTranslationType tranType) { + updateMiscReg(tc, tranType); + + if (directToStage2) { + assert(stage2Tlb); + return stage2Tlb->translateAtomic(req, tc, mode, tranType); + } + bool delay = false; Fault fault; if (FullSystem) - fault = translateFs(req, tc, mode, NULL, delay, false); + fault = translateFs(req, tc, mode, NULL, delay, false, tranType); else fault = translateSe(req, tc, mode, NULL, delay, false); assert(!delay); @@ -708,13 +1096,21 @@ TLB::translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode) } Fault -TLB::translateFunctional(RequestPtr req, ThreadContext *tc, Mode mode) +TLB::translateFunctional(RequestPtr req, ThreadContext *tc, Mode mode, + TLB::ArmTranslationType tranType) { + updateMiscReg(tc, tranType); + + if (directToStage2) { + assert(stage2Tlb); + return stage2Tlb->translateFunctional(req, tc, mode, tranType); + } + bool delay = false; Fault fault; if (FullSystem) - fault = translateFs(req, tc, mode, NULL, delay, false, true); - else + fault = translateFs(req, tc, mode, NULL, delay, false, tranType, true); + else fault = translateSe(req, tc, mode, NULL, delay, false); assert(!delay); return fault; @@ -722,21 +1118,45 @@ TLB::translateFunctional(RequestPtr req, ThreadContext *tc, Mode mode) Fault TLB::translateTiming(RequestPtr req, ThreadContext *tc, - Translation *translation, Mode mode) + Translation *translation, Mode mode, TLB::ArmTranslationType tranType) { + updateMiscReg(tc, tranType); + + if (directToStage2) { + assert(stage2Tlb); + return stage2Tlb->translateTiming(req, tc, translation, mode, tranType); + } + assert(translation); + + return translateComplete(req, tc, translation, mode, tranType, isStage2); +} + +Fault +TLB::translateComplete(RequestPtr req, ThreadContext *tc, + Translation *translation, Mode mode, TLB::ArmTranslationType tranType, + bool callFromS2) +{ bool delay = false; Fault fault; if (FullSystem) - fault = translateFs(req, tc, mode, translation, delay, true); + fault = translateFs(req, tc, mode, translation, delay, true, tranType); else fault = translateSe(req, tc, mode, translation, delay, true); DPRINTF(TLBVerbose, "Translation returning delay=%d fault=%d\n", delay, fault != NoFault); - if (!delay) - translation->finish(fault, req, tc, mode); - else - translation->markDelayed(); + // If we have a translation, and we're not in the middle of doing a stage + // 2 translation tell the translation that we've either finished or its + // going to take a while. By not doing this when we're in the middle of a + // stage 2 translation we prevent marking the translation as delayed twice, + // one when the translation starts and again when the stage 1 translation + // completes. + if (translation && (callFromS2 || !stage2Req || req->hasPaddr() || fault != NoFault)) { + if (!delay) + translation->finish(fault, req, tc, mode); + else + translation->markDelayed(); + } return fault; } @@ -746,7 +1166,229 @@ TLB::getMasterPort() return &tableWalker->getMasterPort("port"); } +DmaPort& +TLB::getWalkerPort() +{ + return tableWalker->getWalkerPort(); +} + +void +TLB::updateMiscReg(ThreadContext *tc, ArmTranslationType tranType) +{ + // check if the regs have changed, or the translation mode is different. + // NOTE: the tran type doesn't affect stage 2 TLB's as they only handle + // one type of translation anyway + if (miscRegValid && ((tranType == curTranType) || isStage2)) { + return; + } + + DPRINTF(TLBVerbose, "TLB variables changed!\n"); + CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); + // Dependencies: SCR/SCR_EL3, CPSR + isSecure = inSecureState(tc); + isSecure &= (tranType & HypMode) == 0; + isSecure &= (tranType & S1S2NsTran) == 0; + aarch64 = !cpsr.width; + if (aarch64) { // AArch64 + aarch64EL = (ExceptionLevel) (uint8_t) cpsr.el; + switch (aarch64EL) { + case EL0: + case EL1: + { + sctlr = tc->readMiscReg(MISCREG_SCTLR_EL1); + ttbcr = tc->readMiscReg(MISCREG_TCR_EL1); + uint64_t ttbr_asid = ttbcr.a1 ? + tc->readMiscReg(MISCREG_TTBR1_EL1) : + tc->readMiscReg(MISCREG_TTBR0_EL1); + asid = bits(ttbr_asid, + (haveLargeAsid64 && ttbcr.as) ? 63 : 55, 48); + } + break; + case EL2: + sctlr = tc->readMiscReg(MISCREG_SCTLR_EL2); + ttbcr = tc->readMiscReg(MISCREG_TCR_EL2); + asid = -1; + break; + case EL3: + sctlr = tc->readMiscReg(MISCREG_SCTLR_EL3); + ttbcr = tc->readMiscReg(MISCREG_TCR_EL3); + asid = -1; + break; + } + scr = tc->readMiscReg(MISCREG_SCR_EL3); + isPriv = aarch64EL != EL0; + // @todo: modify this behaviour to support Virtualization in + // AArch64 + vmid = 0; + isHyp = false; + directToStage2 = false; + stage2Req = false; + } else { // AArch32 + sctlr = tc->readMiscReg(flattenMiscRegNsBanked(MISCREG_SCTLR, tc, + !isSecure)); + ttbcr = tc->readMiscReg(flattenMiscRegNsBanked(MISCREG_TTBCR, tc, + !isSecure)); + scr = tc->readMiscReg(MISCREG_SCR); + isPriv = cpsr.mode != MODE_USER; + if (haveLPAE && ttbcr.eae) { + // Long-descriptor translation table format in use + uint64_t ttbr_asid = tc->readMiscReg( + flattenMiscRegNsBanked(ttbcr.a1 ? MISCREG_TTBR1 + : MISCREG_TTBR0, + tc, !isSecure)); + asid = bits(ttbr_asid, 55, 48); + } else { + // Short-descriptor translation table format in use + CONTEXTIDR context_id = tc->readMiscReg(flattenMiscRegNsBanked( + MISCREG_CONTEXTIDR, tc,!isSecure)); + asid = context_id.asid; + } + prrr = tc->readMiscReg(flattenMiscRegNsBanked(MISCREG_PRRR, tc, + !isSecure)); + nmrr = tc->readMiscReg(flattenMiscRegNsBanked(MISCREG_NMRR, tc, + !isSecure)); + dacr = tc->readMiscReg(flattenMiscRegNsBanked(MISCREG_DACR, tc, + !isSecure)); + hcr = tc->readMiscReg(MISCREG_HCR); + + if (haveVirtualization) { + vmid = bits(tc->readMiscReg(MISCREG_VTTBR), 55, 48); + isHyp = cpsr.mode == MODE_HYP; + isHyp |= tranType & HypMode; + isHyp &= (tranType & S1S2NsTran) == 0; + isHyp &= (tranType & S1CTran) == 0; + if (isHyp) { + sctlr = tc->readMiscReg(MISCREG_HSCTLR); + } + // Work out if we should skip the first stage of translation and go + // directly to stage 2. This value is cached so we don't have to + // compute it for every translation. + stage2Req = hcr.vm && !isStage2 && !isHyp && !isSecure && + !(tranType & S1CTran); + directToStage2 = stage2Req && !sctlr.m; + } else { + vmid = 0; + stage2Req = false; + isHyp = false; + directToStage2 = false; + } + } + miscRegValid = true; + curTranType = tranType; +} + +Fault +TLB::getTE(TlbEntry **te, RequestPtr req, ThreadContext *tc, Mode mode, + Translation *translation, bool timing, bool functional, + bool is_secure, TLB::ArmTranslationType tranType) +{ + bool is_fetch = (mode == Execute); + bool is_write = (mode == Write); + + Addr vaddr_tainted = req->getVaddr(); + Addr vaddr = 0; + ExceptionLevel target_el = aarch64 ? aarch64EL : EL1; + if (aarch64) { + vaddr = purifyTaggedAddr(vaddr_tainted, tc, target_el); + } else { + vaddr = vaddr_tainted; + } + *te = lookup(vaddr, asid, vmid, isHyp, is_secure, false, false, target_el); + if (*te == NULL) { + if (req->isPrefetch()) { + // if the request is a prefetch don't attempt to fill the TLB or go + // any further with the memory access (here we can safely use the + // fault status for the short desc. format in all cases) + prefetchFaults++; + return new PrefetchAbort(vaddr_tainted, ArmFault::PrefetchTLBMiss, isStage2); + } + + if (is_fetch) + instMisses++; + else if (is_write) + writeMisses++; + else + readMisses++; + + // start translation table walk, pass variables rather than + // re-retreaving in table walker for speed + DPRINTF(TLB, "TLB Miss: Starting hardware table walker for %#x(%d:%d)\n", + vaddr_tainted, asid, vmid); + Fault fault; + fault = tableWalker->walk(req, tc, asid, vmid, isHyp, mode, + translation, timing, functional, is_secure, + tranType); + // for timing mode, return and wait for table walk, + if (timing || fault != NoFault) { + return fault; + } + + *te = lookup(vaddr, asid, vmid, isHyp, is_secure, false, false, target_el); + if (!*te) + printTlb(); + assert(*te); + } else { + if (is_fetch) + instHits++; + else if (is_write) + writeHits++; + else + readHits++; + } + return NoFault; +} +Fault +TLB::getResultTe(TlbEntry **te, RequestPtr req, ThreadContext *tc, Mode mode, + Translation *translation, bool timing, bool functional, + TlbEntry *mergeTe) +{ + Fault fault; + TlbEntry *s1Te = NULL; + + Addr vaddr_tainted = req->getVaddr(); + + // Get the stage 1 table entry + fault = getTE(&s1Te, req, tc, mode, translation, timing, functional, + isSecure, curTranType); + // only proceed if we have a valid table entry + if ((s1Te != NULL) && (fault == NoFault)) { + // Check stage 1 permissions before checking stage 2 + if (aarch64) + fault = checkPermissions64(s1Te, req, mode, tc); + else + fault = checkPermissions(s1Te, req, mode); + if (stage2Req & (fault == NoFault)) { + Stage2LookUp *s2Lookup = new Stage2LookUp(this, stage2Tlb, *s1Te, + req, translation, mode, timing, functional, curTranType); + fault = s2Lookup->getTe(tc, mergeTe); + if (s2Lookup->isComplete()) { + *te = mergeTe; + // We've finished with the lookup so delete it + delete s2Lookup; + } else { + // The lookup hasn't completed, so we can't delete it now. We + // get round this by asking the object to self delete when the + // translation is complete. + s2Lookup->setSelfDelete(); + } + } else { + // This case deals with an S1 hit (or bypass), followed by + // an S2 hit-but-perms issue + if (isStage2) { + DPRINTF(TLBVerbose, "s2TLB: reqVa %#x, reqPa %#x, fault %p\n", + vaddr_tainted, req->hasPaddr() ? req->getPaddr() : ~0, fault); + if (fault != NoFault) { + ArmFault *armFault = reinterpret_cast<ArmFault *>(fault.get()); + armFault->annotate(ArmFault::S1PTW, false); + armFault->annotate(ArmFault::OVA, vaddr_tainted); + } + } + *te = s1Te; + } + } + return fault; +} ArmISA::TLB * ArmTLBParams::create() diff --git a/src/arch/arm/tlb.hh b/src/arch/arm/tlb.hh index a66e28b06..ac8c672bf 100644 --- a/src/arch/arm/tlb.hh +++ b/src/arch/arm/tlb.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2012 ARM Limited + * Copyright (c) 2010-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -43,13 +43,13 @@ #ifndef __ARCH_ARM_TLB_HH__ #define __ARCH_ARM_TLB_HH__ -#include <map> #include "arch/arm/isa_traits.hh" #include "arch/arm/pagetable.hh" #include "arch/arm/utility.hh" #include "arch/arm/vtophys.hh" #include "base/statistics.hh" +#include "dev/dma_device.hh" #include "mem/request.hh" #include "params/ArmTLB.hh" #include "sim/fault_fwd.hh" @@ -60,36 +60,51 @@ class ThreadContext; namespace ArmISA { class TableWalker; +class Stage2LookUp; +class Stage2MMU; class TLB : public BaseTLB { public: enum ArmFlags { - AlignmentMask = 0x1f, + AlignmentMask = 0x7, AlignByte = 0x0, AlignHalfWord = 0x1, - AlignWord = 0x3, - AlignDoubleWord = 0x7, - AlignQuadWord = 0xf, - AlignOctWord = 0x1f, + AlignWord = 0x2, + AlignDoubleWord = 0x3, + AlignQuadWord = 0x4, + AlignOctWord = 0x5, - AllowUnaligned = 0x20, + AllowUnaligned = 0x8, // Priv code operating as if it wasn't - UserMode = 0x40, + UserMode = 0x10, // Because zero otherwise looks like a valid setting and may be used // accidentally, this bit must be non-zero to show it was used on // purpose. - MustBeOne = 0x80 + MustBeOne = 0x40 }; - protected: - - TlbEntry *table; // the Page Table - int size; // TLB Size - uint32_t _attr; // Memory attributes for last accessed TLB entry + enum ArmTranslationType { + NormalTran = 0, + S1CTran = 0x1, + HypMode = 0x2, + // Secure code operating as if it wasn't (required by some Address + // Translate operations) + S1S2NsTran = 0x4 + }; + protected: + TlbEntry* table; // the Page Table + int size; // TLB Size + bool isStage2; // Indicates this TLB is part of the second stage MMU + bool stage2Req; // Indicates whether a stage 2 lookup is also required + uint64_t _attr; // Memory attributes for last accessed TLB entry + bool directToStage2; // Indicates whether all translation requests should + // be routed directly to the stage 2 TLB TableWalker *tableWalker; + TLB *stage2Tlb; + Stage2MMU *stage2Mmu; // Access Stats mutable Stats::Scalar instHits; @@ -121,51 +136,101 @@ class TLB : public BaseTLB bool bootUncacheability; public: - typedef ArmTLBParams Params; - TLB(const Params *p); + TLB(const ArmTLBParams *p); + TLB(const Params *p, int _size, TableWalker *_walker); /** Lookup an entry in the TLB * @param vpn virtual address * @param asn context id/address space id to use + * @param vmid The virtual machine ID used for stage 2 translation + * @param secure if the lookup is secure + * @param hyp if the lookup is done from hyp mode * @param functional if the lookup should modify state - * @return pointer to TLB entrry if it exists + * @param ignore_asn if on lookup asn should be ignored + * @return pointer to TLB entry if it exists */ - TlbEntry *lookup(Addr vpn, uint8_t asn, bool functional = false); + TlbEntry *lookup(Addr vpn, uint16_t asn, uint8_t vmid, bool hyp, + bool secure, bool functional, + bool ignore_asn, uint8_t target_el); virtual ~TLB(); + + /// setup all the back pointers + virtual void init(); + + void setMMU(Stage2MMU *m); + int getsize() const { return size; } void insert(Addr vaddr, TlbEntry &pte); - /** Reset the entire TLB */ - void flushAll(); + Fault getTE(TlbEntry **te, RequestPtr req, ThreadContext *tc, Mode mode, + Translation *translation, bool timing, bool functional, + bool is_secure, ArmTranslationType tranType); + + Fault getResultTe(TlbEntry **te, RequestPtr req, ThreadContext *tc, + Mode mode, Translation *translation, bool timing, + bool functional, TlbEntry *mergeTe); + + Fault checkPermissions(TlbEntry *te, RequestPtr req, Mode mode); + Fault checkPermissions64(TlbEntry *te, RequestPtr req, Mode mode, + ThreadContext *tc); + + + /** Reset the entire TLB + * @param secure_lookup if the operation affects the secure world + */ + void flushAllSecurity(bool secure_lookup, uint8_t target_el, + bool ignore_el = false); + + /** Remove all entries in the non secure world, depending on whether they + * were allocated in hyp mode or not + * @param hyp if the opperation affects hyp mode + */ + void flushAllNs(bool hyp, uint8_t target_el, bool ignore_el = false); + + + /** Reset the entire TLB. Used for CPU switching to prevent stale + * translations after multiple switches + */ + void flushAll() + { + flushAllSecurity(false, 0, true); + flushAllSecurity(true, 0, true); + } /** Remove any entries that match both a va and asn * @param mva virtual address to flush * @param asn contextid/asn to flush on match + * @param secure_lookup if the operation affects the secure world */ - void flushMvaAsid(Addr mva, uint64_t asn); + void flushMvaAsid(Addr mva, uint64_t asn, bool secure_lookup, + uint8_t target_el); /** Remove any entries that match the asn * @param asn contextid/asn to flush on match + * @param secure_lookup if the operation affects the secure world */ - void flushAsid(uint64_t asn); + void flushAsid(uint64_t asn, bool secure_lookup, uint8_t target_el); /** Remove all entries that match the va regardless of asn * @param mva address to flush from cache + * @param secure_lookup if the operation affects the secure world + * @param hyp if the operation affects hyp mode */ - void flushMva(Addr mva); + void flushMva(Addr mva, bool secure_lookup, bool hyp, uint8_t target_el); - Fault trickBoxCheck(RequestPtr req, Mode mode, uint8_t domain, bool sNp); - Fault walkTrickBoxCheck(Addr pa, Addr va, Addr sz, bool is_exec, - bool is_write, uint8_t domain, bool sNp); + Fault trickBoxCheck(RequestPtr req, Mode mode, TlbEntry::DomainType domain); + Fault walkTrickBoxCheck(Addr pa, bool is_secure, Addr va, Addr sz, bool is_exec, + bool is_write, TlbEntry::DomainType domain, LookupLevel lookup_level); - void printTlb(); + void printTlb() const; void allCpusCaching() { bootUncacheability = true; } void demapPage(Addr vaddr, uint64_t asn) { - flushMvaAsid(vaddr, asn); + // needed for x86 only + panic("demapPage() is not implemented.\n"); } static bool validVirtualAddress(Addr vaddr); @@ -184,16 +249,18 @@ class TLB : public BaseTLB * Do a functional lookup on the TLB (for checker cpu) that * behaves like a normal lookup without modifying any page table state. */ - Fault translateFunctional(RequestPtr req, ThreadContext *tc, Mode mode); + Fault translateFunctional(RequestPtr req, ThreadContext *tc, Mode mode, + ArmTranslationType tranType = NormalTran); /** Accessor functions for memory attributes for last accessed TLB entry */ void - setAttr(uint32_t attr) + setAttr(uint64_t attr) { _attr = attr; } - uint32_t + + uint64_t getAttr() const { return _attr; @@ -201,12 +268,17 @@ class TLB : public BaseTLB Fault translateFs(RequestPtr req, ThreadContext *tc, Mode mode, Translation *translation, bool &delay, - bool timing, bool functional = false); + bool timing, ArmTranslationType tranType, bool functional = false); Fault translateSe(RequestPtr req, ThreadContext *tc, Mode mode, Translation *translation, bool &delay, bool timing); - Fault translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode); + Fault translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode, + ArmTranslationType tranType = NormalTran); Fault translateTiming(RequestPtr req, ThreadContext *tc, - Translation *translation, Mode mode); + Translation *translation, Mode mode, + ArmTranslationType tranType = NormalTran); + Fault translateComplete(RequestPtr req, ThreadContext *tc, + Translation *translation, Mode mode, ArmTranslationType tranType, + bool callFromS2); Fault finalizePhysical(RequestPtr req, ThreadContext *tc, Mode mode) const; void drainResume(); @@ -229,29 +301,45 @@ class TLB : public BaseTLB */ virtual BaseMasterPort* getMasterPort(); + /** + * Allow the MMU (overseeing both stage 1 and stage 2 TLBs) to + * access the table walker port of this TLB so that it can + * orchestrate staged translations. + * + * @return The table walker DMA port + */ + DmaPort& getWalkerPort(); + // Caching misc register values here. // Writing to misc registers needs to invalidate them. // translateFunctional/translateSe/translateFs checks if they are // invalid and call updateMiscReg if necessary. protected: + bool aarch64; + ExceptionLevel aarch64EL; SCTLR sctlr; + SCR scr; bool isPriv; - CONTEXTIDR contextId; + bool isSecure; + bool isHyp; + TTBCR ttbcr; + uint16_t asid; + uint8_t vmid; PRRR prrr; NMRR nmrr; + HCR hcr; uint32_t dacr; bool miscRegValid; - void updateMiscReg(ThreadContext *tc) - { - sctlr = tc->readMiscReg(MISCREG_SCTLR); - CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); - isPriv = cpsr.mode != MODE_USER; - contextId = tc->readMiscReg(MISCREG_CONTEXTIDR); - prrr = tc->readMiscReg(MISCREG_PRRR); - nmrr = tc->readMiscReg(MISCREG_NMRR); - dacr = tc->readMiscReg(MISCREG_DACR); - miscRegValid = true; - } + ArmTranslationType curTranType; + + // Cached copies of system-level properties + bool haveLPAE; + bool haveVirtualization; + bool haveLargeAsid64; + + void updateMiscReg(ThreadContext *tc, + ArmTranslationType tranType = NormalTran); + public: const Params * params() const @@ -259,6 +347,19 @@ public: return dynamic_cast<const Params *>(_params); } inline void invalidateMiscReg() { miscRegValid = false; } + +private: + /** Remove any entries that match both a va and asn + * @param mva virtual address to flush + * @param asn contextid/asn to flush on match + * @param secure_lookup if the operation affects the secure world + * @param hyp if the operation affects hyp mode + * @param ignore_asn if the flush should ignore the asn + */ + void _flushMva(Addr mva, uint64_t asn, bool secure_lookup, + bool hyp, bool ignore_asn, uint8_t target_el); + + bool checkELMatch(uint8_t target_el, uint8_t tentry_el, bool ignore_el); }; } // namespace ArmISA diff --git a/src/arch/arm/types.hh b/src/arch/arm/types.hh index cd0b74b2d..7b736492b 100644 --- a/src/arch/arm/types.hh +++ b/src/arch/arm/types.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010, 2012-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -82,6 +82,7 @@ namespace ArmISA // Bitfields to select mode. Bitfield<36> thumb; Bitfield<35> bigThumb; + Bitfield<34> aarch64; // Made up bitfields that make life easier. Bitfield<33> sevenAndFour; @@ -143,9 +144,9 @@ namespace ArmISA Bitfield<3, 0> immedLo3_0; Bitfield<15, 0> regList; - + Bitfield<23, 0> offset; - + Bitfield<23, 0> immed23_0; Bitfield<11, 8> cpNum; @@ -213,7 +214,8 @@ namespace ArmISA enum FlagBits { ThumbBit = (1 << 0), - JazelleBit = (1 << 1) + JazelleBit = (1 << 1), + AArch64Bit = (1 << 2) }; uint8_t flags; uint8_t nextFlags; @@ -304,6 +306,37 @@ namespace ArmISA nextFlags &= ~JazelleBit; } + bool + aarch64() const + { + return flags & AArch64Bit; + } + + void + aarch64(bool val) + { + if (val) + flags |= AArch64Bit; + else + flags &= ~AArch64Bit; + } + + bool + nextAArch64() const + { + return nextFlags & AArch64Bit; + } + + void + nextAArch64(bool val) + { + if (val) + nextFlags |= AArch64Bit; + else + nextFlags &= ~AArch64Bit; + } + + uint8_t itstate() const { @@ -374,9 +407,15 @@ namespace ArmISA } void - instNPC(uint32_t val) + instNPC(Addr val) { - npc(val &~ mask(nextThumb() ? 1 : 2)); + // @todo: review this when AArch32/64 interprocessing is + // supported + if (aarch64()) + npc(val); // AArch64 doesn't force PC alignment, a PC + // Alignment Fault can be raised instead + else + npc(val &~ mask(nextThumb() ? 1 : 2)); } Addr @@ -387,7 +426,7 @@ namespace ArmISA // Perform an interworking branch. void - instIWNPC(uint32_t val) + instIWNPC(Addr val) { bool thumbEE = (thumb() && jazelle()); @@ -417,7 +456,7 @@ namespace ArmISA // Perform an interworking branch in ARM mode, a regular branch // otherwise. void - instAIWNPC(uint32_t val) + instAIWNPC(Addr val) { if (!thumb() && !jazelle()) instIWNPC(val); @@ -470,6 +509,18 @@ namespace ArmISA ROR }; + // Extension types for ARM instructions + enum ArmExtendType { + UXTB = 0, + UXTH = 1, + UXTW = 2, + UXTX = 3, + SXTB = 4, + SXTH = 5, + SXTW = 6, + SXTX = 7 + }; + typedef uint64_t LargestRead; // Need to use 64 bits to make sure that read requests get handled properly @@ -508,28 +559,163 @@ namespace ArmISA RND_NEAREST }; + enum ExceptionLevel { + EL0 = 0, + EL1, + EL2, + EL3 + }; + enum OperatingMode { + MODE_EL0T = 0x0, + MODE_EL1T = 0x4, + MODE_EL1H = 0x5, + MODE_EL2T = 0x8, + MODE_EL2H = 0x9, + MODE_EL3T = 0xC, + MODE_EL3H = 0xD, MODE_USER = 16, MODE_FIQ = 17, MODE_IRQ = 18, MODE_SVC = 19, MODE_MON = 22, MODE_ABORT = 23, + MODE_HYP = 26, MODE_UNDEFINED = 27, MODE_SYSTEM = 31, MODE_MAXMODE = MODE_SYSTEM }; + enum ExceptionClass { + EC_INVALID = -1, + EC_UNKNOWN = 0x0, + EC_TRAPPED_WFI_WFE = 0x1, + EC_TRAPPED_CP15_MCR_MRC = 0x3, + EC_TRAPPED_CP15_MCRR_MRRC = 0x4, + EC_TRAPPED_CP14_MCR_MRC = 0x5, + EC_TRAPPED_CP14_LDC_STC = 0x6, + EC_TRAPPED_HCPTR = 0x7, + EC_TRAPPED_SIMD_FP = 0x7, // AArch64 alias + EC_TRAPPED_CP10_MRC_VMRS = 0x8, + EC_TRAPPED_BXJ = 0xA, + EC_TRAPPED_CP14_MCRR_MRRC = 0xC, + EC_ILLEGAL_INST = 0xE, + EC_SVC_TO_HYP = 0x11, + EC_SVC = 0x11, // AArch64 alias + EC_HVC = 0x12, + EC_SMC_TO_HYP = 0x13, + EC_SMC = 0x13, // AArch64 alias + EC_SVC_64 = 0x15, + EC_HVC_64 = 0x16, + EC_SMC_64 = 0x17, + EC_TRAPPED_MSR_MRS_64 = 0x18, + EC_PREFETCH_ABORT_TO_HYP = 0x20, + EC_PREFETCH_ABORT_LOWER_EL = 0x20, // AArch64 alias + EC_PREFETCH_ABORT_FROM_HYP = 0x21, + EC_PREFETCH_ABORT_CURR_EL = 0x21, // AArch64 alias + EC_PC_ALIGNMENT = 0x22, + EC_DATA_ABORT_TO_HYP = 0x24, + EC_DATA_ABORT_LOWER_EL = 0x24, // AArch64 alias + EC_DATA_ABORT_FROM_HYP = 0x25, + EC_DATA_ABORT_CURR_EL = 0x25, // AArch64 alias + EC_STACK_PTR_ALIGNMENT = 0x26, + EC_FP_EXCEPTION = 0x28, + EC_FP_EXCEPTION_64 = 0x2C, + EC_SERROR = 0x2F + }; + + BitUnion8(OperatingMode64) + Bitfield<0> spX; + Bitfield<3, 2> el; + Bitfield<4> width; + EndBitUnion(OperatingMode64) + + static bool inline + opModeIs64(OperatingMode mode) + { + return ((OperatingMode64)(uint8_t)mode).width == 0; + } + + static bool inline + opModeIsH(OperatingMode mode) + { + return (mode == MODE_EL1H || mode == MODE_EL2H || mode == MODE_EL3H); + } + + static bool inline + opModeIsT(OperatingMode mode) + { + return (mode == MODE_EL0T || mode == MODE_EL1T || mode == MODE_EL2T || + mode == MODE_EL3T); + } + + static ExceptionLevel inline + opModeToEL(OperatingMode mode) + { + bool aarch32 = ((mode >> 4) & 1) ? true : false; + if (aarch32) { + switch (mode) { + case MODE_USER: + return EL0; + case MODE_FIQ: + case MODE_IRQ: + case MODE_SVC: + case MODE_ABORT: + case MODE_UNDEFINED: + case MODE_SYSTEM: + return EL1; + case MODE_HYP: + return EL2; + case MODE_MON: + return EL3; + default: + panic("Invalid operating mode: %d", mode); + break; + } + } else { + // aarch64 + return (ExceptionLevel) ((mode >> 2) & 3); + } + } + static inline bool badMode(OperatingMode mode) { switch (mode) { + case MODE_EL0T: + case MODE_EL1T: + case MODE_EL1H: + case MODE_EL2T: + case MODE_EL2H: + case MODE_EL3T: + case MODE_EL3H: + case MODE_USER: + case MODE_FIQ: + case MODE_IRQ: + case MODE_SVC: + case MODE_MON: + case MODE_ABORT: + case MODE_HYP: + case MODE_UNDEFINED: + case MODE_SYSTEM: + return false; + default: + return true; + } + } + + + static inline bool + badMode32(OperatingMode mode) + { + switch (mode) { case MODE_USER: case MODE_FIQ: case MODE_IRQ: case MODE_SVC: case MODE_MON: case MODE_ABORT: + case MODE_HYP: case MODE_UNDEFINED: case MODE_SYSTEM: return false; diff --git a/src/arch/arm/utility.cc b/src/arch/arm/utility.cc index cddc2c5c4..3d7d9c4fc 100644 --- a/src/arch/arm/utility.cc +++ b/src/arch/arm/utility.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2012 ARM Limited + * Copyright (c) 2009-2013 ARM Limited * All rights reserved. * * The license below extends only to copyright in the software and shall @@ -40,6 +40,7 @@ #include "arch/arm/faults.hh" #include "arch/arm/isa_traits.hh" +#include "arch/arm/system.hh" #include "arch/arm/tlb.hh" #include "arch/arm/utility.hh" #include "arch/arm/vtophys.hh" @@ -70,51 +71,68 @@ getArgument(ThreadContext *tc, int &number, uint16_t size, bool fp) M5_DUMMY_RETURN } - if (size == (uint16_t)(-1)) - size = ArmISA::MachineBytes; if (fp) panic("getArgument(): Floating point arguments not implemented\n"); - if (number < NumArgumentRegs) { - // If the argument is 64 bits, it must be in an even regiser - // number. Increment the number here if it isn't even. - if (size == sizeof(uint64_t)) { - if ((number % 2) != 0) - number++; - // Read the two halves of the data. Number is inc here to - // get the second half of the 64 bit reg. - uint64_t tmp; - tmp = tc->readIntReg(number++); - tmp |= tc->readIntReg(number) << 32; - return tmp; + if (inAArch64(tc)) { + if (size == (uint16_t)(-1)) + size = sizeof(uint64_t); + + if (number < 8 /*NumArgumentRegs64*/) { + return tc->readIntReg(number); } else { - return tc->readIntReg(number); + panic("getArgument(): No support reading stack args for AArch64\n"); } } else { - Addr sp = tc->readIntReg(StackPointerReg); - FSTranslatingPortProxy &vp = tc->getVirtProxy(); - uint64_t arg; - if (size == sizeof(uint64_t)) { - // If the argument is even it must be aligned - if ((number % 2) != 0) - number++; - arg = vp.read<uint64_t>(sp + - (number-NumArgumentRegs) * sizeof(uint32_t)); - // since two 32 bit args == 1 64 bit arg, increment number - number++; + if (size == (uint16_t)(-1)) + size = ArmISA::MachineBytes; + + if (number < NumArgumentRegs) { + // If the argument is 64 bits, it must be in an even regiser + // number. Increment the number here if it isn't even. + if (size == sizeof(uint64_t)) { + if ((number % 2) != 0) + number++; + // Read the two halves of the data. Number is inc here to + // get the second half of the 64 bit reg. + uint64_t tmp; + tmp = tc->readIntReg(number++); + tmp |= tc->readIntReg(number) << 32; + return tmp; + } else { + return tc->readIntReg(number); + } } else { - arg = vp.read<uint32_t>(sp + - (number-NumArgumentRegs) * sizeof(uint32_t)); + Addr sp = tc->readIntReg(StackPointerReg); + FSTranslatingPortProxy &vp = tc->getVirtProxy(); + uint64_t arg; + if (size == sizeof(uint64_t)) { + // If the argument is even it must be aligned + if ((number % 2) != 0) + number++; + arg = vp.read<uint64_t>(sp + + (number-NumArgumentRegs) * sizeof(uint32_t)); + // since two 32 bit args == 1 64 bit arg, increment number + number++; + } else { + arg = vp.read<uint32_t>(sp + + (number-NumArgumentRegs) * sizeof(uint32_t)); + } + return arg; } - return arg; } + panic("getArgument() should always return\n"); } void skipFunction(ThreadContext *tc) { PCState newPC = tc->pcState(); - newPC.set(tc->readIntReg(ReturnAddressReg) & ~ULL(1)); + if (inAArch64(tc)) { + newPC.set(tc->readIntReg(INTREG_X30)); + } else { + newPC.set(tc->readIntReg(ReturnAddressReg) & ~ULL(1)); + } CheckerCPU *checker = tc->getCheckerCpuPtr(); if (checker) { @@ -151,6 +169,128 @@ copyRegs(ThreadContext *src, ThreadContext *dest) dest->getDTBPtr()->invalidateMiscReg(); } +bool +inSecureState(ThreadContext *tc) +{ + SCR scr = inAArch64(tc) ? tc->readMiscReg(MISCREG_SCR_EL3) : + tc->readMiscReg(MISCREG_SCR); + return ArmSystem::haveSecurity(tc) && inSecureState( + scr, tc->readMiscReg(MISCREG_CPSR)); +} + +bool +inAArch64(ThreadContext *tc) +{ + CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); + return opModeIs64((OperatingMode) (uint8_t) cpsr.mode); +} + +bool +longDescFormatInUse(ThreadContext *tc) +{ + TTBCR ttbcr = tc->readMiscReg(MISCREG_TTBCR); + return ArmSystem::haveLPAE(tc) && ttbcr.eae; +} + +uint32_t +getMPIDR(ArmSystem *arm_sys, ThreadContext *tc) +{ + if (arm_sys->multiProc) { + return 0x80000000 | // multiprocessor extensions available + tc->cpuId(); + } else { + return 0x80000000 | // multiprocessor extensions available + 0x40000000 | // in up system + tc->cpuId(); + } +} + +bool +ELIs64(ThreadContext *tc, ExceptionLevel el) +{ + if (ArmSystem::highestEL(tc) == el) + // Register width is hard-wired + return ArmSystem::highestELIs64(tc); + + switch (el) { + case EL0: + return opModeIs64(currOpMode(tc)); + case EL1: + { + // @todo: uncomment this to enable Virtualization + // if (ArmSystem::haveVirtualization(tc)) { + // HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2); + // return hcr.rw; + // } + assert(ArmSystem::haveSecurity(tc)); + SCR scr = tc->readMiscReg(MISCREG_SCR_EL3); + return scr.rw; + } + case EL2: + { + assert(ArmSystem::haveSecurity(tc)); + SCR scr = tc->readMiscReg(MISCREG_SCR_EL3); + return scr.rw; + } + default: + panic("Invalid exception level"); + break; + } +} + +bool +isBigEndian64(ThreadContext *tc) +{ + switch (opModeToEL(currOpMode(tc))) { + case EL3: + return ((SCTLR) tc->readMiscReg(MISCREG_SCTLR_EL3)).ee; + case EL2: + return ((SCTLR) tc->readMiscReg(MISCREG_SCTLR_EL2)).ee; + case EL1: + return ((SCTLR) tc->readMiscReg(MISCREG_SCTLR_EL1)).ee; + case EL0: + return ((SCTLR) tc->readMiscReg(MISCREG_SCTLR_EL1)).e0e; + default: + panic("Invalid exception level"); + break; + } +} + +Addr +purifyTaggedAddr(Addr addr, ThreadContext *tc, ExceptionLevel el) +{ + TTBCR tcr; + + switch (el) { + case EL0: + case EL1: + tcr = tc->readMiscReg(MISCREG_TCR_EL1); + if (bits(addr, 55, 48) == 0xFF && tcr.tbi1) + return addr | mask(63, 55); + else if (!bits(addr, 55, 48) && tcr.tbi0) + return bits(addr,55, 0); + break; + // @todo: uncomment this to enable Virtualization + // case EL2: + // assert(ArmSystem::haveVirtualization()); + // tcr = tc->readMiscReg(MISCREG_TCR_EL2); + // if (tcr.tbi) + // return addr & mask(56); + // break; + case EL3: + assert(ArmSystem::haveSecurity(tc)); + tcr = tc->readMiscReg(MISCREG_TCR_EL3); + if (tcr.tbi) + return addr & mask(56); + break; + default: + panic("Invalid exception level"); + break; + } + + return addr; // Nothing to do if this is not a tagged address +} + Addr truncPage(Addr addr) { @@ -163,4 +303,667 @@ roundPage(Addr addr) return (addr + PageBytes - 1) & ~(PageBytes - 1); } +bool +mcrMrc15TrapToHyp(const MiscRegIndex miscReg, HCR hcr, CPSR cpsr, SCR scr, + HDCR hdcr, HSTR hstr, HCPTR hcptr, uint32_t iss) +{ + bool isRead; + uint32_t crm; + IntRegIndex rt; + uint32_t crn; + uint32_t opc1; + uint32_t opc2; + bool trapToHype = false; + + + if (!inSecureState(scr, cpsr) && (cpsr.mode != MODE_HYP)) { + mcrMrcIssExtract(iss, isRead, crm, rt, crn, opc1, opc2); + trapToHype = ((uint32_t) hstr) & (1 << crn); + trapToHype |= hdcr.tpm && (crn == 9) && (crm >= 12); + trapToHype |= hcr.tidcp && ( + ((crn == 9) && ((crm <= 2) || ((crm >= 5) && (crm <= 8)))) || + ((crn == 10) && ((crm <= 1) || (crm == 4) || (crm == 8))) || + ((crn == 11) && ((crm <= 8) || (crm == 15))) ); + + if (!trapToHype) { + switch (unflattenMiscReg(miscReg)) { + case MISCREG_CPACR: + trapToHype = hcptr.tcpac; + break; + case MISCREG_REVIDR: + case MISCREG_TCMTR: + case MISCREG_TLBTR: + case MISCREG_AIDR: + trapToHype = hcr.tid1; + break; + case MISCREG_CTR: + case MISCREG_CCSIDR: + case MISCREG_CLIDR: + case MISCREG_CSSELR: + trapToHype = hcr.tid2; + break; + case MISCREG_ID_PFR0: + case MISCREG_ID_PFR1: + case MISCREG_ID_DFR0: + case MISCREG_ID_AFR0: + case MISCREG_ID_MMFR0: + case MISCREG_ID_MMFR1: + case MISCREG_ID_MMFR2: + case MISCREG_ID_MMFR3: + case MISCREG_ID_ISAR0: + case MISCREG_ID_ISAR1: + case MISCREG_ID_ISAR2: + case MISCREG_ID_ISAR3: + case MISCREG_ID_ISAR4: + case MISCREG_ID_ISAR5: + trapToHype = hcr.tid3; + break; + case MISCREG_DCISW: + case MISCREG_DCCSW: + case MISCREG_DCCISW: + trapToHype = hcr.tsw; + break; + case MISCREG_DCIMVAC: + case MISCREG_DCCIMVAC: + case MISCREG_DCCMVAC: + trapToHype = hcr.tpc; + break; + case MISCREG_ICIMVAU: + case MISCREG_ICIALLU: + case MISCREG_ICIALLUIS: + case MISCREG_DCCMVAU: + trapToHype = hcr.tpu; + break; + case MISCREG_TLBIALLIS: + case MISCREG_TLBIMVAIS: + case MISCREG_TLBIASIDIS: + case MISCREG_TLBIMVAAIS: + case MISCREG_DTLBIALL: + case MISCREG_ITLBIALL: + case MISCREG_DTLBIMVA: + case MISCREG_ITLBIMVA: + case MISCREG_DTLBIASID: + case MISCREG_ITLBIASID: + case MISCREG_TLBIMVAA: + case MISCREG_TLBIALL: + case MISCREG_TLBIMVA: + case MISCREG_TLBIASID: + trapToHype = hcr.ttlb; + break; + case MISCREG_ACTLR: + trapToHype = hcr.tac; + break; + case MISCREG_SCTLR: + case MISCREG_TTBR0: + case MISCREG_TTBR1: + case MISCREG_TTBCR: + case MISCREG_DACR: + case MISCREG_DFSR: + case MISCREG_IFSR: + case MISCREG_DFAR: + case MISCREG_IFAR: + case MISCREG_ADFSR: + case MISCREG_AIFSR: + case MISCREG_PRRR: + case MISCREG_NMRR: + case MISCREG_MAIR0: + case MISCREG_MAIR1: + case MISCREG_CONTEXTIDR: + trapToHype = hcr.tvm & !isRead; + break; + case MISCREG_PMCR: + trapToHype = hdcr.tpmcr; + break; + // No default action needed + default: + break; + } + } + } + return trapToHype; +} + + +bool +mcrMrc14TrapToHyp(const MiscRegIndex miscReg, HCR hcr, CPSR cpsr, SCR scr, + HDCR hdcr, HSTR hstr, HCPTR hcptr, uint32_t iss) +{ + bool isRead; + uint32_t crm; + IntRegIndex rt; + uint32_t crn; + uint32_t opc1; + uint32_t opc2; + bool trapToHype = false; + + if (!inSecureState(scr, cpsr) && (cpsr.mode != MODE_HYP)) { + mcrMrcIssExtract(iss, isRead, crm, rt, crn, opc1, opc2); + inform("trap check M:%x N:%x 1:%x 2:%x hdcr %x, hcptr %x, hstr %x\n", + crm, crn, opc1, opc2, hdcr, hcptr, hstr); + trapToHype = hdcr.tda && (opc1 == 0); + trapToHype |= hcptr.tta && (opc1 == 1); + if (!trapToHype) { + switch (unflattenMiscReg(miscReg)) { + case MISCREG_DBGOSLSR: + case MISCREG_DBGOSLAR: + case MISCREG_DBGOSDLR: + case MISCREG_DBGPRCR: + trapToHype = hdcr.tdosa; + break; + case MISCREG_DBGDRAR: + case MISCREG_DBGDSAR: + trapToHype = hdcr.tdra; + break; + case MISCREG_JIDR: + trapToHype = hcr.tid0; + break; + case MISCREG_JOSCR: + case MISCREG_JMCR: + trapToHype = hstr.tjdbx; + break; + case MISCREG_TEECR: + case MISCREG_TEEHBR: + trapToHype = hstr.ttee; + break; + // No default action needed + default: + break; + } + } + } + return trapToHype; +} + +bool +mcrrMrrc15TrapToHyp(const MiscRegIndex miscReg, CPSR cpsr, SCR scr, HSTR hstr, + HCR hcr, uint32_t iss) +{ + uint32_t crm; + IntRegIndex rt; + uint32_t crn; + uint32_t opc1; + uint32_t opc2; + bool isRead; + bool trapToHype = false; + + if (!inSecureState(scr, cpsr) && (cpsr.mode != MODE_HYP)) { + // This is technically the wrong function, but we can re-use it for + // the moment because we only need one field, which overlaps with the + // mcrmrc layout + mcrMrcIssExtract(iss, isRead, crm, rt, crn, opc1, opc2); + trapToHype = ((uint32_t) hstr) & (1 << crm); + + if (!trapToHype) { + switch (unflattenMiscReg(miscReg)) { + case MISCREG_SCTLR: + case MISCREG_TTBR0: + case MISCREG_TTBR1: + case MISCREG_TTBCR: + case MISCREG_DACR: + case MISCREG_DFSR: + case MISCREG_IFSR: + case MISCREG_DFAR: + case MISCREG_IFAR: + case MISCREG_ADFSR: + case MISCREG_AIFSR: + case MISCREG_PRRR: + case MISCREG_NMRR: + case MISCREG_MAIR0: + case MISCREG_MAIR1: + case MISCREG_CONTEXTIDR: + trapToHype = hcr.tvm & !isRead; + break; + // No default action needed + default: + break; + } + } + } + return trapToHype; +} + +bool +msrMrs64TrapToSup(const MiscRegIndex miscReg, ExceptionLevel el, + CPACR cpacr /* CPACR_EL1 */) +{ + bool trapToSup = false; + switch (miscReg) { + case MISCREG_FPCR: + case MISCREG_FPSR: + case MISCREG_FPEXC32_EL2: + if ((el == EL0 && cpacr.fpen != 0x3) || + (el == EL1 && !(cpacr.fpen & 0x1))) + trapToSup = true; + break; + default: + break; + } + return trapToSup; +} + +bool +msrMrs64TrapToHyp(const MiscRegIndex miscReg, bool isRead, + CPTR cptr /* CPTR_EL2 */, + HCR hcr /* HCR_EL2 */, + bool * isVfpNeon) +{ + bool trapToHyp = false; + *isVfpNeon = false; + + switch (miscReg) { + // FP/SIMD regs + case MISCREG_FPCR: + case MISCREG_FPSR: + case MISCREG_FPEXC32_EL2: + trapToHyp = cptr.tfp; + *isVfpNeon = true; + break; + // CPACR + case MISCREG_CPACR_EL1: + trapToHyp = cptr.tcpac; + break; + // Virtual memory control regs + case MISCREG_SCTLR_EL1: + case MISCREG_TTBR0_EL1: + case MISCREG_TTBR1_EL1: + case MISCREG_TCR_EL1: + case MISCREG_ESR_EL1: + case MISCREG_FAR_EL1: + case MISCREG_AFSR0_EL1: + case MISCREG_AFSR1_EL1: + case MISCREG_MAIR_EL1: + case MISCREG_AMAIR_EL1: + case MISCREG_CONTEXTIDR_EL1: + trapToHyp = (hcr.trvm && isRead) || (hcr.tvm && !isRead); + break; + // TLB maintenance instructions + case MISCREG_TLBI_VMALLE1: + case MISCREG_TLBI_VAE1_Xt: + case MISCREG_TLBI_ASIDE1_Xt: + case MISCREG_TLBI_VAAE1_Xt: + case MISCREG_TLBI_VALE1_Xt: + case MISCREG_TLBI_VAALE1_Xt: + case MISCREG_TLBI_VMALLE1IS: + case MISCREG_TLBI_VAE1IS_Xt: + case MISCREG_TLBI_ASIDE1IS_Xt: + case MISCREG_TLBI_VAAE1IS_Xt: + case MISCREG_TLBI_VALE1IS_Xt: + case MISCREG_TLBI_VAALE1IS_Xt: + trapToHyp = hcr.ttlb; + break; + // Cache maintenance instructions to the point of unification + case MISCREG_IC_IVAU_Xt: + case MISCREG_ICIALLU: + case MISCREG_ICIALLUIS: + case MISCREG_DC_CVAU_Xt: + trapToHyp = hcr.tpu; + break; + // Data/Unified cache maintenance instructions to the point of coherency + case MISCREG_DC_IVAC_Xt: + case MISCREG_DC_CIVAC_Xt: + case MISCREG_DC_CVAC_Xt: + trapToHyp = hcr.tpc; + break; + // Data/Unified cache maintenance instructions by set/way + case MISCREG_DC_ISW_Xt: + case MISCREG_DC_CSW_Xt: + case MISCREG_DC_CISW_Xt: + trapToHyp = hcr.tsw; + break; + // ACTLR + case MISCREG_ACTLR_EL1: + trapToHyp = hcr.tacr; + break; + + // @todo: Trap implementation-dependent functionality based on + // hcr.tidcp + + // ID regs, group 3 + case MISCREG_ID_PFR0_EL1: + case MISCREG_ID_PFR1_EL1: + case MISCREG_ID_DFR0_EL1: + case MISCREG_ID_AFR0_EL1: + case MISCREG_ID_MMFR0_EL1: + case MISCREG_ID_MMFR1_EL1: + case MISCREG_ID_MMFR2_EL1: + case MISCREG_ID_MMFR3_EL1: + case MISCREG_ID_ISAR0_EL1: + case MISCREG_ID_ISAR1_EL1: + case MISCREG_ID_ISAR2_EL1: + case MISCREG_ID_ISAR3_EL1: + case MISCREG_ID_ISAR4_EL1: + case MISCREG_ID_ISAR5_EL1: + case MISCREG_MVFR0_EL1: + case MISCREG_MVFR1_EL1: + case MISCREG_MVFR2_EL1: + case MISCREG_ID_AA64PFR0_EL1: + case MISCREG_ID_AA64PFR1_EL1: + case MISCREG_ID_AA64DFR0_EL1: + case MISCREG_ID_AA64DFR1_EL1: + case MISCREG_ID_AA64ISAR0_EL1: + case MISCREG_ID_AA64ISAR1_EL1: + case MISCREG_ID_AA64MMFR0_EL1: + case MISCREG_ID_AA64MMFR1_EL1: + case MISCREG_ID_AA64AFR0_EL1: + case MISCREG_ID_AA64AFR1_EL1: + assert(isRead); + trapToHyp = hcr.tid3; + break; + // ID regs, group 2 + case MISCREG_CTR_EL0: + case MISCREG_CCSIDR_EL1: + case MISCREG_CLIDR_EL1: + case MISCREG_CSSELR_EL1: + trapToHyp = hcr.tid2; + break; + // ID regs, group 1 + case MISCREG_AIDR_EL1: + case MISCREG_REVIDR_EL1: + assert(isRead); + trapToHyp = hcr.tid1; + break; + default: + break; + } + return trapToHyp; +} + +bool +msrMrs64TrapToMon(const MiscRegIndex miscReg, CPTR cptr /* CPTR_EL3 */, + ExceptionLevel el, bool * isVfpNeon) +{ + bool trapToMon = false; + *isVfpNeon = false; + + switch (miscReg) { + // FP/SIMD regs + case MISCREG_FPCR: + case MISCREG_FPSR: + case MISCREG_FPEXC32_EL2: + trapToMon = cptr.tfp; + *isVfpNeon = true; + break; + // CPACR, CPTR + case MISCREG_CPACR_EL1: + if (el == EL1) { + trapToMon = cptr.tcpac; + } + break; + case MISCREG_CPTR_EL2: + if (el == EL2) { + trapToMon = cptr.tcpac; + } + break; + default: + break; + } + return trapToMon; +} + +bool +decodeMrsMsrBankedReg(uint8_t sysM, bool r, bool &isIntReg, int ®Idx, + CPSR cpsr, SCR scr, NSACR nsacr, bool checkSecurity) +{ + OperatingMode mode; + bool ok = true; + + // R mostly indicates if its a int register or a misc reg, we override + // below if the few corner cases + isIntReg = !r; + // Loosely based on ARM ARM issue C section B9.3.10 + if (r) { + switch (sysM) + { + case 0xE: + regIdx = MISCREG_SPSR_FIQ; + mode = MODE_FIQ; + break; + case 0x10: + regIdx = MISCREG_SPSR_IRQ; + mode = MODE_IRQ; + break; + case 0x12: + regIdx = MISCREG_SPSR_SVC; + mode = MODE_SVC; + break; + case 0x14: + regIdx = MISCREG_SPSR_ABT; + mode = MODE_ABORT; + break; + case 0x16: + regIdx = MISCREG_SPSR_UND; + mode = MODE_UNDEFINED; + break; + case 0x1C: + regIdx = MISCREG_SPSR_MON; + mode = MODE_MON; + break; + case 0x1E: + regIdx = MISCREG_SPSR_HYP; + mode = MODE_HYP; + break; + default: + ok = false; + break; + } + } else { + int sysM4To3 = bits(sysM, 4, 3); + + if (sysM4To3 == 0) { + mode = MODE_USER; + regIdx = intRegInMode(mode, bits(sysM, 2, 0) + 8); + } else if (sysM4To3 == 1) { + mode = MODE_FIQ; + regIdx = intRegInMode(mode, bits(sysM, 2, 0) + 8); + } else if (sysM4To3 == 3) { + if (bits(sysM, 1) == 0) { + mode = MODE_MON; + regIdx = intRegInMode(mode, 14 - bits(sysM, 0)); + } else { + mode = MODE_HYP; + if (bits(sysM, 0) == 1) { + regIdx = intRegInMode(mode, 13); // R13 in HYP + } else { + isIntReg = false; + regIdx = MISCREG_ELR_HYP; + } + } + } else { // Other Banked registers + int sysM2 = bits(sysM, 2); + int sysM1 = bits(sysM, 1); + + mode = (OperatingMode) ( ((sysM2 || sysM1) << 0) | + (1 << 1) | + ((sysM2 && !sysM1) << 2) | + ((sysM2 && sysM1) << 3) | + (1 << 4) ); + regIdx = intRegInMode(mode, 14 - bits(sysM, 0)); + // Don't flatten the register here. This is going to go through + // setIntReg() which will do the flattening + ok &= mode != cpsr.mode; + } + } + + // Check that the requested register is accessable from the current mode + if (ok && checkSecurity && mode != cpsr.mode) { + switch (cpsr.mode) + { + case MODE_USER: + ok = false; + break; + case MODE_FIQ: + ok &= mode != MODE_HYP; + ok &= (mode != MODE_MON) || !scr.ns; + break; + case MODE_HYP: + ok &= mode != MODE_MON; + ok &= (mode != MODE_FIQ) || !nsacr.rfr; + break; + case MODE_IRQ: + case MODE_SVC: + case MODE_ABORT: + case MODE_UNDEFINED: + case MODE_SYSTEM: + ok &= mode != MODE_HYP; + ok &= (mode != MODE_MON) || !scr.ns; + ok &= (mode != MODE_FIQ) || !nsacr.rfr; + break; + // can access everything, no further checks required + case MODE_MON: + break; + default: + panic("unknown Mode 0x%x\n", cpsr.mode); + break; + } + } + return (ok); +} + +bool +vfpNeonEnabled(uint32_t &seq, HCPTR hcptr, NSACR nsacr, CPACR cpacr, CPSR cpsr, + uint32_t &iss, bool &trap, ThreadContext *tc, FPEXC fpexc, + bool isSIMD) +{ + iss = 0; + trap = false; + bool undefined = false; + bool haveSecurity = ArmSystem::haveSecurity(tc); + bool haveVirtualization = ArmSystem::haveVirtualization(tc); + bool isSecure = inSecureState(tc); + + // Non-secure view of CPACR and HCPTR determines behavior + // Copy register values + uint8_t cpacr_cp10 = cpacr.cp10; + bool cpacr_asedis = cpacr.asedis; + bool hcptr_cp10 = false; + bool hcptr_tase = false; + + bool cp10_enabled = cpacr.cp10 == 0x3 + || (cpacr.cp10 == 0x1 && inPrivilegedMode(cpsr)); + + bool cp11_enabled = cpacr.cp11 == 0x3 + || (cpacr.cp11 == 0x1 && inPrivilegedMode(cpsr)); + + if (cp11_enabled) { + undefined |= !(fpexc.en && cp10_enabled); + } else { + undefined |= !(fpexc.en && cp10_enabled && (cpacr.cp11 == cpacr.cp10)); + } + + if (haveVirtualization) { + hcptr_cp10 = hcptr.tcp10; + undefined |= hcptr.tcp10 != hcptr.tcp11; + hcptr_tase = hcptr.tase; + } + + if (haveSecurity) { + undefined |= nsacr.cp10 != nsacr.cp11; + if (!isSecure) { + // Modify register values to the Non-secure view + if (!nsacr.cp10) { + cpacr_cp10 = 0; + if (haveVirtualization) { + hcptr_cp10 = true; + } + } + if (nsacr.nsasedis) { + cpacr_asedis = true; + if (haveVirtualization) { + hcptr_tase = true; + } + } + } + } + + // Check Coprocessor Access Control Register for permission to use CP10/11. + if (!haveVirtualization || (cpsr.mode != MODE_HYP)) { + switch (cpacr_cp10) + { + case 0: + undefined = true; + break; + case 1: + undefined |= inUserMode(cpsr); + break; + } + + // Check if SIMD operations are disabled + if (isSIMD && cpacr_asedis) undefined = true; + } + + // If required, check FPEXC enabled bit. + undefined |= !fpexc.en; + + if (haveSecurity && haveVirtualization && !isSecure) { + if (hcptr_cp10 || (isSIMD && hcptr_tase)) { + iss = isSIMD ? (1 << 5) : 0xA; + trap = true; + } + } + + return (!undefined); +} + +bool +SPAlignmentCheckEnabled(ThreadContext* tc) +{ + switch (opModeToEL(currOpMode(tc))) { + case EL3: + return ((SCTLR) tc->readMiscReg(MISCREG_SCTLR_EL3)).sa; + case EL2: + return ((SCTLR) tc->readMiscReg(MISCREG_SCTLR_EL2)).sa; + case EL1: + return ((SCTLR) tc->readMiscReg(MISCREG_SCTLR_EL1)).sa; + case EL0: + return ((SCTLR) tc->readMiscReg(MISCREG_SCTLR_EL1)).sa0; + default: + panic("Invalid exception level"); + break; + } +} + +int +decodePhysAddrRange64(uint8_t pa_enc) +{ + switch (pa_enc) { + case 0x0: + return 32; + case 0x1: + return 36; + case 0x2: + return 40; + case 0x3: + return 42; + case 0x4: + return 44; + case 0x5: + case 0x6: + case 0x7: + return 48; + default: + panic("Invalid phys. address range encoding"); + } +} + +uint8_t +encodePhysAddrRange64(int pa_size) +{ + switch (pa_size) { + case 32: + return 0x0; + case 36: + return 0x1; + case 40: + return 0x2; + case 42: + return 0x3; + case 44: + return 0x4; + case 48: + return 0x5; + default: + panic("Invalid phys. address range"); + } +} + } // namespace ArmISA diff --git a/src/arch/arm/utility.hh b/src/arch/arm/utility.hh index e4fc658e0..1eea743bb 100644 --- a/src/arch/arm/utility.hh +++ b/src/arch/arm/utility.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010, 2012-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -54,6 +54,8 @@ #include "cpu/static_inst.hh" #include "cpu/thread_context.hh" +class ArmSystem; + namespace ArmISA { inline PCState @@ -118,7 +120,7 @@ void initCPU(ThreadContext *tc, int cpuId); static inline bool inUserMode(CPSR cpsr) { - return cpsr.mode == MODE_USER; + return cpsr.mode == MODE_USER || cpsr.mode == MODE_EL0T; } static inline bool @@ -139,30 +141,139 @@ inPrivilegedMode(ThreadContext *tc) return !inUserMode(tc); } -static inline bool -vfpEnabled(CPACR cpacr, CPSR cpsr) +bool inAArch64(ThreadContext *tc); + +static inline OperatingMode +currOpMode(ThreadContext *tc) +{ + CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); + return (OperatingMode) (uint8_t) cpsr.mode; +} + +static inline ExceptionLevel +currEL(ThreadContext *tc) { - return cpacr.cp10 == 0x3 || - (cpacr.cp10 == 0x1 && inPrivilegedMode(cpsr)); + CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); + return (ExceptionLevel) (uint8_t) cpsr.el; } +bool ELIs64(ThreadContext *tc, ExceptionLevel el); + +bool isBigEndian64(ThreadContext *tc); + +/** + * Removes the tag from tagged addresses if that mode is enabled. + * @param addr The address to be purified. + * @param tc The thread context. + * @param el The controlled exception level. + * @return The purified address. + */ +Addr purifyTaggedAddr(Addr addr, ThreadContext *tc, ExceptionLevel el); + static inline bool -vfpEnabled(CPACR cpacr, CPSR cpsr, FPEXC fpexc) +inSecureState(SCR scr, CPSR cpsr) +{ + switch ((OperatingMode) (uint8_t) cpsr.mode) { + case MODE_MON: + case MODE_EL3T: + case MODE_EL3H: + return true; + case MODE_HYP: + case MODE_EL2T: + case MODE_EL2H: + return false; + default: + return !scr.ns; + } +} + +bool longDescFormatInUse(ThreadContext *tc); + +bool inSecureState(ThreadContext *tc); + +uint32_t getMPIDR(ArmSystem *arm_sys, ThreadContext *tc); + +static inline uint32_t +mcrMrcIssBuild(bool isRead, uint32_t crm, IntRegIndex rt, uint32_t crn, + uint32_t opc1, uint32_t opc2) +{ + return (isRead << 0) | + (crm << 1) | + (rt << 5) | + (crn << 10) | + (opc1 << 14) | + (opc2 << 17); +} + +static inline void +mcrMrcIssExtract(uint32_t iss, bool &isRead, uint32_t &crm, IntRegIndex &rt, + uint32_t &crn, uint32_t &opc1, uint32_t &opc2) +{ + isRead = (iss >> 0) & 0x1; + crm = (iss >> 1) & 0xF; + rt = (IntRegIndex) ((iss >> 5) & 0xF); + crn = (iss >> 10) & 0xF; + opc1 = (iss >> 14) & 0x7; + opc2 = (iss >> 17) & 0x7; +} + +static inline uint32_t +mcrrMrrcIssBuild(bool isRead, uint32_t crm, IntRegIndex rt, IntRegIndex rt2, + uint32_t opc1) { - if ((cpacr.cp11 == 0x3) || - ((cpacr.cp11 == 0x1) && inPrivilegedMode(cpsr))) - return fpexc.en && vfpEnabled(cpacr, cpsr); - else - return fpexc.en && vfpEnabled(cpacr, cpsr) && - (cpacr.cp11 == cpacr.cp10); + return (isRead << 0) | + (crm << 1) | + (rt << 5) | + (rt2 << 10) | + (opc1 << 16); } +static inline uint32_t +msrMrs64IssBuild(bool isRead, uint32_t op0, uint32_t op1, uint32_t crn, + uint32_t crm, uint32_t op2, IntRegIndex rt) +{ + return isRead | + (crm << 1) | + (rt << 5) | + (crn << 10) | + (op1 << 14) | + (op2 << 17) | + (op0 << 20); +} + +bool +mcrMrc15TrapToHyp(const MiscRegIndex miscReg, HCR hcr, CPSR cpsr, SCR scr, + HDCR hdcr, HSTR hstr, HCPTR hcptr, uint32_t iss); +bool +mcrMrc14TrapToHyp(const MiscRegIndex miscReg, HCR hcr, CPSR cpsr, SCR scr, + HDCR hdcr, HSTR hstr, HCPTR hcptr, uint32_t iss); +bool +mcrrMrrc15TrapToHyp(const MiscRegIndex miscReg, CPSR cpsr, SCR scr, HSTR hstr, + HCR hcr, uint32_t iss); + +bool msrMrs64TrapToSup(const MiscRegIndex miscReg, ExceptionLevel el, + CPACR cpacr); +bool msrMrs64TrapToHyp(const MiscRegIndex miscReg, bool isRead, CPTR cptr, + HCR hcr, bool * isVfpNeon); +bool msrMrs64TrapToMon(const MiscRegIndex miscReg, CPTR cptr, + ExceptionLevel el, bool * isVfpNeon); + +bool +vfpNeonEnabled(uint32_t &seq, HCPTR hcptr, NSACR nsacr, CPACR cpacr, CPSR cpsr, + uint32_t &iss, bool &trap, ThreadContext *tc, + FPEXC fpexc = (1<<30), bool isSIMD = false); + static inline bool -neonEnabled(CPACR cpacr, CPSR cpsr, FPEXC fpexc) +vfpNeon64Enabled(CPACR cpacr, ExceptionLevel el) { - return !cpacr.asedis && vfpEnabled(cpacr, cpsr, fpexc); + if ((el == EL0 && cpacr.fpen != 0x3) || + (el == EL1 && !(cpacr.fpen & 0x1))) + return false; + return true; } +bool SPAlignmentCheckEnabled(ThreadContext* tc); + uint64_t getArgument(ThreadContext *tc, int &number, uint16_t size, bool fp); void skipFunction(ThreadContext *tc); @@ -182,6 +293,36 @@ getExecutingAsid(ThreadContext *tc) return tc->readMiscReg(MISCREG_CONTEXTIDR); } +// Decodes the register index to access based on the fields used in a MSR +// or MRS instruction +bool +decodeMrsMsrBankedReg(uint8_t sysM, bool r, bool &isIntReg, int ®Idx, + CPSR cpsr, SCR scr, NSACR nsacr, + bool checkSecurity = true); + +// This wrapper function is used to turn the register index into a source +// parameter for the instruction. See Operands.isa +static inline int +decodeMrsMsrBankedIntRegIndex(uint8_t sysM, bool r) +{ + int regIdx; + bool isIntReg; + bool validReg; + + validReg = decodeMrsMsrBankedReg(sysM, r, isIntReg, regIdx, 0, 0, 0, false); + return (validReg && isIntReg) ? regIdx : INTREG_DUMMY; +} + +/** + * Returns the n. of PA bits corresponding to the specified encoding. + */ +int decodePhysAddrRange64(uint8_t pa_enc); + +/** + * Returns the encoding corresponding to the specified n. of PA bits. + */ +uint8_t encodePhysAddrRange64(int pa_size); + } #endif diff --git a/src/arch/arm/vtophys.cc b/src/arch/arm/vtophys.cc index 7c26962cb..bed76acbd 100644 --- a/src/arch/arm/vtophys.cc +++ b/src/arch/arm/vtophys.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010, 2012-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -45,6 +45,7 @@ #include <string> +#include "arch/arm/faults.hh" #include "arch/arm/table_walker.hh" #include "arch/arm/tlb.hh" #include "arch/arm/vtophys.hh" @@ -65,66 +66,30 @@ ArmISA::vtophys(Addr vaddr) Addr ArmISA::vtophys(ThreadContext *tc, Addr addr) { - SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR); - if (!sctlr.m) { - // Translation is currently disabled PA == VA - return addr; - } - bool success; - Addr pa; + Fault fault; + // Set up a functional memory Request to pass to the TLB + // to get it to translate the vaddr to a paddr + Request req(0, addr, 64, 0x40, -1, 0, 0, 0); ArmISA::TLB *tlb; - // Check the TLBs far a translation - // It's possible that there is a validy translation in the tlb + // Check the TLBs for a translation + // It's possible that there is a valid translation in the tlb // that is no loger valid in the page table in memory // so we need to check here first + // + // Calling translateFunctional invokes a table-walk if required + // so we should always succeed tlb = static_cast<ArmISA::TLB*>(tc->getDTBPtr()); - success = tlb->translateFunctional(tc, addr, pa); - if (success) - return pa; + fault = tlb->translateFunctional(&req, tc, BaseTLB::Read, TLB::NormalTran); + if (fault == NoFault) + return req.getPaddr(); tlb = static_cast<ArmISA::TLB*>(tc->getITBPtr()); - success = tlb->translateFunctional(tc, addr, pa); - if (success) - return pa; + fault = tlb->translateFunctional(&req, tc, BaseTLB::Read, TLB::NormalTran); + if (fault == NoFault) + return req.getPaddr(); - // We've failed everything, so we need to do a - // hardware tlb walk without messing with any - // state - - uint32_t N = tc->readMiscReg(MISCREG_TTBCR); - Addr ttbr; - if (N == 0 || !mbits(addr, 31, 32-N)) { - ttbr = tc->readMiscReg(MISCREG_TTBR0); - } else { - ttbr = tc->readMiscReg(MISCREG_TTBR1); - N = 0; - } - - PortProxy &port = tc->getPhysProxy(); - Addr l1desc_addr = mbits(ttbr, 31, 14-N) | (bits(addr,31-N,20) << 2); - - TableWalker::L1Descriptor l1desc; - l1desc.data = port.read<uint32_t>(l1desc_addr); - if (l1desc.type() == TableWalker::L1Descriptor::Ignore || - l1desc.type() == TableWalker::L1Descriptor::Reserved) { - warn("Unable to translate virtual address: %#x\n", addr); - return -1; - } - if (l1desc.type() == TableWalker::L1Descriptor::Section) - return l1desc.paddr(addr); - - // Didn't find it at the first level, try againt - Addr l2desc_addr = l1desc.l2Addr() | (bits(addr, 19, 12) << 2); - TableWalker::L2Descriptor l2desc; - l2desc.data = port.read<uint32_t>(l2desc_addr); - - if (l2desc.invalid()) { - warn("Unable to translate virtual address: %#x\n", addr); - return -1; - } - - return l2desc.paddr(addr); + panic("Table walkers support functional accesses. We should never get here\n"); } bool diff --git a/src/base/loader/elf_object.cc b/src/base/loader/elf_object.cc index 6d4c29776..9445f1df9 100644 --- a/src/base/loader/elf_object.cc +++ b/src/base/loader/elf_object.cc @@ -1,4 +1,16 @@ /* + * Copyright (c) 2011-2013 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * * Copyright (c) 2003-2005 The Regents of The University of Michigan * All rights reserved. * @@ -61,7 +73,7 @@ ElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) assert(elf != NULL); // Check that we actually have a elf file - if (gelf_getehdr(elf, &ehdr) ==0) { + if (gelf_getehdr(elf, &ehdr) == 0) { DPRINTFR(Loader, "Not ELF\n"); elf_end(elf); return NULL; @@ -94,23 +106,27 @@ ElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) } else if (ehdr.e_machine == EM_386 && ehdr.e_ident[EI_CLASS] == ELFCLASS32) { arch = ObjectFile::I386; - } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { - arch = ObjectFile::Alpha; - } else if (ehdr.e_machine == EM_ARM) { + } else if (ehdr.e_machine == EM_ARM && + ehdr.e_ident[EI_CLASS] == ELFCLASS32) { if (bits(ehdr.e_entry, 0)) { arch = ObjectFile::Thumb; } else { arch = ObjectFile::Arm; } + } else if ((ehdr.e_machine == EM_AARCH64) && + ehdr.e_ident[EI_CLASS] == ELFCLASS64) { + arch = ObjectFile::Arm64; + } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { + arch = ObjectFile::Alpha; } else if (ehdr.e_machine == EM_PPC && ehdr.e_ident[EI_CLASS] == ELFCLASS32) { - if (ehdr.e_ident[EI_DATA] == ELFDATA2MSB) { - arch = ObjectFile::Power; - } else { - fatal("The binary you're trying to load is compiled for " + if (ehdr.e_ident[EI_DATA] == ELFDATA2MSB) { + arch = ObjectFile::Power; + } else { + fatal("The binary you're trying to load is compiled for " "little endian Power.\nM5 only supports big " "endian Power. Please recompile your binary.\n"); - } + } } else if (ehdr.e_machine == EM_PPC64) { fatal("The binary you're trying to load is compiled for 64-bit " "Power. M5\n only supports 32-bit Power. Please " @@ -121,9 +137,7 @@ ElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) } //Detect the operating system - switch (ehdr.e_ident[EI_OSABI]) - { - + switch (ehdr.e_ident[EI_OSABI]) { case ELFOSABI_LINUX: opSys = ObjectFile::Linux; break; @@ -206,7 +220,8 @@ ElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) if(phdr.p_offset <= e_phoff && phdr.p_offset + phdr.p_filesz > e_phoff) { - result->_programHeaderTable = phdr.p_paddr + e_phoff; + result->_programHeaderTable = + phdr.p_paddr + (e_phoff - phdr.p_offset); break; } } @@ -423,15 +438,15 @@ ElfObject::loadWeakSymbols(SymbolTable *symtab, Addr addrMask) } bool -ElfObject::loadSections(PortProxy& memProxy, Addr addrMask) +ElfObject::loadSections(PortProxy& memProxy, Addr addrMask, Addr offset) { - if (!ObjectFile::loadSections(memProxy, addrMask)) + if (!ObjectFile::loadSections(memProxy, addrMask, offset)) return false; vector<Segment>::iterator extraIt; for (extraIt = extraSegments.begin(); extraIt != extraSegments.end(); extraIt++) { - if (!loadSection(&(*extraIt), memProxy, addrMask)) { + if (!loadSection(&(*extraIt), memProxy, addrMask, offset)) { return false; } } diff --git a/src/base/loader/elf_object.hh b/src/base/loader/elf_object.hh index d3d3e5197..84b73b0a8 100644 --- a/src/base/loader/elf_object.hh +++ b/src/base/loader/elf_object.hh @@ -1,4 +1,16 @@ /* + * Copyright (c) 2013 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * * Copyright (c) 2003-2005 The Regents of The University of Michigan * All rights reserved. * @@ -66,7 +78,8 @@ class ElfObject : public ObjectFile virtual ~ElfObject() {} bool loadSections(PortProxy& memProxy, - Addr addrMask = std::numeric_limits<Addr>::max()); + Addr addrMask = std::numeric_limits<Addr>::max(), + Addr offset = 0); virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr addrMask = std::numeric_limits<Addr>::max()); virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask = diff --git a/src/base/loader/object_file.cc b/src/base/loader/object_file.cc index b9f84283b..170e18d5e 100644 --- a/src/base/loader/object_file.cc +++ b/src/base/loader/object_file.cc @@ -66,10 +66,10 @@ ObjectFile::~ObjectFile() bool -ObjectFile::loadSection(Section *sec, PortProxy& memProxy, Addr addrMask) +ObjectFile::loadSection(Section *sec, PortProxy& memProxy, Addr addrMask, Addr offset) { if (sec->size != 0) { - Addr addr = sec->baseAddr & addrMask; + Addr addr = (sec->baseAddr & addrMask) + offset; if (sec->fileImage) { memProxy.writeBlob(addr, sec->fileImage, sec->size); } @@ -83,11 +83,11 @@ ObjectFile::loadSection(Section *sec, PortProxy& memProxy, Addr addrMask) bool -ObjectFile::loadSections(PortProxy& memProxy, Addr addrMask) +ObjectFile::loadSections(PortProxy& memProxy, Addr addrMask, Addr offset) { - return (loadSection(&text, memProxy, addrMask) - && loadSection(&data, memProxy, addrMask) - && loadSection(&bss, memProxy, addrMask)); + return (loadSection(&text, memProxy, addrMask, offset) + && loadSection(&data, memProxy, addrMask, offset) + && loadSection(&bss, memProxy, addrMask, offset)); } diff --git a/src/base/loader/object_file.hh b/src/base/loader/object_file.hh index bdc9a31a1..09cde5b53 100644 --- a/src/base/loader/object_file.hh +++ b/src/base/loader/object_file.hh @@ -52,6 +52,7 @@ class ObjectFile Mips, X86_64, I386, + Arm64, Arm, Thumb, Power @@ -84,7 +85,8 @@ class ObjectFile void close(); virtual bool loadSections(PortProxy& memProxy, Addr addrMask = - std::numeric_limits<Addr>::max()); + std::numeric_limits<Addr>::max(), + Addr offset = 0); virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr addrMask = std::numeric_limits<Addr>::max()) = 0; virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask = @@ -114,7 +116,8 @@ class ObjectFile Section data; Section bss; - bool loadSection(Section *sec, PortProxy& memProxy, Addr addrMask); + bool loadSection(Section *sec, PortProxy& memProxy, Addr addrMask, + Addr offset = 0); void setGlobalPointer(Addr global_ptr) { globalPtr = global_ptr; } public: diff --git a/src/cpu/BaseCPU.py b/src/cpu/BaseCPU.py index cd82207cd..652af0b80 100644 --- a/src/cpu/BaseCPU.py +++ b/src/cpu/BaseCPU.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012 ARM Limited +# Copyright (c) 2012-2013 ARM Limited # All rights reserved. # # The license below extends only to copyright in the software and shall @@ -76,7 +76,7 @@ elif buildEnv['TARGET_ISA'] == 'mips': from MipsISA import MipsISA isa_class = MipsISA elif buildEnv['TARGET_ISA'] == 'arm': - from ArmTLB import ArmTLB + from ArmTLB import ArmTLB, ArmStage2IMMU, ArmStage2DMMU from ArmInterrupts import ArmInterrupts from ArmISA import ArmISA isa_class = ArmISA @@ -171,6 +171,8 @@ class BaseCPU(MemObject): elif buildEnv['TARGET_ISA'] == 'arm': dtb = Param.ArmTLB(ArmTLB(), "Data TLB") itb = Param.ArmTLB(ArmTLB(), "Instruction TLB") + istage2_mmu = Param.ArmStage2MMU(ArmStage2IMMU(), "Stage 2 trans") + dstage2_mmu = Param.ArmStage2MMU(ArmStage2DMMU(), "Stage 2 trans") interrupts = Param.ArmInterrupts( NULL, "Interrupt Controller") isa = VectorParam.ArmISA([ isa_class() ], "ISA instance") @@ -211,6 +213,9 @@ class BaseCPU(MemObject): if buildEnv['TARGET_ISA'] in ['x86', 'arm']: _cached_ports += ["itb.walker.port", "dtb.walker.port"] + if buildEnv['TARGET_ISA'] in ['arm']: + _cached_ports += ["istage2_mmu.stage2_tlb.walker.port", + "dstage2_mmu.stage2_tlb.walker.port"] _uncached_slave_ports = [] _uncached_master_ports = [] @@ -267,18 +272,35 @@ class BaseCPU(MemObject): if iwc and dwc: self.itb_walker_cache = iwc self.dtb_walker_cache = dwc - self.itb.walker.port = iwc.cpu_side - self.dtb.walker.port = dwc.cpu_side + if buildEnv['TARGET_ISA'] in ['arm']: + self.itb_walker_cache_bus = CoherentBus() + self.dtb_walker_cache_bus = CoherentBus() + self.itb_walker_cache_bus.master = iwc.cpu_side + self.dtb_walker_cache_bus.master = dwc.cpu_side + self.itb.walker.port = self.itb_walker_cache_bus.slave + self.dtb.walker.port = self.dtb_walker_cache_bus.slave + self.istage2_mmu.stage2_tlb.walker.port = self.itb_walker_cache_bus.slave + self.dstage2_mmu.stage2_tlb.walker.port = self.dtb_walker_cache_bus.slave + else: + self.itb.walker.port = iwc.cpu_side + self.dtb.walker.port = dwc.cpu_side self._cached_ports += ["itb_walker_cache.mem_side", \ "dtb_walker_cache.mem_side"] else: self._cached_ports += ["itb.walker.port", "dtb.walker.port"] + if buildEnv['TARGET_ISA'] in ['arm']: + self._cached_ports += ["istage2_mmu.stage2_tlb.walker.port", \ + "dstage2_mmu.stage2_tlb.walker.port"] + # Checker doesn't need its own tlb caches because it does # functional accesses only if self.checker != NULL: self._cached_ports += ["checker.itb.walker.port", \ "checker.dtb.walker.port"] + if buildEnv['TARGET_ISA'] in ['arm']: + self._cached_ports += ["checker.istage2_mmu.stage2_tlb.walker.port", \ + "checker.dstage2_mmu.stage2_tlb.walker.port"] def addTwoLevelCacheHierarchy(self, ic, dc, l2c, iwc = None, dwc = None): self.addPrivateSplitL1Caches(ic, dc, iwc, dwc) diff --git a/src/dev/arm/RealView.py b/src/dev/arm/RealView.py index b3c14580e..3c9c22ecc 100644 --- a/src/dev/arm/RealView.py +++ b/src/dev/arm/RealView.py @@ -1,4 +1,4 @@ -# Copyright (c) 2009-2012 ARM Limited +# Copyright (c) 2009-2013 ARM Limited # All rights reserved. # # The license below extends only to copyright in the software and shall @@ -88,6 +88,17 @@ class RealViewCtrl(BasicPioDevice): proc_id1 = Param.UInt32(0x0C000222, "Processor ID, SYS_PROCID1") idreg = Param.UInt32(0x00000000, "ID Register, SYS_ID") +class VGic(PioDevice): + type = 'VGic' + cxx_header = "dev/arm/vgic.hh" + gic = Param.BaseGic(Parent.any, "Gic to use for interrupting") + platform = Param.Platform(Parent.any, "Platform this device is part of.") + vcpu_addr = Param.Addr(0, "Address for vcpu interfaces") + hv_addr = Param.Addr(0, "Address for hv control") + pio_delay = Param.Latency('10ns', "Delay for PIO r/w") + # The number of list registers is not currently configurable at runtime. + ppint = Param.UInt32("HV maintenance interrupt number") + class AmbaFake(AmbaPioDevice): type = 'AmbaFake' cxx_header = "dev/arm/amba_fake.hh" @@ -119,6 +130,15 @@ class CpuLocalTimer(BasicPioDevice): int_num_timer = Param.UInt32("Interrrupt number used per-cpu to GIC") int_num_watchdog = Param.UInt32("Interrupt number for per-cpu watchdog to GIC") +class GenericTimer(SimObject): + type = 'GenericTimer' + cxx_header = "dev/arm/generic_timer.hh" + system = Param.System(Parent.any, "system") + gic = Param.BaseGic(Parent.any, "GIC to use for interrupting") + int_num = Param.UInt32("Interrupt number used per-cpu to GIC") + # @todo: for now only one timer per CPU is supported, which is the + # normal behaviour when Security and Virt. extensions are disabled. + class PL031(AmbaIntDevice): type = 'PL031' cxx_header = "dev/arm/rtc_pl031.hh" @@ -166,6 +186,9 @@ class RealView(Platform): conf_table_reported = False) self.nvmem.port = mem_bus.master cur_sys.boot_loader = loc('boot.arm') + cur_sys.atags_addr = 0x100 + cur_sys.load_addr_mask = 0xfffffff + cur_sys.load_offset = 0 # Reference for memory map and interrupt number @@ -340,12 +363,14 @@ class VExpress_EMM(RealView): realview_io = RealViewCtrl(proc_id0=0x14000000, proc_id1=0x14000000, pio_addr=0x1C010000) gic = Pl390(dist_addr=0x2C001000, cpu_addr=0x2C002000) local_cpu_timer = CpuLocalTimer(int_num_timer=29, int_num_watchdog=30, pio_addr=0x2C080000) + generic_timer = GenericTimer(int_num=29) timer0 = Sp804(int_num0=34, int_num1=34, pio_addr=0x1C110000, clock0='1MHz', clock1='1MHz') timer1 = Sp804(int_num0=35, int_num1=35, pio_addr=0x1C120000, clock0='1MHz', clock1='1MHz') clcd = Pl111(pio_addr=0x1c1f0000, int_num=46) hdlcd = HDLcd(pio_addr=0x2b000000, int_num=117) kmi0 = Pl050(pio_addr=0x1c060000, int_num=44) kmi1 = Pl050(pio_addr=0x1c070000, int_num=45, is_mouse=True) + vgic = VGic(vcpu_addr=0x2c006000, hv_addr=0x2c004000, ppint=25) cf_ctrl = IdeController(disks=[], pci_func=0, pci_dev=0, pci_bus=2, io_shift = 2, ctrl_offset = 2, Command = 0x1, BAR0 = 0x1C1A0000, BAR0Size = '256B', @@ -380,7 +405,9 @@ class VExpress_EMM(RealView): conf_table_reported = False) self.nvmem.port = mem_bus.master cur_sys.boot_loader = loc('boot_emm.arm') - cur_sys.atags_addr = 0x80000100 + cur_sys.atags_addr = 0x8000000 + cur_sys.load_addr_mask = 0xfffffff + cur_sys.load_offset = 0x80000000 # Attach I/O devices that are on chip and also set the appropriate # ranges for the bridge @@ -396,6 +423,8 @@ class VExpress_EMM(RealView): AddrRange(0x40000000, size='512MB'), AddrRange(0x18000000, size='64MB'), AddrRange(0x1C000000, size='64MB')] + self.vgic.pio = bus.master + # Attach I/O devices to specified bus object. Can't do this # earlier, since the bus object itself is typically defined at the @@ -435,3 +464,13 @@ class VExpress_EMM(RealView): self.usb_fake.pio = bus.master self.mmc_fake.pio = bus.master +class VExpress_EMM64(VExpress_EMM): + def setupBootLoader(self, mem_bus, cur_sys, loc): + self.nvmem = SimpleMemory(range = AddrRange(0, size = '64MB')) + self.nvmem.port = mem_bus.master + cur_sys.boot_loader = loc('boot_emm.arm64') + cur_sys.atags_addr = 0x8000000 + cur_sys.load_addr_mask = 0xfffffff + cur_sys.load_offset = 0x80000000 + + diff --git a/src/dev/arm/SConscript b/src/dev/arm/SConscript index 68779ec64..419e2f471 100644 --- a/src/dev/arm/SConscript +++ b/src/dev/arm/SConscript @@ -1,6 +1,6 @@ # -*- mode:python -*- -# Copyright (c) 2009 ARM Limited +# Copyright (c) 2009, 2012-2013 ARM Limited # All rights reserved. # # The license below extends only to copyright in the software and shall @@ -47,6 +47,7 @@ if env['TARGET_ISA'] == 'arm': Source('amba_device.cc') Source('amba_fake.cc') Source('base_gic.cc') + Source('generic_timer.cc') Source('gic_pl390.cc') Source('pl011.cc') Source('pl111.cc') @@ -57,6 +58,7 @@ if env['TARGET_ISA'] == 'arm': Source('realview.cc') Source('rtc_pl031.cc') Source('timer_cpulocal.cc') + Source('vgic.cc') DebugFlag('AMBA') DebugFlag('HDLcd') @@ -64,3 +66,4 @@ if env['TARGET_ISA'] == 'arm': DebugFlag('Pl050') DebugFlag('GIC') DebugFlag('RVCTRL') + DebugFlag('VGIC') diff --git a/src/dev/arm/generic_timer.cc b/src/dev/arm/generic_timer.cc new file mode 100644 index 000000000..555c1050f --- /dev/null +++ b/src/dev/arm/generic_timer.cc @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2013 ARM Limited + * All rights reserved. + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Giacomo Gabrielli + */ + +#include "arch/arm/system.hh" +#include "debug/Checkpoint.hh" +#include "debug/Timer.hh" +#include "dev/arm/base_gic.hh" +#include "dev/arm/generic_timer.hh" + +void +GenericTimer::SystemCounter::setFreq(uint32_t freq) +{ + if (_freq != 0) { + // Altering the frequency after boot shouldn't be done in practice. + warn_once("The frequency of the system counter has already been set"); + } + _freq = freq; + _period = (1.0 / freq) * SimClock::Frequency; + _resetTick = curTick(); +} + +void +GenericTimer::SystemCounter::serialize(std::ostream &os) +{ + SERIALIZE_SCALAR(_freq); + SERIALIZE_SCALAR(_period); + SERIALIZE_SCALAR(_resetTick); +} + +void +GenericTimer::SystemCounter::unserialize(Checkpoint *cp, + const std::string §ion) +{ + UNSERIALIZE_SCALAR(_freq); + UNSERIALIZE_SCALAR(_period); + UNSERIALIZE_SCALAR(_resetTick); +} + +void +GenericTimer::ArchTimer::counterLimitReached() +{ + _control.istatus = 1; + + if (!_control.enable) + return; + + // DPRINTF(Timer, "Counter limit reached\n"); + + if (!_control.imask) { + // DPRINTF(Timer, "Causing interrupt\n"); + _parent->_gic->sendPPInt(_intNum, _cpuNum); + } +} + +void +GenericTimer::ArchTimer::setCompareValue(uint64_t val) +{ + _counterLimit = val; + if (_counterLimitReachedEvent.scheduled()) + _parent->deschedule(_counterLimitReachedEvent); + if (counterValue() >= _counterLimit) { + counterLimitReached(); + } else { + _control.istatus = 0; + _parent->schedule(_counterLimitReachedEvent, + curTick() + (_counterLimit - counterValue()) * _counter->period()); + } +} + +void +GenericTimer::ArchTimer::setTimerValue(uint32_t val) +{ + setCompareValue(counterValue() + sext<32>(val)); +} + +void +GenericTimer::ArchTimer::setControl(uint32_t val) +{ + ArchTimerCtrl new_ctl = val; + if ((new_ctl.enable && !new_ctl.imask) && + !(_control.enable && !_control.imask)) { + // Re-evalute the timer condition + if (_counterLimit >= counterValue()) { + _control.istatus = 1; + + DPRINTF(Timer, "Causing interrupt in control\n"); + //_parent->_gic->sendPPInt(_intNum, _cpuNum); + } + } + _control.enable = new_ctl.enable; + _control.imask = new_ctl.imask; +} + +void +GenericTimer::ArchTimer::serialize(std::ostream &os) +{ + SERIALIZE_SCALAR(_cpuNum); + SERIALIZE_SCALAR(_intNum); + uint32_t control_serial = _control; + SERIALIZE_SCALAR(control_serial); + SERIALIZE_SCALAR(_counterLimit); + bool event_scheduled = _counterLimitReachedEvent.scheduled(); + SERIALIZE_SCALAR(event_scheduled); + Tick event_time; + if (event_scheduled) { + event_time = _counterLimitReachedEvent.when(); + SERIALIZE_SCALAR(event_time); + } +} + +void +GenericTimer::ArchTimer::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_SCALAR(_cpuNum); + UNSERIALIZE_SCALAR(_intNum); + uint32_t control_serial; + UNSERIALIZE_SCALAR(control_serial); + _control = control_serial; + bool event_scheduled; + UNSERIALIZE_SCALAR(event_scheduled); + Tick event_time; + if (event_scheduled) { + UNSERIALIZE_SCALAR(event_time); + _parent->schedule(_counterLimitReachedEvent, event_time); + } +} + +GenericTimer::GenericTimer(Params *p) + : SimObject(p), _gic(p->gic) +{ + for (int i = 0; i < CPU_MAX; ++i) { + std::stringstream oss; + oss << name() << ".arch_timer" << i; + _archTimers[i]._name = oss.str(); + _archTimers[i]._parent = this; + _archTimers[i]._counter = &_systemCounter; + _archTimers[i]._cpuNum = i; + _archTimers[i]._intNum = p->int_num; + } + + ((ArmSystem *) p->system)->setGenericTimer(this); +} + +void +GenericTimer::serialize(std::ostream &os) +{ + nameOut(os, csprintf("%s.sys_counter", name())); + _systemCounter.serialize(os); + for (int i = 0; i < CPU_MAX; ++i) { + nameOut(os, csprintf("%s.arch_timer%d", name(), i)); + _archTimers[i].serialize(os); + } +} + +void +GenericTimer::unserialize(Checkpoint *cp, const std::string §ion) +{ + _systemCounter.unserialize(cp, csprintf("%s.sys_counter", section)); + for (int i = 0; i < CPU_MAX; ++i) { + _archTimers[i].unserialize(cp, csprintf("%s.arch_timer%d", section, i)); + } +} + +GenericTimer * +GenericTimerParams::create() +{ + return new GenericTimer(this); +} diff --git a/src/dev/arm/generic_timer.hh b/src/dev/arm/generic_timer.hh new file mode 100644 index 000000000..bc43f8b3b --- /dev/null +++ b/src/dev/arm/generic_timer.hh @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2013 ARM Limited + * All rights reserved. + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Giacomo Gabrielli + */ + +#ifndef __DEV_ARM_GENERIC_TIMER_HH__ +#define __DEV_ARM_GENERIC_TIMER_HH__ + +#include "base/bitunion.hh" +#include "params/GenericTimer.hh" +#include "sim/core.hh" +#include "sim/sim_object.hh" + +/// @file +/// This module implements the global system counter and the local per-CPU +/// architected timers as specified by the ARM Generic Timer extension (ARM +/// ARM, Issue C, Chapter 17). + +class Checkpoint; +class BaseGic; + +/// Wrapper around the actual counters and timers of the Generic Timer +/// extension. +class GenericTimer : public SimObject +{ + public: + + /// Global system counter. It is shared by the architected timers. + /// @todo: implement memory-mapped controls + class SystemCounter + { + protected: + /// Counter frequency (as specified by CNTFRQ). + uint64_t _freq; + /// Cached copy of the counter period (inverse of the frequency). + Tick _period; + /// Tick when the counter was reset. + Tick _resetTick; + + public: + /// Ctor. + SystemCounter() + : _freq(0), _period(0), _resetTick(0) + { + setFreq(0x01800000); + } + + /// Returns the current value of the physical counter. + uint64_t value() const + { + if (_freq == 0) + return 0; // Counter is still off. + return (curTick() - _resetTick) / _period; + } + + /// Returns the counter frequency. + uint64_t freq() const { return _freq; } + /// Sets the counter frequency. + /// @param freq frequency in Hz. + void setFreq(uint32_t freq); + + /// Returns the counter period. + Tick period() const { return _period; } + + void serialize(std::ostream &os); + void unserialize(Checkpoint *cp, const std::string §ion); + }; + + /// Per-CPU architected timer. + class ArchTimer + { + protected: + /// Control register. + BitUnion32(ArchTimerCtrl) + Bitfield<0> enable; + Bitfield<1> imask; + Bitfield<2> istatus; + EndBitUnion(ArchTimerCtrl) + + /// Name of this timer. + std::string _name; + /// Pointer to parent class. + GenericTimer *_parent; + /// Pointer to the global system counter. + SystemCounter *_counter; + /// ID of the CPU this timer is attached to. + int _cpuNum; + /// ID of the interrupt to be triggered. + int _intNum; + /// Cached value of the control register ({CNTP/CNTHP/CNTV}_CTL). + ArchTimerCtrl _control; + /// Programmed limit value for the upcounter ({CNTP/CNTHP/CNTV}_CVAL). + uint64_t _counterLimit; + + /// Called when the upcounter reaches the programmed value. + void counterLimitReached(); + EventWrapper<ArchTimer, &ArchTimer::counterLimitReached> + _counterLimitReachedEvent; + + /// Returns the value of the counter which this timer relies on. + uint64_t counterValue() const { return _counter->value(); } + + public: + /// Ctor. + ArchTimer() + : _control(0), _counterLimit(0), _counterLimitReachedEvent(this) + {} + + /// Returns the timer name. + std::string name() const { return _name; } + + /// Returns the CompareValue view of the timer. + uint64_t compareValue() const { return _counterLimit; } + /// Sets the CompareValue view of the timer. + void setCompareValue(uint64_t val); + + /// Returns the TimerValue view of the timer. + uint32_t timerValue() const { return _counterLimit - counterValue(); } + /// Sets the TimerValue view of the timer. + void setTimerValue(uint32_t val); + + /// Sets the control register. + uint32_t control() const { return _control; } + void setControl(uint32_t val); + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + + friend class GenericTimer; + }; + + protected: + + static const int CPU_MAX = 8; + + /// Pointer to the GIC, needed to trigger timer interrupts. + BaseGic *_gic; + /// System counter. + SystemCounter _systemCounter; + /// Per-CPU architected timers. + // @todo: this would become a 2-dim. array with Security and Virt. + ArchTimer _archTimers[CPU_MAX]; + + public: + typedef GenericTimerParams Params; + const Params * + params() const + { + return dynamic_cast<const Params *>(_params); + } + + /// Ctor. + GenericTimer(Params *p); + + /// Returns a pointer to the system counter. + SystemCounter *getSystemCounter() { return &_systemCounter; } + + /// Returns a pointer to the architected timer for cpu_id. + ArchTimer *getArchTimer(int cpu_id) { return &_archTimers[cpu_id]; } + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; + +#endif // __DEV_ARM_GENERIC_TIMER_HH__ diff --git a/src/dev/arm/gic_pl390.cc b/src/dev/arm/gic_pl390.cc index d2a660e88..7fc65b2b7 100644 --- a/src/dev/arm/gic_pl390.cc +++ b/src/dev/arm/gic_pl390.cc @@ -56,7 +56,8 @@ Pl390::Pl390(const Params *p) : BaseGic(p), distAddr(p->dist_addr), cpuAddr(p->cpu_addr), distPioDelay(p->dist_pio_delay), cpuPioDelay(p->cpu_pio_delay), intLatency(p->int_latency), - enabled(false), itLines(p->it_lines), msixRegAddr(p->msix_addr), + enabled(false), itLines(p->it_lines), irqEnable(false), + msixRegAddr(p->msix_addr), msixReg(0x0) { itLinesLog2 = ceilLog2(itLines); diff --git a/src/dev/arm/vgic.cc b/src/dev/arm/vgic.cc new file mode 100644 index 000000000..2faf2030e --- /dev/null +++ b/src/dev/arm/vgic.cc @@ -0,0 +1,553 @@ +/* + * Copyright (c) 2013 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Matt Evans + */ + +#include "base/trace.hh" +#include "debug/Checkpoint.hh" +#include "debug/VGIC.hh" +#include "dev/arm/base_gic.hh" +#include "dev/arm/vgic.hh" +#include "dev/terminal.hh" +#include "mem/packet.hh" +#include "mem/packet_access.hh" + +VGic::VGic(const Params *p) + : PioDevice(p), platform(p->platform), gic(p->gic), vcpuAddr(p->vcpu_addr), + hvAddr(p->hv_addr), pioDelay(p->pio_delay), + maintInt(p->ppint) +{ + for (int x = 0; x < VGIC_CPU_MAX; x++) { + postVIntEvent[x] = new PostVIntEvent(x, p->platform); + maintIntPosted[x] = false; + vIntPosted[x] = false; + } + for (int c = 0; c < VGIC_CPU_MAX; c++) { + memset(&vcpuData[c], 0, sizeof(struct vcpuIntData)); + } + assert(sys->numRunningContexts() <= VGIC_CPU_MAX); +} + +Tick +VGic::read(PacketPtr pkt) +{ + Addr addr = pkt->getAddr(); + + if (addr >= vcpuAddr && addr < vcpuAddr + GICV_SIZE) + return readVCpu(pkt); + else if (addr >= hvAddr && addr < hvAddr + GICH_REG_SIZE) + return readCtrl(pkt); + else + panic("Read to unknown address %#x\n", pkt->getAddr()); +} + +Tick +VGic::write(PacketPtr pkt) +{ + Addr addr = pkt->getAddr(); + + if (addr >= vcpuAddr && addr < vcpuAddr + GICV_SIZE) + return writeVCpu(pkt); + else if (addr >= hvAddr && addr < hvAddr + GICH_REG_SIZE) + return writeCtrl(pkt); + else + panic("Write to unknown address %#x\n", pkt->getAddr()); +} + +Tick +VGic::readVCpu(PacketPtr pkt) +{ + Addr daddr = pkt->getAddr() - vcpuAddr; + pkt->allocate(); + + int ctx_id = pkt->req->contextId(); + assert(ctx_id < VGIC_CPU_MAX); + struct vcpuIntData *vid = &vcpuData[ctx_id]; + + DPRINTF(VGIC, "VGIC VCPU read register %#x\n", daddr); + + switch (daddr) { + case GICV_CTLR: + pkt->set<uint32_t>(vid->vctrl); + break; + case GICV_IAR: { + int i = findHighestPendingLR(vid); + if (i < 0 || !vid->vctrl.En) { + pkt->set<uint32_t>(1023); // "No int" marker + } else { + ListReg *lr = &vid->LR[i]; + + pkt->set<uint32_t>(lr->VirtualID | + (((int)lr->CpuID) << 10)); + // We don't support auto-EOI of HW interrupts via real GIC! + // Fortunately, KVM doesn't use this. How about Xen...? Ulp! + if (lr->HW) + panic("VGIC does not support 'HW' List Register feature (LR %#x)!\n", + *lr); + lr->State = LR_ACTIVE; + DPRINTF(VGIC, "Consumed interrupt %d (cpu%d) from LR%d (EOI%d)\n", + lr->VirtualID, lr->CpuID, i, lr->EOI); + } + } break; + default: + panic("VGIC VCPU read of bad address %#x\n", daddr); + } + + updateIntState(ctx_id); + + pkt->makeAtomicResponse(); + return pioDelay; +} + +Tick +VGic::readCtrl(PacketPtr pkt) +{ + Addr daddr = pkt->getAddr() - hvAddr; + pkt->allocate(); + + int ctx_id = pkt->req->contextId(); + + DPRINTF(VGIC, "VGIC HVCtrl read register %#x\n", daddr); + + /* Munge the address: 0-0xfff is the usual space banked by requester CPU. + * Anything > that is 0x200-sized slices of 'per CPU' regs. + */ + if (daddr & ~0x1ff) { + ctx_id = (daddr >> 9); + if (ctx_id > 8) + panic("VGIC: Weird unbanked hv ctrl address %#x!\n", daddr); + daddr &= ~0x1ff; + } + assert(ctx_id < VGIC_CPU_MAX); + struct vcpuIntData *vid = &vcpuData[ctx_id]; + + switch (daddr) { + case GICH_HCR: + pkt->set<uint32_t>(vid->hcr); + break; + + case GICH_VTR: + pkt->set<uint32_t>(0x44000000 | (NUM_LR - 1)); + break; + + case GICH_VMCR: + pkt->set<uint32_t>( + ((uint32_t)vid->VMPriMask << 27) | + ((uint32_t)vid->VMBP << 21) | + ((uint32_t)vid->VMABP << 18) | + ((uint32_t)vid->VEM << 9) | + ((uint32_t)vid->VMCBPR << 4) | + ((uint32_t)vid->VMFiqEn << 3) | + ((uint32_t)vid->VMAckCtl << 2) | + ((uint32_t)vid->VMGrp1En << 1) | + ((uint32_t)vid->VMGrp0En << 0) + ); + break; + + case GICH_MISR: + pkt->set<uint32_t>(getMISR(vid)); + break; + + case GICH_EISR0: + pkt->set<uint32_t>(vid->eisr & 0xffffffff); + break; + + case GICH_EISR1: + pkt->set<uint32_t>(vid->eisr >> 32); + break; + + case GICH_ELSR0: { + uint32_t bm = 0; + for (int i = 0; i < ((NUM_LR < 32) ? NUM_LR : 32); i++) { + if (!vid->LR[i].State) + bm |= 1 << i; + } + pkt->set<uint32_t>(bm); + } break; + + case GICH_ELSR1: { + uint32_t bm = 0; + for (int i = 32; i < NUM_LR; i++) { + if (!vid->LR[i].State) + bm |= 1 << (i-32); + } + pkt->set<uint32_t>(bm); + } break; + + case GICH_APR0: + warn_once("VGIC GICH_APR read!\n"); + pkt->set<uint32_t>(0); + break; + + case GICH_LR0: + case GICH_LR1: + case GICH_LR2: + case GICH_LR3: + pkt->set<uint32_t>(vid->LR[(daddr - GICH_LR0) >> 2]); + break; + + default: + panic("VGIC HVCtrl read of bad address %#x\n", daddr); + } + + pkt->makeAtomicResponse(); + return pioDelay; +} + +Tick +VGic::writeVCpu(PacketPtr pkt) +{ + Addr daddr = pkt->getAddr() - vcpuAddr; + pkt->allocate(); + + int ctx_id = pkt->req->contextId(); + assert(ctx_id < VGIC_CPU_MAX); + struct vcpuIntData *vid = &vcpuData[ctx_id]; + + DPRINTF(VGIC, "VGIC VCPU write register %#x <= %#x\n", daddr, pkt->get<uint32_t>()); + + switch (daddr) { + case GICV_CTLR: + vid->vctrl = pkt->get<uint32_t>(); + break; + case GICV_PMR: + vid->VMPriMask = pkt->get<uint32_t>(); + break; + case GICV_EOIR: { + // We don't handle the split EOI-then-DIR mode. Linux (guest) + // doesn't need it though. + assert(!vid->vctrl.EOImode); + uint32_t w = pkt->get<uint32_t>(); + unsigned int virq = w & 0x3ff; + unsigned int vcpu = (w >> 10) & 7; + int i = findLRForVIRQ(vid, virq, vcpu); + if (i < 0) { + DPRINTF(VGIC, "EOIR: No LR for irq %d(cpu%d)\n", virq, vcpu); + } else { + DPRINTF(VGIC, "EOIR: Found LR%d for irq %d(cpu%d)\n", i, virq, vcpu); + ListReg *lr = &vid->LR[i]; + lr->State = 0; + // Maintenance interrupt -- via eisr -- is flagged when + // LRs have EOI=1 and State=INVALID! + } + } break; + default: + panic("VGIC VCPU write %#x to unk address %#x\n", pkt->get<uint32_t>(), daddr); + } + + // This updates the EISRs and flags IRQs: + updateIntState(ctx_id); + + pkt->makeAtomicResponse(); + return pioDelay; +} + +Tick +VGic::writeCtrl(PacketPtr pkt) +{ + Addr daddr = pkt->getAddr() - hvAddr; + pkt->allocate(); + + int ctx_id = pkt->req->contextId(); + + DPRINTF(VGIC, "VGIC HVCtrl write register %#x <= %#x\n", daddr, pkt->get<uint32_t>()); + + /* Munge the address: 0-0xfff is the usual space banked by requester CPU. + * Anything > that is 0x200-sized slices of 'per CPU' regs. + */ + if (daddr & ~0x1ff) { + ctx_id = (daddr >> 9); + if (ctx_id > 8) + panic("VGIC: Weird unbanked hv ctrl address %#x!\n", daddr); + daddr &= ~0x1ff; + } + assert(ctx_id < VGIC_CPU_MAX); + struct vcpuIntData *vid = &vcpuData[ctx_id]; + + switch (daddr) { + case GICH_HCR: + vid->hcr = pkt->get<uint32_t>(); + // update int state + break; + + case GICH_VMCR: { + uint32_t d = pkt->get<uint32_t>(); + vid->VMPriMask = d >> 27; + vid->VMBP = (d >> 21) & 7; + vid->VMABP = (d >> 18) & 7; + vid->VEM = (d >> 9) & 1; + vid->VMCBPR = (d >> 4) & 1; + vid->VMFiqEn = (d >> 3) & 1; + vid->VMAckCtl = (d >> 2) & 1; + vid->VMGrp1En = (d >> 1) & 1; + vid->VMGrp0En = d & 1; + } break; + + case GICH_APR0: + warn_once("VGIC GICH_APR0 written, ignored\n"); + break; + + case GICH_LR0: + case GICH_LR1: + case GICH_LR2: + case GICH_LR3: + vid->LR[(daddr - GICH_LR0) >> 2] = pkt->get<uint32_t>(); + // update int state + break; + + default: + panic("VGIC HVCtrl write to bad address %#x\n", daddr); + } + + updateIntState(ctx_id); + + pkt->makeAtomicResponse(); + return pioDelay; +} + + +uint32_t +VGic::getMISR(struct vcpuIntData *vid) +{ + return (!!vid->hcr.VGrp1DIE && !vid->VMGrp1En ? 0x80 : 0) | + (!!vid->hcr.VGrp1EIE && vid->VMGrp1En ? 0x40 : 0) | + (!!vid->hcr.VGrp0DIE && !vid->VMGrp0En ? 0x20 : 0) | + (!!vid->hcr.VGrp0EIE && vid->VMGrp0En ? 0x10 : 0) | + (!!vid->hcr.NPIE && !lrPending(vid) ? 0x08 : 0) | + (!!vid->hcr.LRENPIE && vid->hcr.EOICount ? 0x04 : 0) | + (!!vid->hcr.UIE && lrValid(vid) <= 1 ? 0x02 : 0) | + (vid->eisr ? 0x01 : 0); +} + +void +VGic::postVInt(uint32_t cpu, Tick when) +{ + DPRINTF(VGIC, "Posting VIRQ to %d\n", cpu); + if (!(postVIntEvent[cpu]->scheduled())) + eventq->schedule(postVIntEvent[cpu], when); +} + +void +VGic::unPostVInt(uint32_t cpu) +{ + DPRINTF(VGIC, "Unposting VIRQ to %d\n", cpu); + platform->intrctrl->clear(cpu, ArmISA::INT_VIRT_IRQ, 0); +} + +void +VGic::postMaintInt(uint32_t cpu) +{ + DPRINTF(VGIC, "Posting maintenance PPI to GIC/cpu%d\n", cpu); + // Linux DT configures this as Level. + gic->sendPPInt(maintInt, cpu); +} + +void +VGic::unPostMaintInt(uint32_t cpu) +{ + DPRINTF(VGIC, "Unposting maintenance PPI to GIC/cpu%d\n", cpu); + gic->clearPPInt(maintInt, cpu); +} + +/* Update state (in general); something concerned with ctx_id has changed. + * This may raise a maintenance interrupt. + */ +void +VGic::updateIntState(int ctx_id) +{ + // @todo This should update APRs! + + // Build EISR contents: + // (Cached so that regs can read them without messing about again) + struct vcpuIntData *tvid = &vcpuData[ctx_id]; + + tvid->eisr = 0; + for (int i = 0; i < NUM_LR; i++) { + if (!tvid->LR[i].State && tvid->LR[i].EOI) { + tvid->eisr |= 1 << i; + } + } + + assert(sys->numRunningContexts() <= VGIC_CPU_MAX); + for (int i = 0; i < sys->numRunningContexts(); i++) { + struct vcpuIntData *vid = &vcpuData[i]; + // Are any LRs active that weren't before? + if (!vIntPosted[i]) { + if (lrPending(vid) && vid->vctrl.En) { + vIntPosted[i] = true; + postVInt(i, curTick() + 1); + } + } else if (!lrPending(vid)) { + vIntPosted[i] = false; + unPostVInt(i); + } + + // Any maintenance ints to send? + if (!maintIntPosted[i]) { + if (vid->hcr.En && getMISR(vid)) { + maintIntPosted[i] = true; + postMaintInt(i); + } + } else { + if (!vid->hcr.En || !getMISR(vid)) { + unPostMaintInt(i); + maintIntPosted[i] = false; + } + } + } +} + +AddrRangeList +VGic::getAddrRanges() const +{ + AddrRangeList ranges; + ranges.push_back(RangeSize(hvAddr, GICH_REG_SIZE)); + ranges.push_back(RangeSize(vcpuAddr, GICV_SIZE)); + return ranges; +} + +void +VGic::serialize(std::ostream &os) +{ + Tick interrupt_time[VGIC_CPU_MAX]; + for (uint32_t cpu = 0; cpu < VGIC_CPU_MAX; cpu++) { + interrupt_time[cpu] = 0; + if (postVIntEvent[cpu]->scheduled()) { + interrupt_time[cpu] = postVIntEvent[cpu]->when(); + } + } + + DPRINTF(Checkpoint, "Serializing VGIC\n"); + + SERIALIZE_ARRAY(interrupt_time, VGIC_CPU_MAX); + SERIALIZE_ARRAY(maintIntPosted, VGIC_CPU_MAX); + SERIALIZE_ARRAY(vIntPosted, VGIC_CPU_MAX); + SERIALIZE_SCALAR(vcpuAddr); + SERIALIZE_SCALAR(hvAddr); + SERIALIZE_SCALAR(pioDelay); + SERIALIZE_SCALAR(maintInt); + + for (uint32_t cpu = 0; cpu < VGIC_CPU_MAX; cpu++) { + nameOut(os, csprintf("%s.vcpuData%d", name(), cpu)); + uint32_t vctrl_val = vcpuData[cpu].vctrl; + SERIALIZE_SCALAR(vctrl_val); + uint32_t hcr_val = vcpuData[cpu].hcr; + SERIALIZE_SCALAR(hcr_val); + uint64_t eisr_val = vcpuData[cpu].eisr; + SERIALIZE_SCALAR(eisr_val); + uint8_t VMGrp0En_val = vcpuData[cpu].VMGrp0En; + SERIALIZE_SCALAR(VMGrp0En_val); + uint8_t VMGrp1En_val = vcpuData[cpu].VMGrp1En; + SERIALIZE_SCALAR(VMGrp1En_val); + uint8_t VMAckCtl_val = vcpuData[cpu].VMAckCtl; + SERIALIZE_SCALAR(VMAckCtl_val); + uint8_t VMFiqEn_val = vcpuData[cpu].VMFiqEn; + SERIALIZE_SCALAR(VMFiqEn_val); + uint8_t VMCBPR_val = vcpuData[cpu].VMCBPR; + SERIALIZE_SCALAR(VMCBPR_val); + uint8_t VEM_val = vcpuData[cpu].VEM; + SERIALIZE_SCALAR(VEM_val); + uint8_t VMABP_val = vcpuData[cpu].VMABP; + SERIALIZE_SCALAR(VMABP_val); + uint8_t VMBP_val = vcpuData[cpu].VMBP; + SERIALIZE_SCALAR(VMBP_val); + uint8_t VMPriMask_val = vcpuData[cpu].VMPriMask; + SERIALIZE_SCALAR(VMPriMask_val); + + for (int i = 0; i < NUM_LR; i++) { + uint32_t lr = vcpuData[cpu].LR[i]; + nameOut(os, csprintf("%s.vcpuData%d.LR%d", name(), cpu, i)); + SERIALIZE_SCALAR(lr); + } + } +} + +void VGic::unserialize(Checkpoint *cp, const std::string §ion) +{ + DPRINTF(Checkpoint, "Unserializing Arm GIC\n"); + + Tick interrupt_time[VGIC_CPU_MAX]; + UNSERIALIZE_ARRAY(interrupt_time, VGIC_CPU_MAX); + for (uint32_t cpu = 0; cpu < VGIC_CPU_MAX; cpu++) { + if (interrupt_time[cpu]) + schedule(postVIntEvent[cpu], interrupt_time[cpu]); + + uint32_t tmp; + paramIn(cp, csprintf("%s.vcpuData%d", section, cpu), + "vctrl_val", tmp); + vcpuData[cpu].vctrl = tmp; + paramIn(cp, csprintf("%s.vcpuData%d", section, cpu), + "hcr_val", tmp); + vcpuData[cpu].hcr = tmp; + paramIn(cp, csprintf("%s.vcpuData%d", section, cpu), + "eisr_val", vcpuData[cpu].eisr); + paramIn(cp, csprintf("%s.vcpuData%d", section, cpu), + "VMGrp0En_val", vcpuData[cpu].VMGrp0En); + paramIn(cp, csprintf("%s.vcpuData%d", section, cpu), + "VMGrp1En_val", vcpuData[cpu].VMGrp1En); + paramIn(cp, csprintf("%s.vcpuData%d", section, cpu), + "VMAckCtl_val", vcpuData[cpu].VMAckCtl); + paramIn(cp, csprintf("%s.vcpuData%d", section, cpu), + "VMFiqEn_val", vcpuData[cpu].VMFiqEn); + paramIn(cp, csprintf("%s.vcpuData%d", section, cpu), + "VMCBPR_val", vcpuData[cpu].VMCBPR); + paramIn(cp, csprintf("%s.vcpuData%d", section, cpu), + "VEM_val", vcpuData[cpu].VEM); + paramIn(cp, csprintf("%s.vcpuData%d", section, cpu), + "VMABP_val", vcpuData[cpu].VMABP); + paramIn(cp, csprintf("%s.vcpuData%d", section, cpu), + "VMPriMask_val", vcpuData[cpu].VMPriMask); + + for (int i = 0; i < NUM_LR; i++) { + paramIn(cp, csprintf("%s.vcpuData%d.LR%d", section, cpu, i), + "lr", tmp); + vcpuData[cpu].LR[i] = tmp; + } + } + UNSERIALIZE_ARRAY(maintIntPosted, VGIC_CPU_MAX); + UNSERIALIZE_ARRAY(vIntPosted, VGIC_CPU_MAX); + UNSERIALIZE_SCALAR(vcpuAddr); + UNSERIALIZE_SCALAR(hvAddr); + UNSERIALIZE_SCALAR(pioDelay); + UNSERIALIZE_SCALAR(maintInt); +} + +VGic * +VGicParams::create() +{ + return new VGic(this); +} diff --git a/src/dev/arm/vgic.hh b/src/dev/arm/vgic.hh new file mode 100644 index 000000000..e1c4960e9 --- /dev/null +++ b/src/dev/arm/vgic.hh @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2013 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Matt Evans + */ + + +/** @file + * Implementiation of a GIC-400 List Register-based VGIC interface. + * The VGIC is, in this implementation, completely separate from the GIC itself. + * Only a VIRQ line to the CPU and a PPI line to the GIC (for a HV maintenance IRQ) + * is required. + * + * The mode in which the List Registers may flag (via LR.HW) that a hardware EOI + * is to be performed is NOT supported. (This requires tighter integration with + * the GIC.) + */ + +#ifndef __DEV_ARM_VGIC_H__ +#define __DEV_ARM_VGIC_H__ + +#include "base/addr_range.hh" +#include "base/bitunion.hh" +#include "cpu/intr_control.hh" +#include "dev/io_device.hh" +#include "dev/platform.hh" +#include "params/VGic.hh" + +class VGic : public PioDevice +{ + private: + static const int VGIC_CPU_MAX = 256; + static const int NUM_LR = 4; + + static const int GICH_SIZE = 0x200; + static const int GICH_REG_SIZE = 0x2000; + + static const int GICH_HCR = 0x000; + static const int GICH_VTR = 0x004; + static const int GICH_VMCR = 0x008; + static const int GICH_MISR = 0x010; + static const int GICH_EISR0 = 0x020; + static const int GICH_EISR1 = 0x024; + static const int GICH_ELSR0 = 0x030; + static const int GICH_ELSR1 = 0x034; + static const int GICH_APR0 = 0x0f0; + static const int GICH_LR0 = 0x100; + static const int GICH_LR1 = 0x104; + static const int GICH_LR2 = 0x108; + static const int GICH_LR3 = 0x10c; + + static const int GICV_SIZE = 0x2000; + static const int GICV_CTLR = 0x000; + static const int GICV_PMR = 0x004; + static const int GICV_BPR = 0x008; + static const int GICV_IAR = 0x00c; + static const int GICV_EOIR = 0x010; + static const int GICV_RPR = 0x014; + static const int GICV_HPPIR = 0x018; + static const int GICV_ABPR = 0x01c; + static const int GICV_AIAR = 0x020; + static const int GICV_AEOIR = 0x024; + static const int GICV_AHPPIR = 0x028; + static const int GICV_APR0 = 0x0d0; + static const int GICV_IIDR = 0x0fc; + static const int GICV_DIR = 0x1000; + + static const uint32_t LR_PENDING = 1; + static const uint32_t LR_ACTIVE = 2; + + /** Event definition to post interrupt to CPU after a delay + */ + class PostVIntEvent : public Event + { + private: + uint32_t cpu; + Platform *platform; + public: + PostVIntEvent( uint32_t c, Platform* p) + : cpu(c), platform(p) + { } + void process() { platform->intrctrl->post(cpu, ArmISA::INT_VIRT_IRQ, 0);} + const char *description() const { return "Post VInterrupt to CPU"; } + }; + + PostVIntEvent *postVIntEvent[VGIC_CPU_MAX]; + bool maintIntPosted[VGIC_CPU_MAX]; + bool vIntPosted[VGIC_CPU_MAX]; + + Platform *platform; + BaseGic *gic; + + Addr vcpuAddr; + Addr hvAddr; + Tick pioDelay; + int maintInt; + + BitUnion32(ListReg) + Bitfield<31> HW; + Bitfield<30> Grp1; + Bitfield<29,28> State; + Bitfield<27,23> Priority; + Bitfield<19> EOI; + Bitfield<12,10> CpuID; + Bitfield<9,0> VirtualID; + EndBitUnion(ListReg) + + BitUnion32(HCR) + Bitfield<31,27> EOICount; + Bitfield<7> VGrp1DIE; + Bitfield<6> VGrp1EIE; + Bitfield<5> VGrp0DIE; + Bitfield<4> VGrp0EIE; + Bitfield<3> NPIE; + Bitfield<2> LRENPIE; + Bitfield<1> UIE; + Bitfield<0> En; + EndBitUnion(HCR) + + BitUnion32(VCTLR) + Bitfield<9> EOImode; + Bitfield<4> CPBR; + Bitfield<3> FIQEn; + Bitfield<2> AckCtl; + Bitfield<1> EnGrp1; + Bitfield<0> En; // This gets written to enable, not group 1. + EndBitUnion(VCTLR) + + /* State per CPU. EVERYTHING should be in this struct and simply replicated + * N times. + */ + struct vcpuIntData { + ListReg LR[NUM_LR]; + VCTLR vctrl; + + HCR hcr; + uint64_t eisr; + + /* Host info, guest info (should be 100% accessible via GICH_* regs!) */ + uint8_t VMGrp0En; + uint8_t VMGrp1En; + uint8_t VMAckCtl; + uint8_t VMFiqEn; + uint8_t VMCBPR; + uint8_t VEM; + uint8_t VMABP; + uint8_t VMBP; + uint8_t VMPriMask; + }; + + struct vcpuIntData vcpuData[VGIC_CPU_MAX]; + + public: + typedef VGicParams Params; + const Params * + params() const + { + return dynamic_cast<const Params *>(_params); + } + VGic(const Params *p); + + virtual AddrRangeList getAddrRanges() const; + + virtual Tick read(PacketPtr pkt); + virtual Tick write(PacketPtr pkt); + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + + private: + Tick readVCpu(PacketPtr pkt); + Tick readCtrl(PacketPtr pkt); + + Tick writeVCpu(PacketPtr pkt); + Tick writeCtrl(PacketPtr pkt); + + void updateIntState(int ctx_id); + uint32_t getMISR(struct vcpuIntData *vid); + void postVInt(uint32_t cpu, Tick when); + void unPostVInt(uint32_t cpu); + void postMaintInt(uint32_t cpu); + void unPostMaintInt(uint32_t cpu); + + unsigned int lrPending(struct vcpuIntData *vid) + { + unsigned int pend = 0; + for (int i = 0; i < NUM_LR; i++) { + if (vid->LR[i].State & LR_PENDING) + pend++; + } + return pend; + } + unsigned int lrValid(struct vcpuIntData *vid) + { + unsigned int valid = 0; + for (int i = 0; i < NUM_LR; i++) { + if (vid->LR[i].State) + valid++; + } + return valid; + } + + /** Returns LR index or -1 if none pending */ + int findHighestPendingLR(struct vcpuIntData *vid) + { + unsigned int prio = 0xff; + int p = -1; + for (int i = 0; i < NUM_LR; i++) { + if ((vid->LR[i].State & LR_PENDING) && (vid->LR[i].Priority < prio)) { + p = i; + prio = vid->LR[i].Priority; + } + } + return p; + } + + int findLRForVIRQ(struct vcpuIntData *vid, int virq, int vcpu) + { + for (int i = 0; i < NUM_LR; i++) { + if (vid->LR[i].State && + vid->LR[i].VirtualID == virq && + vid->LR[i].CpuID == vcpu) + return i; + } + return -1; + } +}; + +#endif diff --git a/src/sim/System.py b/src/sim/System.py index 302e2fa60..95162be89 100644 --- a/src/sim/System.py +++ b/src/sim/System.py @@ -86,4 +86,5 @@ class System(MemObject): readfile = Param.String("", "file to read startup script from") symbolfile = Param.String("", "file to get the symbols from") load_addr_mask = Param.UInt64(0xffffffffff, - "Address to mask loading binaries with"); + "Address to mask loading binaries with") + load_offset = Param.UInt64(0, "Address to offset loading binaries with") diff --git a/src/sim/process.cc b/src/sim/process.cc index 1654ea5c5..ccaac2096 100644 --- a/src/sim/process.cc +++ b/src/sim/process.cc @@ -695,15 +695,22 @@ LiveProcess::create(LiveProcessParams * params) fatal("Unknown/unsupported operating system."); } #elif THE_ISA == ARM_ISA - if (objFile->getArch() != ObjectFile::Arm && - objFile->getArch() != ObjectFile::Thumb) + ObjectFile::Arch arch = objFile->getArch(); + if (arch != ObjectFile::Arm && arch != ObjectFile::Thumb && + arch != ObjectFile::Arm64) fatal("Object file architecture does not match compiled ISA (ARM)."); switch (objFile->getOpSys()) { case ObjectFile::UnknownOpSys: warn("Unknown operating system; assuming Linux."); // fall through case ObjectFile::Linux: - process = new ArmLinuxProcess(params, objFile, objFile->getArch()); + if (arch == ObjectFile::Arm64) { + process = new ArmLinuxProcess64(params, objFile, + objFile->getArch()); + } else { + process = new ArmLinuxProcess32(params, objFile, + objFile->getArch()); + } break; case ObjectFile::LinuxArmOABI: fatal("M5 does not support ARM OABI binaries. Please recompile with an" diff --git a/src/sim/serialize.hh b/src/sim/serialize.hh index 6d4207090..bbf759cf6 100644 --- a/src/sim/serialize.hh +++ b/src/sim/serialize.hh @@ -58,7 +58,7 @@ class EventQueue; * SimObject shouldn't cause the version number to increase, only changes to * existing objects such as serializing/unserializing more state, changing sizes * of serialized arrays, etc. */ -static const uint64_t gem5CheckpointVersion = 0x0000000000000008; +static const uint64_t gem5CheckpointVersion = 0x0000000000000009; template <class T> void paramOut(std::ostream &os, const std::string &name, const T ¶m); diff --git a/src/sim/system.cc b/src/sim/system.cc index 7de483216..e2bf0a3d2 100644 --- a/src/sim/system.cc +++ b/src/sim/system.cc @@ -79,6 +79,7 @@ System::System(Params *p) init_param(p->init_param), physProxy(_systemPort, p->cache_line_size), loadAddrMask(p->load_addr_mask), + loadAddrOffset(p->load_offset), nextPID(0), physmem(name() + ".physmem", p->memories), memoryMode(p->mem_mode), @@ -274,14 +275,15 @@ System::initState() */ if (params()->kernel != "") { // Validate kernel mapping before loading binary - if (!(isMemAddr(kernelStart & loadAddrMask) && - isMemAddr(kernelEnd & loadAddrMask))) { + if (!(isMemAddr((kernelStart & loadAddrMask) + loadAddrOffset) && + isMemAddr((kernelEnd & loadAddrMask) + loadAddrOffset))) { fatal("Kernel is mapped to invalid location (not memory). " - "kernelStart 0x(%x) - kernelEnd 0x(%x)\n", kernelStart, - kernelEnd); + "kernelStart 0x(%x) - kernelEnd 0x(%x) %#x:%#x\n", kernelStart, + kernelEnd, (kernelStart & loadAddrMask) + loadAddrOffset, + (kernelEnd & loadAddrMask) + loadAddrOffset); } // Load program sections into memory - kernel->loadSections(physProxy, loadAddrMask); + kernel->loadSections(physProxy, loadAddrMask, loadAddrOffset); DPRINTF(Loader, "Kernel start = %#x\n", kernelStart); DPRINTF(Loader, "Kernel end = %#x\n", kernelEnd); diff --git a/src/sim/system.hh b/src/sim/system.hh index c8945c8c1..ecef2c4f2 100644 --- a/src/sim/system.hh +++ b/src/sim/system.hh @@ -237,6 +237,13 @@ class System : public MemObject */ Addr loadAddrMask; + /** Offset that should be used for binary/symbol loading. + * This further allows more flexibily than the loadAddrMask allows alone in + * loading kernels and similar. The loadAddrOffset is applied after the + * loadAddrMask. + */ + Addr loadAddrOffset; + protected: uint64_t nextPID; @@ -321,7 +328,7 @@ class System : public MemObject * Called by pseudo_inst to track the number of work items completed by * this system. */ - uint64_t + uint64_t incWorkItemsEnd() { return ++workItemsEnd; @@ -332,13 +339,13 @@ class System : public MemObject * Returns the total number of cpus that have executed work item begin or * ends. */ - int + int markWorkItem(int index) { int count = 0; assert(index < activeCpus.size()); activeCpus[index] = true; - for (std::vector<bool>::iterator i = activeCpus.begin(); + for (std::vector<bool>::iterator i = activeCpus.begin(); i < activeCpus.end(); i++) { if (*i) count++; } diff --git a/system/arm/aarch64_bootloader/LICENSE.txt b/system/arm/aarch64_bootloader/LICENSE.txt new file mode 100644 index 000000000..d68a74e44 --- /dev/null +++ b/system/arm/aarch64_bootloader/LICENSE.txt @@ -0,0 +1,28 @@ +Copyright (c) 2012, ARM Limited +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of ARM nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/system/arm/aarch64_bootloader/boot.S b/system/arm/aarch64_bootloader/boot.S new file mode 100644 index 000000000..78d9710d4 --- /dev/null +++ b/system/arm/aarch64_bootloader/boot.S @@ -0,0 +1,124 @@ +/* + * boot.S - simple register setup code for stand-alone Linux booting + * + * Copyright (C) 2012 ARM Limited. All rights reserved. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE.txt file. + */ + + .text + + .globl _start +_start: + /* + * EL3 initialisation + */ + mrs x0, CurrentEL + cmp x0, #0xc // EL3? + b.ne start_ns // skip EL3 initialisation + + mov x0, #0x30 // RES1 + orr x0, x0, #(1 << 0) // Non-secure EL1 + orr x0, x0, #(1 << 8) // HVC enable + orr x0, x0, #(1 << 10) // 64-bit EL2 + msr scr_el3, x0 + + msr cptr_el3, xzr // Disable copro. traps to EL3 + + ldr x0, =CNTFRQ + msr cntfrq_el0, x0 + + /* + * Check for the primary CPU to avoid a race on the distributor + * registers. + */ + mrs x0, mpidr_el1 + tst x0, #15 + b.ne 1f // secondary CPU + + ldr x1, =GIC_DIST_BASE // GICD_CTLR + mov w0, #3 // EnableGrp0 | EnableGrp1 + str w0, [x1] + +1: ldr x1, =GIC_DIST_BASE + 0x80 // GICD_IGROUPR + mov w0, #~0 // Grp1 interrupts + str w0, [x1], #4 + b.ne 2f // Only local interrupts for secondary CPUs + str w0, [x1], #4 + str w0, [x1], #4 + +2: ldr x1, =GIC_CPU_BASE // GICC_CTLR + ldr w0, [x1] + mov w0, #3 // EnableGrp0 | EnableGrp1 + str w0, [x1] + + mov w0, #1 << 7 // allow NS access to GICC_PMR + str w0, [x1, #4] // GICC_PMR + + msr sctlr_el2, xzr + + /* + * Prepare the switch to the EL2_SP1 mode from EL3 + */ + ldr x0, =start_ns // Return after mode switch + mov x1, #0x3c9 // EL2_SP1 | D | A | I | F + msr elr_el3, x0 + msr spsr_el3, x1 + eret + +start_ns: + /* + * Kernel parameters + */ + mov x0, xzr + mov x1, xzr + mov x2, xzr + mov x3, xzr + + mrs x4, mpidr_el1 + tst x4, #15 + b.eq 2f + + /* + * Secondary CPUs + */ +1: wfe + ldr x4, =PHYS_OFFSET + 0xfff8 + ldr x4, [x4] + cbz x4, 1b + br x4 // branch to the given address + +2: + /* + * UART initialisation (38400 8N1) + */ + ldr x4, =UART_BASE // UART base + mov w5, #0x10 // ibrd + str w5, [x4, #0x24] + mov w5, #0xc300 + orr w5, w5, #0x0001 // cr + str w5, [x4, #0x30] + + /* + * CLCD output site MB + */ + ldr x4, =SYSREGS_BASE + ldr w5, =(1 << 31) | (1 << 30) | (7 << 20) | (0 << 16) // START|WRITE|MUXFPGA|SITE_MB + str wzr, [x4, #0xa0] // V2M_SYS_CFGDATA + str w5, [x4, #0xa4] // V2M_SYS_CFGCTRL + + // set up the arch timer frequency + //ldr x0, =CNTFRQ + //msr cntfrq_el0, x0 + + /* + * Primary CPU + */ + ldr x0, =PHYS_OFFSET + 0x8000000 // device tree blob + ldr x6, =PHYS_OFFSET + 0x80000 // kernel start address + br x6 + + .ltorg + + .org 0x200 diff --git a/system/arm/aarch64_bootloader/makefile b/system/arm/aarch64_bootloader/makefile new file mode 100644 index 000000000..4428d2620 --- /dev/null +++ b/system/arm/aarch64_bootloader/makefile @@ -0,0 +1,4 @@ +build: + aarch64-linux-gnu-gcc -c -DPHYS_OFFSET=0x80000000 -DCNTFRQ=0x01800000 -DUART_BASE=0x1c090000 -DSYSREGS_BASE=0x1c010000 -DGIC_DIST_BASE=0x2c001000 -DGIC_CPU_BASE=0x2c002000 -Dkernel=0x80080000 -Dmbox=0x8000fff8 -Ddtb=0x80000100 -o boot_emm.o -march=armv8-a boot.S + aarch64-linux-gnu-ld -o boot_emm.arm64 -N -Ttext 0x00000010 boot_emm.o -non_shared -static + rm boot_emm.o
\ No newline at end of file diff --git a/util/cpt_upgrader.py b/util/cpt_upgrader.py index e6ee7d562..fac9e07a7 100755 --- a/util/cpt_upgrader.py +++ b/util/cpt_upgrader.py @@ -225,9 +225,325 @@ def from_7(cpt): # Search for all ISA sections if re.search('.*sys.*\.cpu.*\.isa', sec): mr = cpt.get(sec, 'miscRegs').split() - # Add dummy value for MISCREG_TEEHBR - mr.insert(51,0); - cpt.set(sec, 'miscRegs', ' '.join(str(x) for x in mr)) + if len(mr) == 161: + print "MISCREG_TEEHBR already seems to be inserted." + else: + # Add dummy value for MISCREG_TEEHBR + mr.insert(51,0); + cpt.set(sec, 'miscRegs', ' '.join(str(x) for x in mr)) + +# Version 9 of the checkpoint adds an all ARMv8 state +def from_8(cpt): + if cpt.get('root','isa') != 'arm': + return + import re + print "Warning: The size of the FP register file has changed. "\ + "To get similar results you need to adjust the number of "\ + "physical registers in the CPU you're restoring into by "\ + "NNNN." + # Find the CPU context's and upgrade their registers + for sec in cpt.sections(): + re_xc_match = re.match('^.*?sys.*?\.cpu(\d+)*\.xc\.*', sec) + if not re_xc_match: + continue + + # Update floating point regs + fpr = cpt.get(sec, 'floatRegs.i').split() + # v8 has 128 normal fp and 32 special fp regs compared + # to v7's 64 normal fp and 8 special fp regs. + # Insert the extra normal fp registers at end of v7 normal fp regs + for x in xrange(64): + fpr.insert(64, "0") + # Append the extra special registers + for x in xrange(24): + fpr.append("0") + cpt.set(sec, 'floatRegs.i', ' '.join(str(x) for x in fpr)) + + ir = cpt.get(sec, 'intRegs').split() + # Add in v8 int reg state + # Splice in R13_HYP + ir.insert(20, "0") + # Splice in INTREG_DUMMY and SP0 - SP3 + ir.extend(["0", "0", "0", "0", "0"]) + cpt.set(sec, 'intRegs', ' '.join(str(x) for x in ir)) + + # Update the cpu interrupt field + for sec in cpt.sections(): + re_int_match = re.match("^.*?sys.*?\.cpu(\d+)*$", sec) + if not re_int_match: + continue + + irqs = cpt.get(sec, "interrupts").split() + irqs.append("false") + irqs.append("false") + cpt.set(sec, "interrupts", ' '.join(str(x) for x in irqs)) + + # Update the per cpu interrupt structure + for sec in cpt.sections(): + re_int_match = re.match("^.*?sys.*?\.cpu(\d+)*\.interrupts$", sec) + if not re_int_match: + continue + + irqs = cpt.get(sec, "interrupts").split() + irqs.append("false") + irqs.append("false") + cpt.set(sec, "interrupts", ' '.join(str(x) for x in irqs)) + + # Update the misc regs and add in new isa specific fields + for sec in cpt.sections(): + re_isa_match = re.match("^.*?sys.*?\.cpu(\d+)*\.isa$", sec) + if not re_isa_match: + continue + + cpt.set(sec, 'haveSecurity', 'false') + cpt.set(sec, 'haveLPAE', 'false') + cpt.set(sec, 'haveVirtualization', 'false') + cpt.set(sec, 'haveLargeAsid64', 'false') + cpt.set(sec, 'physAddrRange64', '40') + + # splice in the new misc registers, ~200 -> 605 registers, + # ordering does not remain consistent + mr_old = cpt.get(sec, 'miscRegs').split() + mr_new = [ '0' for x in xrange(605) ] + + # map old v7 miscRegs to new v8 miscRegs + mr_new[0] = mr_old[0] # CPSR + mr_new[16] = mr_old[1] # CPSR_Q + mr_new[1] = mr_old[2] # SPSR + mr_new[2] = mr_old[3] # SPSR_FIQ + mr_new[3] = mr_old[4] # SPSR_IRQ + mr_new[4] = mr_old[5] # SPSR_SVC + mr_new[5] = mr_old[6] # SPSR_MON + mr_new[8] = mr_old[7] # SPSR_UND + mr_new[6] = mr_old[8] # SPSR_ABT + mr_new[432] = mr_old[9] # FPSR + mr_new[10] = mr_old[10] # FPSID + mr_new[11] = mr_old[11] # FPSCR + mr_new[18] = mr_old[12] # FPSCR_QC + mr_new[17] = mr_old[13] # FPSCR_EXC + mr_new[14] = mr_old[14] # FPEXC + mr_new[13] = mr_old[15] # MVFR0 + mr_new[12] = mr_old[16] # MVFR1 + mr_new[28] = mr_old[17] # SCTLR_RST, + mr_new[29] = mr_old[18] # SEV_MAILBOX, + mr_new[30] = mr_old[19] # DBGDIDR + mr_new[31] = mr_old[20] # DBGDSCR_INT, + mr_new[33] = mr_old[21] # DBGDTRRX_INT, + mr_new[34] = mr_old[22] # DBGTRTX_INT, + mr_new[35] = mr_old[23] # DBGWFAR, + mr_new[36] = mr_old[24] # DBGVCR, + #mr_new[] = mr_old[25] # DBGECR -> UNUSED, + #mr_new[] = mr_old[26] # DBGDSCCR -> UNUSED, + #mr_new[] = mr_old[27] # DBGSMCR -> UNUSED, + mr_new[37] = mr_old[28] # DBGDTRRX_EXT, + mr_new[38] = mr_old[29] # DBGDSCR_EXT, + mr_new[39] = mr_old[30] # DBGDTRTX_EXT, + #mr_new[] = mr_old[31] # DBGDRCR -> UNUSED, + mr_new[41] = mr_old[32] # DBGBVR, + mr_new[47] = mr_old[33] # DBGBCR, + #mr_new[] = mr_old[34] # DBGBVR_M -> UNUSED, + #mr_new[] = mr_old[35] # DBGBCR_M -> UNUSED, + mr_new[61] = mr_old[36] # DBGDRAR, + #mr_new[] = mr_old[37] # DBGBXVR_M -> UNUSED, + mr_new[64] = mr_old[38] # DBGOSLAR, + #mr_new[] = mr_old[39] # DBGOSSRR -> UNUSED, + mr_new[66] = mr_old[40] # DBGOSDLR, + mr_new[67] = mr_old[41] # DBGPRCR, + #mr_new[] = mr_old[42] # DBGPRSR -> UNUSED, + mr_new[68] = mr_old[43] # DBGDSAR, + #mr_new[] = mr_old[44] # DBGITCTRL -> UNUSED, + mr_new[69] = mr_old[45] # DBGCLAIMSET, + mr_new[70] = mr_old[46] # DBGCLAIMCLR, + mr_new[71] = mr_old[47] # DBGAUTHSTATUS, + mr_new[72] = mr_old[48] # DBGDEVID2, + mr_new[73] = mr_old[49] # DBGDEVID1, + mr_new[74] = mr_old[50] # DBGDEVID, + mr_new[77] = mr_old[51] # TEEHBR, + mr_new[109] = mr_old[52] # v7 SCTLR -> aarc32 SCTLR_NS + mr_new[189] = mr_old[53] # DCCISW, + mr_new[188] = mr_old[54] # DCCIMVAC, + mr_new[183] = mr_old[55] # DCCMVAC, + mr_new[271] = mr_old[56] # v7 CONTEXTIDR -> aarch32 CONTEXTIDR_NS, + mr_new[274] = mr_old[57] # v7 TPIDRURW -> aarch32 TPIDRURW_NS, + mr_new[277] = mr_old[58] # v7 TPIDRURO -> aarch32 TPIDRURO_NS, + mr_new[280] = mr_old[59] # v7 TPIDRPRW -> aarch32 TPIDRPRW_NS, + mr_new[170] = mr_old[60] # CP15ISB, + mr_new[185] = mr_old[61] # CP15DSB, + mr_new[186] = mr_old[62] # CP15DMB, + mr_new[114] = mr_old[63] # CPACR, + mr_new[101] = mr_old[64] # CLIDR, + mr_new[100] = mr_old[65] # CCSIDR, + mr_new[104] = mr_old[66] # v7 CSSELR -> aarch32 CSSELR_NS, + mr_new[163] = mr_old[67] # ICIALLUIS, + mr_new[168] = mr_old[68] # ICIALLU, + mr_new[169] = mr_old[69] # ICIMVAU, + mr_new[172] = mr_old[70] # BPIMVA, + mr_new[164] = mr_old[71] # BPIALLIS, + mr_new[171] = mr_old[72] # BPIALL, + mr_new[80] = mr_old[73] # MIDR, + mr_new[126] = mr_old[74] # v7 TTBR0 -> aarch32 TTBR0_NS, + mr_new[129] = mr_old[75] # v7 TTBR1 -> aarch32 TTBR1_NS, + mr_new[83] = mr_old[76] # TLBTR, + mr_new[137] = mr_old[77] # v7 DACR -> aarch32 DACR_NS, + mr_new[192] = mr_old[78] # TLBIALLIS, + mr_new[193] = mr_old[79] # TLBIMVAIS, + mr_new[194] = mr_old[80] # TLBIASIDIS, + mr_new[195] = mr_old[81] # TLBIMVAAIS, + mr_new[198] = mr_old[82] # ITLBIALL, + mr_new[199] = mr_old[83] # ITLBIMVA, + mr_new[200] = mr_old[84] # ITLBIASID, + mr_new[201] = mr_old[85] # DTLBIALL, + mr_new[202] = mr_old[86] # DTLBIMVA, + mr_new[203] = mr_old[87] # DTLBIASID, + mr_new[204] = mr_old[88] # TLBIALL, + mr_new[205] = mr_old[89] # TLBIMVA, + mr_new[206] = mr_old[90] # TLBIASID, + mr_new[207] = mr_old[91] # TLBIMVAA, + mr_new[140] = mr_old[92] # v7 DFSR -> aarch32 DFSR_NS, + mr_new[143] = mr_old[93] # v7 IFSR -> aarch32 IFSR_NS, + mr_new[155] = mr_old[94] # v7 DFAR -> aarch32 DFAR_NS, + mr_new[158] = mr_old[95] # v7 IFAR -> aarch32 IFAR_NS, + mr_new[84] = mr_old[96] # MPIDR, + mr_new[241] = mr_old[97] # v7 PRRR -> aarch32 PRRR_NS, + mr_new[247] = mr_old[98] # v7 NMRR -> aarch32 NMRR_NS, + mr_new[131] = mr_old[99] # TTBCR, + mr_new[86] = mr_old[100] # ID_PFR0, + mr_new[81] = mr_old[101] # CTR, + mr_new[115] = mr_old[102] # SCR, + # Set the non-secure bit + scr = int(mr_new[115]) + scr = scr | 0x1 + mr_new[115] = str(scr) + ### + mr_new[116] = mr_old[103] # SDER, + mr_new[165] = mr_old[104] # PAR, + mr_new[175] = mr_old[105] # V2PCWPR -> ATS1CPR, + mr_new[176] = mr_old[106] # V2PCWPW -> ATS1CPW, + mr_new[177] = mr_old[107] # V2PCWUR -> ATS1CUR, + mr_new[178] = mr_old[108] # V2PCWUW -> ATS1CUW, + mr_new[179] = mr_old[109] # V2POWPR -> ATS12NSOPR, + mr_new[180] = mr_old[110] # V2POWPW -> ATS12NSOPW, + mr_new[181] = mr_old[111] # V2POWUR -> ATS12NSOUR, + mr_new[182] = mr_old[112] # V2POWUW -> ATS12NWOUW, + mr_new[90] = mr_old[113] # ID_MMFR0, + mr_new[92] = mr_old[114] # ID_MMFR2, + mr_new[93] = mr_old[115] # ID_MMFR3, + mr_new[112] = mr_old[116] # v7 ACTLR -> aarch32 ACTLR_NS + mr_new[222] = mr_old[117] # PMCR, + mr_new[230] = mr_old[118] # PMCCNTR, + mr_new[223] = mr_old[119] # PMCNTENSET, + mr_new[224] = mr_old[120] # PMCNTENCLR, + mr_new[225] = mr_old[121] # PMOVSR, + mr_new[226] = mr_old[122] # PMSWINC, + mr_new[227] = mr_old[123] # PMSELR, + mr_new[228] = mr_old[124] # PMCEID0, + mr_new[229] = mr_old[125] # PMCEID1, + mr_new[231] = mr_old[126] # PMXEVTYPER, + mr_new[233] = mr_old[127] # PMXEVCNTR, + mr_new[234] = mr_old[128] # PMUSERENR, + mr_new[235] = mr_old[129] # PMINTENSET, + mr_new[236] = mr_old[130] # PMINTENCLR, + mr_new[94] = mr_old[131] # ID_ISAR0, + mr_new[95] = mr_old[132] # ID_ISAR1, + mr_new[96] = mr_old[133] # ID_ISAR2, + mr_new[97] = mr_old[134] # ID_ISAR3, + mr_new[98] = mr_old[135] # ID_ISAR4, + mr_new[99] = mr_old[136] # ID_ISAR5, + mr_new[20] = mr_old[137] # LOCKFLAG, + mr_new[19] = mr_old[138] # LOCKADDR, + mr_new[87] = mr_old[139] # ID_PFR1, + # Set up the processor features register + pfr = int(mr_new[87]) + pfr = pfr | 0x1011 + mr_new[87] = str(pfr) + ### + mr_new[238] = mr_old[140] # L2CTLR, + mr_new[82] = mr_old[141] # TCMTR + mr_new[88] = mr_old[142] # ID_DFR0, + mr_new[89] = mr_old[143] # ID_AFR0, + mr_new[91] = mr_old[144] # ID_MMFR1, + mr_new[102] = mr_old[145] # AIDR, + mr_new[146] = mr_old[146] # v7 ADFSR -> aarch32 ADFSR_NS, + mr_new[148] = mr_old[147] # AIFSR, + mr_new[173] = mr_old[148] # DCIMVAC, + mr_new[174] = mr_old[149] # DCISW, + mr_new[184] = mr_old[150] # MCCSW -> DCCSW, + mr_new[187] = mr_old[151] # DCCMVAU, + mr_new[117] = mr_old[152] # NSACR, + mr_new[262] = mr_old[153] # VBAR, + mr_new[265] = mr_old[154] # MVBAR, + mr_new[267] = mr_old[155] # ISR, + mr_new[269] = mr_old[156] # FCEIDR -> FCSEIDR, + #mr_new[] = mr_old[157] # L2LATENCY -> UNUSED, + #mr_new[] = mr_old[158] # CRN15 -> UNUSED, + mr_new[599] = mr_old[159] # NOP + mr_new[600] = mr_old[160] # RAZ, + + # Set the new miscRegs structure + cpt.set(sec, 'miscRegs', ' '.join(str(x) for x in mr_new)) + + cpu_prefix = {} + # Add in state for ITB/DTB + for sec in cpt.sections(): + re_tlb_match = re.match('(^.*?sys.*?\.cpu(\d+)*)\.(dtb|itb)$', sec) + if not re_tlb_match: + continue + + cpu_prefix[re_tlb_match.group(1)] = True # Save off prefix to add + # Set the non-secure bit (bit 9) to 1 for attributes + attr = int(cpt.get(sec, '_attr')) + attr = attr | 0x200 + cpt.set(sec, '_attr', str(attr)) + cpt.set(sec, 'haveLPAE', 'false') + cpt.set(sec, 'directToStage2', 'false') + cpt.set(sec, 'stage2Req', 'false') + cpt.set(sec, 'bootUncacheability', 'true') + + # Add in extra state for the new TLB Entries + for sec in cpt.sections(): + re_tlbentry_match = re.match('(^.*?sys.*?\.cpu(\d+)*)\.(dtb|itb).TlbEntry\d+$', sec) + if not re_tlbentry_match: + continue + + # Add in the new entries + cpt.set(sec, 'longDescFormat', 'false') + cpt.set(sec, 'vmid', '0') + cpt.set(sec, 'isHyp', 'false') + valid = cpt.get(sec, 'valid') + if valid == 'true': + cpt.set(sec, 'ns', 'true') + cpt.set(sec, 'nstid', 'true') + cpt.set(sec, 'pxn', 'true') + cpt.set(sec, 'hap', '3') + # All v7 code used 2 level page tables + cpt.set(sec, 'lookupLevel', '2') + attr = int(cpt.get(sec, 'attributes')) + # set the non-secure bit (bit 9) to 1 + # as no previous v7 code used secure code + attr = attr | 0x200 + cpt.set(sec, 'attributes', str(attr)) + else: + cpt.set(sec, 'ns', 'false') + cpt.set(sec, 'nstid', 'false') + cpt.set(sec, 'pxn', 'false') + cpt.set(sec, 'hap', '0') + cpt.set(sec, 'lookupLevel', '0') + cpt.set(sec, 'outerShareable', 'false') + + # Add d/istage2_mmu and d/istage2_mmu.stage2_tlb + for key in cpu_prefix: + for suffix in ['.istage2_mmu', '.dstage2_mmu']: + new_sec = key + suffix + cpt.add_section(new_sec) + new_sec = key + suffix + ".stage2_tlb" + cpt.add_section(new_sec) + # Fill in tlb info with some defaults + cpt.set(new_sec, '_attr', '0') + cpt.set(new_sec, 'haveLPAE', 'false') + cpt.set(new_sec, 'directToStage2', 'false') + cpt.set(new_sec, 'stage2Req', 'false') + cpt.set(new_sec, 'bootUncacheability', 'false') + cpt.set(new_sec, 'num_entries', '0') migrations = [] @@ -239,6 +555,7 @@ migrations.append(from_4) migrations.append(from_5) migrations.append(from_6) migrations.append(from_7) +migrations.append(from_8) verbose_print = False diff --git a/util/m5/m5op_arm_A64.S b/util/m5/m5op_arm_A64.S new file mode 100644 index 000000000..a422a3050 --- /dev/null +++ b/util/m5/m5op_arm_A64.S @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2010-2013 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Copyright (c) 2003-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Nathan Binkert + * Ali Saidi + * Chander Sudanthi + */ + +#define m5_op 0xFF + +#include "m5ops.h" + +#define INST(op, ra, rb, func) \ + .long (((op) << 24) | ((func) << 16) | ((ra) << 12) | (0x1 << 8) | (0x1 << 4) | (rb)) +/* m5ops m5func ra coproc 1 op=1 rb */ + +#define LEAF(func) \ + .globl func; \ +func: + +#define RET \ + RET + +#define END(func) \ + +#define SIMPLE_OP(_f, _o) \ + LEAF(_f) \ + _o; \ + RET; \ + END(_f) + +#define ARM INST(m5_op, 0, 0, arm_func) +#define QUIESCE INST(m5_op, 0, 0, quiesce_func) +#define QUIESCENS INST(m5_op, 0, 0, quiescens_func) +#define QUIESCECYC INST(m5_op, 0, 0, quiescecycle_func) +#define QUIESCETIME INST(m5_op, 0, 0, quiescetime_func) +#define RPNS INST(m5_op, 0, 0, rpns_func) +#define WAKE_CPU INST(m5_op, 0, 0, wakecpu_func) +#define M5EXIT INST(m5_op, 0, 0, exit_func) +#define INITPARAM INST(m5_op, 0, 0, initparam_func) +#define LOADSYMBOL INST(m5_op, 0, 0, loadsymbol_func) +#define RESET_STATS INST(m5_op, 0, 0, resetstats_func) +#define DUMP_STATS INST(m5_op, 0, 0, dumpstats_func) +#define DUMPRST_STATS INST(m5_op, 0, 0, dumprststats_func) +#define CHECKPOINT INST(m5_op, 0, 0, ckpt_func) +#define READFILE INST(m5_op, 0, 0, readfile_func) +#define WRITEFILE INST(m5_op, 0, 0, writefile_func) +#define DEBUGBREAK INST(m5_op, 0, 0, debugbreak_func) +#define SWITCHCPU INST(m5_op, 0, 0, switchcpu_func) +#define ADDSYMBOL INST(m5_op, 0, 0, addsymbol_func) +#define PANIC INST(m5_op, 0, 0, panic_func) +#define WORK_BEGIN INST(m5_op, 0, 0, work_begin_func) +#define WORK_END INST(m5_op, 0, 0, work_end_func) + +#define AN_BSM INST(m5_op, an_bsm, 0, annotate_func) +#define AN_ESM INST(m5_op, an_esm, 0, annotate_func) +#define AN_BEGIN INST(m5_op, an_begin, 0, annotate_func) +#define AN_END INST(m5_op, an_end, 0, annotate_func) +#define AN_Q INST(m5_op, an_q, 0, annotate_func) +#define AN_RQ INST(m5_op, an_rq, 0, annotate_func) +#define AN_DQ INST(m5_op, an_dq, 0, annotate_func) +#define AN_WF INST(m5_op, an_wf, 0, annotate_func) +#define AN_WE INST(m5_op, an_we, 0, annotate_func) +#define AN_WS INST(m5_op, an_ws, 0, annotate_func) +#define AN_SQ INST(m5_op, an_sq, 0, annotate_func) +#define AN_AQ INST(m5_op, an_aq, 0, annotate_func) +#define AN_PQ INST(m5_op, an_pq, 0, annotate_func) +#define AN_L INST(m5_op, an_l, 0, annotate_func) +#define AN_IDENTIFY INST(m5_op, an_identify, 0, annotate_func) +#define AN_GETID INST(m5_op, an_getid, 0, annotate_func) + +.text + +SIMPLE_OP(arm, ARM) +SIMPLE_OP(quiesce, QUIESCE) +SIMPLE_OP(quiesceNs, QUIESCENS) +SIMPLE_OP(quiesceCycle, QUIESCECYC) +SIMPLE_OP(quiesceTime, QUIESCETIME) +SIMPLE_OP(rpns, RPNS) +SIMPLE_OP(wakeCPU, WAKE_CPU) +SIMPLE_OP(m5_exit, M5EXIT) +SIMPLE_OP(m5_initparam, INITPARAM) +SIMPLE_OP(m5_loadsymbol, LOADSYMBOL) +SIMPLE_OP(m5_reset_stats, RESET_STATS) +SIMPLE_OP(m5_dump_stats, DUMP_STATS) +SIMPLE_OP(m5_dumpreset_stats, DUMPRST_STATS) +SIMPLE_OP(m5_checkpoint, CHECKPOINT) +SIMPLE_OP(m5_readfile, READFILE) +SIMPLE_OP(m5_writefile, WRITEFILE) +SIMPLE_OP(m5_debugbreak, DEBUGBREAK) +SIMPLE_OP(m5_switchcpu, SWITCHCPU) +SIMPLE_OP(m5_addsymbol, ADDSYMBOL) +SIMPLE_OP(m5_panic, PANIC) +SIMPLE_OP(m5_work_begin, WORK_BEGIN) +SIMPLE_OP(m5_work_end, WORK_END) + +SIMPLE_OP(m5a_bsm, AN_BSM) +SIMPLE_OP(m5a_esm, AN_ESM) +SIMPLE_OP(m5a_begin, AN_BEGIN) +SIMPLE_OP(m5a_end, AN_END) +SIMPLE_OP(m5a_q, AN_Q) +SIMPLE_OP(m5a_rq, AN_RQ) +SIMPLE_OP(m5a_dq, AN_DQ) +SIMPLE_OP(m5a_wf, AN_WF) +SIMPLE_OP(m5a_we, AN_WE) +SIMPLE_OP(m5a_ws, AN_WS) +SIMPLE_OP(m5a_sq, AN_SQ) +SIMPLE_OP(m5a_aq, AN_AQ) +SIMPLE_OP(m5a_pq, AN_PQ) +SIMPLE_OP(m5a_l, AN_L) +SIMPLE_OP(m5a_identify, AN_IDENTIFY) +SIMPLE_OP(m5a_getid, AN_GETID) + |