GEM5 O3 CPU Commit阶段详细代码解读
概述
Commit阶段是GEM5 O3 CPU的最后一个流水线阶段,负责指令的最终提交、异常处理、分支预测更新、架构状态更新等关键功能。它确保指令按程序顺序提交,并处理各种类型的流水线冲刷(squash)。
核心数据结构
1. Commit类定义 (commit.hh:101-586)
class Commit
{
public:
enum CommitStatus { Active, Inactive };
enum ThreadStatus {
Running, Idle, ROBSquashing,
TrapPending, FetchTrapPending, SquashAfterPending
};
// ...
};
Commit类是整个提交阶段的核心控制器,包含了所有必要的状态管理和接口。
2. 关键成员变量
状态管理变量
CommitStatus _status/_nextStatus(commit.hh:126-128): 整体提交阶段状态ThreadStatus commitStatus[MaxThreads](commit.hh:131): 每个线程的提交状态bool changedROBNumEntries[MaxThreads](commit.hh:391): ROB条目数量变化标记
时序缓冲区接口
TimeBuffer<TimeStruct> *timeBuffer(commit.hh:344): 主时序缓冲区TimeBuffer<TimeStruct>::wire toIEW(commit.hh:347): 向IEW阶段发送信息TimeBuffer<IEWStruct>::wire fromIEW(commit.hh:360): 从IEW阶段接收信息TimeBuffer<RenameStruct>::wire fromRename(commit.hh:366): 从Rename阶段接收指令
核心组件指针
ROB *rob(commit.hh:372): 重排序缓冲区指针CPU *cpu(commit.hh:376): O3CPU指针branch_prediction::BPredUnit *bp(commit.hh:378): 分支预测器指针UnifiedRenameMap *renameMap[MaxThreads](commit.hh:480): 重命名映射表
配置参数
const unsigned commitWidth(commit.hh:428): 每周期可提交的指令数const Cycles trapLatency(commit.hh:448): 异常处理延迟const Cycles iewToCommitDelay(commit.hh:412): IEW到Commit的延迟
3. 统计信息结构 (commit.hh:507-572)
struct CommitStats : public statistics::Group
{
statistics::Scalar commitSquashedInsts; // 被冲刷的指令数
statistics::Scalar branchMispredicts; // 分支预测错误数
statistics::Vector instsCommitted; // 已提交指令数
statistics::Vector memRefs; // 内存引用数
statistics::Distribution numCommittedDist; // 每周期提交指令数分布
// ... 更多统计项
};
核心函数解读
1. 构造函数 (commit.cc:100-201)
功能: - 初始化所有成员变量和配置参数 - 设置线程状态和优先级列表 - 注册卡死检测事件(stuckCheckEvent) - 配置统计信息收集 - 设置异常类型集合(faultNum)
关键逻辑:
- 初始化每个线程的PC状态: pc[tid].reset(params.isa[0]->newPCState())
- 设置提交策略: commitPolicy = params.smtCommitPolicy
- 注册退出回调函数,用于输出间接分支预测错误统计
2. tick()函数 - 主时钟驱动 (commit.cc:759-838)
功能: 每个时钟周期的主要处理逻辑
执行流程: 1. 检查ROB冲刷状态 (commit.cc:772-793):
if (commitStatus[tid] == ROBSquashing) {
if (rob->isDoneSquashing(tid)) {
commitStatus[tid] = Running;
} else {
rob->doSquash(tid);
}
}
-
调用核心提交逻辑:
commit()(commit.cc:795) -
标记完成的指令:
markCompletedInsts()(commit.cc:797) -
检查就绪指令 (commit.cc:804-829):
- 检查ROB头部指令是否准备提交
- 更新活动状态以维持CPU调度
3. commit()函数 - 核心提交逻辑 (commit.cc:925-1101)
功能: Commit阶段的核心控制函数,负责处理所有类型的流水线冲刷和指令提交,是每个时钟周期执行的关键逻辑
设计理念: - 按严格的优先级顺序处理各种冲刷请求,确保处理器状态的一致性 - 采用分阶段处理模式:先处理冲刷,再进行正常的指令获取和提交 - 支持多线程并发处理,但保证原子性操作
完整执行流程:
3.1 全系统中断检查和传播 (commit.cc:927-931)
if (FullSystem) {
// Check if we have a interrupt and get read to handle it
if (cpu->checkInterrupts(0))
propagateInterrupt();
}
cpu->checkInterrupts(0): 检查是否有待处理的中断
- propagateInterrupt(): 将中断信息传播给其他流水线阶段
- 中断处理采用延迟处理机制,避免破坏当前周期的指令提交
3.2 多级冲刷处理机制 (commit.cc:934-1050)
冲刷处理遵循严格的优先级顺序,确保最高优先级的冲刷请求得到及时处理:
////////////////////////////////////
// Check for any possible squashes, handle them first
////////////////////////////////////
std::list<ThreadID>::iterator threads = activeThreads->begin();
std::list<ThreadID>::iterator end = activeThreads->end();
int num_squashing_threads = 0;
while (threads != end) {
ThreadID tid = *threads++;
// 按优先级顺序处理冲刷
}
3.2.1 异常冲刷 (最高优先级, commit.cc:946-955):
if (trapSquash[tid]) {
assert(!tcSquash[tid]); // 确保不会同时有TC冲刷
squashFromTrap(tid);
// 处理线程退出情况
if (cpu->isThreadExiting(tid))
cpu->scheduleThreadExitEvent(tid);
}
3.2.2 ThreadContext冲刷 (commit.cc:956-958):
处理特点: - 由ThreadContext状态变化引起(如特权级切换、MMU状态变化等) - 确保不在异常处理过程中执行TC冲刷 - 通常涉及架构状态的重大变化3.2.3 SquashAfter冲刷 (commit.cc:959-964):
else if (commitStatus[tid] == SquashAfterPending) {
// A squash from the previous cycle of the commit stage
// (i.e., commitInsts() called squashAfter) is pending.
squashFromSquashAfter(tid);
}
3.2.4 IEW阶段发来的冲刷 (commit.cc:971-1045):
if (fromIEW->squash[tid] &&
commitStatus[tid] != TrapPending &&
fromIEW->squashedSeqNum[tid] <= youngestSeqNum[tid]) {
// 区分冲刷类型
if (fromIEW->mispredictInst[tid]) {
DPRINTF(Commit,
"[tid:%i] Squashing due to branch mispred "
"PC:%#x [sn:%llu]\n",
tid,
fromIEW->mispredictInst[tid]->pcState().instAddr(),
fromIEW->squashedSeqNum[tid]);
stats.squashDueToBranch++;
} else {
DPRINTF(Commit,
"[tid:%i] Squashing due to order violation [sn:%llu]\n",
tid, fromIEW->squashedSeqNum[tid]);
stats.squashDueToOrderViolation++;
}
// 执行冲刷逻辑
commitStatus[tid] = ROBSquashing;
InstSeqNum squashed_inst = fromIEW->squashedSeqNum[tid];
if (fromIEW->includeSquashInst[tid]) {
squashed_inst--;
}
// 更新最年轻指令序列号
youngestSeqNum[tid] = squashed_inst;
// 冲刷ROB
rob->squash(squashed_inst, tid);
changedROBNumEntries[tid] = true;
// 向IEW发送冲刷信息
toIEW->commitInfo[tid].doneSeqNum = squashed_inst;
toIEW->commitInfo[tid].squash = true;
toIEW->commitInfo[tid].robSquashing = true;
toIEW->commitInfo[tid].mispredictInst = fromIEW->mispredictInst[tid];
// 更新分支预测相关信息
if (toIEW->commitInfo[tid].mispredictInst) {
if (toIEW->commitInfo[tid].mispredictInst->isUncondCtrl()) {
toIEW->commitInfo[tid].branchTaken = true;
}
++stats.branchMispredicts;
}
// 冲刷在途指令并更新版本号
squashInflightAndUpdateVersion(tid);
}
冲刷类型判断:
- 分支预测错误: fromIEW->mispredictInst[tid] 非空
- 内存序违例: fromIEW->mispredictInst[tid] 为空
关键检查条件:
- commitStatus[tid] != TrapPending: 不在异常处理过程中
- fromIEW->squashedSeqNum[tid] <= youngestSeqNum[tid]: 确保冲刷序列号有效
3.3 指令获取和提交处理 (commit.cc:1058-1064)
if (num_squashing_threads != numThreads) {
// If we're not currently squashing, then get instructions.
getInsts();
// Try to commit any instructions.
commitInsts();
}
3.4 ROB状态更新和反馈 (commit.cc:1067-1100)
//Check for any activity
threads = activeThreads->begin();
while (threads != end) {
ThreadID tid = *threads++;
// 更新ROB空闲条目数
if (changedROBNumEntries[tid]) {
toIEW->commitInfo[tid].usedROB = true;
toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid);
wroteToTimeBuffer = true;
changedROBNumEntries[tid] = false;
if (rob->isEmpty(tid))
checkEmptyROB[tid] = true;
}
// 检查ROB是否真正为空的复杂逻辑
if (checkEmptyROB[tid] && rob->isEmpty(tid) &&
!iewStage->hasStoresToWB(tid) && !committedStores[tid] &&
commitStatus[tid] != SquashAfterPending) {
checkEmptyROB[tid] = false;
toIEW->commitInfo[tid].usedROB = true;
toIEW->commitInfo[tid].emptyROB = true;
toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid);
wroteToTimeBuffer = true;
}
}
ROB空状态检查的复杂条件:
- rob->isEmpty(tid): ROB物理上为空
- !iewStage->hasStoresToWB(tid): 没有待写回的store指令
- !committedStores[tid]: 当前周期没有提交store指令
- commitStatus[tid] != SquashAfterPending: 没有待处理的SquashAfter
设计考虑: 这种复杂的空状态检查确保了多周期store操作的正确性
4. commitInsts()函数 - 批量指令提交控制器 (commit.cc:1110-1447)
功能: 在每个周期内尽可能多地提交指令
关键逻辑:
4.1 提交带宽控制 (commit.cc:1127-1135)
int commit_width = rob->countInstsOfGroups(commitWidth);
while (num_committed < commit_width) {
// 提交循环
}
4.2 线程选择 (commit.cc:1140-1159)
ThreadID commit_thread = getCommittingThread();
if (commit_thread == -1 || !rob->isHeadGroupReady(commit_thread))
break;
4.3 指令提交判断 (commit.cc:1173-1431)
- 被冲刷指令: 直接退休 (commit.cc:1173-1186)
- 正常指令: 调用
commitHead()处理 (commit.cc:1189-1190)
4.4 分支预测器更新和性能跟踪 (commit.cc:1196-1252)
4.4.1 性能恢复时间跟踪:
if (ismispred) {
ismispred = false;
stats.recovery_bubble += (cpu->curCycle() - lastCommitCycle) * renameWidth;
}
if (head_inst->mispredicted()) {
ismispred = true;
}
lastCommitCycle = cpu->curCycle();
4.4.2 多类型分支预测器的协同更新:
Stream预测器更新 (commit.cc:1205-1217):
FTB预测器更新 (commit.cc:1218-1234):
if (bp->isFTB()) {
auto dbftb = dynamic_cast<branch_prediction::ftb_pred::DecoupledBPUWithFTB*>(bp);
bool miss = head_inst->mispredicted();
// 返回指令的特殊日志记录
if (head_inst->isReturn()) {
DPRINTF(RAS, "commit inst PC %x miss %d real target %x pred target %x\n",
head_inst->pcState().instAddr(), miss,
head_rv_pc.npc(), *(head_inst->predPC));
}
// 跳过特权返回指令(与RTL行为一致)
if (!head_inst->isNonSpeculative() && head_inst->isControl()) {
dbftb->commitBranch(head_inst, miss);
// 统计间接分支预测错误
if (!head_inst->isReturn() && head_inst->isIndirectCtrl() && miss) {
misPredIndirect[head_inst->pcState().instAddr()]++;
}
}
dbftb->notifyInstCommit(head_inst);
}
BTB预测器更新 (commit.cc:1235-1252):
else if (bp->isBTB()) {
auto dbbtb = dynamic_cast<branch_prediction::btb_pred::DecoupledBPUWithBTB*>(bp);
// 类似FTB的处理逻辑,但使用BTB特定的接口
}
5. commitHead()函数 - 单指令提交核心逻辑 (commit.cc:1477-1747)
功能: 尝试提交ROB头部的单条指令,是指令提交的核心实现函数
参数说明:
- head_inst: ROB头部的动态指令指针
- inst_num: 当前周期已提交的指令数量,用于控制提交顺序
返回值:
- true: 指令成功提交,可以继续提交下一条指令
- false: 指令无法提交,需要等待或处理特殊情况
设计原则: - 确保指令按程序顺序提交,维护架构正确性 - 处理各种特殊情况:未执行指令、异常指令、序列化指令等 - 提供详细的状态反馈,支持流水线的精确控制
5.1 基本有效性检查 (commit.cc:1479-1481)
确保传入的指令指针有效,获取线程ID用于后续处理5.2 未执行指令的复杂处理逻辑 (commit.cc:1485-1524)
// If the instruction is not executed yet, then it will need extra handling.
if (!head_inst->isExecuted()) {
// 关键的序列化检查
if (inst_num > 0 || !iewStage->flushAllStores(tid)) {
DPRINTF(Commit,
"[tid:%i] [sn:%llu] "
"Waiting for all stores to writeback.\n",
tid, head_inst->seqNum);
return false;
}
// 通知IEW阶段处理非推测性指令
toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum;
// 标记指令不能提交,直到被执行
head_inst->clearCanCommit();
// 特殊处理严格有序的load指令
if (head_inst->isLoad() && head_inst->strictlyOrdered()) {
DPRINTF(Commit, "[tid:%i] [sn:%llu] "
"Strictly ordered load, PC %s.\n",
tid, head_inst->seqNum, head_inst->pcState());
toIEW->commitInfo[tid].strictlyOrdered = true;
toIEW->commitInfo[tid].strictlyOrderedLoad = head_inst;
} else {
++stats.commitNonSpecStalls;
}
return false;
}
可提交的未执行指令类型: - 非推测性指令: 系统调用、特权指令等 - Store Conditional: 原子读-修改-写操作 - 内存屏障: 读/写屏障指令 - 原子指令: AMO指令等 - 严格有序Load: 需要序列化的Load指令
关键序列化逻辑:
- inst_num > 0: 确保在一个周期内只有第一条未执行指令可以被处理
- !iewStage->flushAllStores(tid): 确保所有先前的store指令都已写回
5.3 全面的异常处理机制 (commit.cc:1526-1664)
// Check if the instruction caused a fault. If so, trap.
Fault inst_fault = head_inst->getFault();
// Hardware transactional memory fault conversion
if (inst_fault != NoFault && head_inst->inHtmTransactionalState()) {
if (!std::dynamic_pointer_cast<GenericHtmFailureFault>(inst_fault)) {
DPRINTF(HtmCpu, "%s - fault (%s) encountered within transaction"
" - converting to GenericHtmFailureFault\n",
head_inst->staticInst->getName(), inst_fault->name());
inst_fault = std::make_shared<GenericHtmFailureFault>(
head_inst->getHtmTransactionUid(),
HtmFailureFaultCause::EXCEPTION);
}
}
// Store instructions mark themselves as completed
if (!head_inst->isStore() && inst_fault == NoFault) {
head_inst->setCompleted();
}
if (inst_fault != NoFault) {
DPRINTF(CommitTrace, "[sn:%lu pc:%#lx] %s has a fault, mepc: %#lx, mcause: %#lx, mtval: %#lx\n",
head_inst->seqNum, head_inst->pcState().instAddr(),
head_inst->staticInst->disassemble(head_inst->pcState().instAddr()),
cpu->readMiscRegNoEffect(RiscvISA::MiscRegIndex::MISCREG_MEPC, tid),
cpu->readMiscRegNoEffect(RiscvISA::MiscRegIndex::MISCREG_MCAUSE, tid),
cpu->readMiscRegNoEffect(RiscvISA::MiscRegIndex::MISCREG_MTVAL, tid));
// 确保所有store指令完成后再处理异常
if (!iewStage->flushAllStores(tid) || inst_num > 0) {
DPRINTF(Commit,
"[tid:%i] [sn:%llu] "
"Stores outstanding, fault must wait.\n",
tid, head_inst->seqNum);
return false;
}
// 统计页面错误
if (faultNum.find(inst_fault->exception()) != faultNum.end()) {
stats.pagefaulttimes[tid]++;
}
head_inst->setCompleted();
// Checker验证
if (cpu->checker) {
cpu->checker->verify(head_inst);
}
assert(!thread[tid]->noSquashFromTC);
// 进入状态更新模式
thread[tid]->noSquashFromTC = true;
// 执行异常处理
cpu->trap(inst_fault, tid,
head_inst->notAnInst() ? nullStaticInstPtr :
head_inst->staticInst);
cpu->mmu->setOldPriv(cpu->getContext(tid));
// 退出状态更新模式
thread[tid]->noSquashFromTC = false;
commitStatus[tid] = TrapPending;
// Difftest异常处理
if (cpu->difftestEnabled() && inst_fault->isFromISA()) {
auto priv = cpu->readMiscRegNoEffect(
RiscvISA::MiscRegIndex::MISCREG_PRV, tid);
RegVal cause = 0;
// 根据特权级读取对应的cause寄存器
if (priv == RiscvISA::PRV_M) {
cause = cpu->readMiscReg(
RiscvISA::MiscRegIndex::MISCREG_MCAUSE, tid);
} else if (priv == RiscvISA::PRV_S) {
cause = cpu->readMiscReg(
RiscvISA::MiscRegIndex::MISCREG_SCAUSE, tid);
} else {
assert(priv == RiscvISA::PRV_U);
cause = cpu->readMiscReg(
RiscvISA::MiscRegIndex::MISCREG_UCAUSE, tid);
}
// 处理页面错误的特殊情况
auto exception_no = inst_fault->exception();
if (faultNum.find(exception_no) != faultNum.end()) {
cpu->setExceptionGuideExecInfo(
exception_no,
cpu->readMiscReg(RiscvISA::MiscRegIndex::MISCREG_MTVAL, tid),
cpu->readMiscReg(RiscvISA::MiscRegIndex::MISCREG_STVAL, tid),
false, 0, tid);
}
// 处理系统调用
if (cause == RiscvISA::ExceptionCode::ECALL_USER ||
cause == RiscvISA::ExceptionCode::ECALL_SUPER ||
cause == RiscvISA::ExceptionCode::ECALL_MACHINE) {
diffInst(tid, head_inst);
}
}
// 生成异常冲刷事件
generateTrapEvent(tid, inst_fault);
return false;
}
HTM异常处理: 在硬件事务内存环境下,将普通异常转换为HTM失败异常 异常延迟处理: 确保在处理异常前所有store指令都已完成 多特权级支持: 根据当前特权级读取相应的异常信息寄存器
5.4 正常指令提交的完整流程 (commit.cc:1666-1747)
// 特权返回指令的特殊日志记录
if (head_inst->isSerializeAfter() && head_inst->isNonSpeculative() && head_inst->isReturn()) {
DPRINTF(CommitTrace, "Priv return [sn:%llu] PC %s: %s, mepc: %#lx, sepc: %#lx\n",
head_inst->seqNum, head_inst->pcState(),
head_inst->staticInst->disassemble(head_inst->pcState().instAddr()),
cpu->readMiscRegNoEffect(RiscvISA::MISCREG_MEPC, tid),
cpu->readMiscRegNoEffect(RiscvISA::MISCREG_SEPC, tid));
}
// 记录提交的PC地址
committedPC[tid] = head_inst->pcState().instAddr();
// 更新指令统计信息
updateComInstStats(head_inst);
// 性能调试:检测长时间阻塞的load指令
uint64_t delta = (curTick() - lastCommitTick) / 500;
if (head_inst->isLoad() && (delta > 250)) {
DPRINTF(CommitTrace, "Inst[sn:%lu] commit blocked cycles: %lu\n",
head_inst->seqNum, delta);
}
// 架构数据库记录(用于详细的时序分析)
if (archDBer && head_inst->isMemRef())
dumpTicks(head_inst);
lastCommitTick = curTick();
// 调试信息输出
DPRINTF(Commit, "[tid:%i] [sn:%llu] Committing instruction with PC %s\n",
tid, head_inst->seqNum, head_inst->pcState());
// Store Conditional指令的特殊处理
if (head_inst->isStoreConditional()) {
DPRINTF(Commit, "[tid:%i] [sn:%llu] Store Conditional success: %i\n",
tid, head_inst->seqNum, head_inst->lockedWriteSuccess());
cpu->setSCSuccess(head_inst->lockedWriteSuccess(), head_inst->physEffAddr);
}
// 更新重命名映射表(架构状态提交)
for (int i = 0; i < head_inst->numDestRegs(); i++) {
renameMap[tid]->setEntry(head_inst->flattenedDestIdx(i),
head_inst->extRenamedDestIdx(i));
DPRINTF(Commit, "Committing rename map entry %s -> %s\n",
head_inst->destRegIdx(i),
head_inst->extRenamedDestIdx(i).toString());
}
// HTM指令的特殊处理
if (head_inst->isHtmStart())
iewStage->setLastRetiredHtmUid(tid, head_inst->getHtmTransactionUid());
// 从ROB中退休指令
rob->retireHead(tid);
// 记录store指令提交
if (head_inst->isStore() || head_inst->isAtomic())
committedStores[tid] = true;
return true; // 成功提交
关键提交步骤: 1. 统计信息更新: 各种性能计数器的更新 2. 架构状态提交: 重命名映射表的更新 3. 特殊指令处理: Store Conditional、HTM指令等 4. ROB管理: 指令从ROB中退休 5. 状态标记: 更新各种提交状态标志
6. markCompletedInsts()函数 - 指令完成标记 (commit.cc:1810-1827)
功能: 标记从IEW阶段传来的已完成指令,使其在ROB中变为可提交状态
// Grab completed insts out of the IEW instruction queue, and mark
// instructions completed within the ROB.
for (int inst_num = 0; inst_num < fromIEW->size; ++inst_num) {
assert(fromIEW->insts[inst_num]);
if (!fromIEW->insts[inst_num]->isSquashed()) {
DPRINTF(Commit, "[tid:%i] Marking PC %s, [sn:%llu] ready "
"within ROB.\n",
fromIEW->insts[inst_num]->threadNumber,
fromIEW->insts[inst_num]->pcState(),
fromIEW->insts[inst_num]->seqNum);
// Mark the instruction as ready to commit.
fromIEW->insts[inst_num]->setCanCommit();
}
}
处理逻辑:
- 遍历IEW传来的所有完成指令
- 跳过已被冲刷的指令
- 调用setCanCommit()标记指令可提交
- 提供详细的调试信息
7. getInsts()函数 - 指令获取管理 (commit.cc:1750-1784)
功能: 从Rename阶段获取新指令并插入到ROB中
DPRINTF(Commit, "Getting instructions from Rename stage.\n");
// Read any renamed instructions and place them into the ROB.
int insts_to_process = std::min((int)renameWidth, fromRename->size);
for (int inst_num = 0; inst_num < insts_to_process; ++inst_num) {
const DynInstPtr &inst = fromRename->insts[inst_num];
ThreadID tid = inst->threadNumber;
// 版本控制检查
if (localSquashVer.largerThan(inst->getVersion())) {
inst->setSquashed();
}
// 插入条件检查
if (!inst->isSquashed() &&
commitStatus[tid] != ROBSquashing &&
commitStatus[tid] != TrapPending) {
changedROBNumEntries[tid] = true;
DPRINTF(Commit, "[tid:%i] [sn:%llu] Inserting PC %s into ROB.\n",
tid, inst->seqNum, inst->pcState());
rob->insertInst(inst);
assert(rob->getThreadEntries(tid) <= rob->getMaxEntries(tid));
youngestSeqNum[tid] = inst->seqNum;
} else {
DPRINTF(Commit, "[tid:%i] [sn:%llu] "
"Instruction PC %s was squashed, skipping.\n",
tid, inst->seqNum, inst->pcState());
}
}
关键检查:
- 带宽限制: 处理指令数不超过renameWidth
- 版本控制: 使用localSquashVer检查指令是否应被冲刷
- 状态检查: 确保线程不在冲刷或异常处理状态
- ROB容量: 断言检查ROB不会溢出
8. squashInflightAndUpdateVersion()函数 - 在途指令冲刷 (commit.cc:1788-1807)
功能: 冲刷Rename到Commit之间的在途指令,并更新冲刷版本号
DPRINTF(Commit, "Squashing in-flight renamed instructions\n");
int cycle = 0; // Mark instructions renamed this cycle as squashed
auto tb_ptr = renameQueue->getWire(cycle);
DPRINTF(Commit, "%u insts in flight at cycle %d\n", tb_ptr->size, cycle);
for (unsigned i_idx = 0; i_idx < tb_ptr->size; i_idx++) {
const DynInstPtr &inst = tb_ptr->insts[i_idx];
DPRINTF(Commit, "[tid:%i] [sn:%llu] Squashing in-flight "
"instruction PC %s\n",
inst->threadNumber, inst->seqNum, inst->pcState());
inst->setSquashed();
}
// 更新冲刷版本号
localSquashVer.update(localSquashVer.nextVersion());
toIEW->commitInfo[tid].squashVersion = localSquashVer;
DPRINTF(Commit, "Updating squash version to %u\n",
localSquashVer.getVersion());
版本控制机制: 使用版本号确保冲刷的精确性,避免冲刷错误的指令
9. 冲刷相关函数详解
9.1 squashAll()函数 - 全局冲刷实现 (commit.cc:648-689)
功能: 冲刷指定线程的所有在途指令 - 计算冲刷序列号 - 调用ROB冲刷:rob->squash(squashed_inst, tid)
- 向IEW发送冲刷信息
9.2 squashFromTrap()函数 - 异常冲刷处理 (commit.cc:692-710)
功能: 处理异常引起的冲刷
- 调用squashAll()
- 设置异常冲刷标记: toIEW->commitInfo[tid].isTrapSquash = true
- 清理异常相关状态
9.3 squashFromTC()函数 - ThreadContext冲刷 (commit.cc:713-727)
功能: 处理ThreadContext引起的冲刷 - 类似异常冲刷,但不涉及异常处理逻辑
10. 线程调度策略实现
7.1 getCommittingThread()函数 (commit.cc:1931-1956)
功能: 根据SMT策略选择要提交的线程 - 单线程: 直接返回活动线程 - 多线程: 调用roundRobin()或oldestReady()
7.2 roundRobin()函数 (commit.cc:1959-1983)
功能: 轮询调度策略 - 按优先级列表轮流选择线程 - 更新优先级列表顺序
7.3 oldestReady()函数 (commit.cc:1986-2024)
功能: 最老指令优先策略 - 选择ROB头部序列号最小的线程
关键设计特点
1. 分组提交机制
- 支持按指令组进行提交,提高提交带宽利用率
rob->countInstsOfGroups(commitWidth)计算实际提交宽度
2. 多级冲刷优先级
按优先级处理不同类型的冲刷:
1. 异常冲刷 (最高优先级)
2. ThreadContext冲刷
3. SquashAfter冲刷
4. IEW发来的冲刷 (分支预测错误、内存序违例)
3. 异常处理机制
- 延迟异常处理:
generateTrapEvent() - 异常状态管理:
TrapPending状态 - 支持HTM(Hardware Transactional Memory)异常
4. 分支预测器协作
- 支持多种分支预测器: FTB、BTB、Stream等
- 在指令提交时更新分支预测器状态
- 维护分支预测错误统计
5. 性能优化特性
- 卡死检测: 超过40000个周期未提交时触发panic
- 指令跟踪: 支持difftest和执行跟踪
- 统计信息收集: 详细的性能计数器
与其他阶段的交互
1. 与IEW阶段
- 接收完成的指令:
fromIEW - 发送ROB状态信息:
toIEW - 处理冲刷请求
2. 与Rename阶段
- 接收新指令:
fromRename - 更新重命名映射表
3. 与Fetch阶段
- 发送冲刷信息影响取指
4. 与ROB
- 插入新指令:
rob->insertInst() - 退休指令:
rob->retireHead() - 冲刷指令:
rob->squash()
总结
Commit阶段是O3 CPU流水线的关键组件,确保指令的正确顺序提交和系统状态的一致性。其设计充分考虑了性能和正确性的平衡,支持多线程、异常处理、分支预测更新等复杂功能。通过精心设计的冲刷机制和状态管理,保证了乱序执行CPU的正确性。