FPGA学习笔记——Verilog中可综合和不可综合语句
目录
一、 绝对可综合的语句(RTL核心)
1. 模块声明 (Module Declaration)
2. 端口定义 (Input, Output, Inout)
3. wire和reg变量声明
4. 参数和局部参数 (Parameter, Localparam)
5. 赋值语句 (Assignments)
6. 过程块 (Always Blocks)
7. 条件语句 (If-Else)
8. 多路选择语句 (Case)
9. 循环语句 (For Loops)
10. 算术和逻辑运算符
11. 位选择和部分选择
12. 模块实例化 (Module Instantiation)
13. Generate 语句
二、 通常(或绝对)不可综合的语句
1.初始语句 (initial):
2.时间延迟 (#delay):
3.仿真系统任务 (System Tasks):
4.实时事件触发器 (event):
5.wait 语句:
6.while, repeat, forever 循环(非固定边界):
7.force 和 release:
三、 需要谨慎使用或工具相关的语句
可综合的意思是,这些代码能够被EDA工具(如Synopsys Design Compiler, Vivado, Quartus等)转换成确定的数字电路网表(由基本门、触发器、宏单元等组成)。其核心是描述硬件结构和寄存器传输级(RTL)行为。
一、 绝对可综合的语句(RTL核心)
1. 模块声明 (Module Declaration)
module module_name (input clk, // 输入端口input rst_n,input [7:0] data_in,output reg [7:0] data_out // 输出端口
);
// ... 逻辑代码 ...
endmodule
2. 端口定义 (Input, Output, Inout)
input
,output
,inout
关键字用于定义模块的端口方向。
3. wire和reg变量声明
wire
:表示电路中的物理连线,用于连接元件。通常由assign
语句或模块实例化驱动。
reg
:不一定代表触发器! 它表示一个保持值的存储体。在always
块中赋值的变量必须声明为reg
类型,它可能被综合成触发器(时序逻辑)或组合逻辑(如多路选择器)。
4. 参数和局部参数 (Parameter, Localparam)
parameter WIDTH = 8;
localparam STATE_IDLE = 2'b00;
5. 赋值语句 (Assignments)
连续赋值 (Continuous Assignment
assign
): 用于描述组合逻辑,等式右端操作数的任何变化都会立即导致左端更新。
wire a, b, c;
assign c = a & b; // 综合为一个与门
过程赋值 (Procedural Assignment): 在
always
或initial
块中使用(但initial
通常不可综合)。阻塞赋值 (
=
):顺序执行,用于组合逻辑建模。非阻塞赋值 (<=
):并行执行,用于时序逻辑建模(触发器)。
6. 过程块 (Always Blocks)
时序逻辑 (Flip-Flops):使用时钟(
clk
)或时钟+复位(rst
)的边沿作为敏感列表。
always @(posedge clk or negedge rst_n) beginif (!rst_n) begin// 复位逻辑:异步复位data_out <= 8‘b0;end else begin// 时钟上升沿触发的逻辑data_out <= data_in; // 一个8位寄存器end
end
组合逻辑 (Combinational Logic):使用电平敏感的通配符
*
或列出所有输入信号。
always @(*) begin // 或 always @(a, b, sel)case (sel)2‘b00: y = a;2’b01: y = b;default: y = 1‘b0;endcase
end
// 这会综合为一个多路选择器(MUX)
注意:描述组合逻辑的
always
块中,必须确保所有条件下每个输出都有赋值,否则会隐含锁存器(Latch)!可以使用default
分支或赋默认值来避免。
7. 条件语句 (If-Else)
通常被综合为多路选择器(MUX)或优先级编码逻辑。
if (enable) beginout = in1;
end else beginout = in2;
end
8. 多路选择语句 (Case)
通常被综合为一个多路选择器。比同等功能的
if-else
结构更并行,面积可能更优。
case (opcode)3‘b000: result = a + b;3’b001: result = a - b;3‘b010: result = a & b;default: result = 8’b0; // 防止产生锁存器!
endcase
9. 循环语句 (For Loops)
可综合,但有严格条件:循环次数必须在编译时是固定的(即循环边界是常量)。
它会被综合工具展开(Unroll),生成多份硬件电路。
// 可综合:循环8次,被展开为8个相同的逻辑单元
integer i;
always @(*) beginfor (i = 0; i < 8; i = i + 1) beginparity[i] = ^data[((i+1)*8)-1 : i*8]; // 计算每个字节的奇偶校验位end
end
不可综合示例:循环次数在运行时才确定的
for
循环。
10. 算术和逻辑运算符
+
,-
,*
,&
,|
,^
,~
,<<
,>>
等都可综合。注意:
*
(乘法)和/
(除法)会综合成乘法器/除法器,可能很耗资源。对于大位宽操作,需要谨慎。
<< n
(逻辑左移n位)通常综合为连线的重排,不消耗逻辑资源。
>> n
(逻辑右移n位)同上。
11. 位选择和部分选择
wire [31:0] bus;
wire [7:0] byte = bus[15:8]; // 部分选择
wire bit = bus[0]; // 位选择
12. 模块实例化 (Module Instantiation)
这是层次化设计的基础,用于调用其他模块或供应商提供的IP核(如PLL, RAM等)。
and_gate u_and_gate (.a (input_a), // 端口连接.b (input_b),.c (output_c)
);
13. Generate 语句
用于生成重复的硬件结构或有条件地实例化代码,在编译时确定。
genvar i;
generatefor (i=0; i<4; i=i+1) begin : gen_loopmy_module u_mod (.in(a[i]), .out(b[i]));end
endgenerate
二、 通常(或绝对)不可综合的语句
1.初始语句 (initial
):
用于testbench初始化信号,生成激励。
除FPGA上用于初始化
reg
变量的少数情况外(如reg var = 0;
),绝大多数initial
块不能被ASIC综合工具接受。
// 在模块中尝试初始化寄存器(ASIC综合通常不支持)
reg [7:0] counter = 8'b0; // 这种写法在FPGA综合中可能被接受,用于上电初始化initial begin// 这种在initial块中对信号进行赋值的写法绝对不可综合state = IDLE;data_bus = 32'hFFFF_FFFF;enable = 0;
end
2.时间延迟 (#delay
):
如
#5 a = b;
。RTL设计是功能描述,不关心绝对延时。
initial beginclk = 0;#10; // 延迟10个时间单位rst_n = 1; // 10个时间单位后,将复位信号拉高#5 data = 8'hFF; // 再延迟5个时间单位后赋值
end
3.仿真系统任务 (System Tasks):
$display
,$monitor
,$finish
,$stop
,$random
等,用于仿真调试和测试。
always @(posedge clk) beginif (data_valid) begin$display("At time %t, data = %h", $time, data_out); // 打印信息$monitor("Signal changed: a = %b, b = %b", a, b); // 监控信号变化data_array[addr] = $random; // 使用随机数end
endinitial begin#1000 $finish; // 仿真1000个单位后结束
end
4.实时事件触发器 (event
):
用于进程间同步,无直接硬件对应。
event start_operation; // 声明一个事件initial begin-> start_operation; // 触发事件
endalways @(start_operation) begin // 等待事件发生// ... 执行操作
end
5.wait
语句:
基于电平的无限等待,综合工具无法处理。
// 等待“start”信号变为高电平
always @(posedge clk) beginwait (start == 1'b1); // 等待start变高// ... 后续操作
end
6.while
, repeat
, forever
循环(非固定边界):
综合工具无法确定其运行时间和硬件规模。
// 不确定循环次数,直到满足条件
always @(posedge clk) beginwhile (data != 8‘hAA) begin // 循环次数在编译时未知data <= data + 1;end
end// 无限循环
initial beginforever begin // 永远运行,没有边界#5 clk = ~clk; // 常用于testbench生成时钟end
end
7.force
和 release
:
仿真中的强制信号操作。
initial begin#100;force top.dut.counter = 8‘d255; // 强制将层次化路径中的某个信号拉高#200;release top.dut.counter; // 释放强制
end
三、 需要谨慎使用或工具相关的语句
integer
和real
:
integer
通常可综合,它只是一个32位的寄存器。
real
(浮点数)基本不可综合,除非使用特殊的IP核。用户自定义原语 (UDP):
理论上可综合,但支持度因工具而异,现在基本被模块替代,不推荐使用。
tri
(三态线):
可综合,但通常只用于顶层接口(连接片外总线)或FPGA内部的一些特殊资源(如IOB)。芯片内部绝大多数是单向信号。
以上就是Verilog中可综合和不可综合语句。(如果有错误,还请大家指出来,谢谢!)