arch-arm: Improve implementation of AT instructions
Move AT instructions out of setMiscReg. Modification includes: - Add template for AT instructions in misc64.isa. - Add decoder and execution of AT instruction in aarch64.isa and data64.isa. - Add AtOp64 and AtOp64Hub to perform the behavior of AT instructions. Change-Id: I7e8b802421f7335203edb9f8d748ad8669954b8c
This commit is contained in:
committed by
Giacomo Travaglini
parent
91c5218f91
commit
abf939f880
@@ -39,6 +39,7 @@
|
||||
#include "arch/arm/isa.hh"
|
||||
|
||||
#include "arch/arm/tlbi_op.hh"
|
||||
#include "debug/MiscRegs.hh"
|
||||
|
||||
namespace gem5
|
||||
{
|
||||
@@ -2533,4 +2534,113 @@ TlbiOp64::performTlbi(ExecContext *xc, MiscRegIndex dest_idx, RegVal value) cons
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<Fault, uint64_t>
|
||||
AtOp64::performAt(ExecContext *xc, MiscRegIndex dest_idx, RegVal val) const
|
||||
{
|
||||
ThreadContext* tc = xc->tcBase();
|
||||
|
||||
switch (dest_idx) {
|
||||
case MISCREG_AT_S1E1R_Xt:
|
||||
return addressTranslation64(tc, MMU::S1E1Tran, BaseMMU::Read, 0, val);
|
||||
case MISCREG_AT_S1E1W_Xt:
|
||||
return addressTranslation64(tc, MMU::S1E1Tran, BaseMMU::Write, 0, val);
|
||||
case MISCREG_AT_S1E0R_Xt:
|
||||
return addressTranslation64(tc, MMU::S1E0Tran, BaseMMU::Read,
|
||||
MMU::UserMode, val);
|
||||
case MISCREG_AT_S1E0W_Xt:
|
||||
return addressTranslation64(tc, MMU::S1E0Tran, BaseMMU::Write,
|
||||
MMU::UserMode, val);
|
||||
case MISCREG_AT_S1E2R_Xt:
|
||||
return addressTranslation64(tc, MMU::S1E2Tran, BaseMMU::Read, 0, val);
|
||||
case MISCREG_AT_S1E2W_Xt:
|
||||
return addressTranslation64(tc, MMU::S1E2Tran, BaseMMU::Write, 0, val);
|
||||
case MISCREG_AT_S12E1R_Xt:
|
||||
return addressTranslation64(tc, MMU::S12E1Tran, BaseMMU::Read, 0, val);
|
||||
case MISCREG_AT_S12E1W_Xt:
|
||||
return addressTranslation64(tc, MMU::S12E1Tran, BaseMMU::Write,
|
||||
0, val);
|
||||
case MISCREG_AT_S12E0R_Xt:
|
||||
return addressTranslation64(tc, MMU::S12E0Tran, BaseMMU::Read,
|
||||
MMU::UserMode, val);
|
||||
case MISCREG_AT_S12E0W_Xt:
|
||||
return addressTranslation64(tc, MMU::S12E0Tran, BaseMMU::Write,
|
||||
MMU::UserMode, val);
|
||||
case MISCREG_AT_S1E3R_Xt:
|
||||
return addressTranslation64(tc, MMU::S1E3Tran, BaseMMU::Read, 0, val);
|
||||
case MISCREG_AT_S1E3W_Xt:
|
||||
return addressTranslation64(tc, MMU::S1E3Tran, BaseMMU::Write, 0, val);
|
||||
default:
|
||||
return std::make_pair(NoFault, 0);
|
||||
}
|
||||
|
||||
return std::make_pair(NoFault, 0);
|
||||
}
|
||||
|
||||
std::pair<Fault, uint64_t>
|
||||
AtOp64::addressTranslation64(ThreadContext* tc,
|
||||
ArmISA::MMU::ArmTranslationType tran_type,
|
||||
BaseMMU::Mode mode, Request::Flags flags, RegVal val) const
|
||||
{
|
||||
// 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_once("Doing AT (address translation) in functional mode! Fix Me!\n");
|
||||
|
||||
auto req = std::make_shared<Request>(
|
||||
val, 0, flags, Request::funcRequestorId,
|
||||
tc->pcState().instAddr(), tc->contextId());
|
||||
|
||||
Fault fault = getMMUPtr(tc)->translateAtomic(
|
||||
req, tc, mode, tran_type);
|
||||
|
||||
PAR par = 0;
|
||||
bool raise_fault = false;
|
||||
if (fault == NoFault) {
|
||||
Addr paddr = req->getPaddr();
|
||||
uint64_t attr = getMMUPtr(tc)->getAttr();
|
||||
// clear LAPE bit from attribute.
|
||||
attr &= ~ uint64_t(0x800);
|
||||
uint64_t attr1 = attr >> 56;
|
||||
if (!(attr1 >> 4) || attr1 == 0x44) {
|
||||
attr |= 0x100;
|
||||
attr &= ~ uint64_t(0x80);
|
||||
}
|
||||
par = (paddr & mask(47, 12)) | attr;
|
||||
DPRINTF(MiscRegs, "AT: Translated addr %#x: PAR_EL1: %#x\n",
|
||||
val, par);
|
||||
} else {
|
||||
ArmFault *arm_fault = static_cast<ArmFault *>(fault.get());
|
||||
arm_fault->update(tc);
|
||||
// Set fault bit and FSR
|
||||
FSR fsr = arm_fault->getFsr(tc);
|
||||
|
||||
arm_fault->annotate(ArmFault::CM, 1); // CM
|
||||
arm_fault->annotate(ArmFault::WnR, 1); // Force WnR as 1
|
||||
|
||||
par.f = 1; // F bit
|
||||
par.fst = fsr.status; // FST
|
||||
par.ptw = (arm_fault->iss() >> 7) & 0x1; // S1PTW
|
||||
par.s = arm_fault->isStage2() ? 1 : 0; // S
|
||||
// set RES1 bit [11].
|
||||
par |= 0x800;
|
||||
|
||||
// Only raise fault for external abort and stage 2 fault,
|
||||
// see R~NHWXL~ in Arm-ARM.
|
||||
raise_fault = arm_fault->isExternalAbort() || par.ptw;
|
||||
|
||||
DPRINTF(MiscRegs, "AT: Translated addr %#x fault fsr %#x: PAR: %#x\n",
|
||||
val, fsr, par);
|
||||
}
|
||||
|
||||
// Fault filter.
|
||||
if (fault != NoFault && !raise_fault) {
|
||||
fault = NoFault;
|
||||
}
|
||||
|
||||
return std::make_pair(fault, par);
|
||||
}
|
||||
|
||||
} // namespace gem5
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#define __ARCH_ARM_INSTS_MISC64_HH__
|
||||
|
||||
#include "arch/arm/insts/static_inst.hh"
|
||||
#include "arch/arm/mmu.hh"
|
||||
#include "arch/arm/tlbi_op.hh"
|
||||
#include "arch/arm/types.hh"
|
||||
|
||||
@@ -339,6 +340,23 @@ class TlbiOp64 : public MiscRegRegImmOp64
|
||||
ArmISA::MiscRegIndex idx, RegVal value) const;
|
||||
};
|
||||
|
||||
class AtOp64 : public MiscRegRegImmOp64
|
||||
{
|
||||
protected:
|
||||
AtOp64(const char *mnem, ArmISA::ExtMachInst _machInst,
|
||||
OpClass __opClass, ArmISA::MiscRegIndex _dest,
|
||||
RegIndex _op1) :
|
||||
MiscRegRegImmOp64(mnem, _machInst, __opClass, _dest, _op1)
|
||||
{}
|
||||
|
||||
std::pair<Fault, uint64_t> performAt(ExecContext *xc,
|
||||
ArmISA::MiscRegIndex idx, RegVal val) const;
|
||||
|
||||
std::pair<Fault, uint64_t> addressTranslation64(ThreadContext* tc,
|
||||
ArmISA::MMU::ArmTranslationType tran_type,
|
||||
BaseMMU::Mode mode, Request::Flags flags, RegVal val) const;
|
||||
};
|
||||
|
||||
} // namespace gem5
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1293,46 +1293,6 @@ ISA::setMiscReg(RegIndex idx, RegVal val)
|
||||
idx = MISCREG_CPSR;
|
||||
}
|
||||
break;
|
||||
case MISCREG_AT_S1E1R_Xt:
|
||||
addressTranslation64(MMU::S1E1Tran, BaseMMU::Read, 0, val);
|
||||
return;
|
||||
case MISCREG_AT_S1E1W_Xt:
|
||||
addressTranslation64(MMU::S1E1Tran, BaseMMU::Write, 0, val);
|
||||
return;
|
||||
case MISCREG_AT_S1E0R_Xt:
|
||||
addressTranslation64(MMU::S1E0Tran, BaseMMU::Read,
|
||||
MMU::UserMode, val);
|
||||
return;
|
||||
case MISCREG_AT_S1E0W_Xt:
|
||||
addressTranslation64(MMU::S1E0Tran, BaseMMU::Write,
|
||||
MMU::UserMode, val);
|
||||
return;
|
||||
case MISCREG_AT_S1E2R_Xt:
|
||||
addressTranslation64(MMU::S1E2Tran, BaseMMU::Read, 0, val);
|
||||
return;
|
||||
case MISCREG_AT_S1E2W_Xt:
|
||||
addressTranslation64(MMU::S1E2Tran, BaseMMU::Write, 0, val);
|
||||
return;
|
||||
case MISCREG_AT_S12E1R_Xt:
|
||||
addressTranslation64(MMU::S12E1Tran, BaseMMU::Read, 0, val);
|
||||
return;
|
||||
case MISCREG_AT_S12E1W_Xt:
|
||||
addressTranslation64(MMU::S12E1Tran, BaseMMU::Write, 0, val);
|
||||
return;
|
||||
case MISCREG_AT_S12E0R_Xt:
|
||||
addressTranslation64(MMU::S12E0Tran, BaseMMU::Read,
|
||||
MMU::UserMode, val);
|
||||
return;
|
||||
case MISCREG_AT_S12E0W_Xt:
|
||||
addressTranslation64(MMU::S12E0Tran, BaseMMU::Write,
|
||||
MMU::UserMode, val);
|
||||
return;
|
||||
case MISCREG_AT_S1E3R_Xt:
|
||||
addressTranslation64(MMU::S1E3Tran, BaseMMU::Read, 0, val);
|
||||
return;
|
||||
case MISCREG_AT_S1E3W_Xt:
|
||||
addressTranslation64(MMU::S1E3Tran, BaseMMU::Write, 0, val);
|
||||
return;
|
||||
case MISCREG_L2CTLR:
|
||||
warn("miscreg L2CTLR (%s) written with %#x. ignored...\n",
|
||||
miscRegName[idx], uint32_t(val));
|
||||
@@ -1596,57 +1556,6 @@ ISA::unserialize(CheckpointIn &cp)
|
||||
updateRegMap(tmp_cpsr);
|
||||
}
|
||||
|
||||
void
|
||||
ISA::addressTranslation64(MMU::ArmTranslationType tran_type,
|
||||
BaseMMU::Mode mode, Request::Flags flags, RegVal val)
|
||||
{
|
||||
// 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_once("Doing AT (address translation) in functional mode! Fix Me!\n");
|
||||
|
||||
auto req = std::make_shared<Request>(
|
||||
val, 0, flags, Request::funcRequestorId,
|
||||
tc->pcState().instAddr(), tc->contextId());
|
||||
|
||||
Fault fault = getMMUPtr(tc)->translateFunctional(
|
||||
req, tc, mode, tran_type);
|
||||
|
||||
PAR par = 0;
|
||||
if (fault == NoFault) {
|
||||
Addr paddr = req->getPaddr();
|
||||
uint64_t attr = getMMUPtr(tc)->getAttr();
|
||||
uint64_t attr1 = attr >> 56;
|
||||
if (!attr1 || attr1 ==0x44) {
|
||||
attr |= 0x100;
|
||||
attr &= ~ uint64_t(0x80);
|
||||
}
|
||||
par = (paddr & mask(47, 12)) | attr;
|
||||
DPRINTF(MiscRegs,
|
||||
"MISCREG: Translated addr %#x: PAR_EL1: %#xx\n",
|
||||
val, par);
|
||||
} else {
|
||||
ArmFault *arm_fault = static_cast<ArmFault *>(fault.get());
|
||||
arm_fault->update(tc);
|
||||
// Set fault bit and FSR
|
||||
FSR fsr = arm_fault->getFsr(tc);
|
||||
|
||||
par.f = 1; // F bit
|
||||
par.fst = fsr.status; // FST
|
||||
par.ptw = (arm_fault->iss() >> 7) & 0x1; // S1PTW
|
||||
par.s = arm_fault->isStage2() ? 1 : 0; // S
|
||||
|
||||
DPRINTF(MiscRegs,
|
||||
"MISCREG: Translated addr %#x fault fsr %#x: PAR: %#x\n",
|
||||
val, fsr, par);
|
||||
}
|
||||
setMiscRegNoEffect(MISCREG_PAR_EL1, par);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
ISA::addressTranslation(MMU::ArmTranslationType tran_type,
|
||||
BaseMMU::Mode mode, Request::Flags flags, RegVal val)
|
||||
|
||||
@@ -173,8 +173,6 @@ namespace ArmISA
|
||||
protected:
|
||||
void addressTranslation(MMU::ArmTranslationType tran_type,
|
||||
BaseMMU::Mode mode, Request::Flags flags, RegVal val);
|
||||
void addressTranslation64(MMU::ArmTranslationType tran_type,
|
||||
BaseMMU::Mode mode, Request::Flags flags, RegVal val);
|
||||
|
||||
public:
|
||||
SelfDebug*
|
||||
|
||||
@@ -624,6 +624,21 @@ namespace Aarch64
|
||||
TLBI_CASE_VARIANTS(MISCREG_TLBI_RVALE3OS)
|
||||
return new Tlbi64ShareableHub(
|
||||
machInst, miscReg, rt, dec.dvmEnabled);
|
||||
// AT instructions
|
||||
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:
|
||||
return new At64Hub(machInst, miscReg,
|
||||
MiscRegIndex::MISCREG_PAR_EL1, rt);
|
||||
default:
|
||||
return new Msr64(machInst, miscReg, rt);
|
||||
}
|
||||
|
||||
@@ -401,6 +401,20 @@ let {{
|
||||
exec_output += DvmInitiateAcc.subst(msrTlbiSIop)
|
||||
exec_output += DvmCompleteAcc.subst(msrTlbiSIop)
|
||||
|
||||
atCode = msr_check_code + '''
|
||||
uint64_t par_result;
|
||||
std::tie(fault, par_result) = performAt(xc, flat_idx, XOp1);
|
||||
MiscDest_ud = XOp1;
|
||||
MiscDest2_ud = par_result;
|
||||
'''
|
||||
msrAtIop = ArmInstObjParams("msr", "At64Hub", "AtOp64",
|
||||
{
|
||||
"code" : atCode
|
||||
})
|
||||
header_output += AtDeclare.subst(msrAtIop)
|
||||
decoder_output += AtConstructor.subst(msrAtIop)
|
||||
exec_output += BasicExecute.subst(msrAtIop)
|
||||
|
||||
msrNZCVCode = '''
|
||||
CPSR cpsr = XOp1;
|
||||
CondCodesNZ = cpsr.nz;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// -*- mode:c++ -*-
|
||||
// Copyright (c) 2010-2014, 2016-2018, 2021-2022 Arm Limited
|
||||
// Copyright (c) 2010-2014, 2016-2018, 2021-2022, 2024 Arm Limited
|
||||
// All rights reserved
|
||||
//
|
||||
// The license below extends only to copyright in the software and shall
|
||||
@@ -470,6 +470,7 @@ def operands {{
|
||||
|
||||
#Abstracted control reg operands
|
||||
'MiscDest': CntrlReg('dest'),
|
||||
'MiscDest2': CntrlReg('dest2'),
|
||||
'MiscOp1': CntrlReg('op1'),
|
||||
'MiscNsBankedDest': CntrlNsBankedReg('dest'),
|
||||
'MiscNsBankedOp1': CntrlNsBankedReg('op1'),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// -*- mode:c++ -*-
|
||||
|
||||
// Copyright (c) 2011,2017-2022 Arm Limited
|
||||
// Copyright (c) 2011,2017-2022,2024 Arm Limited
|
||||
// All rights reserved
|
||||
//
|
||||
// The license below extends only to copyright in the software and shall
|
||||
@@ -303,6 +303,22 @@ class %(class_name)s : public %(base_class)s
|
||||
};
|
||||
}};
|
||||
|
||||
def template AtDeclare {{
|
||||
class %(class_name)s : public %(base_class)s
|
||||
{
|
||||
private:
|
||||
ArmISA::MiscRegIndex dest2;
|
||||
%(reg_idx_arr_decl)s;
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
%(class_name)s(ExtMachInst machInst, MiscRegIndex _dest,
|
||||
MiscRegIndex _dest2, RegIndex _op1);
|
||||
|
||||
Fault execute(ExecContext *, trace::InstRecord *) const override;
|
||||
};
|
||||
}};
|
||||
|
||||
def template DvmDeclare {{
|
||||
/**
|
||||
* Static instruction class for "%(mnemonic)s".
|
||||
@@ -339,6 +355,18 @@ def template DvmTlbiConstructor {{
|
||||
}
|
||||
}};
|
||||
|
||||
def template AtConstructor {{
|
||||
%(class_name)s::%(class_name)s(ExtMachInst machInst, MiscRegIndex _dest,
|
||||
MiscRegIndex _dest2, RegIndex _op1) :
|
||||
%(base_class)s("%(mnemonic)s", machInst, %(op_class)s,
|
||||
_dest, _op1),
|
||||
dest2(_dest2)
|
||||
{
|
||||
%(set_reg_idx_arr)s;
|
||||
%(constructor)s;
|
||||
}
|
||||
}};
|
||||
|
||||
def template DvmConstructor {{
|
||||
%(class_name)s::%(class_name)s(ExtMachInst machInst, bool dvm_enabled) :
|
||||
%(base_class)s("%(mnemonic)s", machInst, %(op_class)s),
|
||||
|
||||
Reference in New Issue
Block a user