Verilog HDL程序笔记1:写出属于你的第一个Verilog HDL模块
文章目录
前言
Verilog HDL是一种硬件描述语言,以文本形式来描述数字系统硬件的结构和行为的语言,用它可以表示逻辑电路图、逻辑表达式,还可以表示数字逻辑系统所完成的逻辑功能。
提示:以下是本篇文章正文内容
一、Verilog 模块的基本概念
Verilog有两个重要的特点:模块化和层次化。所谓的模块化有点类似java里的方法。模块内部实现逻辑是面向过程的,而开发者需要将所描述的电路抽象,将整个电路包裹在一个黑箱中,只留下输入和输出的接口。
上图所示是一个二选一选择器,可以看到我们只能够看到这个电路的输入和输出。如果有接触过这个电路的朋友应该知道,这个电路起到的是一个选择数据的作用,通过控制sl(select)的值可以控制out选择输出a或者b。
这是我在verilog中第一个实现的程序,接下来我将带领大家从头开始书写这个程序。
二、Verilog HDL中的变量
如果我上来就直接放整个程序的代码大家肯定会一头雾水。学习这门课程的同学肯定会有其他编程课的先修课程。在c,c++或者java之类的编程语言中,存在着一种十分重要的元素:变量。而变量是有类型的,就像当今社会中各式各样的打工人一样,变量也是各司其职。
1.wire型
第一种要介绍的变量叫做wire。wire顾名思义,可以让我们联想到电线,铜线,电缆之类的物体。wire就像这些物体一样,在结构实体之间(比如门)负责物理连接的工作。
起到这种作用的变量统一叫做网络数据类型变量。和wire相似的还有tri型变量。我们目前着重使用wire型。
输入输出变量默认自定义为wire型
网络型变量不能储存值,就好像我们日常生活中的电线不能储存信息一样。而且这个类型的变量必须要有驱动器驱动,否则这个变量就会变成高阻,即其值为Z。
那么什么是驱动器驱动呢?例如门、连续赋值语句,assign语句就可以成为驱动器。
2.reg型变量
寄存器是数据储存单元的抽象,而reg型变量是寄存器数据类型的关键字。也就是说reg型变量不同于wire型变量,他是可以赋值的。我们可以通过连续赋值语句对reg型变量赋值,这样的操作和我们改变触发器储存的值相当。
reg型变量默认初始值为不定值X
reg型数据变量常用来表示“always”模块内的指定信息。在“always”模块内被赋值的每一个信号都必须定义成reg型
三、Verilog HDL第一段代码
这里就会有小伙伴迷茫了,你说的assign语句,always模块又是什么呢?别急,下面我们就开始写程序啦
我们还是看回刚刚的二选一选择器这张图
假设我们是个刚学编程的宝宝,严厉的父亲给了我们一个任务,将上述电路图的Verilog代码写出来。
老父亲不讲武德,来骗,来偷袭我一个9岁的宝宝。这好吗?这不好!
光凭一张电路图,还不给内部电路我怎么写?没法写呀!
那我们就物尽其用。光看着这副光秃秃的电路图我们可以得到哪些信息呢?大家先回答我这些问题:
1、这幅图的哪些引脚看着像输入? a,b,sl
2、这幅图的哪些引脚看着像输出? out
3、这幅电路图想实现的逻辑是什么? sl=0时out输出a,sl=1时out输出b
欸?这么以来思路是不是就清晰多了?Verilog是外国人设计的,说输入输出他不懂,那我们改成input,output他是不是就懂了?那这个input、output是不是就是输入输出变量了?他的默认类型是???? wire型变量
input a,b,sl;
output out;
对的没错。我们已经开始上手了!
我们在第一点中讲的Verilog有一个很重要的特点是什么?模块化!那我们刚刚那副电路图是不是就可以把他看成一个模块?虽然我们不知道内部电路,但是我们有电路的接口。严厉的父亲是不是就是想我们写一个模块呢?!
将计就计!
在Verilog HDL中定义一个模块常常是以下的这种格式:
module module_name(parameter1,.....);
//coding here
endmodule
可以看出我们需要给我们定义的模块命名以及传递参数。
刚刚那幅电路图的模块教科书上应该叫做muxtwo。但是我怕大家会混论,我将他的名字定义为狗,dog。
那么我们要传入的参数是什么呢?没错!a,b,sl,out。也就是输入和输出。
module dog(a,b,sl,out);
//coding here
endmodule
这样我们一个简单的模块就写完了。可是这是一个空的模块,什么功能都没有。现在我们就来填满他,将上面我们写过的两端代码复制下来:
module dog(a,b,sl,out);
input a,b,sl;
output out;
endmodule
这样的话我们就告诉了电脑,我们的输入是a,b,sl,输出是out。可是依然缺少逻辑代码,以至于我们的“dog”模块还是无法完成我们想要的功能。
module dog(a,b,sl,out);
input a,b,sl;
output out;
if(!sl) out=a;
else out=b;
endmodule
好了我加上了,当sl=0时out就等于a的值,当sl等于1时out就等于b的值。没问题吧?!
噢不!出错了!怎么回事呢?我们来细细品一品。
输入输出默认是wire类型,而out等于a的值?诶?不对劲,不是说wire不能赋值吗?没错我们需要将wire型改成reg型。而且需要使用always赋值。
module dog(a,b,sl,out);
input a,b,sl;
output out;
reg out;
always @(sl or a or b)
if(!sl) out=a;
else out=b;
endmodule
我们可以看到always这句话有点奇怪。我们可以理解为always里的语句是和括号里的(sl or a or b)挂钩的,always模块中的任何一个输入信号或电平发生变化时,该语句下方的模块将被执行。
我们再次编译这段代码,就会发现我们的dog编译大成功!!!
总结
好了我们完成了严厉的父亲的作业,同时也掌握了两种变量类型以及如何定义一个模块。更重要的是我们正式地进入了Verilog的世界!