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

相关推荐
Kay_Liang1 小时前
【Hive 踩坑实录】从元数据库初始化到 HiveServer2 启动的全流程问题解决
大数据·linux·hive·hadoop·笔记·mysql·ubuntu
Larry_Yanan1 小时前
QML学习笔记(四十八)QML与C++交互:QML中可实例化C++对象
c++·笔记·qt·学习·ui·交互
MeowKnight9582 小时前
【数据结构】单链表 练习记录
笔记
Felicity_Gao6 小时前
uni-app VOD 与 COS 选型、开发笔记
前端·笔记·uni-app
崎岖Qiu10 小时前
【设计模式笔记06】:单一职责原则
java·笔记·设计模式·单一职责原则
im_AMBER11 小时前
数据结构 09 二叉树作业
数据结构·笔记·学习
www.0213 小时前
linux服务器升级显卡驱动(笔记)
linux·运维·服务器·笔记·ubuntu·服务器环境
せいしゅん青春之我13 小时前
【JavaEE初阶】TCP核心机制10——异常情况的处理
java·网络·笔记·网络协议·tcp/ip·java-ee
wdfk_prog13 小时前
[Linux]学习笔记系列 -- [kernel][time]hrtimer
linux·笔记·学习
摇滚侠13 小时前
Spring Boot3零基础教程,把 Java 程序打包为 Linux 可执行文件,笔记91
java·linux·笔记