FPGA智能传感系统(一)Verilog基础入门

  Verilog模块的基本构成要素有三大部分: 端口信息输入/输出说明逻辑功能描述。这里将其看成一种计算机语言就行了,没有那么网上说的什么花里胡哨的。计算机语言就是用来实现功能的,我们日常接触最多的就是c++python这种,做的一般是计算仿真,而这个verilog做的是与硬件相关的,也就是直接控制信号的与或非这种。

  而学习一门计算机语言最快的方式就是直接上手干,话不多说看个例子:

module block1(a, b, c, d, e);
input a, b, c;
output d, e; .
	assign d=a|(b&~c);
	assign e=(b&~c );
endmodule

  可以看到verilog模块由两部分组成:端口信息内部功能。上述代码所述功能是输入三个信号a,b,c(这里没有指定位宽,说明这里都是一位位宽信号); 输出de也是没有指定位宽,表示一根线输出。中间assign赋值语句就是内部功能,表示输入与输出之间的关系。d信号的输出等于a或上bc的非,e同理。

Verilog基本模块

结构

  verilog模块的结构在moduleenmodule关键词之间,主要有四个主要部分组成。上述是verilog的一个基本的程序模块,如果我们想要设计一个verilog模块的话,其大体组成部分如下图所示:

verilog HDL程序模块

  1. 模块端口定义用来声明设计电路模块的输入输出端口。端口定义格式如:module模块名(端口1,端口2,端口3,…);。

  任何一个模块都是以module开头的。在端口定义的圆括弧中,是设计电路模块与外界联系的全部输入输出端口信号或引脚,它是设计实体对外的一个通信界面,是外界可以看到的部分(不包含电源和接地端),多个端口名之间用“,”分隔," ; "结尾。

  1. 模块内容包括I/O说明、信号类型声明和功能描述。模块的I/O说明用来声明模块端口定义中各端口数据流动方向包括输入(input) 、输出(output) 和双向(inout) 。I/O说明格式如下:
input ina , inb,cin;
output sum, cont;

  这里写成一行的话位宽都是一样的。所以有时候需要指定位宽的时候我们对每个输入、输出单独写。

  1. 信号类型声明用来说明设计电路的功能描述中,所用的信号的数据类型以及函数声明。信号的数据类型主要有连线(wire) 、寄存器(reg)、整型(integer) 、实型(real) 和时间(time)等类型。在通常设计的时候用的最多的就是连线型(wire)和整型(reg),有时候也会用到整型。

  2. 功能描述Verilog HDL程序设计中最主要的部分,用来描述设计模块的内部结构和模块端口间的逻辑关系,在电路上相当于器件的内部电路结构

  功能描述可以用assign语句、元件例化(instantiate) 、always块语句、initial块语句等方法来实现,通常把确定这些设计模块描述的方法称为建模。

语句

  (1) 用assign语句建模的方法很简单,只需要在“assign”后面再加一个表达式即可。assign语句一般适合对组合逻辑进行赋值,称为连续赋值方式。

module adder1 (sum, cout, ina, inb, cin) ; //模块端口定义
	input ina, inb, cin;
	output sum,cout; //I/O声 明
	assign {cout, sum} = ina+inb+cin; //功能描述语句
endmodule //endmodule后不加分号

  默认的数据类型为wire (连线)型,{ }为拼接运算符,是将coutsum这样两个1位操作数拼接为一个2位操作数。

  (2) 元件例化方式建模是利用Verilog HDL提供的元件库实现的。.例如,用与门例化元件定义一个3输入端与门可以写为and myand3(y,a,b,c); and为关键字,名称为myand3

  (3) always块语句可以产生各种逻辑,常用于时序逻辑的功能描述。一个程序设计模块中,可以包含一个或多个always语句。程序运行中,在某种条件满足时,就重复执行一遍always结构中的语句

module cnt8(out,cout,data,load,cin,clk,clr);
	input [7:0] data; // 输入数据八个比特
	input load, cin, clk, clr; // 一个比特
	output| 7:0] out;
	output cout;
	reg [7:0] out; //寄存器型参量,具有寄存功能
	always @(posedge clk) //时钟 上升沿,每次上升沿,执行always语句
		begin
			if (clr) out < =8'b0;
			else if (load) out <= data;
			else out <= out+8'b1;
		end
	assign cout = &out & cin; //&out”-与缩减运算式
endmodule

  输出out八位、cout输出进位一位、data八位,load置数信号一位,cin输入进位,clk时钟,一位,clr复位。这里输出信号为out,之后又将其定义为寄存器信号。

  always@括号中的是条件,posedge clk表示的时钟上升沿。也就是时钟上升沿一进来进开始执行内部语句。如果clr复位信号为高电平,输出out就被赋值为8比特0(这里的<=就是赋值语句)。当out全为1且进位cin也为1的时候cout才为1

  由于这里out信号在always块中赋值,所以必须定义为寄存器型变量。也就是always块中的变量必须定义为寄存器类型assign赋值的变量必须是wire型。

  (4) initial块语句与always语句类似,不过在程序中它只执行1次就结束了。

词法、语法

  1. Verilog HDL的常数包括数字未知X高阻z三种。数字可以用二进制、十进制、八进制和十六进制等4种不同数制来表示,完整的数字格式
<位宽>'<进制符号><数字>

  其中,位宽表示数字对应的二进制数的位数宽度; 进制符号包括bB (表示二进制数),dD (表示十进制数),hH (表示十六进制数),oO (表示八进制数)。

  1. 字符串是用双引号括起来的可打印字符序列,它必须包含在同一行中。

  2. 标识符是用户编程时为常量、变量、模块、寄存器、端口、连线、示例和begin-end块等元素定义的名称。标识符可以是字母、数字和下划线等符号组成的任意序列。

  3. 关键字Verilog HDL预先定义的单词,它们在程序中有不同的使用目的。所有关键字都用小写

  4. 操作符也称为运算符,是Verilog HDL预定义的函数名字,这些函数对被操作的对象(即操作数)进行规定的运算,得到一个结果。

  操作符通常由1~3个字符组成,例如,“+”表示加操作,“= =” (两个=字符)表示逻辑等操作,“===”(3个=字符)表示全等操作。

  有些操作符的操作数只有1个,称为单目操作;有些操作符的操作数有2个,称为双目操作;有些操作符的操作数有3个,称为三目操作

  1. 常量是-一个恒定不变的值数,一般在程序前部定义。常量定义格式为
parameter常量名1 =表达式,常量名2 =表达式,...,
常量名n=表达式;

  parameter是常量定义关键字,常量名是用户定义的标识符,表达式是为常量赋的值。

  1. 变量是在程序运行时其值可以改变的量。在Verilog HDL中,变量分为网络型(nets type)和寄存器型(register type)两种。

  nets型变量是输出值始终根据输入变化而更新的变量,它一般用来定义硬件电路中的各种物理连线。常用的是wire类型。

  register型变量是一种数值容器,不仅可以容纳当前值,也可以保持历史值,这一属性与触发器或寄存器的记忆功能有很好的对应关系。

  register型变 量与wire型变量的根本区别: register型变量需要被明确地赋值,并且在被重新赋值前–直保持原值。.

  register型变量是在alwaysinitial等 过程语句中定义,并通过过程语句赋值。

常用的register型变量及说明

  integerrealtime等3种 寄存器型变量都是纯数学的抽象描述,不对应任何具体的硬件电路,但它们可以描述与模拟有关的许算。例如,可以利用time型变量控制经过特定的时间后关闭显示等。

  reg型变量是数字系统中存储设备的抽象,常用于具体的硬件描述,因此是最常用的寄存器型变量。reg型变量定义的关键字是reg,定义格式如下:

reg [位宽]变量1, 变量2,...,变量n;

  用reg定义的变量有-一个范围选项( 即位宽),默认的位宽是1。位宽为1位的变量称为标量,位宽超过1位的变量称为向量。

  向量定义时需要位宽选项:

reg[7: 0] data; //定义1个8位寄存器型.变量, 最高有效位是7,最低有效位是0
reg[0: 7] data; //I定义1个8位寄存器型变量,最高有效位是0,最低有效位是7
  1. 数组:若干个相同宽度的向量构成数组。在数字系统中,reg型数组变量即为memory (存储器)型变量
mymemory[1023:0];

  上述语句定义了一个1024个字存储器变量mymemory,每个字的字长为8位。在表达式中可以用下面的语句来使用存储器:

mymemory[7]=75; // 存储器mymemory的第7个字被赋值75。

Verilog语句

  基本逻辑门关键字是Verilog HDL 预定义的逻辑门,包括andornotxornandnor等。

  1. 过程赋值语句

  过程赋值语句出现在initial和always块语句中,赋值符号是“=”,格式为

  赋值变量=表达式;

  在过程赋值语句中,赋值号“=”左边的赋值变量必须是reg (寄存器)型变量,其值在该语句结束即可得到。如果一个块语句中包含若干条过程赋值语句,那么这些过程赋值语句是按照语句编写的顺序由上至下一条一条地执行,前面的语句没有完成,后面的语句就不能执行,就象被阻塞了一样。 因此,过程赋值语句也称为阻塞赋值语句。

  1. 非阻塞赋值语句

  非阻塞赋值语句也是出现在initialalways块语句中,赋值符号是“<=”,格式为

  赋值变量<=表达式;

  在非阻塞赋值语句中,赋值号“<=”左边的赋值变量也必须是reg型变量其值不象在过程赋值语句那样,语句结束时即刻得到,而在该块语句结束才可得到

  1. 循环语句

  循环语句包含for语句、repeat语句、while语句和forever语句4种。

模块实例化

  与C语言相比,verilog语句是并行的,比如两个always块都是时钟沿出发的,那么它们就是并行的。

  特殊符号“#”常用来表示延迟。使用'define编译引导能提供简单的文本替代功能。

`define <宏名> <宏文本>

  举例如下:

`define on 1'b1 // 0比特1定义on
`define off 1'b0 // 0比特0定义off
`define and delay #3 // 定义延时

  使用'include编译引导在编译的时候能把其指定的整个文件包括进来一起处理。如’include “global.v"等。

  可以将模块的实例通过端口连接起来构成一个大的系统或元件。每个实例都有自己的名字。实例名是每个对象唯一的标记,通过这个标记可以查看每个实例的内部。实例中端口的次序与模块的定义的次序相同。模块实例化与调用程序不同。每个实例都是模块的一个完全拷贝,相互独立、并行。

  在调用模块时,可以用顺序连接和按名连接把模块定义的端口与外部信号连接起来。

  顺序连接:需要连接的信号需要与模块声明的端口列表一致;

模块实例化

  按名连接:端口和外部信号按名字连接在一起。当设计大规模系统时,端口太多,记住端口顺序不大可能,可以采用按名连接方法。

  不需要连接的端口直接忽略掉即可:

我的微信公众号名称:小小何先生
公众号介绍:主要研究分享深度学习、机器博弈、强化学习等相关内容!期待您的关注,欢迎一起学习交流进步!

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值