Verilog电路设计思路
使用Verilog设计电路的一些思路
注意事项:
时序逻辑电路使用非阻塞赋值
组合逻辑电路使用阻塞赋值
组合逻辑电路
- 概念:输出仅由当前的输入决定
- 注意:不能蕴含触发器的逻辑,即不具有记忆功能(case语句的default子句、连续赋值语句、电平敏感的always语句)
- 常见的组合逻辑电路:复用器、译码器、编码器、三态缓冲器、比较器、加法器、乘法器。
- 实现方法:
- 使用assign连续赋值语句(数据流级)和电平敏感的always行为语句(行为级)
- 使用always引导的语句块实现对于中间变量的逻辑运算
- 使用assign引导的连续赋值语句实现简单变换和多路输出(如果有的话)
- 注意:always的使用的中间变量为reg型,assign和子模块使用的中间变量为wire型
- 设计思路:
- 给定电路原理图:使用门原语和模块实例
- 给定布尔方程:使用连续赋值语句和布尔运算(真值表得到布尔方程)
- 给定模块功能/IO(真值表):使用行为级描述(if/case配合真值表)
- 可采用的设计模式:
- assign连续赋值语句 + 条件表达式(?:) + 布尔运算
- always语句块 + 条件表达式(?:)
- always语句块 + 条件语句(if/case)
- assign连续赋值语句 + 函数(function [automatic])可以在数据流语句中引入行为级语句逻辑
- always语句块 + 函数(function [automatic])
- always语句块 + 任务(task [automatic])
- 建议不直接修改输出变量,而是使用中间变量,在输出时使用assign实现(综合好像能得到一个buf)
时序电路
- 概念:输出由当前输入和内部的状态决定
- 注意:具有记忆功能,内部包含==锁存器latch(电平敏感)和触发器flip-flop(边沿敏感)==等储存器件,case语句的default子句可以为空
- 常见时序电路:锁存器latch、触发器flip-flop
- 实现方法:
- 使用always引导的语句块(电平敏感或边沿敏感)实现逻辑运算
- 使用assign引导的连续赋值语句实现简单变换和多路输出(例如assign qbar=~q)
- 不能使用门原语,门原语定义的时序电路不可综合(例如使用两个与非门实现的RS锁存器)
- 时序逻辑:
- 同步控制(复位/置位):
- 只有在时钟信号的有效跳变沿状态才能改变
- always的事件控制列表没有复位/置位信号
- 语句块中先检查复位/置位信号,然后执行其他逻辑。使用嵌套的if-else可以控制复位/置位/输入逻辑的优先级(复位>置位>其他逻辑)
- 异步控制(复位/置位):
- 复位/置位信号激活时立即响应
- always的控制列表中包括时钟边沿和复位/置位信号边沿
- 语句块中先检查是时钟触发的还是复位/置位信号触发的,并执行相应的逻辑。使用嵌套的if-else指定优先级(复位>置位>其他逻辑)
- 同步控制(复位/置位):
可综合电路
- 关键:使用Verilog HDL中的可综合子集
- 可综合的Verilog HDL结构
- 端口:input, inout, output
- 参数:parameter
- 模块定义:module
- 信号和变量:wire, reg, tri 允许向量
- 实例调用:module instance primitive gate instance
- 函数任务:function, task 不考虑时序结构
- 过程:always, if, then, else, case 不支持initial
- 过程块:begin, end, named block, disable
- 数据流:assign 不考虑#延迟信息
- 循环:for, while, forever 需要包含@(posedge clock)或@(negedge clock)
- 使用复位机制取代initial进行初始化
- 赋值
- 组合逻辑电路使用阻塞赋值=
- 时序电路使用非阻塞赋值<=
- 同时描述时序和组合逻辑使用非阻塞赋值<=
- 编码风格
- 有意义的信号和变量名
- 避免混合使用上升沿触发和下降沿触发
- 使用圆括号而不是运算优先级
- 条件语句中说明所有的可能情况
- 不要多个always对同一变量赋值
常见改错题思路
- 变量类型错误
- 注意input和output的端口类型检查
- 变量位宽
- 赋值方式
- 阻塞赋值和非阻塞赋值
- 敏感量列表
- always的敏感量列表是电平触发还是边沿触发
- 位运算/逻辑运算