Verilog 2.0 完成你的第一款数字芯片?
文章目录
在本节中,你将 有可能学/做到:
- 通过教程实现在数电课程中所用到的CD4000芯片
- 学会组合逻辑电路的(部分)硬件语言描述(Verilog)
前期准备
在开始前,希望大家已经看过之前发的教学文章,或者等价有以下基础:
- 数电基础,在本节中至少要有组合逻辑电路基础
- Vivado环境搭建及基本使用基础
- 能理解为什么实现的时候不需要理会芯片的NC端,VCC端,VDD端
那我们就不啰嗦了,直接来看第一个要实现的芯片:
CD4000
功能描述
首先,来重新看看他的功能描述: CD4000 双3输入端或非门+单非门,
代码和RTL验证
那我们先直接上代码:
module cd4000(
input A,B,C,D,E,F,G,
output wire K,L,H
);
assign K = ~(D|E|F);
assign H = ~(A|B|C);
assign L = ~G;
endmodule
先看看写得对不对,在Vivado中点开RTL ANALYSIS/Open Elaborated Design:
Step 1 语法
可见实现是几乎一致了,下面来看看语法:
-
module------endmodule,指电路中的一个模块。
在module的后面紧接的就是模块名,
然后括号里面的就是描述这个模块的(输入输出)端口,用逗号分隔开,
在括号的后面要加个分号。
-
input/output,指电路模块中,端口类型,有:
- input:输入端口
- output:输出端口
- inout:输入输出端口,在介绍iic的时候再介绍
注意:端口类型不一定需要再module的括号内写,下一个例子会给到。
-
wire,指数据类型,可综合的数据类型有:
-
wire 线网型,就是一根线。
在代码中提前提到放在output后面,是希望大家以后看到wire的时候能想起这样一幅图:
上面的一根根蓝色导线,也就是wire,他只是一根导线,没有驱动能力,也没有存储的能力。
-
reg(register),也就是寄存器,由于本篇讲的是组合逻辑电路,这里先略过。
-
其他的留待需要的时候再讲。
-
-
assign,如翻译,指定,也就是说,他会指定一个(/一组)wire,作为等号右面逻辑块的输出,也就是说,有了这个指定关系,这个wire就是这逻辑块的输出端口。
-
与或非,指逻辑门(或者位运算符),常用的有:
- ~ 取反(非)
- & 按位与(目前就把他当成与就行)
- | 按位或(目前就把他当成或就行)
- ^ 按位异或(同上,异或)
- ~^ 按位同或(同上,同或)
注意:当比较的位宽不一致的时候,Verilog会选择高位补0来填充
CD4002
功能描述
CD 4002 双4输入端或非门,和4000有点相似:
代码与RTL验证
也是直接上代码:
module cd4002(
ABCD, J,
EFGH, K
);
input [3:0] ABCD;
input [3:0] EFGH;
output J,K;
assign J = ~(|ABCD);
assign K = ~(|EFGH);
endmodule
先看看RTL:
Step 2 语法
那么现在我们来看看有什么语法上的新增/扩展:
- 模块的端口声明,可以先写端口。后面再补端口类型和位宽
- 位宽,格式是 [MSB : LSB],其中:
- 程序员算数都是从0开始的
- MSB(Most Significant Bit):最高有效位
- LSB(Least Significant Bit):最低有效位
- 本例中,或非门是4输入的,所以是[3 : 0]
- 这里如果大家觉得太简单,可以适当百度一下"大小端问题",以获取更高难度
- 缩位(缩减)运算符, 是比较不常见的单目运算符:
- |ABCD : 对ABCD这一组wire,一位位wire进行或运算
- &ABCD : 对ABCD这一组wire,一位位wire进行与运算
- 此外,还有&(与非缩位),|(或非缩位)、~或~(同或缩位)这几种
CD4025
功能描述
CD4025 三3输入端或非门
代码与RTL验证
大家可能都发现了,相关的芯片中,重复的功能其实是很多的,那我们能怎样去利用这一点呢?看看代码:
module cd4025(
input [2:0] ABC,
input [2:0] DEF,
input [2:0] GHI,
output J,
output K,
output L // 者个是verilog中的注释
);
function [0:0] M_NOR; // 三输入或非门
// port declaration
input [2:0] NOR_IN;
begin
M_NOR = ~|NOR_IN;
end
endfunction
assign J = M_NOR(ABC);
assign K = M_NOR(DEF);
assign L = M_NOR(GHI);
endmodule
然后看看RTL验证:
Step 3 语法
- 在 Verilog中,注释的方式和C语言是一致的//,也有段注释/**/
- function ,函数关键字:
- 没错,Verilog中也有函数这一个概念,不过他只能有一个输出(位宽可以指定)
- 在函数中,由于独立于模块存在,所以需要重新做端口声明。
- begin----end,指function块里面的代码,在Verilog中,每一种能承载逻辑块的语法基本都需要加begin----end,后面会介绍更多的块。
- 在function后面需要加endfunction
- 在函数的“调用”中,需要注意,与C语言不同,这里一次调用,就是生成了一块逻辑!而不仅是运行完就算了。
CD4085
功能描述
CD4085 双2路2输入端与或非门
可见,两个INHIBIT脚,接在或非门中,即其为1时,输出恒为0
代码与RTL验证
直接看代码:
module cd4085(
INHIBIT1,
AB1,CD1,
E1,
INHIBIT2,
AB2,CD2,
E2,
);
input INHIBIT1, INHIBIT2;
input [1:0] AB1, CD1, AB2, CD2;
output wire E1,E2;
reg And_AB1_out, And_CD1_out;
reg And_AB2_out, And_CD2_out;
reg E1_out, E2_out;
always @(*) begin
And_AB1_out = &AB1;
And_CD1_out = &CD1;
E1_out = ~|{INHIBIT1, And_AB1_out, And_CD1_out};
And_AB2_out = &AB2;
And_CD2_out = &CD2;
E2_out = ~|{INHIBIT2, And_AB2_out, And_CD2_out};
end
assign E1 = E1_out;
assign E2 = E2_out;
endmodule
看起来好像很复杂? 来看看RTL验证:
Step 4 语法
作为本篇中几乎难的一个,我们来看看他到底增添了什么:
-
always块:
- 顾名思义,他就是一个一直(always)在跑的电路
- @(*),括号里面指的是敏感信号表,指你这一块电路需要什么信号进行输入/触发,如果写的是组合逻辑电路的话,可以选择偷懒用* 通配符代替
- begin----end块,证明always也是一个块语句,但是有一点反直觉的是,always的内部,是顺序执行的。
- 虽然上面提到,他是“顺序执行”的,是实际上,应该理解成,他是顺序理解的。每一个信号都应只被真正赋值一次(因为还有各种if,case等语句,会有分支执行),在时序逻辑电路设计中,会加强这一点,这里留个印象就行了。
- !!你的输入为什么是reg!!,为什么要做组合逻辑中提及reg!!!这里就需要用到上一点中的“顺序理解”的概念,由于他是顺序走的,所以对上一步的结果需要一定的“缓存”,但是当他看完你是安全无公害的时候,就会释放回组合逻辑电路了。
-
拼接运算符{}
他的作用就是将几个(/组)信号,给合并成一个信号,他除了简单耦合之外,还能有重复或者复制的功能(这里可以先跳到下一个芯片,再回来):
- {3{1’b0}} = 3’b0
- {3{1’b0},1’b1} = 4’b0001
这里面的妙用,会在下一节中讲到,这里先,建立一个认识就行。
CD40147
CD40147 10-4线编码器:
最后一个芯片啦,就不讲什么门那些枯燥的东西啦。
代码及RTL验证?
先来看看代码:
module cd40147(
input [9:0] encoder_in,
output reg [3:0] bcd_out
);
always @(*) begin
casez(encoder_in)
10'b1?_????_????: bcd_out = 4'd9;
10'b01_????_????: bcd_out = 4'd8;
10'b00_1???_????: bcd_out = 4'd7;
10'b00_01??_????: bcd_out = 4'd6;
10'b00_001?_????: bcd_out = 4'd5;
10'b00_0001_????: bcd_out = 4'd4;
10'b00_0000_1???: bcd_out = 4'd3;
10'b00_0000_01??: bcd_out = 4'd2;
10'b00_0000_001?: bcd_out = 4'd1;
10'b00_0000_0001: bcd_out = 4'd0;
default:
bcd_out = 4'b0000;
endcase
end
endmodule
再看看RTL:
可见,他直接就把我们这个行为综合成一个ROM了,这也是大家数电后几章中,我们可以通过ROM/RAM来自定义逻辑。
Step 5 语法
- Verilog中的数制,这里放一张图,说明一下:
-
case,casez:
- 与C语言类似,Verilog中也有case语句,其用法见上,这里特别注意的是,在写case语句的时候,最好把default带上,原因会在时序逻辑电路的时候讲。
- casez中,可以搭配 ? 来实现优先级,即?表示不管你是0还是1
小结及“作业?”
在这一节中,通过5个CD4000系列的芯片,我们差不多就可以完成组合逻辑电路的设计了。
学习了以下的关键字/语法:
- module----endmodule
- input,output,inout
- wire,reg
- ~,&,|,^, ~^
- assign
- 位宽的写法和计算
- 缩减运算符
- function
- always
- 拼接运算符
- case,casez
然而,可能会被留意到了,if 语句和三目运算符在这里是没提及的,一方面是这些芯片内部除非闲着没事干,否则也不需要,另一方面是,这两个基本和C语言是一致的,所以这里也就让大家自行查阅资料去了。
其实除此之外,还有算术运算符,关系运算符,逻辑运算符等等,会留到时序逻辑电路设计中讲到,这里没讲是因为没相关应用。。
那么估计大家也发现了,笔者挑的芯片是跳着来选的,那么中间的那些也是组合逻辑电路的就留给读者去实现啦,在整个教学系列介绍的时候,会公布里面大部分的源码,供大家学习使用。
如果觉得还行的话,欢迎关注我的个人微信公众号: