fpga系列 HDL:SystemVerilog中的always_comb +always @(*)&assign+控制逻辑示例对比

Verilog 的三种主要描述方式

1. Continuous Assignment

assign y = a & b;

适合简单组合逻辑。


2. Procedural Assignment always @(*)

always @(*) begin
    ...
end
  • 适合复杂组合逻辑。
    • 很多组合逻辑无法用一个简单表达式描述。很难写成一个优雅的 assign

    • 于是 Verilog 提供了always @(*) begin...end用类似软件语言的写法描述组合逻辑。

    • always @(*) begin y = a & b; end综合为AND Gate

    • 根据敏感列表,always @(*) 综合器无法推导出 DFF,可导出组合逻辑 + Latch

3. Sequential Logic

always @(posedge clk)

适合寄存器。

always_comb

  • always_comb 是 SystemVerilog 专门用于描述**组合逻辑(Combinational Logic)**的过程块,可以看作是对 Verilog 中always @(*)的增强版和更安全版。

  • always_comb 中如果代码推导出了 latch,那就是编码错误,工具通常会报错或强警告。

  • 基本对应关系

VerilogSystemVerilog
always @(*)always_comb
always @(posedge clk)always_ff @(posedge clk)
锁存器逻辑always_latch

工程上通常遵循:

场景推荐
单行逻辑表达式assign
MUXassignalways_comb
if/case/for 等复杂逻辑always_comb
寄存器always_ff

典型写法

MUX

always_comb begin
    if (sel)
        y = a;
    else
        y = b;
end

Case状态转移

always_comb begin
    case(state)
        IDLE: next_state = RUN;
        RUN : next_state = STOP;
        default: next_state = IDLE;
    endcase
end

默认赋值防锁存器

推荐:

always_comb begin
    y = 0;

    if (en)
        y = a;
end

保证所有路径都赋值。

ALU 控制逻辑示例

assign写法

  • 逻辑包含运算、条件判断、溢出检测、默认赋值,如果用 assign,会变成大量嵌套三元运算符:
assign result =
    (op == ALU_ADD) ? (a+b) :
    (op == ALU_SUB) ? (a-b) :
    (op == ALU_AND) ? (a&b) :
    (op == ALU_OR ) ? (a|b) :
    (op == ALU_XOR) ? (a^b) :
    (op == ALU_SLT) ? ($signed(a)<$signed(b)) :
    32'd0;

verilog写法

module alu (
    input  [31:0] a,
    input  [31:0] b,
    input  [2:0]  op,

    output reg [31:0] result,
    output reg        overflow,
    output            zero
);

localparam ALU_ADD = 3'd0;
localparam ALU_SUB = 3'd1;
localparam ALU_AND = 3'd2;
localparam ALU_OR  = 3'd3;
localparam ALU_XOR = 3'd4;
localparam ALU_SLT = 3'd5;

always @(*) begin

    // 默认值
    result   = 32'd0;
    overflow = 1'b0;

    case(op)

        ALU_ADD: begin
            result = a + b;

            overflow =
                (~a[31] & ~b[31] & result[31]) |
                ( a[31] &  b[31] & ~result[31]);
        end

        ALU_SUB: begin
            result = a - b;

            overflow =
                (~a[31] &  b[31] & result[31]) |
                ( a[31] & ~b[31] & ~result[31]);
        end

        ALU_AND:
            result = a & b;

        ALU_OR:
            result = a | b;

        ALU_XOR:
            result = a ^ b;

        ALU_SLT:
            result = ($signed(a) < $signed(b));

        default: begin
            result   = 32'd0;
            overflow = 1'b0;
        end

    endcase

end

assign zero = (result == 32'd0);

endmodule
  • Verilog 为什么必须写 output reg因为中的 result 是在过程块(procedural block)里赋值的。Verilog 规定:
assign     → wire
always     → reg
  • 所以必须写:
output reg [31:0] result;
  • 否则编译报错:
output [31:0] result;

always @(*) begin
    result = a + b;
end
  • 但是这里的 reg 不是寄存器。综合结果为组合逻辑

在这里插入图片描述

  • 改为clk的情况:

在这里插入图片描述

SystemVerilog 写法(推荐)

typedef enum logic [2:0] {
    ALU_ADD,
    ALU_SUB,
    ALU_AND,
    ALU_OR,
    ALU_XOR,
    ALU_SLT
} alu_op_t;

module alu (
    input  logic [31:0] a,
    input  logic [31:0] b,
    input  alu_op_t     op,

    output logic [31:0] result,
    output logic        zero,
    output logic        overflow
);

always_comb begin

    // 默认值,避免Latch
    result   = '0;
    overflow = 1'b0;

    case(op)

        ALU_ADD: begin
            result = a + b;

            overflow =
                (~a[31] & ~b[31] & result[31]) |
                ( a[31] &  b[31] & ~result[31]);
        end

        ALU_SUB: begin
            result = a - b;

            overflow =
                (~a[31] &  b[31] & result[31]) |
                ( a[31] & ~b[31] & ~result[31]);
        end

        ALU_AND:
            result = a & b;

        ALU_OR:
            result = a | b;

        ALU_XOR:
            result = a ^ b;

        ALU_SLT:
            result = ($signed(a) < $signed(b));

        default:
            result = '0;

    endcase

end

assign zero = (result == 32'd0);

endmodule

现代编码风格对比

VerilogSystemVerilog
reg [31:0] result;logic [31:0] result;
always @(*)always_comb
always @(posedge clk)always_ff @(posedge clk)
parameter IDLE=0;typedef enum ...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值