跳到主要内容
SystemVerilog

SystemVerilog 设计专用语法

SystemVerilog设计专用语法指南,涵盖always变体、时序逻辑建模、复位策略、generate等硬件设计专属内容

SV 设计

SystemVerilog 设计专用语法

这些语法主要用于RTL设计,描述实际硬件电路行为


层级总览

第三层  时序       always, always_ff, always_comb, always_latch
        ↓            (什么时候动)
第四层  生成       generate, genvar
        ↓            (编译期批量生成)

第三层:时序 — 什么时候动

3.1 always 四种变体

// ① 时序 — 上升沿触发(最常用)
always @(posedge clk) begin
    if (!rst_n)  count <= 0;
    else         count <= count + 1;
end

// ② 时序 — 带异步复位
always @(posedge clk or negedge rst_n) begin
    if (!rst_n)  result <= 0;
    else         result <= data;
end    // rst_n 下降沿直接复位, 不等 clk

// ③ 组合 — 老写法
always @(*) begin
    sum = a + b;     // *=任何输入变化都触发
end

// ④ SV 推荐写法
always_comb begin                    // 明确组合逻辑
    result_comb = mult_stage1 + c_stage1;
end

always_ff @(posedge clk) begin       // 明确时序逻辑
    q <= d;
end
写法意图推荐?
always @(posedge clk)时序✅ 通用
always_ff @(posedge clk)明确时序✅ SV 推荐
always @(*)组合⚠️ 老写法
always_comb明确组合✅ SV 推荐

3.2 initial vs always 对比

特性initialalways
执行次数1 次无限循环
可综合✅(有时钟的那种)
用在TB 初始化设计逻辑/时钟生成
多个块之间并行并行

3.3 clk — 芯片的心跳

clk = clock(时钟)的缩写。一根不停在 0 和 1 之间跳变的线。

clk:   ┌──┐  ┌──┐  ┌──┐  ┌──┐  ┌──┐  ┌──
       │  │  │  │  │  │  │  │  │  │  │
────────┘  └──┘  └──┘  └──┘  └──┘  └──
       ← 一个周期 →      ← 频率 = 1/周期
概念直白解释
clk周期性 0/1 跳变的线
频率每秒跳多少次(1 GHz = 每秒 10 亿次)
周期跳一次多久
为什么叫 clock芯片的”时钟”,所有寄存器踩同一个鼓点

设计中生成 clk:

// 设计中通常由外部提供时钟
input logic clk;

// 或者用 PLL/MMCM 生成
// 时钟生成单元例化

3.4 信号命名约定 — rst / rst_n / _n 后缀

rst = reset(复位)。当 rst 有效时,所有寄存器回到初始状态。

两种常见命名:

信号名有效电平怎么判断在复位
rst高有效if (rst)
rst_n低有效if (!rst_n)

后缀约定:

后缀全称含义常见度
(无后缀)高电平有效,默认约定⭐⭐⭐
_nnegative低电平有效⭐⭐⭐
_ppositive高电平有效,显式标出⭐ 极少用

绝大多数信号默认高有效,不加后缀就够了。_n 之所以普遍,正是因为它打破了默认——不加别人会误以为高有效。_p 则是”本来默认就是高有效还非要标”,几乎没有代码这样写。

rst    = 1  →  正在复位
rst_n  = 0  →  正在复位    (低有效,反直觉所以要后缀提醒)

if (!rst_n) 等价于 if (rst_n == 0) —— “复位被拉低了?”

真实芯片里复位通常低有效,因为上电瞬间电源不稳定,用低电平做复位更安全可靠。


时序逻辑建模

基本时序逻辑

// D触发器
always_ff @(posedge clk) begin
    q <= d;
end

// 带使能的D触发器
always_ff @(posedge clk) begin
    if (en)
        q <= d;
end

// 带复位的D触发器
always_ff @(posedge clk) begin
    if (!rst_n)
        q <= 1'b0;
    else
        q <= d;
end

非阻塞赋值(<=)在设计中的应用

// 流水线寄存器
always_ff @(posedge clk) begin
    stage1 <= data_in;
    stage2 <= stage1;
    stage3 <= stage2;
end

// 移位寄存器
always_ff @(posedge clk) begin
    shift_reg <= {shift_reg[WIDTH-2:0], serial_in};
end

// 计数器
always_ff @(posedge clk) begin
    if (!rst_n)
        count <= 0;
    else if (count == MAX)
        count <= 0;
    else
        count <= count + 1;
end

复位策略

异步复位

// 异步复位,同步释放
always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        // 异步复位:rst_n下降沿立即生效
        state <= IDLE;
        data <= 0;
    end else begin
        // 正常工作:只在clk上升沿更新
        state <= next_state;
        data <= next_data;
    end
end

敏感列表@(posedge clk or negedge rst_n)

  • negedge rst_n在敏感列表中
  • 复位信号变化时立即响应,不等时钟

同步复位

// 同步复位:只在clk边沿检查复位
always_ff @(posedge clk) begin
    if (!rst_n) begin
        // 同步复位:只在clk上升沿时检查rst_n
        state <= IDLE;
        data <= 0;
    end else begin
        state <= next_state;
        data <= next_data;
    end
end

敏感列表@(posedge clk)

  • 复位检查只在时钟边沿发生

异步复位 vs 同步复位对比

特性异步复位同步复位
响应速度立即响应等待时钟边沿
敏感列表negedge rst_n只含posedge clk
抗亚稳态需要同步处理天然同步
面积稍大稍小
推荐场景大多数设计高速设计

异步复位同步释放

// 推荐做法:异步复位,同步释放
logic rst_n_sync;

always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        rst_n_sync <= 1'b0;  // 异步复位
    end else begin
        rst_n_sync <= 1'b1;  // 同步释放
    end
end

// 使用同步后的复位
always_ff @(posedge clk or negedge rst_n_sync) begin
    if (!rst_n_sync)
        state <= IDLE;
    else
        state <= next_state;
end

第四层:生成 — 编译期批量生成

4.1 generate / genvar — 编译期批量生成

genvar i;
generate
    for (i = 0; i < 16; i++) begin : gen_block
        assign out[i] = data[i] & mask[i];
    end
endgenerate
// 等价于手写 16 行 assign, 不用复制粘贴

4.2 generate if — 条件生成

generate
    if (WIDTH == 8) begin : gen_8bit
        assign out = data[7:0];
    end else if (WIDTH == 16) begin : gen_16bit
        assign out = data[15:0];
    end else begin : gen_default
        assign out = data[WIDTH-1:0];
    end
endgenerate

4.3 generate for — 循环生成

// 生成16个D触发器
genvar i;
generate
    for (i = 0; i < 16; i++) begin : gen_ff
        always_ff @(posedge clk) begin
            q[i] <= d[i];
        end
    end
endgenerate

4.4 generate case — 多路选择生成

generate
    case (MODE)
        0: begin : gen_mode0
            assign out = a & b;
        end
        1: begin : gen_mode1
            assign out = a | b;
        end
        default: begin : gen_default
            assign out = 1'b0;
        end
    endcase
endgenerate

时钟生成

设计中的时钟

// 设计中通常不自己生成时钟
// 时钟由外部PLL/MMCM提供

module my_design (
    input logic clk,        // 外部输入时钟
    input logic rst_n,
    // ...
);
    // 直接使用clk
    always_ff @(posedge clk) begin
        // ...
    end
endmodule

仿真中的时钟生成

// TB中生成时钟(不可综合)
initial clk = 0;
always #5 clk = ~clk;           // 每 5ns 翻转 → 周期 10ns → 频率 100MHz

// 或者
always #(CLK_PERIOD/2) clk = ~clk;

附录:设计语法速查表

语法用途可综合
always_ff时序逻辑
always_comb组合逻辑
always_latch锁存器
generate编译期生成
genvar生成变量
initial初始化(TB)
forever无限循环(TB)

最后更新: 2026-07-16