首先给大家道个歉,博客有很久没有更新了,事儿比较多,更方面的原因吧。最近和北航出版社王姐探讨了关于出版这本书的事情,出版的话还有很多工作要做,但是出版也好,有利于给自己些重新审阅写的一些东西,有些大家的意见反馈啥的都可以在出版的时候给予纠正,同时增加一些遗漏的东西。其实出版的版费算起来的话出个一千册也就是几千块钱,相比这么大的工作量来讲,能给自己坚持的还是大家的支持和自己追求那种对执着,大家在学习这个技术的路上也有很多需要坚持的地方,希望大家也能够坚持下去,没有开发板没关系,暂且没有动力没关系,但是我们都有一颗年轻的心!
发完感慨,回归正题,看到这章的题目是一个选择题,选项就是不同的硬件电路描述语言,这好比我们要说话,首先想的是我们要用什么语言来表达,但是不管用普通话还是英语,表达的意思是一样的,学习FPGA也一样。从这一章开始介绍语言了,开始了小学生活,本章的安排是先介绍了两种应用广泛的语言的基本结构,然后对它们的应用选择进行了比较个人的观点陈述,仅供大家参考了。需要说明的是,如果你觉得自己是一个老手,那么这一章节甚至所有的语法章节都可以跳过去,前提是你自己觉得自己有那个自信跳过去。
顺带说以下,有时博客不是实时在线,为了和大家交流,建立了一个群,群号是232619168,而且目前正在构建一个平台,能够给大家免费网络讲讲,大家有独特的应用也可以来给大家讲讲,如果有做过类似平台的,可以联系我,谢谢!
要学习Verilog HDL,那我必须先了解Verilog HDL语言的基本机构,那么Verilog HDL语言的基本结构是什么呢?
Verillog的基本单元是模块;其主要由一下几个部分组成:端口定义,I/O说明,内部信号的声明,模块功能的定义,我们还是看个例子比较实际一些。
module FreDevider (
Clock,
rst,
Clkout
);
//模块名(端口1,端口2,端口3);
input Clock;
input rst;
output Clkout; // I/O说明
reg Clkout; //内部信号的声明
always @( posedge Clock or posedge rst) //模块功能的定义
begin
if(rst)
Clkout <=0;
else
Clkout <= ~Clkout;
end
endmodule
这个模块实现的功能是对输入时钟进行分频,所谓的模块模块就好比一个小的电路板,我们把不同的模块拼接起来就构成更大的模块,更大的电路板,这样去理解模块这个概念会比较有趣味些,熟悉C语言的就直接理解成函数就成。
每个模块的必须关键字是module和endmodule,它们是成双成对的,在书写代码的时候一定要记得写完module就要写endmodule,在verilog或者其他语言中都会有这样的情况,暂且在此提一下,主要的好处是在写到后面的时候不会忘记书写一些关键字,所有其他内容在接下来根据这个例子来说明。
端口列表,就是用来表明该模块的进进出出的,也即输入或输出口进行标识。这样一来,模块组合的时候,便于该模块与其他模块相连接,知道有哪些路可走,这也是端口列表的意义所在。参照上面的例子,
(
Clock,
rst,
Clkout
);
就是模块的端口列表定义,端口列表在书写的时候尽量保证一个信号占用一行,以逗号隔开,这样做的好处主要有两点,一个是查看代码的时候比较直观,另外一个原因是方便I/O声明以及模块例化的时候直接复制粘贴,省掉重复性的输入工作,特别是在端口比较多的情况下,这个属于代码规范里需要做的,暂且我们提这些。
当模块被引用时,端口列表有两种形式与其他模块连接:
这样不用标明端口定义时的端口名,缺点就是必须严格按照模块定义时的端口顺序映射,其格式为:
模块名 实例名(
连接端口1的信号名,
连接端口2的信号名,
连接端口3的信号名,
…,
连接端口n的信号名
);
对上面例子模块的引用:
FreDevider instance (
Clock,
rst,
Clkout
);
有人会有疑问,假如中间有一个信号不用连接怎么办呢?这里留一个悬念,但要说明的是,直接跳过去视而不见是不行的哈,后面的信号会顶过来的。
这种方式是比较通用和常见的,它具有很强的灵活性,不用按照端口定义时的顺序对应。其格式为:
模块名 实例名(
. 端口1名(连接信号1名),
. 端口2名(连接信号2名),
. 端口3名(连接信号3名),
…,
. 端口n名(连接信号n名)
)(备注,中间没用的端口可以省略)。
对上面例子模块的引用:
FreDevider instance(
. Clock(Clock),
. rst(rst) ,
. Clkout(Clkout)
);
前面有了对端口列表的解释,知道了端口列表告诉编译器的是通往模块内部有哪些路可走,路是有了,但是并不是所有的路都是能有回头路的,有点像现实生活,不过生活有时还是有回头路的呵呵。在verilog中有三种路,分别是input、output、inout型,上面的例子中就是
input Clock;
input rst;
output Clkout;
有了这些,就知道哪些路是去往模块内,哪些是从模块输出来的,哪些既可以进也可以出,这三种类型的完整格式为:
I/O口类型 [信号位宽-1:0] 端口名;
三种I/O口类型对应的格式:
输入口:
input [信号位宽-1:0] 端口名1;
输出口:
output [信号位宽-1:0] 端口名1;
输入输出口:
inout [信号位宽-1:0] 端口名1;
每种类型的关键字是非常形象的表达了该类型的功能的,特别是inout型,让人想到了古代象形文字,呵呵。
内部信号声明就是模块内用到的变量以及端口有关的wire和reg类型的变量的声明,不管是进来的路、出去的路、可进可出的路,都给其规定经过的信号和模块本身的中间信号具有的属性身份,具体的映射后面会有提到一些规定,比如模块内输入信号不能定义成reg型的等,其声明格式为:
变量类型 [信号位宽-1:0] 变量/端口名;
如例子中:reg Clkout;
关于信号的类型将在下一章进行详细说明,不仅仅是wire和reg了,除了这个之外,还有一个参量类型,即paramater型,也应该归结到内部信号声明部分。
好了,有了模块名、端口列表、端口输入输出类型说明、模块内具有身份属性的信号,如此好的准备之下,该让这些信号之间发生一些事情了,这就是模块的功能定义。模块功能定义就是用相应的方法描述模块内不同信号之间的逻辑功能,是模块的核心。主要有三种方式产生逻辑:
如:assign RST_N=~ RST;
其为连续赋值语句,后面有详细介绍。例子描述了一个非门;
采用实例元件的方法像在电路图输入方式下调入库元件一样,键入元件的名字和相连的引脚即可,包括我们所说的IP核;
运用“always”块来描述要实现的逻辑;
如分频模块的例子,他就是运用“always”块描述的。
用户377235 2014-10-15 22:14
用户377235 2014-4-18 14:23
用户1336188 2013-11-29 14:51
用户450888 2013-11-1 10:37
用户724606 2013-10-9 09:25
用户433875 2013-6-18 22:39
用户420773 2013-3-15 16:58
用户377235 2013-1-17 13:39
handong123123_906892115 2012-12-18 09:48
用户593939 2012-12-17 22:38