这篇笔记主要是记录有关verilog的语法以及一些遇到过的问题。
1.fork...join
fork...join常用于仿真代码的编写中。fork...join 会同时启动其内部的所有 begin...end 块。块内的每个 begin...end 都是一个独立的进程。这些进程并发执行,直到所有进程都执行完毕,join 语句才会完成,仿真才会继续执行后面的代码。
fork
begin: join_FIFO_wr2
FIFO_write(16'd64); // 进程1: 向FIFO写入数据64
end
begin: join_RAM_wr2
#0; // 进程2: 延迟0个时间单位(详见下文)
for(i=32; i<40; i=i+1) begin
RAM_write(i); // 从地址32开始,连续写入8个数据
end
end
begin: join_FIFO_rd2
#0; // 进程3: 延迟0个时间单位
FIFO_read(16'd32); // 从FIFO读取32个数据
end
begin: join_RAM_rd2
#160; // 进程4: 延迟160个时间单位
for(i=0; i<32; i=i+1) begin
RAM_read(i); // 从地址0开始,连续读取32个数据
end
end
join // 等待所有四个进程执行完毕
执行的时间轴:
Fork-Join并发执行时间线
2.task...endtask
2.1定义
task <task_name>;
// 端口方向声明 (input, output, inout)
// 局部变量声明 (reg, integer, etc.)
//声明要放在begin的前面
begin
// 过程语句
end
endtask
2.2调用
// 调用任务
<task_name>;
// 带参数的调用
<task_name>(expr1, expr2, ..., exprN);
需要注意调用任务只能是一个独立的语句,不能用在表达式中。
实际例子:
module tb_test;
// 输入数据
reg [31:0] data_in;
// 使用 reg 类型接收任务输出
reg is_even;
reg [4:0] ones_count;
// 任务定义
task analyze_data;
input [31:0] data_in;
output is_even;
output [4:0] ones_count;
integer i;
begin
// 检查是否为偶数
is_even = (data_in[0] == 1'b0);
// 计算1的个数
ones_count = 0;
for (i = 0; i < 32; i = i + 1) begin
if (data_in[i] == 1'b1) begin
ones_count = ones_count + 1;
end
end
end
endtask
// 调用示例
initial begin
// 设置输入
data_in = 32'hA5A5A5A5;
// 调用任务 - 现在传递的是 reg 变量
analyze_data(data_in, is_even, ones_count);
// 立即显示结果(任务完成后)
$display("Even: %b, Ones count: %d", is_even, ones_count);
$display("Input data: %h", data_in);
// 测试另一个值
#10;
data_in = 32'h0000000F;
analyze_data(data_in, is_even, ones_count);
$display("Even: %b, Ones count: %d", is_even, ones_count);
$display("Input data: %h", data_in);
end
endmodule
在Verilog 中,任务的输出参数必须是能够存储值的变量类型(reg、integer 等),而不能是 wire 类型。在过程赋值中, task、always、initial 基本类似,使用 = 或 <=,而不使用用 assign。
还有一个很奇怪的点,task里面输入是默认为wire类型,但是你不能自己再定义为wire类型,比如说:
task analyze_data;
input wire [31:0] data_in; // 这样子写,modelsim仿真会报错

不知道为什么会这样子,所以输入一般都不定义,使用默认类型。
2.3注意事项
在仿真代码中,任务可以包含时序控制,这是任务与函数的根本区别。
task pulse_generate;
input start;
output pulse;
begin
pulse = 1'b0;
@(posedge start); // 等待 start 的上升沿
#5 pulse = 1'b1; // 延迟 5 个时间单位
#10 pulse = 1'b0; // 再延迟 10 个时间单位
end
endtask
3.Block RAM(块 RAM)和 Distributed RAM(分布式 RAM)的区别
Block RAM(块RAM)
-
专用硬件:FPGA芯片中预制的专用存储电路
-
大容量存储:单个BRAM通常为18Kb或36Kb,可级联成更大容量
-
独立资源:使用BRAM不消耗逻辑资源(LUT/FF)
-
真正双端口:支持两个完全独立的读写端口
-
适用场景:
-
大型数据缓冲区
-
FIFO存储器
-
处理器缓存
-
大型查找表
-
Distributed RAM(分布式RAM)
-
逻辑资源构建:使用可编程逻辑单元(LUT)实现存储功能
-
小容量灵活分布:每个LUT可配置为少量存储(如64位)
-
消耗逻辑资源:使用分布式RAM会占用可用于其他逻辑的LUT
-
低延迟访问:由于分布在逻辑单元中,访问延迟极低
-
适用场景:
-
小型寄存器文件
-
移位寄存器
-
浅FIFO
-
延迟线
-
小容量查找表
-
|------|--------------------|-----------------|
| 特性 | Block RAM | Distributed RAM |
| 物理本质 | 专用的硬件存储模块 | 由逻辑单元(LUT)配置而成 |
| 资源类型 | 专用存储资源 | 可编程逻辑资源 |
| 容量 | 大容量(通常18Kb/36Kb每块) | 小容量(每个LUT约64位) |
| 位置 | 芯片中固定的专用位置 | 分布在所有逻辑单元中 |
| 端口配置 | 支持真正双端口 | 通常为单端口或简单双端口 |
| 性能 | 较高的时钟频率 | 较低的访问延迟 |
| 功耗 | 静态功耗低 | 静态功耗相对较高 |
| 使用场景 | 大数据缓冲区、FIFO | 小型寄存器、移位寄存器 |
4.CLB Logic 与 XtremeDSP Slices 对比
4.1 CLB Logic(可配置逻辑块)
组成结构:
LUT:实现组合逻辑功能
触发器:实现时序逻辑和寄存器
多路器:数据选择器
进位链:快速算术运算
主要特点:
高度灵活:可以配置为实现几乎任何数字逻辑功能
通用性:适合控制逻辑、状态机、数据通路等
资源丰富:在FPGA中数量最多
编程自由:支持复杂的逻辑表达式
典型应用:
状态机和控制逻辑
数据路由和选择
接口协议实现
自定义算法逻辑
有限脉冲响应滤波器
4.2XtremeDSP Slices(DSP切片)
组成结构:
专用乘法器:高性能乘法运算
累加器:乘积累加操作
算术逻辑单元:各种算术运算
预加器:优化对称滤波器
流水线寄存器:提高时序性能
主要特点:
高性能:专门优化的数学运算硬件
低功耗:相比用CLB实现同样功能功耗更低
高密度:单个DSP切片可完成复杂运算
确定性时序:预定义的时序特性
典型应用:
复数乘法
有限脉冲响应滤波器
快速傅里叶变换
数字上下变频
矩阵运算
相关器
| 特性 | CLB Logic(可配置逻辑块) | XtremeDSP Slices(DSP切片) |
|---|---|---|
| 本质 | 通用可编程逻辑资源 | 专用数字信号处理硬件 |
| 主要功能 | 实现任意逻辑功能 | 高性能数学运算 |
| 核心组件 | LUT、触发器、多路器 | 乘法器、累加器、ALU |
| 灵活性 | 极高 | 有限但高度优化 |
| 性能 | 中等,依赖设计 | 极高,针对特定运算优化 |
| 功耗效率 | 相对较低 | 非常高 |
4.3例子
用CLB实现18×18乘法器
需要约200-300个LUT,最大频率约200-300MHz,功耗相对较高。
用DSP切片实现18×18乘法器
只需要1个DSP切片,最大频率500-700MHz, 功耗极低
5.UART
UART 负责完成数据的串并转换,而信号的传输则由外部驱动电路 实现。电信号的传输过程有着不同的电平标准和接口规范,针对异步串行通信的接口标准有 RS232、RS422、 RS485 等,它们定义了接口不同的电气特性,如 RS-232 是单端输入输出,而 RS-422/485 为差分输入输出 等。
| 特性 | RS-232 | RS-422 | RS-485 |
|---|---|---|---|
| 信号类型 | 单端(对地电压) | 差分 | 差分 |
| 传输线数量 | 1根Tx,1根Rx,共地线 | 1对Tx,1对Rx(4线) | 1对数据线(2线) |
| 通信方式 | 全双工 | 全双工 | 半双工(主流) |
| 驱动能力 | 1个发送器,1个接收器 | 1个发送器,最多10个接收器 | 最多32个发送器/接收器 |
| 通信距离 | 短(<15米) | 长(约1200米) | 长(约1200米) |
| 最大速率 | 低(< 20 m) | 高(10 Mbps @ 12 m) | 高(10 Mbps @ 12 m) |
| 抗干扰能力 | 弱 | 强 | 强 |
| 逻辑电平 | +3V to +15V = '0' -3V to -15V = '1' | ±2V to ±6V(两线间电压差) | ±1.5V to ±5V(两线间电压差) |
| 典型应用 | 电脑串口、老式调制解调器 | 工业环境长距离点对点通信 | 工业总线(PLC、传感器网络) |