FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
登录
首页-技术文章/快讯-技术分享-正文

从零开始学Verilog:数据类型与运算符详解

二牛学FPGA二牛学FPGA
技术分享
1小时前
0
0
2

Quick Start

  • 步骤一:安装EDA工具(如Vivado或ModelSim),并创建一个空工程。
  • 步骤二:新建一个Verilog源文件(.v),输入以下代码作为第一个模块:
    module hello_world;
    initial begin
    $display("Hello, Verilog!");
    #10 $finish;
    end
    endmodule
  • 步骤三:在仿真器中编译该文件,无语法错误即通过。
  • 步骤四:运行仿真(run -all),观察控制台输出“Hello, Verilog!”。
  • 步骤五:修改代码,声明一个reg类型变量并赋值:
    reg [3:0] counter;
    initial begin
    counter = 4'b1010;
    $display("counter = %b", counter);
    end
  • 步骤六:运行仿真,确认输出为“counter = 1010”。
  • 步骤七:尝试使用运算符,如加法:
    reg [3:0] a, b, sum;
    initial begin
    a = 4'b0011;
    b = 4'b0101;
    sum = a + b;
    $display("sum = %b", sum);
    end
  • 步骤八:运行仿真,验证sum输出为“1000”(即3+5=8)。

前置条件与环境

项目/推荐值说明替代方案
EDA工具Vivado 2020.1+ 或 ModelSim SE-64 10.5+Quartus Prime、Icarus Verilog(开源)
仿真器Vivado Simulator 或 ModelSimVCS、NC-Verilog
器件/板卡无(仅仿真学习)任意FPGA开发板(如Xilinx Artix-7)
时钟/复位仿真中手动提供时钟周期(如#10 clk = ~clk)PLL或外部晶振(上板时)
接口依赖无(纯仿真)UART/SPI等(上板时)
约束文件仅仿真不需要;上板时需要XDC/SDCQSF(Quartus)
操作系统Windows 10/11 或 Linux CentOS 7+macOS(需虚拟机)

目标与验收标准

  • 功能点:掌握Verilog中wire、reg、integer、parameter等数据类型的声明与使用。
  • 功能点:熟练使用算术、逻辑、位、关系、移位、拼接等运算符
  • 性能指标:无(纯语法学习,不涉及时序约束)。
  • 验收方式:能独立编写一个包含多种数据类型和运算符的仿真测试模块,并正确输出预期结果。
  • 关键日志:仿真控制台显示所有$display输出,无编译错误或警告。

实施步骤

工程结构

创建一个新目录,包含以下文件:
- top.v:主模块(用于测试)。
- tb.v:测试激励模块(可选,但推荐)。
对于纯语法学习,直接在top.v中写initial块即可。

关键模块:数据类型

Verilog有四大基本数据类型:wire(线网)、reg(寄存器)、integer(整数)、parameter(参数)。

// wire:用于组合逻辑连接,不能存储值wire [7:0] data_bus;assign data_bus = 8'hA5;// reg:用于过程赋值(always/initial),可存储值reg [3:0] count;initial count = 4'd0;// integer:32位有符号整数,常用于循环integer i;initial for(i=0; i<10; i=i+1) $display("%d", i);// parameter:编译时常量parameter WIDTH = 8;reg [WIDTH-1:0] data;

注意wire只能在assign或模块端口赋值,reg只能在alwaysinitial中赋值。混用会导致编译错误。

关键模块:运算符

运算符分为以下几类,每类给出示例:

// 算术运算符:+ - * / %reg [3:0] a = 4'd7, b = 4'd3;reg [3:0] sum = a + b;  // 10 -> 4'b1010// 逻辑运算符:&& || !wire logic_result = (a > 4'd5) && (b < 4'd5);// 位运算符:& | ~ ^wire [3:0] bitwise_and = a & b;  // 4'b0011// 关系运算符:> = <= == !=wire eq = (a == b);  // 0// 移位运算符:<>wire [3:0] shifted = a << 1;  // 4'b1110// 拼接运算符:{ }wire [7:0] concat = {a, b};  // 8'b01110011// 条件运算符:? :wire [3:0] max = (a > b) ? a : b;

注意:算术运算中,结果宽度由操作数最大宽度决定,可能溢出。使用$signed()$unsigned()控制符号。

时序/CDC/约束

本教程为语法入门,不涉及时序约束或跨时钟域。但需注意:
- 在always @(posedge clk)中,赋值使用非阻塞赋值<=,避免竞争。
- 组合逻辑使用阻塞赋值=

验证

编写测试模块,覆盖所有数据类型和运算符:

module tb;    reg [3:0] a, b;    wire [7:0] concat;    assign concat = {a, b};    initial begin        a = 4'b1010; b = 4'b0101;        #10;        $display("a=%b, b=%b, concat=%b", a, b, concat);        $display("a+b=%b", a + b);        $display("a&amp;b=%b", a &amp; b);        $display("a&gt;&gt;1=%b", a &gt;&gt; 1);        $display("max=%b", (a &gt; b) ? a : b);        #10 $finish;    endendmodule

验收点:仿真输出所有$display结果,且符合预期。

常见坑与排查

  • 坑1:把wire放在always块中赋值 → 编译错误。需改为reg或使用assign
  • 坑2:算术运算结果溢出但未察觉 → 使用足够宽度的变量,或检查高位。
  • 坑3:逻辑运算符与位运算符混淆(如&& vs &) → 逻辑运算符返回1位布尔值,位运算符按位操作。
  • 坑4:拼接运算符中位宽不匹配 → 确保每个元素位宽明确,如{4'b1010, 4'b0101}
  • 坑5:移位运算符对reg类型操作时,结果可能为x → 确保操作数已初始化。

原理与设计说明

Verilog的数据类型和运算符设计遵循硬件描述的核心需求:wire对应物理连线,reg对应存储单元(触发器或锁存器)。parameter允许设计可配置,避免硬编码。运算符直接映射到硬件门电路:加法器、比较器、多路选择器等。理解这一点有助于写出高效的RTL代码。

关键trade-off
- 使用integer类型在仿真中方便,但综合时会被视为32位寄存器,浪费资源。推荐使用reg指定位宽。
- 拼接运算符{}可以简化数据打包,但过多嵌套会降低可读性,建议用assign分步完成。
- 条件运算符?:综合为多路选择器,嵌套深度过大时影响时序。可改用case语句。

验证与结果

测试用例输入预期输出实际输出(仿真)
加法a=4'b1010 (10), b=4'b0101 (5)4'b1111 (15)4'b1111
位与a=4'b1010, b=4'b01014'b00004'b0000
移位右移1位a=4'b10104'b01014'b0101
拼接a=4'b1010, b=4'b01018'b101001018'b10100101
条件运算符a=10, b=51010

测量条件:Vivado 2020.1 Simulator,默认设置,无时序约束。

故障排查(Troubleshooting)

  • 现象:编译错误“Illegal assignment to wire” → 原因:在always块中给wire赋值。检查点:确认变量类型。修复:改为reg或使用assign。
  • 现象:仿真输出为x或z → 原因:变量未初始化或未驱动。检查点:查看initial块或assign语句。修复:在initial中赋初值。
  • 现象:算术结果截断 → 原因:结果位宽不足。检查点:比较操作数和结果位宽。修复:扩展结果位宽或使用$signed。
  • 现象:逻辑运算结果始终为0或1 → 原因:误用位运算符代替逻辑运算符。检查点:检查运算符类型。修复:使用&&、||、!。
  • 现象:拼接结果顺序错误 → 原因:拼接顺序与期望相反。检查点:确认{}内元素顺序。修复:调整顺序。
  • 现象:移位后高位丢失 → 原因:移位操作未考虑位宽。检查点:移位位数是否超过位宽。修复:使用中间变量或限制移位位数。
  • 现象:条件运算符嵌套导致综合警告 → 原因:嵌套过深。检查点:检查代码复杂度。修复:改用case语句。
  • 现象:仿真时间过长 → 原因:无限循环。检查点:检查for或while循环条件。修复:添加$finish或限制循环次数。

扩展与下一步

  • 扩展1:学习wireregalways @(*)中的使用,实现组合逻辑。
  • 扩展2:掌握for循环和generate语句,实现参数化设计。
  • 扩展3:学习系统任务如$monitor$dumpvars用于调试。
  • 扩展4:尝试编写一个简单的计数器模块,综合并上板验证。
  • 扩展5:研究运算符的优先级,避免因优先级错误导致的逻辑错误。
  • 扩展6:学习使用typedefstruct(SystemVerilog)进行更高级的数据组织。

参考与信息来源

  • IEEE Std 1364-2001 (Verilog HDL) 官方标准
  • “Verilog HDL: A Guide to Digital Design and Synthesis” by Samir Palnitkar
  • Xilinx Vivado Design Suite User Guide (UG901)
  • EDA Playground 在线仿真平台(https://www.edaplayground.com/)

技术附录

术语表

  • wire:线网类型,用于连接模块端口或组合逻辑输出。
  • reg:寄存器类型,用于存储值,在always或initial中赋值。
  • integer:32位有符号整数,常用于仿真循环。
  • parameter:编译时常量,用于参数化设计。
  • 阻塞赋值(=):立即执行,用于组合逻辑。
  • 非阻塞赋值(<=):在always块结束时更新,用于时序逻辑。

检查清单

  • [ ] 所有变量类型正确(wire/reg)。
  • [ ] 所有运算符使用正确,优先级明确。
  • [ ] 拼接运算符中位宽匹配。
  • [ ] 算术运算结果位宽足够。
  • [ ] 仿真无编译错误。
  • [ ] 所有$display输出与预期一致。

关键约束速查

约束说明示例
位宽声明使用[MSB:LSB]格式reg [7:0] data;
基数表示二进制'b,十进制'd,十六进制'h8'b1010_1010
符号扩展使用$signed()$signed(a) + $signed(b)
阻塞赋值组合逻辑中使用=always @(*) c = a & b;
非阻塞赋值时序逻辑中使用<=always @(posedge clk) q <= d;
标签:
本文原创,作者:二牛学FPGA,其版权均为FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训所有。
如需转载,请注明出处:https://z.shaonianxue.cn/39242.html
二牛学FPGA

二牛学FPGA

初级工程师
这家伙真懒,几个字都不愿写!
79618.18W3.96W3.67W
分享:
成电国芯FPGA赛事课即将上线
基于UART的通信协议实现:FPGA实战指南
基于UART的通信协议实现:FPGA实战指南上一篇
从零开始学Verilog:数据类型与运算符详解下一篇
从零开始学Verilog:数据类型与运算符详解
相关文章
总数:822
FIFO深度计算与异步FIFO设计实践指南

FIFO深度计算与异步FIFO设计实践指南

QuickStart准备Vivado2020.1+或Quartus…
技术分享
4天前
0
0
14
0
FPGA/数字IC验证与嵌入式软件工程师职业发展对比指南

FPGA/数字IC验证与嵌入式软件工程师职业发展对比指南

在集成电路与嵌入式系统领域,FPGA/数字IC设计验证工程师与嵌入式软件…
技术分享
8天前
0
0
26
0
FPGA 零基础入门指南:2026 年高效学习路线图

FPGA 零基础入门指南:2026 年高效学习路线图

QuickStart:30分钟跑通第一个FPGA工程本指南假设你…
技术分享
3小时前
0
0
2
0
评论表单游客 您好,欢迎参与讨论。
加载中…
评论列表
总数:0
FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
没有相关内容