Skip to main content

verilog-code

编写和审查可综合的 Verilog RTL 代码。当用户要求编写、设计、实现、修复或审查任何 Verilog/RTL 模块、 硬件模块或数字逻辑时自动触发。触发词包括:写Verilog、写RTL、实现模块、设计电路、review代码、 审查Verilog、FSM、状态机、FIFO、pipeline、流水线、arbiter、仲裁器、counter、计数器、 shift register、移位寄存器、handshake、握手协议、AXI、APB、SPI、I2C、UART、 clock divider、分频器、debounce、去抖、edge detector、边沿检测、synchronizer、同步器、 dual-port RAM、双端口RAM。即使用户只说"写一个模块"或"实现这个功能"而没有显式提到"Verilog", 也应使用此 skill。涵盖新代码生成和已有 Verilog 代码的 review/debug。

소스 정보

저장소
Ljj05170930/verilog-code-plugin
최근 소스 활동
2026년 4월 12일 11:49
감지된 SKILL.md 언어
중국어
스타
0
포크
1

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

파일 탐색기
4 개 파일

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
verilog-code
description
编写和审查可综合的 Verilog RTL 代码。当用户要求编写、设计、实现、修复或审查任何 Verilog/RTL 模块、 硬件模块或数字逻辑时自动触发。触发词包括:写Verilog、写RTL、实现模块、设计电路、review代码、 审查Verilog、FSM、状态机、FIFO、pipeline、流水线、arbiter、仲裁器、counter、计数器、 shift register、移位寄存器、handshake、握手协议、AXI、APB、SPI、I2C、UART、 clock divider、分频器、debounce、去抖、edge detector、边沿检测、synchronizer、同步器、 dual-port RAM、双端口RAM。即使用户只说"写一个模块"或"实现这个功能"而没有显式提到"Verilog", 也应使用此 skill。涵盖新代码生成和已有 Verilog 代码的 review/debug。
user-invocable
true
# Verilog RTL 编码指南 ## 1. 模式检测 根据用户意图判断工作模式: **WRITE 模式**(用户要求创建/实现/设计模块): - 遵循下方所有编码规则 - 如果要实现的模块匹配已知设计模式(FSM、FIFO、pipeline 等),先读取 `references/design-patterns.md` 中对应章节作为起点 **REVIEW 模式**(用户要求检查/审查/debug 已有代码): - 读取 `references/review-checklist.md`,按照结构化流程逐项审查 - 如果发现的问题匹配已知错误类型,参考 `references/common-mistakes.md` --- ## 2. 硬件思维 — Verilog 不是软件 这是写出正确 Verilog 的根基。在写每一行代码前,用以下思维替代软件的顺序执行模型: **并行执行**:每个 `always` 块是一个独立的硬件电路,所有 `always` 块同时运行。它们不是"按顺序执行的函数",而是"同时工作的独立电路"。 **非阻塞赋值 `<=`(时钟块)**:在 `always @(posedge clk)` 中,所有 RHS 在时钟沿**同时采样**,然后所有 LHS **同时更新**。这意味着: ```verilog always @(posedge clk) begin a <= b; // a 拿到的是 b 的旧值 b <= a; // b 拿到的是 a 的旧值 → 实现了交换 end ``` 这不是"先执行第一行再执行第二行",而是一个寄存器组在时钟沿同时锁存。 **阻塞赋值 `=`(组合块)**:在 `always @(*)` 中使用,描述组合逻辑的连线关系。虽然有执行顺序,但综合结果是同一个门级电路。 **绝对禁止混用**:同一个 `always` 块内不得同时出现 `<=` 和 `=`。时钟块用 `<=`,组合块用 `=`。 **`wire` 是导线,`reg` 是存储或组合输出**:`reg` 不一定是寄存器——在组合 `always` 块中的 `reg` 综合后是纯组合逻辑。关键在于它被 `always` 块驱动。 --- ## 3. 可综合性规则 RTL 代码中**禁止使用**以下仿真专用语法: | 禁止的语法 | 原因 | 替代方案 | |---|---|---| | `initial` 块 | 无硬件对应物 | 使用复位信号初始化 | | `#10` 等延时 | 不可综合 | 用时钟周期控制时序 | | `$display`, `$monitor`, `$finish` | 系统任务 | 仅在 TB 中使用 | | `fork`/`join` | 无硬件对应物 | 用并行 always 块 | | `force`/`release`/`deassign` | 不可综合 | 用正常赋值逻辑 | **必须遵守的规则**: - **完整条件**:所有 `if` 必须有 `else`,所有 `case` 必须有 `default`。不完整的条件会推断出 latch,这几乎从来不是你想要的 - **敏感列表**:组合逻辑用 `always @(*)`,不要手动列出信号。时序逻辑用 `always @(posedge clk or negedge rst_n)`(异步复位)或 `always @(posedge clk)`(同步复位) - **复位**:每个触发器都必须有复位值。使用 active-low 异步复位 (`rst_n`) 作为项目惯例 - **单驱动**:同一信号只能在一个 `always` 块或一条 `assign` 中驱动,不可多驱动 - **无内部三态**:内部信号不要用三态,用 mux 代替 - **整数除法**:非 2 的幂的除法和取模通常不可综合,用移位代替 --- ## 4. 模块结构模板 所有模块遵循以下统一结构,与项目现有风格保持一致: ```verilog module module_name #( parameter DATA_WIDTH = 8, parameter ADDR_WIDTH = 4 ) ( input wire clk, input wire rst_n, // ---- Input ports ------------------------------------------------ input wire [DATA_WIDTH-1:0] data_in, input wire valid_in, // ---- Output ports ----------------------------------------------- output reg [DATA_WIDTH-1:0] data_out, output reg valid_out ); // ========================================================================= // Local parameters // ========================================================================= localparam DEPTH = 1 << ADDR_WIDTH; // ========================================================================= // Internal signals // ========================================================================= reg [DATA_WIDTH-1:0] data_reg; wire some_condition; // ========================================================================= // Combinational logic // ========================================================================= assign some_condition = /* ... */; // ========================================================================= // Sequential logic // ========================================================================= always @(posedge clk or negedge rst_n) begin if (!rst_n) begin data_reg <= {DATA_WIDTH{1'b0}}; data_out <= {DATA_WIDTH{1'b0}}; valid_out <= 1'b0; end else begin // 功能逻辑 end end endmodule ``` **结构约定**: - `clk` 和 `rst_n` 始终是前两个端口 - 端口用 `// ---- 注释行 ----` 分组 - 模块内部按区域划分:Local parameters → Internal signals → Combinational → Sequential - 区域之间用 `// ===` 注释分隔(匹配项目现有风格) - 参数名 `UPPER_SNAKE_CASE`,信号名 `snake_case`,模块名 `snake_case` - Active-low 信号加 `_n` 后缀(如 `rst_n`, `cs_n`) - 时钟信号加 `clk` 前缀(如 `clk`, `clk_div2`) --- ## 5. 关键编码规则 ### 5.1 计数器边界 计数器 wrap-around 比较 `MAX_VAL - 1`,不是 `MAX_VAL`。这是最常见的 off-by-one 错误: ```verilog // 正确:0 到 N-1 共 N 个计数 if (count == MAX_COUNT - 1) begin count <= {WIDTH{1'b0}}; end else begin count <= count + 1'b1; end ``` ### 5.2 位宽匹配 显式指定所有字面量的位宽,不要使用无宽度字面量: ```verilog // 错误 count <= count + 1; // 1 是 32 位整数 data <= 0; // 0 是 32 位整数 // 正确 count <= count + 1'b1; data <= {DATA_WIDTH{1'b0}}; ``` 使用 `$clog2()` 从深度推导地址宽度: ```verilog localparam ADDR_WIDTH = $clog2(DEPTH); ``` ### 5.3 复位方法论 异步 active-low 复位,复位分支始终放在 if-else 的第一个分支: ```verilog always @(posedge clk or negedge rst_n) begin if (!rst_n) begin // 所有寄存器的复位值 — 不要漏掉任何一个 state <= IDLE; count <= {WIDTH{1'b0}}; data_out <= {DATA_WIDTH{1'b0}}; valid_out <= 1'b0; end else begin // 正常功能逻辑 end end ``` ### 5.4 FSM 编码 使用 `localparam` 定义状态,不要用 `` `define``。始终有 `default` 分支回到安全状态: ```verilog localparam [1:0] S_IDLE = 2'd0, S_LOAD = 2'd1, S_PROC = 2'd2, S_DONE = 2'd3; reg [1:0] state, state_next; ``` 组合逻辑中的 next-state 信号用 `_next` 后缀,寄存器版本不加后缀。 ### 5.5 流水线规则 - 所有数据信号必须经过**相同级数**的流水线寄存器 - `valid` 信号必须与数据**同步流水** - 添加反压(backpressure)时,stall 信号必须同时冻结数据和 valid ### 5.6 Valid/Ready 握手协议 - `valid` 不能依赖 `ready`(发送端不看接收端是否准备好就可以发起请求) - `ready` 可以依赖 `valid` - `valid` 一旦拉高,在 `ready` 为低期间不得撤回 - `valid` 为高期间数据必须保持稳定 ### 5.7 内存/数组声明 ```verilog // 正确:使用 [0:DEPTH-1] 显式声明范围 reg [DATA_WIDTH-1:0] mem [0:DEPTH-1]; // 读写模式 always @(posedge clk) begin if (wr_en) mem[wr_addr] <= wr_data; rd_data <= mem[rd_addr]; // 读优先,1 周期延迟 end ``` --- ## 6. 输出自检清单 生成 Verilog 代码后,在呈现给用户之前,逐条对照以下清单验证: - [ ] 每个 `if` 都有 `else`,每个 `case` 都有 `default` - [ ] 没有 `initial` 块、`#delay`、系统任务(`$display` 等) - [ ] 复位分支中列出了所有寄存器的复位值,无遗漏 - [ ] 时钟 `always` 块只用 `<=`,组合 `always` 块只用 `=`,无混用 - [ ] 所有字面量显式指定位宽(无裸 `0`、`1` 等整数字面量) - [ ] 组合逻辑敏感列表是 `@(*)`,时序逻辑是 `@(posedge clk or negedge rst_n)` - [ ] 计数器边界条件正确(比较 N-1 而不是 N,注意 off-by-one) - [ ] 无多驱动信号(同一信号在多个 always/assign 中赋值) - [ ] `clk`, `rst_n` 是模块的前两个端口 - [ ] 参数名 `UPPER_SNAKE_CASE`,信号名 `snake_case` - [ ] 组合 always 块中的信号在所有分支中都有赋值(防止 latch 推断) - [ ] FSM 的 case 语句有 default 分支,且 default 回到安全状态 --- ## 7. 参考文件 以下参考文件在需要时读取,不要每次都全部加载: - **`references/design-patterns.md`** — 当实现的模块匹配以下任何模式时读取: FSM、FIFO、pipeline、handshake/skid buffer、arbiter、counter、shift register、 edge detector、debouncer、clock divider、dual-port RAM、synchronizer - **`references/common-mistakes.md`** — 当调试综合错误、仿真不匹配、或需要理解某个 常见 Verilog 陷阱时读取 - **`references/review-checklist.md`** — 在 REVIEW 模式下读取,按照结构化流程审查代码 --- ## 8. Icarus Verilog 兼容性 RTL 代码使用 Verilog-2001/2005 语法,确保与 Icarus Verilog (`iverilog -g2012`) 兼容: - RTL 中使用 `reg`/`wire`,不要用 SystemVerilog 的 `logic` - 不要在 RTL 中使用 `always_ff`/`always_comb`/`always_latch`(这些是 SV 语法,仅 TB 中使用) - `$clog2()` 在 `-g2012` 模式下支持 - `generate` 块正常支持 - TB 文件是 SystemVerilog (`.sv`),由 `tb-creator` skill 处理,本 skill 不管 TB ## 9. 项目工作流提示 生成 RTL 文件后,提醒用户: - RTL 文件放在 `RTL/` 目录下 - 运行 VS Code 的 "compile and run" 任务来编译和仿真 - 如果有新的 RTL 文件,`gen_filelist.py` 会自动扫描 `RTL/` 目录
GitHub에서 보기