diff --git a/src/arch/arm/ArmISA.py b/src/arch/arm/ArmISA.py index e73046d08b..37970dce83 100644 --- a/src/arch/arm/ArmISA.py +++ b/src/arch/arm/ArmISA.py @@ -58,6 +58,10 @@ class ArmDefaultSERelease(ArmRelease): "FEAT_FCMA", "FEAT_JSCVT", "FEAT_PAuth", + # Armv8.4 + "FEAT_FLAGM", + # Armv8.5 + "FEAT_FLAGM2", # Armv9.2 "FEAT_SME", # Other diff --git a/src/arch/arm/ArmSystem.py b/src/arch/arm/ArmSystem.py index 9e2da8e255..e08108fa07 100644 --- a/src/arch/arm/ArmSystem.py +++ b/src/arch/arm/ArmSystem.py @@ -85,6 +85,9 @@ class ArmExtension(ScopedEnum): # Armv8.4 "FEAT_SEL2", "FEAT_TLBIOS", + "FEAT_FLAGM", + # Armv8.5 + "FEAT_FLAGM2", # Armv9.2 "FEAT_SME", # Optional in Armv9.2 # Others @@ -164,6 +167,9 @@ class ArmDefaultRelease(Armv8): # Armv8.4 "FEAT_SEL2", "FEAT_TLBIOS", + "FEAT_FLAGM", + # Armv8.5 + "FEAT_FLAGM2", # Armv9.2 "FEAT_SME", ] @@ -194,11 +200,15 @@ class Armv83(Armv82): class Armv84(Armv83): - extensions = Armv83.extensions + ["FEAT_SEL2", "FEAT_TLBIOS"] + extensions = Armv83.extensions + ["FEAT_SEL2", "FEAT_TLBIOS", "FEAT_FLAGM"] -class Armv92(Armv84): - extensions = Armv84.extensions + ["FEAT_SME"] +class Armv85(Armv84): + extensions = Armv84.extensions + ["FEAT_FLAGM2"] + + +class Armv92(Armv85): + extensions = Armv85.extensions + ["FEAT_SME"] class ArmSystem(System): diff --git a/src/arch/arm/insts/misc64.cc b/src/arch/arm/insts/misc64.cc index c7423d9e72..4f573fca83 100644 --- a/src/arch/arm/insts/misc64.cc +++ b/src/arch/arm/insts/misc64.cc @@ -54,6 +54,27 @@ ImmOp64::generateDisassembly(Addr pc, const loader::SymbolTable *symtab) const return ss.str(); } +std::string +RegOp64::generateDisassembly(Addr pc, const loader::SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss, "", false); + printIntReg(ss, op1); + return ss.str(); +} + +std::string +RegImmImmOp64::generateDisassembly(Addr pc, const loader::SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss, "", false); + printIntReg(ss, op1); + ccprintf(ss, "#0x%x", imm1); + ss << ", "; + ccprintf(ss, "#0x%x", imm2); + return ss.str(); +} + std::string RegRegImmImmOp64::generateDisassembly( Addr pc, const loader::SymbolTable *symtab) const diff --git a/src/arch/arm/insts/misc64.hh b/src/arch/arm/insts/misc64.hh index b7b66c2674..3a67210b92 100644 --- a/src/arch/arm/insts/misc64.hh +++ b/src/arch/arm/insts/misc64.hh @@ -57,6 +57,38 @@ class ImmOp64 : public ArmISA::ArmStaticInst Addr pc, const loader::SymbolTable *symtab) const override; }; +class RegOp64 : public ArmISA::ArmStaticInst +{ + protected: + RegIndex op1; + + RegOp64(const char *mnem, ArmISA::ExtMachInst _machInst, + OpClass __opClass, RegIndex _op1) : + ArmISA::ArmStaticInst(mnem, _machInst, __opClass), op1(_op1) + {} + + std::string generateDisassembly( + Addr pc, const loader::SymbolTable *symtab) const override; +}; + +class RegImmImmOp64 : public ArmISA::ArmStaticInst +{ + protected: + RegIndex op1; + uint64_t imm1; + uint64_t imm2; + + RegImmImmOp64(const char *mnem, ArmISA::ExtMachInst _machInst, + OpClass __opClass, RegIndex _op1, + uint64_t _imm1, uint64_t _imm2) : + ArmISA::ArmStaticInst(mnem, _machInst, __opClass), + op1(_op1), imm1(_imm1), imm2(_imm2) + {} + + std::string generateDisassembly( + Addr pc, const loader::SymbolTable *symtab) const override; +}; + class RegRegImmImmOp64 : public ArmISA::ArmStaticInst { protected: diff --git a/src/arch/arm/isa/formats/aarch64.isa b/src/arch/arm/isa/formats/aarch64.isa index 0aafa9e465..9ad2de2c72 100644 --- a/src/arch/arm/isa/formats/aarch64.isa +++ b/src/arch/arm/isa/formats/aarch64.isa @@ -424,6 +424,15 @@ namespace Aarch64 // MSR immediate: moving immediate value to selected // bits of the PSTATE switch (op1 << 3 | op2) { + case 0x0: + // CFINV + return new Cfinv(machInst); + case 0x1: + // XAFLAG + return new Xaflag(machInst); + case 0x2: + // AXFLAG + return new Axflag(machInst); case 0x3: // UAO return new MsrImm64( @@ -2080,6 +2089,26 @@ namespace Aarch64 } } + StaticInstPtr + decodeRotIntoFlags(ExtMachInst machInst) + { + RegIndex rn = (RegIndex)(uint8_t)bits(machInst, 9, 5); + uint8_t imm6 = bits(machInst, 20, 15); + uint8_t mask = bits(machInst, 3, 0); + return new Rmif(machInst, rn, imm6, mask); + } + + StaticInstPtr + decodeEvalIntoFlags(ExtMachInst machInst) + { + RegIndex rn = (RegIndex)(uint8_t)bits(machInst, 9, 5); + int sz = bits(machInst, 14); + if (sz) + return new Setf16(machInst, rn); + else + return new Setf8(machInst, rn); + } + StaticInstPtr decodeCondCompare(ExtMachInst machInst) { @@ -2328,7 +2357,16 @@ namespace Aarch64 switch (bits(machInst, 23, 22)) { case 0x0: - return decodeAddSubWithCarry(machInst); + switch (bits(machInst, 11, 10)) { + case 0b00: + return decodeAddSubWithCarry(machInst); + case 0b01: + return decodeRotIntoFlags(machInst); + case 0b10: + return decodeEvalIntoFlags(machInst); + default: // 0b11 + return new Unknown64(machInst); + } case 0x1: return decodeCondCompare(machInst); case 0x2: diff --git a/src/arch/arm/isa/insts/misc64.isa b/src/arch/arm/isa/insts/misc64.isa index abe30fce63..46d72d21c3 100644 --- a/src/arch/arm/isa/insts/misc64.isa +++ b/src/arch/arm/isa/insts/misc64.isa @@ -248,4 +248,81 @@ let {{ header_output += ImmOp64Declare.subst(hltIop) decoder_output += SemihostConstructor64.subst(hltIop) exec_output += BasicExecute.subst(hltIop) + + flagmCheckCode = ''' + if (!HaveExt(xc->tcBase(), ArmExtension::FEAT_FLAGM)) { + return std::make_shared( + machInst, true); + } + ''' + cfinvCode = 'CondCodesC = ~CondCodesC' + cfinvIop = ArmInstObjParams("cfinv", "Cfinv", "ArmStaticInst", + flagmCheckCode + cfinvCode) + header_output += BasicDeclare.subst(cfinvIop) + decoder_output += BasicConstructor64.subst(cfinvIop) + exec_output += BasicExecute.subst(cfinvIop) + + axflagCode = ''' + bool z = CondCodesNZ || CondCodesV; + bool c = CondCodesC && !CondCodesV; + CondCodesNZ = z; // This implies zeroing PSTATE.N + CondCodesC = c; + CondCodesV = 0; + ''' + axflagIop = ArmInstObjParams("axflag", "Axflag", "ArmStaticInst", + flagmCheckCode + axflagCode) + header_output += BasicDeclare.subst(axflagIop) + decoder_output += BasicConstructor64.subst(axflagIop) + exec_output += BasicExecute.subst(axflagIop) + + xaflagCode = ''' + const RegVal nz = CondCodesNZ; + const RegVal n = !CondCodesC && !bits(nz, 0); + const RegVal z = CondCodesC && bits(nz, 0); + const RegVal c = CondCodesC || bits(nz, 0); + const RegVal v = !CondCodesC && bits(nz, 0); + + CondCodesNZ = (n << 1) | z; + CondCodesC = c; + CondCodesV = v; + ''' + xaflagIop = ArmInstObjParams("xaflag", "Xaflag", "ArmStaticInst", + flagmCheckCode + xaflagCode) + header_output += BasicDeclare.subst(xaflagIop) + decoder_output += BasicConstructor64.subst(xaflagIop) + exec_output += BasicExecute.subst(xaflagIop) + + rmifCode = ''' + RegVal tmp = XOp1 << imm1; + int nz = CondCodesNZ; + if (bits(imm2, 0)) CondCodesV = bits(tmp, 0); + if (bits(imm2, 1)) CondCodesC = bits(tmp, 1); + if (bits(imm2, 2)) nz = insertBits(nz, 0, bits(tmp, 2)); + if (bits(imm2, 3)) nz = insertBits(nz, 1, bits(tmp, 3)); + + CondCodesNZ = nz; + ''' + rmifIop = ArmInstObjParams("rmif", "Rmif", "RegImmImmOp64", + flagmCheckCode + rmifCode) + header_output += RegImmImmOp64Declare.subst(rmifIop) + decoder_output += RegImmImmOp64Constructor.subst(rmifIop) + exec_output += BasicExecute.subst(rmifIop) + + setfCode = ''' + const int msb = %d; + RegVal tmp = Op1; + CondCodesNZ = (bits(tmp, msb) << 1) | (bits(tmp, msb, 0) ? 0 : 1); + CondCodesV = bits(tmp, msb) ^ bits(tmp, msb + 1); + ''' + setf8Iop = ArmInstObjParams("setf8", "Setf8", "RegOp64", + flagmCheckCode + setfCode % 7) + header_output += RegOp64Declare.subst(setf8Iop) + decoder_output += RegOp64Constructor.subst(setf8Iop) + exec_output += BasicExecute.subst(setf8Iop) + + setf16Iop = ArmInstObjParams("setf16", "Setf16", "RegOp64", + flagmCheckCode + setfCode % 15) + header_output += RegOp64Declare.subst(setf16Iop) + decoder_output += RegOp64Constructor.subst(setf16Iop) + exec_output += BasicExecute.subst(setf16Iop) }}; diff --git a/src/arch/arm/isa/templates/misc64.isa b/src/arch/arm/isa/templates/misc64.isa index af6b4c6888..a2024f713c 100644 --- a/src/arch/arm/isa/templates/misc64.isa +++ b/src/arch/arm/isa/templates/misc64.isa @@ -58,6 +58,56 @@ def template ImmOp64Constructor {{ } }}; +def template RegOp64Declare {{ +class %(class_name)s : public %(base_class)s +{ + private: + %(reg_idx_arr_decl)s; + + public: + // Constructor + %(class_name)s(ExtMachInst machInst, RegIndex _op1); + + Fault execute(ExecContext *, trace::InstRecord *) const override; +}; +}}; + +def template RegOp64Constructor {{ + %(class_name)s::%(class_name)s(ExtMachInst machInst, RegIndex _op1) : + %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, _op1) + { + %(set_reg_idx_arr)s; + %(constructor)s; + } +}}; + +def template RegImmImmOp64Declare {{ +class %(class_name)s : public %(base_class)s +{ + private: + %(reg_idx_arr_decl)s; + + public: + // Constructor + %(class_name)s(ExtMachInst machInst, + RegIndex _op1, + uint64_t _imm1, uint64_t _imm2); + Fault execute(ExecContext *, trace::InstRecord *) const override; +}; +}}; + +def template RegImmImmOp64Constructor {{ + %(class_name)s::%(class_name)s(ExtMachInst machInst, + RegIndex _op1, + uint64_t _imm1, uint64_t _imm2) : + %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + _op1, _imm1, _imm2) + { + %(set_reg_idx_arr)s; + %(constructor)s; + } +}}; + def template RegRegImmImmOp64Declare {{ class %(class_name)s : public %(base_class)s { diff --git a/src/arch/arm/process.cc b/src/arch/arm/process.cc index 9b0f3b269f..b2378cc505 100644 --- a/src/arch/arm/process.cc +++ b/src/arch/arm/process.cc @@ -314,6 +314,11 @@ ArmProcess64::armHwcapImpl2() const uint64_t hwcap = 0; + ThreadContext *tc = system->threads[contextIds[0]]; + + const AA64ISAR0 isa_r0 = tc->readMiscReg(MISCREG_ID_AA64ISAR0_EL1); + hwcap |= (isa_r0.ts >= 2) ? Arm_Flagm2 : Arm_None; + return hwcap; } diff --git a/src/arch/arm/regs/misc.cc b/src/arch/arm/regs/misc.cc index ec5670e647..9e633c0c84 100644 --- a/src/arch/arm/regs/misc.cc +++ b/src/arch/arm/regs/misc.cc @@ -3891,6 +3891,9 @@ ISA::initializeMiscRegMetadata() isar0_el1.rdm = release->has(ArmExtension::FEAT_RDM) ? 0x1 : 0x0; isar0_el1.tme = release->has(ArmExtension::TME) ? 0x1 : 0x0; isar0_el1.tlb = release->has(ArmExtension::FEAT_TLBIOS) ? 0x1 : 0x0; + isar0_el1.ts = release->has(ArmExtension::FEAT_FLAGM2) ? + 0x2 : release->has(ArmExtension::FEAT_FLAGM) ? + 0x1 : 0x0; return isar0_el1; }()) .faultRead(EL1, HCR_TRAP(tid3))