arch-arm: Implement FEAT_FLAGM(2)
Change-Id: I21f1eb91ad9acb019a776a7d5edd38754571a62e Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com> Reviewed-by: Richard Cooper <richard.cooper@arm.com> Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/70719 Maintainer: Jason Lowe-Power <power.jg@gmail.com> Reviewed-by: Jason Lowe-Power <power.jg@gmail.com> Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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<UndefinedInstruction>(
|
||||
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)
|
||||
}};
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user