Verilog/SystemVerilog 语言基础
最小模块
跳转到“最小模块”module mux2 #( parameter int WIDTH = 8) ( input logic [WIDTH-1:0] a, input logic [WIDTH-1:0] b, input logic sel, output logic [WIDTH-1:0] y); always_comb begin y = sel ? b : a; endendmodulelogic 表示四态变量,可由一个连续赋值、一个过程块或一个模块输出驱动,但不能有多个过程驱动。真正需要多驱动解析的网络使用 wire/net 类型。
常用运算符
跳转到“常用运算符”| 类别 | 运算符 | 注意 |
|---|---|---|
| 算术 | + - * / % | 除法和取模可能生成昂贵电路 |
| 位运算 | & | ^ ~ | 对每一位操作 |
| 逻辑 | && || ! | 结果用于条件判断 |
| 归约 | &a |a ^a | 将向量归约为 1 位 |
| 比较 | == != < <= > >= | 注意符号和 x |
| 拼接 | {a, b} | 位宽为各段之和 |
| 复制 | {N{value}} | 常用于扩展和掩码 |
| 选择 | cond ? a : b | 通常综合为多路选择器 |
===/!== 会把 x/z 也作为普通值比较,主要用于 Testbench;设计逻辑通常使用 ==/!=,并通过复位和断言处理未知值。
begin-end
跳转到“begin-end”if、always、循环和 case 分支语法上只接受一条 statement;begin-end 把多条语句组成一个块。建议即使只有一条语句也保留,避免以后加语句时改变控制范围。
if (enable) begin data <= next_data; valid <= 1'b1;end else begin valid <= 1'b0;end语句块中的书写顺序不会自动让硬件串行工作;电路行为由赋值类型、数据依赖和时钟决定。
if 与 case
跳转到“if 与 case”always_comb begin grant = 4'b0000; priority casez (request) 4'b1???: grant = 4'b1000; 4'b01??: grant = 4'b0100; 4'b001?: grant = 4'b0010; 4'b0001: grant = 4'b0001; default: grant = 4'b0000; endcaseendcase逐位精确匹配,包括x/z。casez将比较表达式和分支项两侧的z/?都视为通配符;只适合已控制输入四态来源的明确掩码匹配,否则输入上的z可能掩盖问题。- 避免
casex:它会把真实输入中的x也当通配符,可能掩盖未初始化或冲突。 priority表明按顺序选择;unique表明最多一个分支匹配。仿真器可据此检查意图,但前提是代码确实满足承诺。
循环的两种阶段
跳转到“循环的两种阶段”- 过程块中的固定边界
for:综合时展开重复逻辑。 generate for:在 elaboration 阶段生成模块实例或结构。#delay、无限循环、文件 I/O 和fork-join通常只属于仿真环境,不应出现在可综合设计中。
易错点
跳转到“易错点”- 将 C 语言的“变量赋值”直觉套到信号和寄存器上。
- 省略位宽和符号,导致扩展或截断错误。
- 组合块遗漏默认值或
default。 - 同一信号由
assign和always同时驱动。 - 把
x当作综合优化提示;综合结果和仿真行为可能因此分离。