一条 store 指令的前世今生
发射: 从 instQueue 到 storePipeline
Gem5 执行到 IEW::executeInsts()
函数时,根据 fromIssue->size
得知此时允许发射的指令有多少条,然后通过循环次从 instQueue 中取出可以发射的指令: instQueue.getInstToExecute()
若是此时指令已经被冲刷 (inst->isSquashed()
) : 标记该指令已执行并且可以提交 (由 commit 阶段来处理被冲刷指令) 后继续处理下一条指令
对于访存指令 (inst->isMemRef()
) , 如果是 store 指令 (inst->isStore()
) , 则将指令加入 store pipeline: ldstQueue.issueToStorePipe(inst)
。随后执行流水线: ldstQueue.executePipeSx()
ldstQueue.issueToStorePipe()
调用该指令对应硬件线程号的 LSQUnit::issueToStorePipe()
, 主要是该 store 指令加入 storePipeSx[0]
的尾部
执行: 从 storePipeline 到 storeQueue
ldstQueue.executePipeSx()
调用所有线程对应的 LSQUnit::executePipeSx()
, 分别执行 load 流水线和 store 流水线: executeLoadPipeSx()
, executeStorePipeSx()
.
对于 store 流水线:第一级进行地址翻译 storeDoTranslate()
, 第二级写入 StoreQueue storeDoWriteSQ()
并检查是否被冲刷,第二三四级清空流水线 emptyStorePipeSx()
。如果指令需要 replay 则终止该指令流水 inst->endPipelining()
并处理下一条指令。特别地,对于发生 TLBmiss 而需要 replay 的,还需要通知发射队列: iewStage->deferMemInst(inst)
stage1: address translation
在 xs-gem5 中,指令的 initiateAcc()
API 仅仅用于进行 TLB 访问, 在此处被调用
- inst->initiateAcc()
- xc->writeMem()
- cpu->pushRequest()
- iew.ldstQueue.pushRequest()
- LSQ::pushRequest()
- 计算是否需要突发传输:计算地址访问范围是否跨 cache block
- 如果跨 cache block: 则将请求设置为
SplitDataRequest
- 如果不跨 cache block: 则将请求设置为
SingleDataRequest
- 如果跨 cache block: 则将请求设置为
- 设置请求并开始地址翻译:
request->initiateTranslation()
- 将要写入的数据放入 inst->memData
- 计算是否需要突发传输:计算地址访问范围是否跨 cache block
SplitDataRequest
根据 cacheline 大小,将整个需要访问的内存区间划分成多个对 cacheline 的请求(头部和尾部需要单独处理以排除不需要访问的区间), 压入 _reqs
,对其中的每一个请求设置一些标志位后调用 MMU 开始地址翻译:sendFragmentToTranslation()->translateTiming()
stage2: write into StoreQueue
如果指令地址翻译已完成并且需要访存,则调用 LSQUnit::write()
,作用是将要写入的数据和指令信息写入 storeQueue 的 entry
如果没有 fault, 则检查该 store 指令是否和在飞 load 指令存在违例:checkViolations()
提交: 从 storeQueue 到 storeBuffer
指令进入 LSQ::commitStore() 时将 storeQueue 中最年轻的指令标记为可以写回
随后指令进入 LSQ::writebackStoreBuffer()
- 指令先被写入 storeBuffer: offloadToStoreBuffer()
- 对于 split 请求
- 其每个子请求均插入 storeBuffer:
insertStoreBuffer()
- 所有子请求均成功插入后,标记 store 指令完成并从 storeQueue 中移除该指令:
completeStore()
- 其每个子请求均插入 storeBuffer:
- 对于 split 请求
- 指令进入 storeBuffer 之后准备写入 cache : storeBufferEvictToCache()