目录
[一、 绝对可综合的语句(RTL核心)](#一、 绝对可综合的语句(RTL核心))
[1. 模块声明 (Module Declaration)](#1. 模块声明 (Module Declaration))
[2. 端口定义 (Input, Output, Inout)](#2. 端口定义 (Input, Output, Inout))
[3. wire和reg变量声明](#3. wire和reg变量声明)
[4. 参数和局部参数 (Parameter, Localparam)](#4. 参数和局部参数 (Parameter, Localparam))
[5. 赋值语句 (Assignments)](#5. 赋值语句 (Assignments))
[6. 过程块 (Always Blocks)](#6. 过程块 (Always Blocks))
[7. 条件语句 (If-Else)](#7. 条件语句 (If-Else))
[8. 多路选择语句 (Case)](#8. 多路选择语句 (Case))
[9. 循环语句 (For Loops)](#9. 循环语句 (For Loops))
[10. 算术和逻辑运算符](#10. 算术和逻辑运算符)
[11. 位选择和部分选择](#11. 位选择和部分选择)
[12. 模块实例化 (Module Instantiation)](#12. 模块实例化 (Module Instantiation))
[13. Generate 语句](#13. Generate 语句)
[二、 通常(或绝对)不可综合的语句](#二、 通常(或绝对)不可综合的语句)
[1.初始语句 (initial):](#1.初始语句 (initial):)
[3.仿真系统任务 (System Tasks):](#3.仿真系统任务 (System Tasks):)
[4.实时事件触发器 (event):](#4.实时事件触发器 (event):)
[5.wait 语句:](#5.wait 语句:)
[6.while, repeat, forever 循环(非固定边界):](#6.while, repeat, forever 循环(非固定边界):)
[7.force 和 release:](#7.force 和 release:)
[三、 需要谨慎使用或工具相关的语句](#三、 需要谨慎使用或工具相关的语句)
可综合的意思是,这些代码能够被EDA工具(如Synopsys Design Compiler, Vivado, Quartus等)转换成确定的数字电路网表(由基本门、触发器、宏单元等组成)。其核心是描述硬件结构 和寄存器传输级(RTL)行为。
一、 绝对可综合的语句(RTL核心)
1. 模块声明 (Module Declaration)
rust
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
): 用于描述组合逻辑,等式右端操作数的任何变化都会立即导致左端更新。
rust
wire a, b, c;
assign c = a & b; // 综合为一个与门
过程赋值 (Procedural Assignment) : 在
always
或initial
块中使用(但initial
通常不可综合)。阻塞赋值 (
=
) :顺序执行,用于组合逻辑建模。非阻塞赋值 (<=
):并行执行,用于时序逻辑建模(触发器)。
6. 过程块 (Always Blocks)
时序逻辑 (Flip-Flops) :使用时钟(
clk
)或时钟+复位(rst
)的边沿作为敏感列表。
rust
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
// 复位逻辑:异步复位
data_out <= 8'b0;
end else begin
// 时钟上升沿触发的逻辑
data_out <= data_in; // 一个8位寄存器
end
end
组合逻辑 (Combinational Logic) :使用电平敏感的通配符
*
或列出所有输入信号。
rust
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)或优先级编码逻辑。
rust
if (enable) begin
out = in1;
end else begin
out = in2;
end
8. 多路选择语句 (Case)
通常被综合为一个多路选择器。比同等功能的
if-else
结构更并行,面积可能更优。
rust
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),生成多份硬件电路。
rust
// 可综合:循环8次,被展开为8个相同的逻辑单元
integer i;
always @(*) begin
for (i = 0; i < 8; i = i + 1) begin
parity[i] = ^data[((i+1)*8)-1 : i*8]; // 计算每个字节的奇偶校验位
end
end
不可综合示例 :循环次数在运行时才确定的
for
循环。
10. 算术和逻辑运算符
+
,-
,*
,&
,|
,^
,~
,<<
,>>
等都可综合。注意:
*
(乘法)和/
(除法)会综合成乘法器/除法器,可能很耗资源。对于大位宽操作,需要谨慎。
<< n
(逻辑左移n位)通常综合为连线的重排,不消耗逻辑资源。
>> n
(逻辑右移n位)同上。
11. 位选择和部分选择
rust
wire [31:0] bus;
wire [7:0] byte = bus[15:8]; // 部分选择
wire bit = bus[0]; // 位选择
12. 模块实例化 (Module Instantiation)
这是层次化设计的基础,用于调用其他模块或供应商提供的IP核(如PLL, RAM等)。
rust
and_gate u_and_gate (
.a (input_a), // 端口连接
.b (input_b),
.c (output_c)
);
13. Generate 语句
用于生成重复的硬件结构或有条件地实例化代码,在编译时确定。
rust
genvar i;
generate
for (i=0; i<4; i=i+1) begin : gen_loop
my_module u_mod (.in(a[i]), .out(b[i]));
end
endgenerate
二、 通常(或绝对)不可综合的语句
1.初始语句 (initial
):
用于testbench初始化信号,生成激励。
除FPGA上用于初始化
reg
变量的少数情况外(如reg var = 0;
),绝大多数initial
块不能被ASIC综合工具接受。
rust
// 在模块中尝试初始化寄存器(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设计是功能描述,不关心绝对延时。
rust
initial begin
clk = 0;
#10; // 延迟10个时间单位
rst_n = 1; // 10个时间单位后,将复位信号拉高
#5 data = 8'hFF; // 再延迟5个时间单位后赋值
end
3.仿真系统任务 (System Tasks):
$display
,$monitor
,$finish
,$stop
,$random
等,用于仿真调试和测试。
rust
always @(posedge clk) begin
if (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
end
initial begin
#1000 $finish; // 仿真1000个单位后结束
end
4.实时事件触发器 (event
):
用于进程间同步,无直接硬件对应。
rust
event start_operation; // 声明一个事件
initial begin
-> start_operation; // 触发事件
end
always @(start_operation) begin // 等待事件发生
// ... 执行操作
end
5.wait
语句:
基于电平的无限等待,综合工具无法处理。
rust
// 等待"start"信号变为高电平
always @(posedge clk) begin
wait (start == 1'b1); // 等待start变高
// ... 后续操作
end
6.while
, repeat
, forever
循环(非固定边界):
综合工具无法确定其运行时间和硬件规模。
rust
// 不确定循环次数,直到满足条件
always @(posedge clk) begin
while (data != 8'hAA) begin // 循环次数在编译时未知
data <= data + 1;
end
end
// 无限循环
initial begin
forever begin // 永远运行,没有边界
#5 clk = ~clk; // 常用于testbench生成时钟
end
end
7.force
和 release
:
仿真中的强制信号操作。
rust
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中可综合和不可综合语句。(如果有错误,还请大家指出来,谢谢!)