gem5流程学习-1
执行gem5的命令是:
/mnt/c/work/gem5/build/RISCV/gem5.debug /mnt/c/work/gem5/configs/learning_gem5/part1/simple-riscv.py
gem5.debug是debug版本,正常编出来的是gem5.opt
- 入口函数 /mnt/c/work/gem5/src/sim/main.cc
try {
py::module_::import("m5").attr("main")();
}
这会加载 gem5 的 Python 前端模块 m5,并执行它的 main() 函数,m5.main() 会解析命令行,加载用户的 Python 配置脚本 - simple-riscv.py。
分析下simple-riscv.py

process.cmd 接受 gem5.debug的参数,就是binary文件。
m5.simulate()开启仿真。
看一段译码的调用栈:
gem5::RiscvISA::Decoder::decode(gem5::RiscvISA::Decoder * const this, gem5::PCStateBase & _next_pc) (\mnt\c\work\gem5\src\arch\riscv\decoder.cc:137)
gem5::BaseSimpleCPU::preExecute(gem5::BaseSimpleCPU * const this) (\mnt\c\work\gem5\src\cpu\simple\base.cc:369)
gem5::TimingSimpleCPU::completeIfetch(gem5::TimingSimpleCPU * const this, gem5::PacketPtr pkt) (\mnt\c\work\gem5\src\cpu\simple\timing.cc:841)
gem5::TimingSimpleCPU::IcachePort::ITickEvent::process(gem5::TimingSimpleCPU::IcachePort::ITickEvent * const this) (\mnt\c\work\gem5\src\cpu\simple\timing.cc:903)
gem5::EventQueue::serviceOne(gem5::EventQueue * const this) (\mnt\c\work\gem5\src\sim\eventq.cc:249)
gem5::doSimLoop(gem5::EventQueue * eventq) (\mnt\c\work\gem5\src\sim\simulate.cc:339)
gem5::simulate(gem5::Tick num_cycles) (\mnt\c\work\gem5\src\sim\simulate.cc:238)
...
在gem5::simulate之前的调用栈是在pybind11里面,这块目前不容易看,应该不需要改动,目前不需要细看。
2.执行 decode的函数:
StaticInstPtr
Decoder::decode(ExtMachInst mach_inst, Addr addr)
{
DPRINTF(Decode, "Decoding instruction 0x%08x at address %#x\n",
mach_inst.instBits, addr);
StaticInstPtr &si = instMap[mach_inst];
if (!si)
si = decodeInst(mach_inst);
si->size(compressed(mach_inst) ? 2 : 4);
DPRINTF(Decode, "Decode: Decoded %s instruction: %#x\n",
si->getName(), mach_inst);
return si;
}
真正的功能在si = decodeInst(mach_inst);
这个会根据arch的不同,调用不同的函数:
using namespace gem5;
StaticInstPtr
RiscvISA::Decoder::decodeInst(RiscvISA::ExtMachInst machInst)
{
文件: /mnt/c/work/gem5/build/RISCV/arch/riscv/generated/decoder-ns.cc.inc
在这个函数中,译码完成,返回一个具体指令的对象。
这些inc文件中的代码都是自动生成的,怎么生成的后面再讨论。
先画一张 c_jr 指令的 cycle 级执行流程图:
┌────────────────────────────────────────────────────┐
│ CPU 取指阶段 (Fetch) │
│────────────────────────────────────────────────────│
│ 1. 从内存/Cache 取 16bit 的 compressed 指令 c_jr │
│ 2. 更新 PC 到下一条(暂不跳转) │
└───────────────┬────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────┐
│ 译码阶段 (Decode) /mnt/c/work/gem5/build/RISCV/arch/riscv/generated/decoder-ns.cc.inc
| /mnt/c/work/gem5/build/RISCV/arch/riscv/generated/decode-method.cc.inc
│────────────────────────────────────────────────────│
│ A. 查表匹配到 C_jr 构造函数 │
│ - 设置 src/dest 寄存器编号 │
│ - 设置 flags: IsControl, IsReturn 等 │
│ - 记录 OpClass = IntAluOp │
│ B. 返回 C_jr 指令对象给 CPU │
└───────────────┬────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────┐
│ 生成微操作 / 执行语义 (Execute) /mnt/c/work/gem5/build/RISCV/arch/riscv/generated/exec-ns.cc.inc
│────────────────────────────────────────────────────│
│ 1. CPU 调用 C_jr::execute(xc, traceData) │
│ 2. execute() 来源于 src/arch/riscv/isa/compressed.isa│
│ - PC = GPR[RC1] │
│ - 发信号给分支预测器更新状态 │
│ - 返回 Fault::NoFault │
└───────────────┬────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────┐
│ CPU 功能单元调度 (FU) │
│────────────────────────────────────────────────────│
│ 1. 根据 OpClass = IntAluOp 分配整数 ALU 单元 │
│ 2. 功能单元延迟来自 CPU 配置 (FuncUnitConfig.py) │
│ - TimingSimpleCPU: 固定 1 cycle │
│ - O3CPU: 根据 FU latency + pipeline hazard 决定 │
└───────────────┬────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────┐
│ 分支预测 & Pipeline 控制 (Branch) │
│────────────────────────────────────────────────────│
│ - 如果预测错误:flush pipeline,重新取指 │
│ - flush 会额外浪费几 cycle(取决于流水深度) │
└───────────────┬────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────┐
│ 提交阶段 (Commit) │
│────────────────────────────────────────────────────│
│ - 将 PC 更新到跳转目标 │
│ - 清理 ROB 中的该条指令 │
│ - 下一条指令开始流入流水线 │
└────────────────────────────────────────────────────┘
- 下面看执行的地方,执行也在 TimingSimpleCPU::completeIfetch(PacketPtr pkt) 函数中。
preExecute(); -> 译码
// hardware transactional memory
if (curStaticInst && curStaticInst->isHtmStart()) {
// if this HtmStart is not within a transaction,
// then assign it a new htmTransactionUid
if (!t_info.inHtmTransactionalState())
t_info.newHtmTransactionUid();
SimpleThread* thread = t_info.thread;
thread->htmTransactionStarts++;
DPRINTF(HtmCpu, "htmTransactionStarts++=%u\n",
thread->htmTransactionStarts);
}
if (curStaticInst && curStaticInst->isMemRef()) {
// load or store: just send to dcache
Fault fault = curStaticInst->initiateAcc(&t_info, traceData);
// If we're not running now the instruction will complete in a dcache
// response callback or the instruction faulted and has started an
// ifetch
if (_status == BaseSimpleCPU::Running) {
if (fault != NoFault && traceData) {
traceFault();
}
postExecute();
// @todo remove me after debugging with legion done
if (curStaticInst && (!curStaticInst->isMicroop() ||
curStaticInst->isFirstMicroop()))
instCnt++;
advanceInst(fault);
}
} else if (curStaticInst) {
// non-memory instruction: execute completely now
Fault fault = curStaticInst->execute(&t_info, traceData); -> 执行
执行函数call stack:
gem5::RiscvISAInst::C_jr::execute(const gem5::RiscvISAInst::C_jr * const this, gem5::ExecContext * xc, gem5::trace::InstRecord * traceData) (\mnt\c\work\gem5\build\RISCV\arch\riscv\generated\exec-ns.cc.inc:2623)
gem5::TimingSimpleCPU::completeIfetch(gem5::TimingSimpleCPU * const this, gem5::PacketPtr pkt) (\mnt\c\work\gem5\src\cpu\simple\timing.cc:876)
gem5::TimingSimpleCPU::IcachePort::ITickEvent::process(gem5::TimingSimpleCPU::IcachePort::ITickEvent * const this) (\mnt\c\work\gem5\src\cpu\simple\timing.cc:903)
gem5::EventQueue::serviceOne(gem5::EventQueue * const this) (\mnt\c\work\gem5\src\sim\eventq.cc:249)
gem5::doSimLoop(gem5::EventQueue * eventq) (\mnt\c\work\gem5\src\sim\simulate.cc:339)
gem5::simulate(gem5::Tick num_cycles) (\mnt\c\work\gem5\src\sim\simulate.cc:238)
pybind11::detail::argument_loader<unsigned long>::call_impl<gem5::GlobalSimLoopExitEvent*, gem5::GlobalSimLoopExitEvent* (*&)(unsigned long), 0ul, pybind11::detail::void_type>(gem5::GlobalSimLoopExitEvent*

浙公网安备 33010602011771号