十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

XiangShan XSPdb 断点与触发机制详解:信号断点、表达式触发与 FSM 触发引擎

XiangShan XSPdb 断点与触发机制详解:信号断点、表达式触发与 FSM 触发引擎 XiangShan XSPdb 断点与触发机制详解信号断点、表达式触发与 FSM 触发引擎【免费下载链接】XiangShanOpen-source high-performance RISC-V processor项目地址: https://gitcode.com/GitHub_Trending/xia/XiangShan本文围绕香山处理器XiangShan仿真调试工具 XSPdb 的断点系统设计展开。XSPdb 是基于 Pythonpdb构建、面向香山 difftest 接口的调试器其断点能力分为三个层次基于xclock回调的信号断点xbreak、基于 C 表达式引擎的布尔表达式断点xbreak_expr以及支持多步序列条件的 FSM 触发器xbreak_fsm。读完本文你将掌握这三种触发机制的命令用法、表达式语法的完整语义包括within/hold时间窗助手、C 引擎的编译与求值流程以及仓库中可直接复用的香山信号实战表达式与 FSM 触发程序。一、断点系统总览XSPdb 断点系统的设计目标见 断点设计文档是基于信号值、表达式或 FSM 风格的多步条件来停止仿真或触发动作。三类触发器各解决一类调试需求触发器命令适用场景实现基础信号断点xbreak单个信号满足比较条件等于、变化等时中断xclock回调 ComUseCondCheck表达式断点xbreak_expr多信号布尔表达式支持within()/hold()时间助手C 表达式引擎每时钟沿求值FSM 触发器xbreak_fsm多状态、多步骤的复杂序列条件C FSM 引擎复用表达式引擎设计文档的关键说明xbreak注册的信号断点由xclock回调驱动每个时钟上升沿检查一次xbreak_expr支持带within()与hold()时间助手的布尔表达式xbreak_fsm从文本文件加载触发程序用于多步条件详细规格分别定义在 trigger_expr_spec.md 与 trigger_fsm_spec.md 中。相关管理命令包括xbreak_list列出断点、xbreak_clear清除全部、xbreak_update更新ch条件的当前基准值。所有命令的解析与底层 API 调用集中在 cmd_break.py 的CmdBreak类中实现。二、信号断点xbreak2.1 命令格式xbreak signal_name [condition] [value]condition支持eq, ne, gt, lt, ge, le, ch或等价符号, !, , , , 缺省为eqvalue缺省为0既可以是立即数十进制/十六进制也可以是另一个信号名此时比较两个信号的实时值ch表示 change值变化条件在condition_map中映射到ComUseCondCmp_NE比较语义。上述缺省值与参数解析可直接在 do_xbreak 的源码中确认value 0、condition eq为初始值int(args[2], 0)解析失败时会回退为信号名。2.2 实现机制基于 xclock 的每拍检查从 api_xbreak 的实现看信号断点的工作流程是首次设置断点时创建ComUseCondCheck(self.dut.xclock)检查器并将其回调注册到dut.xclock.StepRis时钟上升沿步骤回调上回调描述名为xdut_signal_break每个断点生成一个 keyxbreak-signal_name-condition-value并调用checker.SetCondition(xbreak_key, sig, val, cmp)注册比较条件信号通过self.dut.GetInternalSignal(signal_name)从 DUT 内部信号树解析当值参数是字符串且能解析为信号时比较对象是另一个信号的实时值否则构造一个与信号等宽的XData常量self.xsp.XData(sig.W(), ...)命中后call_break_callbackscmd_break.py会调用用户回调、处理callback_once触发一次后自动移除断点并与 fork backup 波形捕获联动_fork_backup_on_break以便在断点命中瞬间保存波形备份。api_xbreak还支持callback与callback_once参数这使得断点不仅可以停下来还能作为脚本化的观察点回调在批量脚本中配合xfork_backup_*使用。2.3 配套管理命令命令功能源码位置xunbreak key按 key 前缀移除断点不带参数会交互式询问是否清空xunbreak all清除全部do_xunbreakxbreak_list列出所有信号断点key、当前信号值、比较符、目标值、是否已提示命中do_xbreak_listxbreak_clear清除全部信号断点并注销时钟回调api_xbreak_clearxbreak_update刷新ch值变化断点的基准值把保存的val更新为信号当前值用于从此刻起再次变化时触发api_xbreak_update_ch当断点列表为空时实现会主动注销xdut_signal_break时钟回调见api_xunbreak中kcount 0分支避免空检查的每拍开销。2.4 香山实战表达式仓库的 表达式示例集 整理了在香山处理器调试中常用且有价值的断点表达式分为指令提交、异常、缓存访存三类均基于 difftest 接口暴露的 ROB 与流水线信号在特定 PC 地址的指令提交时中断最常用的断点例如 PC 为0x80000000的指令提交xbreak SimTop_top.SimTop.cpu.l_soc.core_with_l2.core.backend.inner_ctrlBlock.rob.difftest_commit_pc 0x80000000在特定指令编码提交时中断例如wfi指令编码0x10500073xbreak SimTop_top.SimTop.cpu.l_soc.core_with_l2.core.backend.inner_ctrlBlock.rob.difftest_commit_instr 0x10500073在任何异常发生时中断通用异常断点xbreak SimTop_top.SimTop.cpu.l_soc.core_with_l2.core.backend.inner_ctrlBlock.rob.io_exception_valid_REG 1仅在特定类型的异常例如中断发生时中断——多条件组合时改用xbreak_exprxbreak_expr SimTop_top.SimTop.cpu.l_soc.core_with_l2.core.backend.inner_ctrlBlock.rob.io_exception_valid_REG 1 SimTop_top.SimTop.cpu.l_soc.core_with_l2.core.backend.inner_ctrlBlock.rob.io_exception_bits_isInterrupt_r 1D-Cache 在特定地址发生 Miss 时中断调试性能问题或内存一致性问题的利器xbreak_expr SimTop_top.SimTop.cpu.l_soc.core_with_l2.core.memBlock.inner_dcache.dcache.mainPipe.s3_valid 1 SimTop_top.SimTop.cpu.l_soc.core_with_l2.core.memBlock.inner_dcache.dcache.mainPipe.s3_req_vaddr 0x80001000 SimTop_top.SimTop.cpu.l_soc.core_with_l2.core.memBlock.inner_dcache.dcache.missReqArb._io_out_valid_T 1I-Cache 在特定地址发生 Miss 时中断定位指令缓存未命中导致的前端性能瓶颈xbreak_expr SimTop_top.SimTop.cpu.l_soc.core_with_l2.core.frontend.inner_ifu.s2_valid 1 SimTop_top.SimTop.cpu.l_soc.core_with_l2.core.frontend.inner_ifu.s2_icacheMeta_0_pAddr_addr 0x80000000 SimTop_top.SimTop.cpu.l_soc.core_with_l2.core.frontend.inner_icache.missUnit.acquireArb._io_out_valid_T 1断点示例文档 还给出了与波形/步进联动的组合用法# 信号断点 xbreak SimTop_top.SimTop.timer eq 10000 xstep 100000 # 表达式触发 xbreak_expr within(SimTop_top.SimTop.timer 1000, 20) # FSM 触发 xbreak_fsm /abs/path/to/docs/XSPdb/examples/pc_sequence.fsm三、表达式断点xbreak_expr与 v1 表达式引擎3.1 命令集与 key 格式表达式引擎规格 v1 定义的用户命令为xbreak_expr expr编译表达式并武装断点返回自动生成的 keyxexpr-idid为当前会话内单调递增整数也可通过 API 的name参数自定义xunbreak_expr key按 key 移除已编译的表达式xbreak_expr_list列出所有已编译表达式及其触发状态。从 api_xbreak_expr 的实现看Python 侧只做两件事转发表达式字符串与 DUT 的XSignalCFG实例self.dut.xcfg其余解析和编译全部在 C 侧完成——这正是规格中Python 只转发C 解析编译的设计落地。编译失败时会打印xbreak_expr compile failed: 原因且不注册。3.2 表达式语法v1采用 Python 风格语法布尔逻辑and、or、not等价写法、||、!位运算 | ^ ~ 算术运算 - * / %比较运算 ! 括号分组整数字面量十进制、0x十六进制、0b二进制允许_分隔符信号名foo.bar.baz经XSignalCFG解析时间窗助手within(cycles, expr)与hold(cycles, expr)示例(sigA 1 and sigB ! 0) or ((sigC 0x3) 2)3.3 求值语义所有算术/位运算/移位按无符号 64 位求值比较运算分两种路径若任一操作数是宽于 64 位的信号走XData全宽比较且要求两侧操作数宽度一致此时另一侧操作数只能是信号或字面常量不能是计算表达式因为 v1 禁用了宽位宽算术。两侧都不超过 64 位或均为常量时走无符号 64 位比较and/or短路求值not在操作数为 0 时返回1否则返回0允许负数常量以无符号 64 位补码形式存储算术/位运算/移位不传播 X/Z 值比较使用XData语义X/Z 可能使相等判断为假within(N, expr)当expr现在为真、或最近N个周期含当前内为真时返回真within(0, expr)等价于expr本身hold(N, expr)当expr已连续为真至少N个周期时返回真hold(0, expr)与hold(1, expr)等价于expr本身within/hold是有状态节点只在被求值时更新内部状态。若它们位于被短路跳过的分支下该周期内其状态不更新——编写表达式时需注意把有状态助手放在不会长期短路的路径上。3.4 宽度规则与编译期校验编译期C 侧会做宽度检查对宽于 64 位的信号使用算术/位运算/移位时编译直接失败并给出明确错误wide arithmetic/bitwise/shift is not supported in v1宽信号比较允许但两侧操作数宽度必须一致信号对信号或信号对宽度匹配的常量。这一拒绝宽位宽算术而非静默截断的取舍是为了避免 64 位截断导致的误判。3.5 C 引擎设计表达式引擎的数据结构见 规格文档enum class ExprOp { CONST, SIGNAL, ADD, SUB, MUL, DIV, MOD, BAND, BOR, BXOR, BNOT, SHL, SHR, LAND, LOR, LNOT, EQ, NE, GT, GE, LT, LE, WITHIN, HOLD }; struct ExprNode { ExprOp op; int lhs; // 子节点 id未使用时为 -1 int rhs; // 子节点 id未使用时为 -1 XData* sig; // SIGNAL 节点 uint64_t imm; // CONST 值 uint32_t width; // SIGNAL 节点为信号宽度否则为 64 bool is_signal; uint64_t window; // WITHIN/HOLD 的时间窗 uint64_t last_true_cycle; // WITHIN 用 uint64_t last_hold_cycle; // HOLD 用 uint64_t hold_count; // HOLD 用 };ExprEngine对外暴露的 APIclass ExprEngine { public: int NewConst(uint64_t v); int NewSignal(XData* sig); int NewUnary(ExprOp op, int child); int NewBinary(ExprOp op, int lhs, int rhs); int NewCompare(ExprOp op, int lhs, int rhs); int NewCompareSigSig(ExprOp op, XData* lhs, XData* rhs); int NewCompareSigConst(ExprOp op, XData* lhs, uint64_t rhs); int NewCompareConstSig(ExprOp op, uint64_t lhs, XData* rhs); int NewWithin(int child, uint64_t window); int NewHold(int child, uint64_t window); uint64_t Eval(int root); void Clear(); };值处理求值只返回uint64_t。需要全宽信号语义的比较直接走XData路径——两个宽信号比较调用lhs_sig.Comp(rhs_sig, opcode, eq)要求宽度匹配信号对常量比较则在编译期构造一个引擎持有的临时XData常量宽度与信号一致常量零扩展或按补码截断到该宽度。触发流程ComUseExprCheck在每个时钟沿StepRis被调用执行清除上一拍的触发标记按注册顺序求值各表达式遇到第一个为真的表达式禁用所有绑定的时钟clk-Disable()、将该表达式标记为已触发、停止评估其余表达式。求值前ComUseExprCheck会把引擎当前周期设置为回调周期ComUseStepCb::cycle使within/hold能够以周期为单位测量时间窗。触发树求值顺序表达式存为扁平向量中的节点树深度优先求值并对布尔and/or短路v1 不做记忆化子表达式重复出现时编译器可选择共享节点 id 即 DAG 或复制节点。引擎还可按估计成本重排and/or操作数以提升短路效率但当子树包含有状态的within/hold节点时跳过重排以保持其状态更新语义。求值采用显式栈机器迭代实现而非递归。3.6 C 解析器词法规则标识符为[A-Za-z_][A-Za-z0-9_\.]*数字支持0x/0b/十进制且允许_分隔符运算符含 ! || - * / % | ^ ~ ! 与括号关键字and/or/not是/||/!的同义词。优先级从高到低一元~、-、乘除* / %加减 -移位 位运算 ^ |比较 ! 支持链式逻辑非not/!逻辑与and/逻辑或or/||其中比较支持链式写法a b c被编译为(a b) and (b c)。within/hold按函数调用形式解析可出现在任何主表达式位置。信号解析使用XSignalCFG::NewXData(name)引擎按名字缓存XData对象避免重复分配。3.7 Python API 面与诊断api_xbreak_expr(expr: str, name: str ) - str api_xunbreak_expr(key: str) - None api_xbreak_expr_list() - list[tuple]api_xbreak_expr内部调用ComUseExprCheck::CompileExpr(expr, cfg)并注册返回的 root idxbreak_expr命令返回生成的 key如xexpr-3。编译出错时打印原因且不注册命中时的行为与xbreak一致——停表禁用时钟并在控制台报告。v1 明确不做宽位宽64 位算术/位运算/移位、X/Z 传播、更高级的时间窗算子FSM 触发语言则由 trigger_fsm_spec.md 单独定义。四、FSM 触发器xbreak_fsm与状态机触发语言4.1 设计目标FSM 触发器规格 v1 定义了一个软件 FSM 触发引擎运行在 C、每个时钟沿推进一次转换条件复用xbreak_expr的表达式引擎因此转换条件中同样可用within/hold。目标是提供面向复杂多步序列的状态机触发语言状态/标志/计数器数量没有硬性上限纯软件实现。v1 的非目标X/Z 传播、类硬件资源限制ILA 风格的计数器/标志上限、单实例内并行 FSM任一时刻只有一个活动状态。4.2 用户命令xbreak_fsm fsm_file从文本文件加载 FSM 程序并武装xbreak_fsm_status显示当前状态与触发状态xbreak_fsm_clear移除 FSM 触发器及其回调。Python 侧实现见 api_xbreak_fsm_file检查文件存在后读取全文交给ComUseFsmTrigger同样注册到dut.xclock.StepRis回调描述名xdut_fsm_break执行LoadProgram(program_text, self.dut.xcfg)api_xbreak_fsm_status 返回name/state/triggered/trigger_state四元组。4.3 FSM 程序语法总则一个程序包含多个state块start state可选地指定初始状态缺省为第一个状态#开始行注释每行一条非空语句行尾;可选。状态定义state S0: if expr goto S1 elif expr goto S2 else goto S0转换语句if expr goto state/if expr triggerelif expr goto state/else goto state/else trigger也接受无条件转换goto state、trigger转换按书写顺序求值取第一个匹配的条件若都不匹配且没有elseFSM 停留在当前状态。动作语句在该状态活跃的每个周期、于转换检查之前执行set $flag_done clear $flag_done inc $counter_timeout reset $counter_timeout标志flag是 1 位计数器counter是 64 位变量名必须以$flag或$counter开头值更新立即可见同一周期内即可被转换条件引用。条件语法即表达式引擎语法and/or/not、位/算术/比较运算符、within/hold信号名经XSignalCFG解析$flag*与$counter*可作为表达式中的合法标识符。4.4 官方示例程序规格文档# 等待 sigA 出现然后在 200 个周期内观察到 sigB 连续 4 拍为 1 则触发 start IDLE state IDLE: reset $counter_timeout if sigA 1 goto WAIT_B else goto IDLE state WAIT_B: inc $counter_timeout if hold(4, sigB 1) trigger elif $counter_timeout 200 goto IDLE else goto WAIT_B该示例展示了三类机制的协同reset/inc维护超时计数器、hold(4, sigB 1)表达连续 4 拍、超时后回退IDLE重新开始等待。4.5 语义与 C 引擎每周期先执行当前状态的动作再按顺序评估转换FSM 始终保持单一活动状态trigger会禁用所有绑定时钟并记录触发时所在的状态GetTriggeredState()xbreak_fsm_status与断点名称汇总api_get_breaked_names均以FSM:state形式上报within/hold按节点持有状态语义见表达式规格标志/计数器在加载程序时与xbreak_fsm_clear时复位为 0。引擎设计ComUseFsmTrigger继承ComUseStepCb并注册到StepRis持有ExprEngine编译转换条件、状态表vectorFsmState含有序转换/动作以及标志/计数器存储并维护XData镜像供表达式访问。每周期流程1) 更新引擎周期SetCycle2) 执行当前状态动作更新标志/计数器3) 评估转换取首个匹配或默认4) 若为trigger禁用时钟并标记已触发。诊断行为解析错误报告行号与原因未知状态目标产生编译错误对计数器使用set/clear、对标志使用inc/reset会被拒绝。4.6 仓库中的真实 FSM 触发程序香山仓库提供两个可直接xbreak_fsm加载的示例配合 断点示例文档 中的xbreak_fsm /abs/path/to/docs/XSPdb/examples/pc_sequence.fsm使用路径需替换为实际绝对路径pc_sequence.fsm——追踪提交指令的 PC 序列。观察到0x...04 → 0x...08 → 0x80000000的提交序列时触发中间出现的其他 PC 值被忽略若在等待中途再次看到序列首 PC则重新对齐。程序使用SimTop_top.SimTop.cpu.l_soc.core_with_l2.core.backend.inner_ctrlBlock.rob.difftest_commit_pc作为观测信号三个状态WAIT_PC_0 → WAIT_PC_4 → WAIT_PC_80依次等待序列中的每个 PC最后一步trigger。csr_trace.fsm——追踪一次完整的 CSR 读写操作。观测信号来自后端 CSR 执行单元Exu_Csr_io_redirect_valid新指令进入 CSR 单元Exu_Csr_io_redirect_bits_is_write/is_read区分写操作csrw、csrrw等与纯读操作csrr等Exu_Csr_is_read当前操作是否含读分量Exu_Csr_release当前 CSR 操作完成。状态流为IDLE → WRITE → READ_WRITE → trigger纯读走IDLE → READ → IDLE完整覆盖 写且读 的csrrw类操作在释放时触发断点。五、三类触发器的架构关系与使用建议从 cmd_break.py 的CmdBreak类结构可以归纳出统一的回调模型三类触发器都遵循惰性创建检查器 → 注册xclock.StepRis回调 → 每拍检查 → 命中后禁用时钟的模式仅回调描述名不同xdut_signal_break/xdut_expr_break/xbreak_fsm_break且各自的断点集合清空后都会注销对应回调。api_get_breaked_namescmd_break.py把三类触发器与指令提交断点、目标提交观察点统一汇总为断点命中的名称列表供调试界面与 fork backup 使用。按调试复杂度选择触发器单信号等值/范围判断如 timer 到 10000、commit PC 命中→xbreak多信号组合、带时间窗的条件如20 个周期内 timer 命中过、信号连续 4 拍为高→xbreak_exprwithin/hold跨越多拍、需要中间状态/超时回退的序列PC 序列、CSR 读写流程→xbreak_fsm。三者命中的行为一致禁用绑定时钟使仿真停在命中沿控制台报告命中来源并可联动xfork_backup_*在断点命中时保存波形备份用于回放见 XSPdb 总览 中 Fork backup waveform:xfork_backup_*for xbreak-triggered wave capture 的说明。六、延伸阅读文档/文件内容断点设计文档本文主体断点系统设计概述与命令清单trigger_expr_spec.mdxbreak_expr表达式引擎 v1 完整规格trigger_fsm_spec.mdxbreak_fsmFSM 触发器 v1 完整规格xbreak_expr_examples.md香山调试常用表达式断点集合breakpoints.md 示例三类断点命令组合用法pc_sequence.fsm / csr_trace.fsm可直接加载的 FSM 触发程序cmd_break.py断点命令解析与 C 检查器的 Python 侧实现XSPdb README调试器总览、快速上手与批量脚本运行方式批量运行方式可参考 README 中的示例python3 scripts/pdb-run.py --script /abs/path/to/docs/XSPdb/examples/xspdb_script_example.txt断点命令可写入脚本中复现上述调试流程。【免费下载链接】XiangShanOpen-source high-performance RISC-V processor项目地址: https://gitcode.com/GitHub_Trending/xia/XiangShan创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表