Verilog和FPGA的自学笔记4——多路选择器(always语句)

标题写多路选择器,实际上......

今天记录一下如何用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的理解,感谢大家!!

系列链接:

上一篇:Verilog和FPGA的自学笔记3------仿真文件Testbench的编写

下一篇:Verilog和FPGA的自学笔记5------三八译码器(case语句与锁存器)

相关推荐
爱吃汽的小橘2 小时前
使用乒乓ram去直流分量
fpga开发
技术小白爱FPGA4 小时前
Altera Fpga PCI master 设计
fpga开发
你也渴望鸡哥的力量么5 小时前
爬虫学习笔记
笔记·爬虫·学习
日更嵌入式的打工仔5 小时前
InitLWIP() 初始化
笔记·嵌入式硬件·学习
峰顶听歌的鲸鱼5 小时前
38.Shell脚本编程2
linux·运维·服务器·笔记·学习方法
聪明的笨猪猪7 小时前
Java Spring “MVC ”面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试
LXS_3578 小时前
Day 09(下) B2a实例解说----exampleB2a.cc+ActionInitialization+PrimaryGeneratorAction
笔记·学习方法·改行学it·geant4·b2a
繁星星繁9 小时前
C++11学习笔记
c++·笔记·学习
金水谣10 小时前
10.8考研笔记
笔记