FPGA语法篇——Verilog 语法知识
Verilog语法
目录
- Verilog语法
- 一、Verilog基础知识
- 逻辑值
- 数字进制
- 标识符
- 数据类型
- 寄存器类型
- 线网类型
- 参数类型
- 运算符
- 二、Verilog程序框架
- Verilog注释
- Verilog关键字
- Verilog程序框架
- 模块调用、例化——模块化设计
- 三、Verilog高级知识点
- 结构语句
- initial与always
- 赋值语句
- 阻塞赋值(Blocking)
- 非阻塞赋值(Non-Blocking)
- 总结
- assign 和 always 区别
- 条件语句
- if_else语句:
- case语句:
- latch锁存器
- 四、Verilog状态机FSM
- 状态机FSM概念
- 状态机模型
- Mealy状态机(输出=输入+之前状态)
- Moore 状态机(输出=之前状态)
- 状态机设计
- 1.状态空间定义
- 2.状态跳转(时序逻辑)
- 3.下一个状态的判断(组合逻辑)
- 4.各个状态下的动作(组合逻辑)
- 总结
一、Verilog基础知识
逻辑值
0、1、X(未知)、Z(高阻态)
数字进制
二进制:4’b0101 表示 4 位二进制数字 0101;
十进制:4’d2 表示 4 位十进制数字 2(二进制 0010);
十六进制:4’ha 表示 4 位十六进制数字 a(二进制 1010)
当代码中没有指定数字的位宽与进制时,默认为 32 位的十进制,比如 100,实际上表示的值为 32’d100。
标识符
用于定义模块名,端口名,信号名,由字母、数字、$和_(下划线)组成,第一个字符必须是字母或者下划线,区分大小写。
不建议大小写混合使用,普通内部信号建议全部小写,参数定义建议大写。
采用一些前缀或后缀,比如:时钟采用 clk 前缀:clk_50m,clk_cpu;低电平采用_n 缀:enable_n;
数据类型
寄存器类型、线网类型和参数类型。
寄存器类型
是一个数据存储单元,常用 reg 类型,默认初始值为X(未知)。
//reg define
reg [31:0] delay_cut; //32位寄存器
reg key_reg; //默认位宽为 1
只能在 always 语句和 initial 语句中被赋值。(不允许像C语言一样,在定义同时赋值)
如果该过程语句描述的是时序逻辑,即 always 语句带有时钟信号,则该寄存器变量对应为寄存器;
如果该过程语句描述的是组合逻辑,即 always 语句不带有时钟信号,则该寄存器变量对应为硬件连线。
线网类型
表示结构化实体(e.g.门)的物理连线。不能存储值,它的值由驱动它的元件决定。驱动元件有连续赋值、门、assign等。默认是Z高阻态。 有tri 和 wire型。
//wire define
wire data_en; //数据使能信号
wire [7:0] data ; //数据
参数类型
参数其实就是一个常量,用parameter定义(类似C语言中的define)我们可以一次定义多个参数,参数与参数之间需要用逗号隔开。参数的定义是局部的,只在当前模块中有效。
//parameter define
parameter DATA_WIDTH = 8; //数据位宽为8位
//可以[DATA_WIDTH : 0]只修改参数值来修改位宽
参数型数据用于定义状态机的状态、数据位宽和延迟大小等,在模块调用时可以通过参数传递来改变调用模块中已定义的参数。
运算符
算术运算符: Verilog 实现乘除比较浪费组合逻辑资源,尤其是除法。所以 2 的指数次幂的乘除习惯用移位,非 2 的指数次幂的乘除调用现成的 IP(ISE提供)
关系运算符
逻辑运算符: !、&& 、 ||
条件操作符: a ? b : c
位运算符: ~(取反)、&、 |、^(异或)
移位运算符: << a << b 将 a 左移 b 位
左移时位宽增加,右移时位宽不变。
4‘b1001 <<2 = 6’b100100
拼接运算符: {a,b} 将 a 和 b 拼接起来作为一个新信号。
二、Verilog程序框架
Verilog注释
//与/* */
Verilog关键字
关键字 | 含义 |
---|---|
module | 模块开始定义 |
input | 输入端口定义 |
output | 输出端口定义 |
inout | 双向端口定义 |
parameter | 信号的参数定义 |
wire | wire信号定义 |
reg | reg信号定义 |
always | 产生reg信号语句的关键字 |
assign | 产生wire信号语句的关键字 |
begin | 语句的起始标志 |
end | 语句的结束标志 |
posedge/negedge | 时序电路的标志 |
case | Case语句起始标记 |
default | Case语句的默认分支标志 |
endcase | Case语句结束标记 |
endmodule | 模块结束定义 |
Verilog程序框架
基本设计单元是模块(Block),类比C语言中的函数。
模块由两部分组成,一部分描述接口,一部分描述逻辑功能,
每个Veirlog程序包括端口定义、IO说明、内部信号说明、功能定义。下面以程序示例讲解知识点。
// 模块名(端口定义);
module block(a,b,c,d);//IO说明input a,b;output c,d; /************************************************1.未说明类型就是wire类型,reg类型定义为:output reg [3:0] led //在位宽之前加reg2.端口定义和IO说明可以放在一起,例如module led( input sys_clk , //系统时钟input sys_rst_n, //系统复位,低电平有效output reg [3:0] led //4 位 LED 灯 ); ************************************************///内部信号说明就是只在此模块内部使用的一些信号,不是输入输出/************************************************功能定义:3种方法:assign描述组合逻辑always描述组合/时序逻辑例化示例元件 例如 and #2 u1(q,a,b) 3种逻辑功能是并行的************************************************///assign 给wire类型赋值assign c = a|b;assign d = a&b;
endmodule
模块调用、例化——模块化设计
Verilog 语法中的模块例化。FPGA 逻辑设计中通常是一个大的模块中包含了一个或多个功能子模块,Verilog 通过模块调用或模块实例化来实现这些子模块与高层模块的连接。【把系统划分为几个模块,每个模块对应一个module,一个module一个Verilog程序文件。顶层模块只做例化(调用其它模块),不做逻辑。】
首先将被调用模块例化,例化模块名加u_
//顶层模块
module seg_led_static_top ( input sys_clk , // 系统时钟input sys_rst_n, // 系统复位信号(低有效)output [5:0] seg_sel , // 数码管位选output [7:0] seg_led // 数码管段选 );//parameter defineparameter TIME_SHOW = 25'd25000_000; // 数码管变化的时间间隔 0.5s//wire definewire flag; // 数码管变化的通知信号//每隔 0.5s 产生一个时钟周期的脉冲信号
time_count #(.MAX_NUM (TIME_SHOW) //参数TIME_SHOW控制数码管每隔多长时间改变显示的数值,底层代码给参数MAX_NUM了值,此处也是一种参数赋值方式,就是把TIME_SHOW的值给MAX_NUM) u_time_count( //例化模块名加_u.clk (sys_clk ), //由模块代码看以看到clk是模块的输入.rst_n (sys_rst_n),//所以这就是把上层模块的信号输入到底层模块,这里()里可以是wire或者reg,而下面的output的连接必须是wire型的.flag (flag ) //而底层模块的输出信号是连接到了上层模块中定义的其他变量 //信号传递的时候信号的位宽必须一致);//属于底层文件
//计时模块代码module time_count( input clk , // 时钟信号input rst_n , // 复位信号output reg flag // 一个时钟周期的脉冲信号
);parameter MAX_NUM = 25000_000; // 计数器最大计数值
reg [24:0] cnt; // 时钟分频计数器
三、Verilog高级知识点
结构语句
initial与always
initial:
只执行一次,立即执行,用于tb文件编写,产生激励信号或对reg变量赋初值。
initial beginsys_clk <= 1b'0;touch_key <= 1b'0;#10 touch_key <= 1b'1;
end
always:
一直执行,但需要结合一定的时间控制才有作用
always的时间控制可以是电平触发也可是边沿触发。可以是单个信号也可以是多个信号,多个信号用or连接
/**************边沿触发(时序逻辑行为)**************/
//用于产生 0.5 秒使能信号的计数器//@()里的多个事件名或信号名组成的列表叫做敏感列表,只有满足敏感列表才能执行后面的语句
always @(posedge sys_clk or negedge sys_rst_n) beginif (sys_rst_n == 1'b0) counter <= 1'b0;else if (counter_en)counter <= 1'b0;elsecounter <= counter + 1'b1;
end/**************电平触发(组合逻辑行为)**************/
always @(a or b or c or d or e) beginout1 = a ? (b + c) : (d + e);
end
//如果输入变量很多,敏感列表就很长且易错
always @( * ) begin //表示后面语句块中所有输入变量都是敏感的out1 = a ? (b + c) : (d + e);
end
赋值语句
分为阻塞赋值和非阻塞赋值;RHS(Right hand side)是赋值符号右侧信号, LHS是左侧
阻塞赋值(Blocking)
b = a;
计算 RHS 的值并更新 LHS。
在一个 always 块中,后面的赋值语句是在前一句赋值语句结束后才开始赋值的。即 always 块内的语句是一种顺序关系。
非阻塞赋值(Non-Blocking)
b <= a;
(1)赋值开始的时候,计算 RHS;
(2)赋值结束的时候,更新 LHS。
在计算非阻塞赋值的 RHS 以及 LHS 期间,允许其它的非阻塞赋值语句同时计算 RHS 和更新 LHS。
非阻塞赋值只能用于对寄存器类型的变量进行赋值,因此只能用在initial和always块等过程块中。
需要注意的是赋值语句是一直在always中执行,所以随着clk的上升沿一直来,bc最后也都变成a =0;
总结
1.描述组合逻辑电路,用阻塞赋值,比如 assign 赋值语句和不带时钟的 always 赋值语句,这种电路结构只与输入电平的变化有关系
2.描述时序逻辑电路,用非阻塞赋值,综合成时序逻辑的电路结构,比如 带时钟的 always 语句;这种电路结构往往与触发沿有关系,只有在触发沿时才可能发生赋值的变化
注意 :
- 同一个always中不要既用阻塞又用非阻塞
- 不允许在多个always中对同一个变量赋值(因为并行执行)
assign 和 always 区别
assign 不能带时钟。 always 可以带也可以不带。在 always 不带时钟时,逻辑功能和 assign 完全一致,都只产生组合逻辑。比较简单的组合逻辑推荐使用 assign 语句,比较复杂的组合逻辑推荐使用 always 语句。
assign counter_en = (counter == (COUNT_MAX - 1'b1)) ? 1'b1 : 1'b0; always @(*) begincase (led_ctrl_cnt) 2'd0 : led = 4'b0001;51 2'd1 : led = 4'b0010;2'd2 : led = 4'b0100;2'd3 : led = 4'b1000;54 default : led = 4'b0000; endcase
end
条件语句
if_else语句:
1.必须在过程块(有initial和always语句引导的)中使用
2.表达式值为X,Z时按假处理
3.if之后如果多句,要用begin end
4.不允许if嵌套
case语句:
与C中的case不同,没有switch关键字。
case (curr_st)4'h0: next_st = S1;4'h1: next_st = S2;4'h2: next_st = S3;4'h3: next_st = S4;default: next_st = S0;endcase
1.所有表达式的位宽必须相等,不能用’bx代替n’bx,
2.casez:比较时不考虑z
casex:比较时不考虑z和x
reg [7:0] sel; //1100_0011
casez(sel) //这种就不用考虑下面表达式中的高阻值8'b1100_zzzz:语句1;8'b1100_xxzz:语句2;//xx与00不相等,所以执行语句1
endcasecasex(sel)此时两个表达式相当于相同了,error!
latch锁存器
锁存器是电平触发的存储器,是组合逻辑产生的,寄存器是边沿触发的存储器,在时序电路中使用,由时钟触发产生的。
if 缺少 else 分支,case 缺少 default 分支会导致代码在综合过程中出现了 latch。latch只在组合逻辑电路中产生,也就是只有不带时钟的 always 语句中 if 或者 case 语句不完整才会产生 latch,带时钟的语句 if或者 case 语句不完整描述不会产生 latch。
四、Verilog状态机FSM
状态机FSM概念
我们一直在强调硬件描述语言是并行执行的,所以如果按顺序流程来完成一个操作的时候,就需要很多的if_else,降低了代码的可读性,也让代码编写难度增加(与单片机编写程序的区分)。所以就需要引入状态机,将一项功能的完成分解为若干步,每一步对应于二进制的一个状态,通过预先设计的顺序在各状态之间进行转换,状态转换的过程就是实现逻辑功能的过程,就像数电里学过的画状态转换图/表。
状态机,(Finite State Machine,FSM有限状态机)一种在有限个状态之间按一定规律转换的时序电路,是组合逻辑和时序逻辑的组合。
状态机模型
Mealy状态机(输出=输入+之前状态)
- F 是当前状态和输入信号的函数,状态是否改变、如何改变,取决于组合逻辑 F 的输出;
- 状态寄存器,其由一组触发器组成,用来记忆状态机当前所处的状态,状态的改变只发生在时钟的跳边沿;
- 状态机的输出是由输出组合逻辑 G 提供的,G 也是当前状态和输入信号的函数。
Moore 状态机(输出=之前状态)
Moore型不是没有输入,而是输出与输入无关。
状态机设计
四段论:
- 状态空间定义;
- 状态跳转;
- 下个状态判断;
- 各个状态下的动作;
1.状态空间定义
/************************方法1:************************/
//state space
parameter S0 = 2'b00;
parameter S1 = 2'b01;
parameter S2 = 2'b10;
parameter S3 = 2'b11;
// internal varialbe
reg [1:0] current_state;
reg [1:0] next_state;/************************方法2:推荐************************/
//独热码:每个状态只有一个寄存器置位,译码逻辑简单
//state space
parameter S0 = 2'b1000;
parameter S1 = 2'b0100;
parameter S2 = 2'b0010;
parameter S3 = 2'b0001;
// internal varialbe
reg [3:0] current_state;
reg [3:0] next_state;
2.状态跳转(时序逻辑)
就是上面框图中的状态寄存器
always @(posedge clk or negedge rst_n) beginif(!rst_n)current_state <= S0;elsecurrent_state <= S1;
3.下一个状态的判断(组合逻辑)
就是上面框图中的产生下一状态的组合逻辑F
always @(current_state or input signals) begincase(current_state ) //强烈建议使用case 而不用if_elseS0: beginif(a)next_state = S1;else next_state = S0;S1:.......;S2:.......;S3:.......;default:.......;endcase
end
4.各个状态下的动作(组合逻辑)
就是上面框图中的产生输出的组合逻辑G
//action
wire qook;
assign qook = (current_state == S1) ? 1'b1 : 1'b0;//下面是用always写上面的语句
always @(current_state ) beginif(current_state == S1)qook = 1;else qook = 0;
end
总结
这里我们实际用了一个三段式状态机。基本格式是:
第一个 always 语句实现同步状态跳转;
第二个 always 语句采用组合逻辑判断状态转移条件;
第三个 always 语句描述状态输出(可以用组合电路输出,也可以时序电路输出)。
可以在组合逻辑之后再加一级寄存器实现时序逻辑输出
1.滤除组合逻辑输出的尖峰脉冲
2.进行时序计算和约束
3.对于总线形式的输出信号来说,容易使总线数据对齐,减小总线数据间的偏移,减小接收数据采样出错的频率。比如8位位宽信号,如果用组合逻辑,可能导致并行的8个数据从输入端到达输出端的时间不一致。
FPGA语法篇——Verilog 语法知识相关推荐
- FPGA 40 专题 verilog语法编程规范
FPGA 40 专题 verilog语法编程规范 在这里主要是给自己写一个备忘录,加强个人记忆. 详细可以参考地址1:https://www.runoob.com/w3cnote/verilog2-c ...
- FPGA笔记1——Verilog语法
目录 一.Verilog基础语法 1.1 逻辑值: 1.2 数字进制: 1.3 标识符 1.4 数据类型: 寄存器 线网 参数类型 1.5 运算符 二.Verilog程序框架 2.1 注释 2.2 关 ...
- 英语语法篇 - 英语语法综述
文章目录 简单句 英语的5种基本句型: 八大句子成分 复杂句和复合句 复杂句 从句(4 + 2) 同一类句子成分里可能有不同的词类. 十大词性(词类) 谓语动词 非谓语动词 总结 简单句 没法再拆成更 ...
- FPGA笔记之verilog语言(基础语法篇)
文章目录 FPGA笔记之verilog语言(基础语法篇) 1. verilog 的基础结构 1.1 verilog设计的基本单元--module 1.2 module的使用 1.3 I/O的说明 1. ...
- Cyclone FPGA踏足笔记(二):Verilog语法学习总结
欢迎来我的个人博客:https://codinglover.top/ 转转! 前言 花了一个月时间零零碎碎看了下Verilog的语法,终于把Verilog的基本语法学了个大概,可以自己写点小东西了,由 ...
- Verilog 语法入门知识
Verilog 语法入门知识 一.变量类型 ①数值 数值表示采用 <二进制位数>'<数值表示的进制><数值>的结构. 其中进制可以为b.o.d.h分别代表二.八.十 ...
- 【FPGA】——Verilog语法
简介 (一)概述 Verilog是一种硬件描述语言,以文本形式来描述数字系统硬件的结构和行为的语言,可表示逻辑电路图.逻辑表达式,还可以表示数字逻辑系统所完成的逻辑功能. 数字电路设计者利用这种语言, ...
- [转]verilog语法学习心得
verilog语法学习心得 1.数字电路基础知识: 布尔代数.门级电路的内部晶体管结构.组合逻辑电路分析与设计.触发器.时序逻辑电路分析与设计 2.数字系统的构成: 传感器 AD 数字处理器 D ...
- Verilog语法和典型电路
这里写目录标题 Verilog语法知识 Q:锁存器 Q:D触发器 Q:消除毛刺 Q:同步复位和异步复位 Q:边沿检测 Q:握手信号 Q:脉冲展宽(单bit慢采快) Q:二进制与格雷码的转换 Q:二进制 ...
- Flex 布局教程:语法篇
阮一峰的网络日志 » 首页 » 档案 上一篇:ES6 的功能侦测库 下一篇:Flex 布局教程:实 分类: 开发者手册 Flex 布局教程:语法篇 作者: 阮一峰 日期: 2015年7月10日 网页布 ...
最新文章
- 随笔(2018.8.31)
- Ubuntu16.04LTS安装ROS Kinetic
- 职业化之可以固化的六个工作模式
- ldap的shema
- 主从复制中忽略库的参数
- 韩国财长:韩国将按计划推进加密货币征税
- android UI 标签
- Orchard Core 使用工作流处理页面提交
- MySQL备份与恢复-innobackupex
- linux如何查看内存?
- 【项目管理/PMP/PMBOK第六版/新考纲】计算题! 假设情景分析/类比估算/处理变更/结束采购/高层级风险/组织过程资产
- 获取google chrome浏览器的安装位置
- C51 基本函数、中断函数和库函数的详解
- 网络——路由进阶与安全
- Jacoco 入门使用
- 领域模型-软件需求分析
- Android ExpandableListView 使用实例
- 淋巴瘤最新研究进展(2022年4月)
- 分水岭变换的分割,watershed函数
- OpenGL glut OFF 读取 + 半边数据结构存储