从上一节内容总结:一个Verilog模块一致包含四个部分:端口定义、I/O说明、内部信号声明和功能定义,下面将通过其他例子更加具体体会
第2个示例:4选1数选器
首先明确功能表
本示例将着重学习以下几点:
1.如何用矢量(总线)类型描述多变量输入/出类型(类比C语言中的数组或Python中的列表)——
类型(input/output)+[数据数目:0] 变量名,这里的:更多的意思可以翻译成0-数目这么多数
2.更加熟悉always语句各类型的定义描述等模式
赋值只能是reg类型,@(or)组合输入的敏感量
3.case条件语句
case(控制变量/表达式)
选项:语句;
......
default:缺省句;
endcase
4.数的表示法,具体见下图
e.g. 2'b00——含义为2位,2进制数,00
在这里需要注意两条
1.Verilog中x和z可以作为数分别代表不定数和高阻态
2.位长度可以缺省
除了case语句外还可使用if-else语句实现
这里用到了begin...end的顺序执行语句块(类似C语言中的大括号或Python中的缩进)
需要提醒一点:养成良好的编码习惯,if else/case default不要缺省else和default,否则引入不必要的锁存器
第3个示例:四位加法器
重点掌握模块的互相调用,类似于高级语言的函数调用
关于全加器的逻辑功能都很熟悉了
在已经清楚之后,我们需要分清两个步骤:
1.写一个全加器的模块——底层模块
2.写一个调用全加器级联的模块——顶层模块
这里面调用相关模块的行为称作实例化
管脚 按顺序映射 调用 实例 的使用 格式为:
< 模块名> < 实例名> < 端口列表>;
可以 不按顺序 的调用实例格式为:
< 模块名> < 实例名> <. 实例端口1( 模块端口1]), . 实例端口2( 模块端口2)……>;
这种方式就把实例与模块端口一一对应了
也就是说上面的顶层调用模块还可以这样实现
add_full
u1(.A(A[0]),.B(B[0]),.C(C[0]),.Carry(C[1]),.S(S[0])),
u2(.C(C[1]),.B(B[1]),.A(A[1]),.Carry(C[2]),.S(S[1])),
u3(.B(B[2]),.A(A[2]),.C(C[2]),.Carry(C[3]),.S(S[2])),
u4(.A(A[3]),.B(B[3]),.C(C[3]),.Carry(C[4]),.S(S[3]));