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语句与锁存器)

相关推荐
思成不止于此13 小时前
【C++ 数据结构】二叉搜索树:原理、实现与核心操作全解析
开发语言·数据结构·c++·笔记·学习·搜索二叉树·c++40周年
碧海潮生_CC14 小时前
【CUDA笔记】03 CUDA GPU 架构与一般的程序优化思路(下)
笔记·架构·cuda
钟屿14 小时前
Back to Basics: Let Denoising Generative Models Denoise 论文阅读学习
论文阅读·人工智能·笔记·学习·计算机视觉
d111111111d15 小时前
SPI通信协议--在STM32中介绍(学习笔记)
笔记·stm32·单片机·嵌入式硬件·学习
愚昧之山绝望之谷开悟之坡15 小时前
业务接待-公务接待-商务接待
笔记
大数据追光猿17 小时前
LangChain / LangGraph / AutoGPT / CrewAI / AutoGen 五大框架对比
经验分享·笔记·python·langchain·agent
✎ ﹏梦醒͜ღ҉繁华落℘17 小时前
freeRTOS学习笔记(十四)--内存
笔记·学习
客梦18 小时前
Java 学生管理系统
java·笔记
hd51cc20 小时前
动态链接编程 学习笔记
笔记·学习
小此方21 小时前
笔记:树。
数据结构·笔记