4. 规格文档实战
在数字IP项目中,规格文档不是“写给评审看的说明文”,而是后续RTL设计、验证、综合、签核共同依赖的唯一事实源。一份可执行的规格,必须让不同角色读出同一套行为:设计者知道接口与状态如何实现,验证者知道激励与检查点如何构造,后端知道时钟、复位与寄存器地址如何约束。本章围绕“需求→可执行规格”的转化,重点拆解寄存器映射、时序图与状态机描述三类核心表达。
一、核心原理:规格的三层可执行化
需求通常以自然语言出现,例如“支持低功耗唤醒”“传输延迟不超过8周期”。这类描述无法直接驱动设计。可执行规格需要完成三层转化:
- 接口层:把功能需求落到端口、协议、位宽、时钟域与复位策略上,明确输入输出方向与握手规则。
- 状态层:把行为需求落到状态机的状态、迁移条件、输出动作与异常回退路径上。
- 数据层:把配置与观测需求落到寄存器映射、字段权限、默认值、读写属性与地址偏移上。
三层之间必须可追溯。例如“低功耗唤醒”在接口层表现为pwrup_req与clk_en,在状态层表现为IDLE→WAKE→ACTIVE迁移,在数据层表现为PM_CTRL[0]使能位与PM_STATUS[2]唤醒标志。缺少任何一层,规格都会在实现阶段产生歧义。
二、方法流程:寄存器映射的规范化写法
寄存器映射是规格中最容易被低估的部分。它不仅是地址表,更是软硬件接口契约。推荐使用“地址偏移 + 字段表 + 访问属性 + 复位值”四元组描述,并明确字段的读写行为与副作用。
| 寄存器名 | 偏移 | 字段 | 位域 | 属性 | 复位值 | 说明 |
|---|---|---|---|---|---|---|
| CTRL | 0x00 | EN | [0] | RW | 0x0 | 模块使能,0→1 触发初始化 |
| CTRL | 0x00 | MODE | [2:1] | RW | 0x0 | 00 直通,01 缓存,10 旁路 |
| STATUS | 0x04 | BUSY | [0] | RO | 0x0 | 1 表示传输进行中 |
| STATUS | 0x04 | ERR | [3:1] | RO | 0x0 | 错误编码,0 表示无错误 |
| IRQ_EN | 0x08 | ERR_EN | [0] | RW | 0x0 | 错误中断使能 |
| IRQ_CLR | 0x0C | ERR_CLR | [0] | W1C | 0x0 | 写 1 清除错误标志 |
字段属性必须精确到“写 1 清除”“读清零”“自清除”等语义。例如W1C若写成RW,验证者会构造错误的回读序列,设计者也可能实现成普通寄存器,导致中断无法清除。
// 推荐:寄存器描述片段(SystemRDL 风格)
reg CTRL {
field { sw=rw; hw=r; reset=0; } EN[0:0];
field { sw=rw; hw=r; reset=0; } MODE[2:1];
};
reg IRQ_CLR {
field { sw=w; hw=r; woclr; reset=0; } ERR_CLR[0:0];
};
三、时序图与状态机:把“什么时候发生”写清楚
时序图解决“信号在时间轴上的先后关系”,状态机解决“系统在什么条件下进入什么状态”。两者必须互相印证:时序图中的握手信号,应能对应状态机中的迁移条件;状态机中的输出动作,应能在时序图中找到具体波形。
以一次带错误上报的传输为例,规格中应明确:req拉高后,ack在1~2周期内响应;若err有效,则busy拉低、irq置位,直到IRQ_CLR.ERR_CLR写入1。状态机可描述为:
IDLE --req & en--> ACTIVE
ACTIVE --done--> IDLE
ACTIVE --err--> ERROR
ERROR --err_clr--> IDLE
任意状态 --rst_n=0--> IDLE
注意:状态机描述必须包含复位迁移与异常回退,否则验证无法覆盖“错误后能否恢复”。同时,状态编码建议在规格中给出,避免设计与验证各自定义导致比对失败。
四、案例与复盘:一次规格歧义引发的返工
某项目规格中写“传输完成后产生中断”。设计者理解为“数据写入FIFO即完成”,验证者理解为“对端确认接收后才完成”,结果在联调阶段出现中断提前、数据丢失。复盘发现,问题不在RTL,而在规格缺少三个关键限定:
- “完成”的判定点未绑定到具体信号,如
wr_done或ack。 - 中断与状态寄存器的置位顺序未定义,导致回读时序不一致。
- 错误场景下中断是否屏蔽、是否可清除未写入寄存器映射。
综上,从需求到可执行规格,本质是把模糊意图压缩为接口、状态、数据三层可验证表达。寄存器映射提供软硬件契约,时序图提供时间约束,状态机提供行为骨架。三者一致,规格才真正具备驱动设计、验证与签核的能力。