else
memAccessFlags |= ArmISA::TLB::AllowUnaligned;
if (acrel) {
- flags[IsMemBarrier] = true;
flags[IsWriteBarrier] = true;
flags[IsReadBarrier] = true;
}
_numVecElemDestRegs = 0;
_numIntDestRegs = 0;
_numCCDestRegs = 0;
- flags[IsMemBarrier] = true;
flags[IsMicroop] = true;
flags[IsReadBarrier] = true;
flags[IsWriteBarrier] = true;
self.instFlags.append("IsMicroop")
if self.flavor in ("release", "acquire_release", "acquire"):
- self.instFlags.append("IsMemBarrier")
+ self.instFlags.extend(["IsReadBarrier", "IsWriteBarrier"])
if self.flavor in ("release", "acquire_release"):
self.instFlags.append("IsWriteBarrier")
if self.flavor in ("acquire_release", "acquire"):
self.memFlags.append("Request::LLSC")
if self.flavor in ("acquire", "acex"):
- self.instFlags.extend(["IsMemBarrier",
- "IsWriteBarrier",
- "IsReadBarrier"])
+ self.instFlags.extend(["IsWriteBarrier", "IsReadBarrier"])
self.memFlags.append("Request::ACQUIRE")
# Disambiguate the class name for different flavors of loads
self.Name = "%s_%s" % (self.name.upper(), self.Name)
if self.flavor in ("acquire", "acex"):
- self.instFlags.extend(["IsMemBarrier",
- "IsWriteBarrier",
- "IsReadBarrier"])
+ self.instFlags.extend(["IsWriteBarrier", "IsReadBarrier"])
self.memFlags.append("Request::ACQUIRE")
def emit(self):
self.memFlags.append("ArmISA::TLB::AllowUnaligned")
if self.flavor in ("acquire", "acex", "acexp"):
- self.instFlags.extend(["IsMemBarrier",
- "IsWriteBarrier",
- "IsReadBarrier"])
+ self.instFlags.extend(["IsWriteBarrier", "IsReadBarrier"])
self.memFlags.append("Request::ACQUIRE")
if self.flavor in ("acex", "exclusive", "exp", "acexp"):
dsbIop = InstObjParams("dsb", "Dsb", "ImmOp",
{"code": dsbCode,
"predicate_test": predicateTest},
- ['IsMemBarrier', 'IsSerializeAfter'])
+ ['IsReadBarrier', 'IsWriteBarrier',
+ 'IsSerializeAfter'])
header_output += ImmOpDeclare.subst(dsbIop)
decoder_output += ImmOpConstructor.subst(dsbIop)
exec_output += PredOpExecute.subst(dsbIop)
dmbIop = InstObjParams("dmb", "Dmb", "ImmOp",
{"code": dmbCode,
"predicate_test": predicateTest},
- ['IsMemBarrier'])
+ ['IsReadBarrier', 'IsWriteBarrier'])
header_output += ImmOpDeclare.subst(dmbIop)
decoder_output += ImmOpConstructor.subst(dmbIop)
exec_output += PredOpExecute.subst(dmbIop)
exec_output += BasicExecute.subst(isbIop)
dsbIop = InstObjParams("dsb", "Dsb64", "ArmStaticInst", "",
- ['IsMemBarrier', 'IsSerializeAfter'])
+ ['IsReadBarrier', 'IsWriteBarrier',
+ 'IsSerializeAfter'])
header_output += BasicDeclare.subst(dsbIop)
decoder_output += BasicConstructor64.subst(dsbIop)
exec_output += BasicExecute.subst(dsbIop)
dmbIop = InstObjParams("dmb", "Dmb64", "ArmStaticInst", "",
- ['IsMemBarrier'])
+ ['IsReadBarrier', 'IsWriteBarrier'])
header_output += BasicDeclare.subst(dmbIop)
decoder_output += BasicConstructor64.subst(dmbIop)
exec_output += BasicExecute.subst(dmbIop)
self.memFlags.append("ArmISA::TLB::AllowUnaligned")
if self.flavor in ("release", "relex"):
- self.instFlags.extend(["IsMemBarrier",
- "IsWriteBarrier",
+ self.instFlags.extend(["IsWriteBarrier",
"IsReadBarrier"])
self.memFlags.append("Request::RELEASE")
self.memFlags.append("ArmISA::TLB::AlignWord")
if self.flavor in ("release", "relex"):
- self.instFlags.extend(["IsMemBarrier",
- "IsWriteBarrier",
+ self.instFlags.extend(["IsWriteBarrier",
"IsReadBarrier"])
self.memFlags.append("Request::RELEASE")
self.instFlags.append("IsMicroop")
if self.flavor in ("release", "relex", "relexp"):
- self.instFlags.extend(["IsMemBarrier",
- "IsWriteBarrier",
+ self.instFlags.extend(["IsWriteBarrier",
"IsReadBarrier"])
self.memFlags.append("Request::RELEASE")
// A new class of Semihosting constructor templates has been added.
// Their main purpose is to check if the Exception Generation
// Instructions (HLT, SVC) are actually a semihosting command.
-// If that is the case, the IsMemBarrier flag is raised, so that
-// in the O3 model we perform a coherent memory access during
+// If that is the case, the IsReadBarrier and IsWriteBarrier flags are raised,
+// so that in the O3 model we perform a coherent memory access during
// the semihosting operation.
// Please note: since we don't have a thread context pointer in the
// constructor we cannot check if semihosting is enabled in the
auto semihost_imm = machInst.thumb? %(thumb_semihost)s :
%(arm_semihost)s;
if (_imm == semihost_imm) {
- flags[IsMemBarrier] = true;
+ flags[IsReadBarrier] = true;
+ flags[IsWriteBarrier] = true;
}
}
}};
// In AArch64 there is only one instruction for issuing
// semhosting commands: HLT #0xF000
if (_imm == 0xF000) {
- flags[IsMemBarrier] = true;
+ flags[IsReadBarrier] = true;
+ flags[IsWriteBarrier] = true;
}
}
}};
fault = std::make_shared<SystemCallFault>();
}});
}
- 0x7: sync({{ ; }}, IsMemBarrier);
+ 0x7: sync({{ ; }}, IsReadBarrier, IsWriteBarrier);
0x5: break({{fault = std::make_shared<BreakpointFault>();}});
}
format MiscOp {
278: dcbt({{ }});
246: dcbtst({{ }});
- 598: sync({{ }}, [ IsMemBarrier ]);
- 854: eieio({{ }}, [ IsMemBarrier ]);
+ 598: sync({{ }}, [ IsReadBarrier, IsWriteBarrier ]);
+ 854: eieio({{ }}, [ IsReadBarrier, IsWriteBarrier ]);
}
}
0x03: decode FUNCT3 {
format FenceOp {
0x0: fence({{
- }}, uint64_t, IsMemBarrier, No_OpClass);
+ }}, uint64_t, IsReadBarrier, IsWriteBarrier, No_OpClass);
0x1: fence_i({{
}}, uint64_t, IsNonSpeculative, IsSerializeAfter, No_OpClass);
}
if (RL) {
rel_fence = new MemFenceMicro(machInst, No_OpClass);
rel_fence->setFlag(IsFirstMicroop);
- rel_fence->setFlag(IsMemBarrier);
+ rel_fence->setFlag(IsReadBarrier);
+ rel_fence->setFlag(IsWriteBarrier);
rel_fence->setFlag(IsDelayedCommit);
}
if (AQ) {
acq_fence = new MemFenceMicro(machInst, No_OpClass);
acq_fence->setFlag(IsLastMicroop);
- acq_fence->setFlag(IsMemBarrier);
+ acq_fence->setFlag(IsReadBarrier);
+ acq_fence->setFlag(IsWriteBarrier);
}
if (RL && AQ) {
if (RL) {
rel_fence = new MemFenceMicro(machInst, No_OpClass);
rel_fence->setFlag(IsFirstMicroop);
- rel_fence->setFlag(IsMemBarrier);
+ rel_fence->setFlag(IsReadBarrier);
+ rel_fence->setFlag(IsWriteBarrier);
rel_fence->setFlag(IsDelayedCommit);
}
if (AQ) {
acq_fence = new MemFenceMicro(machInst, No_OpClass);
acq_fence->setFlag(IsLastMicroop);
- acq_fence->setFlag(IsMemBarrier);
+ acq_fence->setFlag(IsReadBarrier);
+ acq_fence->setFlag(IsWriteBarrier);
}
if (RL && AQ) {
// 7-14 should cause an illegal instruction exception
0x0F: decode I {
0x0: Nop::stbar(IsWriteBarrier, MemWriteOp);
- 0x1: Nop::membar(IsMemBarrier, MemReadOp);
+ 0x1: Nop::membar(IsReadBarrier, IsWriteBarrier,
+ MemReadOp);
}
0x10: Priv::rdpcr({{Rd = Pcr;}});
0x11: Priv::rdpic({{Rd = Pic;}}, {{Pcr<0:>}});
//0x6: group15();
0x6: decode MODRM_MOD {
0x3: decode MODRM_REG {
- 0x5: BasicOperate::LFENCE(
- {{/*Nothing*/}}, IsReadBarrier,
- IsSerializeAfter);
- 0x6: BasicOperate::MFENCE(
- {{/*Nothing*/}}, IsMemBarrier);
- 0x7: BasicOperate::SFENCE(
- {{/*Nothing*/}}, IsWriteBarrier);
+ 0x5: BasicOperate::LFENCE({{/*Nothing*/}},
+ IsReadBarrier, IsSerializeAfter);
+ 0x6: BasicOperate::MFENCE({{/*Nothing*/}},
+ IsReadBarrier, IsWriteBarrier);
+ 0x7: BasicOperate::SFENCE({{/*Nothing*/}},
+ IsWriteBarrier);
default: Inst::UD2();
}
default: decode MODRM_REG {
def __init__(self):
self.className = "Mfence"
self.mnemonic = "mfence"
- self.instFlags = "| (1ULL << StaticInst::IsMemBarrier)"
+ self.instFlags = "| (1ULL << StaticInst::IsReadBarrier)" + \
+ "| (1ULL << StaticInst::IsWriteBarrier)"
def getAllocator(self, microFlags):
allocString = '''
# - If IsControl is set, then exactly one of IsDirectControl or IsIndirect
# Control will be set, and exactly one of IsCondControl or IsUncondControl
# will be set.
-# - IsSerializing, IsMemBarrier, and IsWriteBarrier are implemented as flags
-# since in the current model there's no other way for instructions to inject
-# behavior into the pipeline outside of fetch. Once we go to an exec-in-exec
-# CPU model we should be able to get rid of these flags and implement this
-# behavior via the execute() methods.
class StaticInstFlags(Enum):
wrapper_name = 'StaticInstFlags'
# older instructions have committed.
'IsSerializeBefore',
'IsSerializeAfter',
- 'IsMemBarrier', # Is a memory barrier
'IsWriteBarrier', # Is a write barrier
'IsReadBarrier', # Is a read barrier
return staticInst->isSerializeAfter() || status[SerializeAfter];
}
bool isSquashAfter() const { return staticInst->isSquashAfter(); }
- bool isMemBarrier() const { return staticInst->isMemBarrier(); }
+ bool isFullMemBarrier() const { return staticInst->isFullMemBarrier(); }
+ bool isReadBarrier() const { return staticInst->isReadBarrier(); }
bool isWriteBarrier() const { return staticInst->isWriteBarrier(); }
bool isNonSpeculative() const { return staticInst->isNonSpeculative(); }
bool isQuiesce() const { return staticInst->isQuiesce(); }
/* Mark up barriers in the LSQ */
if (!discarded && inst->isInst() &&
- inst->staticInst->isMemBarrier())
+ inst->staticInst->isFullMemBarrier())
{
DPRINTF(MinorMem, "Issuing memory barrier inst: %s\n", *inst);
lsq.issuedMemBarrierInst(inst);
completed_inst = completed_mem_inst;
}
completed_mem_issue = completed_inst;
- } else if (inst->isInst() && inst->staticInst->isMemBarrier() &&
+ } else if (inst->isInst() && inst->staticInst->isFullMemBarrier() &&
!lsq.canPushIntoStoreBuffer())
{
DPRINTF(MinorExecute, "Can't commit data barrier inst: %s yet as"
ex_info.inFlightInsts->pop();
/* Complete barriers in the LSQ/move to store buffer */
- if (inst->isInst() && inst->staticInst->isMemBarrier()) {
+ if (inst->isInst() && inst->staticInst->isFullMemBarrier()) {
DPRINTF(MinorMem, "Completing memory barrier"
" inst: %s committed: %d\n", *inst, committed_inst);
lsq.completeMemBarrierInst(inst, committed_inst);
bool
LSQ::LSQRequest::isBarrier()
{
- return inst->isInst() && inst->staticInst->isMemBarrier();
+ return inst->isInst() && inst->staticInst->isFullMemBarrier();
}
bool
void
LSQ::issuedMemBarrierInst(MinorDynInstPtr inst)
{
- assert(inst->isInst() && inst->staticInst->isMemBarrier());
+ assert(inst->isInst() && inst->staticInst->isFullMemBarrier());
assert(inst->id.execSeqNum > lastMemBarrier[inst->id.threadId]);
/* Remember the barrier. We only have a notion of one
// Make sure we are only trying to commit un-executed instructions we
// think are possible.
assert(head_inst->isNonSpeculative() || head_inst->isStoreConditional()
- || head_inst->isMemBarrier() || head_inst->isWriteBarrier()
+ || head_inst->isReadBarrier() || head_inst->isWriteBarrier()
|| head_inst->isAtomic()
|| (head_inst->isLoad() && head_inst->strictlyOrdered()));
}
}
- if (inst->isMemBarrier()) {
+ if (inst->isFullMemBarrier()) {
stats.membars[tid]++;
}
}
toRename->iewInfo[tid].dispatchedToSQ++;
- } else if (inst->isMemBarrier() || inst->isWriteBarrier()) {
+ } else if (inst->isReadBarrier() || inst->isWriteBarrier()) {
// Same as non-speculative stores.
inst->setCanCommit();
instQueue.insertBarrier(inst);
++freeEntries;
completed_inst->memOpDone(true);
count[tid]--;
- } else if (completed_inst->isMemBarrier() ||
+ } else if (completed_inst->isReadBarrier() ||
completed_inst->isWriteBarrier()) {
// Completes a non mem ref barrier
memDepUnit[tid].completeInst(completed_inst);
DPRINTF(IQ, "[tid:%i] Instruction [sn:%llu] PC %s squashed.\n",
tid, squashed_inst->seqNum, squashed_inst->pcState());
- bool is_acq_rel = squashed_inst->isMemBarrier() &&
+ bool is_acq_rel = squashed_inst->isFullMemBarrier() &&
(squashed_inst->isLoad() ||
(squashed_inst->isStore() &&
!squashed_inst->isStoreConditional()));
(!squashed_inst->isNonSpeculative() &&
!squashed_inst->isStoreConditional() &&
!squashed_inst->isAtomic() &&
- !squashed_inst->isMemBarrier() &&
+ !squashed_inst->isReadBarrier() &&
!squashed_inst->isWriteBarrier())) {
for (int src_reg_idx = 0;
#include <map>
#include <vector>
+#include "base/debug.hh"
#include "cpu/o3/inst_queue.hh"
#include "cpu/o3/mem_dep_unit.hh"
#include "debug/MemDepUnit.hh"
MemDepUnit<MemDepPred, Impl>::insertBarrierSN(const DynInstPtr &barr_inst)
{
InstSeqNum barr_sn = barr_inst->seqNum;
- // Memory barriers block loads and stores, write barriers only stores.
- // Required also for hardware transactional memory commands which
- // can have strict ordering semantics
- if (barr_inst->isMemBarrier() || barr_inst->isHtmCmd()) {
+
+ if (barr_inst->isReadBarrier() || barr_inst->isHtmCmd())
loadBarrierSNs.insert(barr_sn);
+ if (barr_inst->isWriteBarrier() || barr_inst->isHtmCmd())
storeBarrierSNs.insert(barr_sn);
- DPRINTF(MemDepUnit, "Inserted a memory barrier %s SN:%lli\n",
- barr_inst->pcState(), barr_sn);
- } else if (barr_inst->isWriteBarrier()) {
- storeBarrierSNs.insert(barr_sn);
- DPRINTF(MemDepUnit, "Inserted a write barrier %s SN:%lli\n",
- barr_inst->pcState(), barr_sn);
- }
- if (loadBarrierSNs.size() || storeBarrierSNs.size()) {
- DPRINTF(MemDepUnit, "Outstanding load barriers = %d; "
- "store barriers = %d\n",
- loadBarrierSNs.size(), storeBarrierSNs.size());
+ if (DTRACE(MemDepUnit)) {
+ const char *barrier_type = nullptr;
+ if (barr_inst->isReadBarrier() && barr_inst->isWriteBarrier())
+ barrier_type = "memory";
+ else if (barr_inst->isReadBarrier())
+ barrier_type = "read";
+ else if (barr_inst->isWriteBarrier())
+ barrier_type = "write";
+
+ if (barrier_type) {
+ DPRINTF(MemDepUnit, "Inserted a %s barrier %s SN:%lli\n",
+ barrier_type, barr_inst->pcState(), barr_sn);
+ }
+
+ if (loadBarrierSNs.size() || storeBarrierSNs.size()) {
+ DPRINTF(MemDepUnit, "Outstanding load barriers = %d; "
+ "store barriers = %d\n",
+ loadBarrierSNs.size(), storeBarrierSNs.size());
+ }
}
}
completed(inst);
InstSeqNum barr_sn = inst->seqNum;
- if (inst->isMemBarrier() || inst->isHtmCmd()) {
- assert(hasLoadBarrier());
+ if (inst->isWriteBarrier() || inst->isHtmCmd()) {
assert(hasStoreBarrier());
- loadBarrierSNs.erase(barr_sn);
storeBarrierSNs.erase(barr_sn);
- DPRINTF(MemDepUnit, "Memory barrier completed: %s SN:%lli\n",
- inst->pcState(), inst->seqNum);
- } else if (inst->isWriteBarrier()) {
- assert(hasStoreBarrier());
- storeBarrierSNs.erase(barr_sn);
- DPRINTF(MemDepUnit, "Write barrier completed: %s SN:%lli\n",
- inst->pcState(), inst->seqNum);
+ }
+ if (inst->isReadBarrier() || inst->isHtmCmd()) {
+ assert(hasLoadBarrier());
+ loadBarrierSNs.erase(barr_sn);
+ }
+ if (DTRACE(MemDepUnit)) {
+ const char *barrier_type = nullptr;
+ if (inst->isWriteBarrier() && inst->isReadBarrier())
+ barrier_type = "Memory";
+ else if (inst->isWriteBarrier())
+ barrier_type = "Write";
+ else if (inst->isReadBarrier())
+ barrier_type = "Read";
+
+ if (barrier_type) {
+ DPRINTF(MemDepUnit, "%s barrier completed: %s SN:%lli\n",
+ barrier_type, inst->pcState(), inst->seqNum);
+ }
}
}
void
MemDepUnit<MemDepPred, Impl>::wakeDependents(const DynInstPtr &inst)
{
- // Only stores, atomics, barriers and
- // hardware transactional memory commands have dependents.
- if (!inst->isStore() && !inst->isAtomic() && !inst->isMemBarrier() &&
+ // Only stores, atomics and barriers have dependents.
+ if (!inst->isStore() && !inst->isAtomic() && !inst->isReadBarrier() &&
!inst->isWriteBarrier() && !inst->isHtmCmd()) {
return;
}
bool isSerializeBefore() const { return flags[IsSerializeBefore]; }
bool isSerializeAfter() const { return flags[IsSerializeAfter]; }
bool isSquashAfter() const { return flags[IsSquashAfter]; }
- bool isMemBarrier() const { return flags[IsMemBarrier]; }
+ bool
+ isFullMemBarrier() const
+ {
+ return flags[IsReadBarrier] && flags[IsWriteBarrier];
+ }
+ bool isReadBarrier() const { return flags[IsReadBarrier]; }
bool isWriteBarrier() const { return flags[IsWriteBarrier]; }
bool isNonSpeculative() const { return flags[IsNonSpeculative]; }
bool isQuiesce() const { return flags[IsQuiesce]; }