前言
最近又针对Verilog基础语法做了一些练习,提炼了一些以前没有注意或者尚未学习到的基础小知识,在这里做一个总结,以便以后复习和回顾。
小知识
- assign连续赋值语句在程序中不存在先后关系,也就是说无论前后,综合出的电路都是相同的。
- 有时候在程序中出现了未加以声明的隐性wire型数据中间变量,难以查找其BUG,可以在RTL代码(顶层模块)首行添加“`default_nettype none”,使得该错误成为一个error,便于查找BUG。
- “&&”、“||” 、“!”为逻辑运算符,“&”、“|”、“~”为位运算符,两者在数据均为单bit位时计算结果相同,但是当数据为多位时,前者是按照逻辑运算,只包含“0”或“1”两个结果。后者则是将每一位纳入运算,得到结果。两个数据进行位运算时,注意两者的位宽是否相同,防止自动补数据导致结果出错。
- 在做缩减运算时,&B,表示变量B内部数据最低位与次低位与运算,结果再与次次低位相与,直到最高位,得到一个二进制结果。同理在 ^B中为变量B由低位到高位逐位做异或运算。
- 连接运算符“{ }”在使用时必须明确连接字符的位宽,不确定位宽的数据是禁止进行连接的。
- 拼接运算符内使用重复语句,多用于进行有符号数据的拓展,将有符号数据符号位拓展原位宽与指定位宽之差的次数,即可得到拓展后的数据,保留其数据大小和符号。如 4’b0101(3)拓展到8’b00000101(3),以及 4’b1101 (-3)拓展到8’b11111101 (-3),注意重复后数据外要添加“{ }”。
- 模块实例化以后有两种方式连接到顶层端口,①顺序连接:类似于C语言,实例化模块以后在括号中按被调用模块原信号与顶层模块连接信号对应顺序填入顶层信号即可(这种写法不能在实例化的端口处对数据进行取反等运算操作)。②名称连接:实例化模块后在括号中填入“ .调用模块信号(顶层信号)”即可建立对应的连接。
- 一定要注意检查模块内部变量的位宽是否正确。
- 当需要一个bit位与多bit位进行位运算时,需要对单bit数据进行拼接拓展 ,防止因为自动补全数据到相同位宽导致结果出错。
- 为了防止产生latch,组合逻辑电路在所有条件情况下都要有对应的赋值。
- Verilog中case语句中的条件不同于C语言(C语言中不允许条件重叠),verilog中是可以重叠的,但是仅仅在识别到最早满足条件的语句中执行。casez语句中判断条件的每一位可以用 “z” 代表不关心,进而用于排除一些条件中不便于筛选的干扰条件项。
- 在case语句中对多个选项选择执行时,可以在always块开始时对所有选择项目赋初值,用以解决不同选项进入执行时其他选项的清零,这种写法下所有情况都有对应的初值,避免了latch的产生。
- 多路数据求取最值,可以每次先对部分数据求取最值,将得到的中间最值数据再进行二次对比得到结果。
- generate - for 语句必须满足①必须要由genvar定义for语句变量。②for语句的执行语句必须要加 “begin - end” ,即使执行语句只有一句。③for语句必须有名称。④generate模块内部数据赋值的话需要加assign或者always,不能直接写赋值。
- for语句只能在always块中使用,由于for循环会被展开成所有变量情况的执行语句,无法有效复用寄存器资源,所以仅在testbench文件中使用,并且由于for循环变量为integer型,在测试激励中无法看到每个循环的for变量数值。
- 多个“ ?: ”叠加时,注意?和:的数量相同,且最外层?和:对应匹配。且输出端口的数据也是可以作为?:语句的判断条件的。
- 选中变量的部分位时,A[a : b]中的a和b只能是常数,不能是变量。当处理位宽较大的数据时,可以灵活采用位拼接(因为位拼接内部的数据可以存在变量)。
- 检测数据变换的上升沿:先对输入数据打一拍,随后将打一拍的数据信号取反以后和原数据相与,即out = in & ~in_reg;常见的误解是out = in ^ in_reg,这种写法会在数据变化时和之后一个时钟周期均输出高电平,而非一个时钟周期的脉冲信号。检测下降沿采用将其转化成上升沿的检测方法:out = ~in & in_reg;双边缘检测对打一拍的数据和原数据取异或即可:out = in ^ in_reg;(always@(posedge clk or negedge clk)begin这种写法不可综合)。
- 在状态机和计数器的组合设计中,计数器以当前state为判断条件时,滞后数据变化2拍,以下一状态next_state为判断条件时滞后数据变化1拍。当涉及数据的读取时,时序逻辑读取数据需要保证赋值条件滞后于数据变化1拍,才能不遗漏数据。
总结
先写这么多,后面还有新的内容,持续更新哟!