标题写多路选择器,实际上......
今天记录一下如何用Verilog在FPGA上做一个多路选择器。
是的,虽说要做mux,重点却在于always语句
组合逻辑?时序逻辑?
先说说Verilog的逻辑。
Verilog主要包含两大逻辑:组合逻辑与时序逻辑。
如果要看完整定义,给大家放下面了:
- 组合逻辑:输出仅由当前输入决定,与电路过去的状态无关,没有记忆功能。
- 时序逻辑:输出不仅取决于当前输入,还依赖于电路过去的状态(即有记忆功能)。
如果要人话 废话 一点,组合逻辑只是一个逻辑运算,没有反馈(输出再接回输入),输出仅由输入决定,输入变化,输出立马跟着变。
而时序逻辑有反馈,有了反馈,自然可以构成记忆电路。这方面典型的就是锁存器和触发器了。
上面是我们再熟悉不过的RS触发器,可以看到两个输出是有反馈回输入的。
Verilog 的数字进制格式
再说说Verilog中数字咋写。
在数字电路方面,我们一般会用二进制,十进制,和十六进制,其对应书写格式如下:
- 位宽+单引号'+进制类型+数
几个栗子:
- 两位二进制3:2'b11
- 8位十六进制FF:8'hff(不区分大小写)
注意一个问题,Verilog中的位宽永远是二进制的,2'hff这样写就不对!(不要问谁曾经这么写......捂脸)
如果不注明位宽和进制类型,光给编译器扔个数,那人家就默认你写了个32位的十进制数。
太好啦,终于把两个逻辑和数字进制格式说清楚啦,接下来就可以和always见面啦!
always语句!
语法见下:个人认为这种玩意特简洁......
cpp
always @(敏感列表) begin
逻辑书写之地
end
先大体看一眼。
电平信号?组合逻辑!
举个例子:
cpp
//此乃mux精髓所在^_^
always @(*) begin
if(sel == 1'b1)
out = A;
else
out = B;
end
说说几个膈应人的地方(为啥说膈应呢因为学的时候没人跟我解释@*空格一堆乱七八糟都是些啥)
always 、@ 和 (星) (CSDN编辑器里不知道咋写,晕死......) 之间可以有空格,也可以没有,大家怎么喜欢怎么来。
@是敏感列表操作符,用来触发always语句执行条件的。后面的括号内部需要写敏感列表,也就是always的执行条件。
这里我们写*,其实是一种省略。意思就是当always语块内部有一个电平输入信号发生变化时,就会执行本always语句。比如上面示例代码中,输入信号有sel,A,B三个,则当任何一个变化时,都会导致always语句的执行。
如果你不想省略,可以写成以下这样:
cpp
always @(sel or A or B) begin
if(sel == 1'b1)
out = A;
else
out = B;
end
当然我懒,我是不会写的哈哈。
至于if-else语句,除了花括号用begin和end以外,其余一毛一样,就不废话啦。
时序逻辑来也!
如果我们把敏感列表中的电平信号换成时钟信号,就变成了always的时序逻辑,比如:
cpp
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
q = 1'b0;
else
q = d;
end
上面的例子中写了俩边沿信号,分别是clk(时钟)和rst_n(复位),之间用关键字"or"连接。前面两个posedge 和 negedge 则是信号类型的关键字:
- posedge:在信号上升沿到来时触发
- negedge :在信号下降沿到来时触发
这种边沿触发的信号,一般用于触发器或者寄存器,对应时序逻辑了!
如果想写多个触发条件,继续往后写即可:
cpp
always @(类型 信号1 or 类型 信号2 or ...... or 类型 信号n)
这里可能有人要问了,如果电平信号和边沿信号掺和在一起,这算啥?
cpp
always @(key or posedge clk)
有人管这玩意叫(非正常的)混合逻辑,虽然没有明令禁止,但大家最好不要写这种东西,指不定综合工具会给你整出个啥来......
好啦,不用多说我也知道,大家现在一定都会写mux的Verilog代码啦!为延续程序员Ctrl+C Ctrl+V传统,代码给大家放在下面啦嘻嘻:
cpp
module mux(
input A, //输入信号in1
input B, //输入信号in2
input sel, //选择控制信号sel
output reg out //输出信号out
);
always@(*) begin //"*"为通配符,在这个模块中的任何一个输入信号或电平发生变化时
if(sel == 1'b1)
out = A;
else
out = B;
end
endmodule
写.v文件时有一点要注意,always的输出信号(本代码中的out)必须定义为reg型,否则将编译错误!
比如这样就不行:
cpp
output out //错误:out作为always的输出信号必须是reg
接下来就是仿真文件了,仨信号一一变化即可。还不会写仿真文件的欢迎参考我的上篇博文~~~
如果有不明白或错误之处,也希望大家在评论区给出,帮助大家的同时也能再次提升自己对于FPGA和Verilog的理解,感谢大家!!
系列链接: