p1 Verilog
前言、安装使用、语法、题目、开发调试、高级特性。
1.Verilog建模描述
-
描述实际电路中不同级别的抽象,即在不同层次上用Verilog语言来描述。
-
门级描述(结构化建模):把基本门和/或功能单元连接起来,从而产生特定的功能元件。该过程类似于在Logisim中连接电路。
-
行为级描述:主要描述电路输入信号与输出信号之间的逻辑关系。低层次内部结构和实现细节等的考虑,以及将其转化为物理电路的过程(综合synthesis),由软件自动完成。
(1)利用连续赋值语句assign描述电路
(2)利用initial结构、always结构和过程控制语句描述电路
连续赋值语句assign:持续性地将右侧表达式的值赋给左侧的信号。左边必须为wire型数据。
过程控制语句与有关结构:一个模块中可以包含多个initial或always结构,并且会同时执行。
- initial结构:从仿真0时刻开始执行其中的语句,整个仿真过程中只执行一次。
- always结构:边沿敏感和电平敏感(电平敏感为对该信号的改变敏感)
- 语句块:顺序块和并行块
- 阻塞和非阻塞赋值:尽量组合逻辑-阻塞赋值、时序逻辑-非阻塞赋值
2.语法合集
- 选择Edit -> Language Templates打开语言模板;或者直接快捷方式
- 最后一句端口定义没有","
- 写testbench记得always #time clk=~clk;
- 运算符
- "+", "-", "*", "/", "%"等基本运算
- "&", "|", "~", "^", ">>", "<<"等位运算
- "&&", "||", "!" 等逻辑运算
- ">", "<", ">=", "<="等关系运算
- 条件运算符"? :"
- 注意数据类型,数据不要溢出!
- 添加`default_nettype none取消缺省类型
- 对于同一变量非阻塞赋值与阻塞赋值的统一
3.组合电路
- assign赋值语句
- always+非阻塞赋值语句
- 尽量用assign+三目的形式实现组合逻辑,从而保持always代码块中仅有非阻塞赋值语句
- 在always块中,我们可以选择利用case分支语句或者if分支语句对op进行判断,并利用always块保证对每次更新后的变量重新计算输出变量的值。
4.时序电路
- 初始化
- 状态更新
- 输出更新
关键点在于 寻找到所有的状态,并正确的完成状态转移,同时要处理好敏感变量
Mealy和Moore类型状态机
- 状态机在时钟上升沿来到之后,根据输入和时钟上升沿之前的状态组合逻辑运算出状态转移后的当前状态,进行状态更新
- Moore型状态机,该状态决定了输出,即仅由当前状态决定了输出。
- Mealy型状态机,根据输入和时钟上升沿之前的状态组合逻辑运算出状态转移后的当前状态,然后再根据当前状态和当前输入决定输出
- 实现过程中,由于mealy型输出需要时刻受到input的反馈,因此必须要用assign来赋值;Moore型可以按照always块进行,也可以按照assign进行。
- 统一起见,状态机书写划分为 initial - always - assign 分别对应完成 初始化 - 状态转移+状态存储 - 输出模块
- 需要注意,同步复位和异步复位需要通过assign体现时,可以通过state及input在always模块中的复位体现,或者异步复位直接在assign中操作,但实际上如果复位了state及input也不需要再看reset了。所以可以直接就state和assign控制即可。
- 复位方式的检查仍旧是重点:同步复位或异步复位都可以利用assign输出,但是需要注意always里的敏感变量以及state的赋值
- 可以根据评测机报错信息仔细检查某一状态下的代码,但此法会产生提交时间限制。
- 通过评测机报错信息针对性改正,多试一试testbench不同状态。如果发现错误,尽可能不要再整体变动状态数目了,最好在原先的基础上添加变量调整。
- 检查的时候终点重点关注状态,确保在状态转移时各个中间变量的值按照要求清零,或变化成目标值。
- 注意BlockChecker一题:状态转移时中间变量不一定是清零了,如sume只是减1
- 每一个.v文件都要写对应的testbench
代码规范
- 单目运算符与变量间不添加空格,如“~”、“!”。
- 双目运算符(除逗号外)和三目运算符两侧添加空格,如“+”、“=”、“<”、“&&”。
- 分号和逗号要紧附前面内容,不应添加空格。
- 避免连续使用多个空格。
同学经验分享
- 状态机的状态分析一定要仔细看清 状态转移
“状态机都是状态不多,但是情况非常复杂”
HDLbits练习
- 基础的输入输出端口设置需要严格对准!组合逻辑电路中的变量端口位数要正确!
- always, initial, if-else勤加begin-end, case切记endcase
- verilog没有自加运算!!
- 组合逻辑记得进行初始化
- generate应用https://hdlbits.01xz.net/wiki/Adder100i
- assign赋值是组合逻辑,时刻相连,不能直接赋值左右两边取反
课堂及问答
- 第一道题组合逻辑,二三道是moore型状态机的考察。后两题比较顺利,但是注意考虑非法状态的进入条件。
- 第一题组合逻辑,最坑的点是一定要认真读题,组合逻辑整体难度较低,但是题意务必正确理解。
ans和input分别对应答案和输入,及输出的具体要求需要谨慎。
上机时always写法需要正确理解always@(*),否则模块内部会出现玄学bug,因此建议直接assign和三目写组合逻辑。 - 二三题是状态机考察,重点在于状态转移图考虑要周全,我的习惯是按照:initial-always-assign三个主要模块写。
重点注意初始化、复位、状态转移时各变量的变化。
- 如何自动生成端口模块?