当前位置: 首页 > news >正文

苏州网站优化公司女性pose拍照

苏州网站优化公司,女性pose拍照,做西服的网站,WordPress页面调用文章Verilog语言学习#xff01; 目录 文章目录 前言 一、Verilog语言是什么#xff1f; 1.1 Verilog简介 1.2 Verilog 和 C 的区别 1.3 Verilog 学习 二、Verilog基础知识 2.1 Verilog 的逻辑值 2.2 数字进制 2.3 Verilog标识符 2.4 Verilog 的数据类型 2.4.1 寄存器类型 2.4.2 … Verilog语言学习 目录 文章目录 前言 一、Verilog语言是什么 1.1 Verilog简介 1.2 Verilog 和 C 的区别 1.3 Verilog 学习 二、Verilog基础知识 2.1 Verilog 的逻辑值 2.2 数字进制 2.3 Verilog标识符 2.4 Verilog 的数据类型 2.4.1 寄存器类型 2.4.2 线网类型 2.4.3 参数类型 2.5 Verilog 运算符 2.5.1 算术运算符 2.5.2 关系运算符 2.5.3 逻辑运算符 2.5.4 条件运算符 2.5.5 位运算符 2.5.6 移位运算符 2.5.7 拼接运算符 2.5.8 运算符的优先级 2.6 注释 2.7 Verilog关键字 三、程序框架 3.1 模块的结构 3.2 模块的端口定义 3.3 I/O说明 3.4 内部信号声明 3.5 功能定义 3.5.1 assign声明语句 3.5.2 实例元件 3.5.3 always块 3.6 模块的调用 四、Verilog语句 4.1 结构语句 4.1.1 initial语句 4.1.2 always语句 1always 语句语法 2always 语句的沿触发和电平触发 3always块的or事件控制 4电平敏感时序控制 4.2 赋值语句 4.2.1 阻塞赋值blocking 4.2.2 非阻塞赋值Non-Blocking 4.2.3 赋值语句的使用 1赋值语句的选择 2assign 和 always 区别 3带时钟和不带时钟的 always  4.3 条件语句 4.3.1 if_elas语句 4.3.2 case语句多分支选择语句 五、状态机 5.1 状态机概念 5.2 状态机模型 5.2.1 Mealy 状态机 5.2.2 Moore 状态机 5.3 状态机设计 5.3.1 状态空间定义 5.3.2 状态跳转 5.3.3 下个状态判断 5.3.4 各个状态下的动作 5.3.5 三段式状态机 总结 前言 在 FPGA 设计里面Verilog 语言可以对大规模的电路和复杂的逻辑电路进行设计且目前 Verilog 已经在 FPGA 开发/IC 设计领域占据绝对的领导地位。本文就介绍了Verilog语言的基础内容。 一、Verilog语言是什么 1.1 Verilog简介 Verilog 是一种硬件描述语言以文本形式来描述数字系统硬件的结构和行为的语言用它可以表示逻辑电路图、逻辑表达式还可以表示数字逻辑系统所完成的逻辑功能。 1.2 Verilog 和 C 的区别 Verilog 是硬件描述语言在编译下载到 FPGA 之后会生成电路所以 Verilog 全部是并行处理与运行的。这里的并行是指电路在上电之后给各个模块一个时钟信号这些模块会同时开始工作。所以FPGA是并行处理的。 C 语言是软件语言编译下载到单片机/CPU 之后还是软件指令而不会根据你的代码生成相应的硬件电路而单片机/CPU 处理软件指令需要取址、译码、执行是串行执行的。这里的串行是指C语言在编译下载到单片机上后是存储器中的一组指令单片机对第一条指令进行要取址、译码、执行处理后再对第二条处理再对第三条... ...这样一条一条依次处理就是串行执行的一个过程。 Verilog 和 C 的区别也是 FPGA 和单片机/CPU 的区别由于 FPGA 全部并行处理所以处理速度非常快这个是 FPGA 的最大优势这一点是单片机/CPU 替代不了的。因为单片机/CPU是串行处理。 1.3 Verilog 学习 Verilog 作为一种高级的硬件描述语言它的很多语法现象与C语言非常相似因此在有C语言的基础上对照类比学习会非常容易。Verilog 学习过程中要培养硬件设计的思想把新概念和硬件结构结合联系起来着重理解Verilog 的并行特性。 二、Verilog基础知识 2.1 Verilog 的逻辑值 先看下逻辑电路中有四种值即四种状态 逻辑 0表示低电平也就是对应我们电路的 GND 逻辑 1表示高电平也就是对应我们电路的 VCC 逻辑 X表示未知有可能是高电平也有可能是低电平 逻辑 Z表示高阻态外部没有激励信号是一个悬空状态。 在数字电路里常会使用逻辑值0和1来代表逻辑的假和真0代表假、1代表真。0和1对应在实际电路中就代表高低电平0代表低电平、1代表高电平。在Verilog语言中0和1也表示高低电平逻辑0表示低电平逻辑1表示高电平。 图中第一个模块左边电路接GND右边电路输出就是低电平用逻辑0表示。图中第二个模块左边电路接VCC右边电路输出就是高电平用逻辑1表示。 在Verilog语言中除了逻辑1和逻辑0还有另外两个逻辑一个是逻辑 X另外一个是逻辑 Z。逻辑 X 和逻辑 Z 其实是数字电路里的概念在Verilog语言里面也和数字电路里一样的。对于逻辑 X 而言它表示的是一个未知的电平有可能是低电平也有可能是高电平。 图中第三个模块左边两个器件上面一个接VCC下面一个接GND这两个器件同时输出到一个端口这个端口的值就是一个未知的状态有可能是高电平逻辑1也有可能是低电平逻辑0也就是右边的输出端用 X 表示这种未知的状态。 逻辑 Z 就表示高阻态外部没有激励信号而是是一个悬空状态。高阻态不止是针对FPGA的引脚而言对于一些内部信号同样会呈献高阻态。 图中第四个模块可以看到器件的使能端给了一个0也就是左边的输入并没有传递给右边的输出那么这个输出端的状态就没有被输入端来驱动。 逻辑 X 与逻辑 Z 的区别 逻辑 X 虽然它的状态是未知但是它只能是逻辑1或逻辑0这两个状态。Z高阻态处于悬空的状态。就是它没有输入也不能判断它是高电平逻辑1还是低电平逻辑0它甚至有可能处于高电平和低电平之间的状态。对于这种没有外部输入信号的一个状态就称为高阻态。 2.2 数字进制 Verilog 数字进制格式包括二进制、八进制、十进制和十六进制一般常用的为二进制、十进制和十六进制。 Verilog 语言中二进制用b或B表示、八进制用o或O表示、十进制用d或D表示、十六进制用h或H表示。Verilog 语言数字进制的表示是和C语言一致的。 Verilog 语言中数字表示的语法格式位宽进制数值。 二进制表示例子4’b0101 表示 4 位二进制数字 0101 4表示数据位宽也就是这个数据是一个4位的位宽。b表示二进制表示后面数值是用二进制来表示的。0101表示二进制数值。 十进制表示例子4’d2 表示 4 位十进制数字 2二进制 0010 4表示数据位宽也就是对这个十进制的数值以二进制且4位的位宽 0010的形式来存储。d表示十进制表示后面数值是用十进制来表示的。2表示十进制数值为2。 十六进制表示例子4’ha 表示 4 位十六进制数字 a二进制 1010 4表示数据位宽也就是对这个十六进制的数值以二进制且4位的位宽 1010的形式来存储。h表示十六进制表示后面数值是用十六进制来表示的。4表示十六进制数值为4。 十六进制的计数方式为 01 2…9abcdef最大计数为 ff十进制表示为 15。 注意数据位宽是表示这个数的二进制位宽因为在数字电路中数值实际上都是以二进制的形式来存储的。所以十进制和十六进制表示的数据位宽都是数值的二进制位宽。 如果没有指定数值的位宽默认位宽为32位的位宽。如果既没有指定数值的位宽也没有指定进制就默认32位的十进制。 可以给数值加下划线来提高数值的可读性下划线在编译的时候会自动忽略掉。 例如16’b1001_1010_1010_100116’h9AA9 2.3 Verilog标识符 Verilog标识符类似于C语言里的变量名。 标识符定义         标识符(identifier用于定义模块名、端口名和信号名等。 Verilog 的标识符可以是任意一组字母、数字、$和_(下划线)符号的组合。 但标识符的第一个字符必须是字母或者下划线。 标识符是区分大小写的。 规范建议 不建议大小写混合使用。普通内部信号建议全部小写。信号命名最好体现信号的含义做到简洁、清晰、易懂。 以下是一些书写规范的要求 用有意义的有效的名字如 sum、cpu_addr 等。sum表示和、addr表示地址用下划线区分词语组合如 cpu_addrCPU地址。采用一些前缀或后缀比如时钟采用 clk 前缀clk_50m50MHz时钟clk_cpuCPU时钟信号低电平采用_n 后缀enable_n低电平使能。统一缩写如全局复位信号 rst。同一信号在不同层次保持一致性如同一时钟信号必须在各模块保持一致。自定义的标识符不能与保留字关键词同名。参数统一采用大写如定义参数使用 SIZE。 2.4 Verilog 的数据类型 在 Verilog 语法中主要有三大类数据类型即寄存器类型、线网类型和参数类型。 从名称中可以看出真正在数字电路中起作用的数据类型应该是寄存器类型和线网类型。也就是说 寄存器数据类型和线网类型都是可以映射到实际的物理电路上去的。参数类型是给编译器来识别的数据类型。 2.4.1 寄存器类型 寄存器类型表示一个抽象的数据存储单元通过赋值语句可以改变寄存器的值。 寄存器数据类型的关键字是regreg类型数据的默认初始值为不定值X。 reg类型数据只能在 always 语句和 initial 语句中被赋值不能在定义寄存器时就赋初值。这一点和C语言命名定义变量时就给一个初始值是不一样的。并且Verilog语言中寄存器的值是从一个赋值到另一个赋值过程中被保存下来。 如果该过程语句描述的是时序逻辑即 always 语句带有时钟信号则该寄存器变量对应为触发器如果该过程语句描述的是组合逻辑即 always 语句不带有时钟信号则该寄存器变量对应为硬件连线。 寄存器类型的缺省值是 X未知状态。 寄存器数据类型有很多种如 reg、integer、real 等其中最常用的就是 reg 类型。 reg定义语法格式关键字reg [寄存器位宽 ] 标识符名称 ;reg位宽高位在前低位在后。reg定义中没给出位宽的时候就默认位宽是1. 代码示例 //reg definereg [31:0] delay_cnt; //延时计数器 reg类型、位宽为32、名为delay_cntreg  key_flag ; //按键标志 上述代码定义了一个reg类型位宽为32名为 delay_cnt 的寄存器和一个reg类型位宽为1名为 key_flag 的寄存器。 2.4.2 线网类型 线网表示 Verilog 结构化元件间的物理连线。它的值由驱动元件的值决定例如连续赋值或门的输出。如果没有驱动元件连接到线网线网的缺省值为 z高阻态。 线网数据类型表示结构实体例如门之间的物理连线。 线网数据类型的变量不能存储值它的值是由驱动他的元件所决定的例如门或连接赋值语句assign。 如果没有驱动元件连接到线网类型的变量上该线网类型的变量就是高阻的即其值为Z。 线网类型同寄存器类型一样也是有很多种如 tri 和 wire 等其中最常用的就是 wire 类型。 Verilog 语言中wire型信号的格式同reg型信号的格式很类似 wire定义语法格式关键字reg [寄存器位宽 ] 标识符名称 ;wire位宽高位在前低位在后。wire定义中没给出位宽的时候就默认位宽是1. 代码示例 //wire define wire data_en; //数据使能信号 wire [7:0] data ; //数据 上述代码定义了一个wire类型位宽为1名为 data_en 的线网数据和一个wire类型位宽为8名为 data 的线网数据。 2.4.3 参数类型 参数其实就是一个常量在Verilog 语言中用 parameter 定义常量。这一点有点类似于C语言中define的作用但是语法结构不一样。 参数型数据常被用于定义状态机的状态、数据位宽和延迟大小等。 采用标识符来代表一个常量可以提高程序的可读性和可维护性。 由于它可以在编译时修改参数的值因此它又常被用于一些参数可调的模块中使用户在实例化模块时可以根据需要配置参数。 在定义参数时我们可以一次定义多个参数参数与参数之间需要用逗号隔开。这里我们需要注意的是参数的定义是局部的只在当前模块中有效。 parameter定义语法格式parameter  标识符名称 等号 ;parameter定义常量可以一次定义多个参数参数参数之间需要用逗号隔开。parameter定义中每个参数定义的右边必须是一个常熟表达式。 代码示例 //parameter define parameter DATA_WIDTH 8; //数据位宽为8位 上述代码定义了一个parameter类型名为 DATA_WIDTH 值为8的参数。 2.5 Verilog 运算符 Verilog 中的运算符按照功能可以 分为下述类型 1、算术运算符、 2、关系运算符、 3、逻辑运算符、 4、条件运算符、 5、位运算符、 6、移位运算符、 7、拼接运算符。 下面分别对这些运算符进行介绍。Verilog 中的运算符很多和C语言是保持一致的可以类比学习。 2.5.1 算术运算符 算术运算符简单来说就是数学运算里面的加减乘除数字逻辑处理有时候也需要进行数字运算 所以需要算术运算符。常用的算术运算符主要包括加减乘除和模除模除运算也叫取余运算。 算术运算符如下表所示 需要注意 在除法运算的时候只能实现整除也就是说在 Verilog 语言中 a/b 的小数部分是被省略掉的。只取整数部分。模除运算a%b 的结果就是a除以b的余数。模除运算要求%两侧均为整数数据。进行取模运算时结果值得符号位采用模运算式里第一个操作数的符号位。 模除运算举例 11 % 3 2        余数为212 % 3 0        余数为0即无余数-10 % 3 -1      结果取第一个操作数 -10 的符号位余数为 -111 % -3 2        结果取第一个操作数 11 的符号位余数为 2. Verilog 实现乘除比较浪费组合逻辑资源尤其是除法。一般 2 的指数次幂的乘除法使用移位运算来完成运算下文移位运算符会具体介绍。非 2 的指数次幂的乘除法一般是调用现成的 IP QUARTUS/ISE 等工具软件会有提供不过这些工具软件提供的 IP 也是由最底层的组合逻辑(与或非门等) 搭建而成的。 在进行算数运算操作时如果某一个操作数有不确定的值X则整个结果也为不定值X。 2.5.2 关系运算符 关系运算符主要是用来做一些条件判断用的。 在进行关系运算符时 如果声明的关系是假的则返回值是 0如果声明的关系是真的则返回值是 1。如果某个操作数的值不定则关系是模糊的返回值是不定值。 所有的关系运算符有着相同的优先级别关系运算符的优先级别低于算术运算符的优先级别。 关系运算符如下表所示 如果要判断两个变量是否是相等的需要用 一个等于号是赋值运算这一点和C语言类似。 2.5.3 逻辑运算符 逻辑运算符是连接多个关系表达式用的可实现更加复杂的判断一般不单独使用都需要配合具体语句来实现完整的意思。 逻辑运算符如下表所示 逻辑运算真值表 ab!a!baba||b真真假假真真真假假真假真假真真假假真假假真真假假 2.5.4 条件运算符 条件操作符一般来构建从两个输入中选择一个作为输出的条件选择结构功能等同于 always 中的 if-else 语句。 条件操作符如下表所示。 a ? b : c 这里a是一个判断条件? 表示是否满足 a 这个判断条件如果 a 条件满足就执行 b 如果 a 条件不满足就执行 c 条件运算符就相当于 if-else 语句的简单写法。 条件运算符举例 result (a b) ? a : b; 代码对等号左边变量result赋值 等号右边的条件运算符的运行逻辑是先判断a是否大于b 若a大于b给result赋值a若b大于a给result赋值b。 代码的作用就是将a和b比较取最大值将最大值赋值给result。 上述代码就相当于如下代码逻辑 if(a b)result a; elseresult b; 2.5.5 位运算符 位运算符是一类最基本的运算符可以认为它们直接对应数字逻辑中的与、或、非门等逻辑门。 常用的位运算符如下表所示 位运算符的与、或、非与逻辑运算符逻辑与、逻辑或、逻辑非使用时候容易混淆逻辑运算符一般用在条件判断上位运算符一般用在信号赋值上。 注意 两个不同长度的数据进行位运算时系统会自动地将两个数据按右端对齐位数少的操作数会在相应的高位用0补齐。 位运算符的运算逻辑 ~非一变零零变一。 操作数结果值1001XX 与全一为一有零为零。 01X0000101XX0XX | 或全零为零有一为一。 |01X001X1111XX1X ^异或相异为一相同为零。 ^01X001X110XXXXX ^~同或相同为一相异为零。 ^~01X010X101XXXXX 2.5.6 移位运算符 移位运算符包括左移位运算符和右移位运算符。 移位运算符如下表所示 两种移位运算符都用 0 来填补移出的空位。 左移时位宽增加右移时位宽不变。 举例 4b1001 2 6b100100;4b1001 1  4b0100; 假设 a 有 8bit 数据位宽那么 a2表示 a 左移 2bita 还是 8bit 数据位宽a 的最高 2bit 数据被移位丢弃了最低 2bit 数据固定补 0。如果 a 是 3二进制00000011那么 3 左移 2bit32就是 12 二进制00001100。一般使用左移位运算代替乘法右移位运算代替除法但是这种也只能表示 2 的指数次幂的乘除法。 2.5.7 拼接运算符 Verilog 中有一个特殊的运算符是 C 语言中没有的就是位拼接运算符。用这个运算符可以把两个或多个信号的某些位拼接起来进行运算操作。 位拼接运算符如下表所示。 注意 在位拼接表达式中不允许存在没有指明位数的信号这是因为在计算机拼接信号位宽的大小时必须知道其中每个信号的位宽。 举例 c { a ,b [3:0] }; 就相当于 c { a ,b[3] ,b[2] ,b[1] ,b[0] };{ 4 { w } }  就相当于 { w ,w ,w ,w }{ b ,{3 { a ,b } } }  就相当于 { b ,a ,b ,a ,b ,a ,b } 2.5.8 运算符的优先级 运算符的优先级如下表所示 为了提程序的可读性明确表达各运算符之间的优先关系建议使用括号。 2.6 注释 Verilog HDL 中有两种注释的方式一种是以“/*”符号开始“*/”结束在两个符号之间的语句都是注释语句因此可扩展到多行。 示例如下 /* statement1 statement2......statementn */ 以上 n 个语句都是注释语句。 另一种是以//开头的语句它表示以//开始到本行结束都属于注释语句。 示例如下 //statement1 建议使用//作为注释。 2.7 Verilog关键字 Verilog 和 C 语言类似都因编写需要定义了一系列保留字叫做关键字或关键词。这些关键字用来组织语言结构是识别语法的关键。 下表列出了 Verilog 中的关键字 注意 在编写Verilog语言时定义的变量名不要与关键字重合产生冲突。只有小写的关键字才是保留字。例如标识符 always(这是个关键词)与标识符 ALWAYS(非关键词)是不同的。 经常使用的关键字如下表所示 三、程序框架 3.1 模块的结构 C语言中基本的功能模块是函数。Verilog语言也与此类似。 Verilog语言中的基本设计单元是“模块”block。 一个模块是由两部分组成的一部分描述接口另一部分描述逻辑功能即定义输入是如何影响输出的。 在许多方面程序模块和电路图符号是一致的这是因为电路图符号的引脚也就是程序模块的接口。而程序模块描述了电路符号所能实现的逻辑功能。 代码示例 module block(a,b,c,d);input a,b;output c,d;assign c a | b; assign d a b;endmodule 第 1 行为模块定义模块定义以 module 开始endmodule 结束。 代码block(a,s,c,d);是模块端口的定义这里定义了一个名为block的模块它有a,s,c,d四个端口。 input表示输入output表示输出。 代码input a,b;就表示a和b是输入信号代码output c,d;就表示c和d是输出信号。 以上这两句代码部分就叫做I/O的说明。 assign是给线网类型的变量赋值的一种方法。这里端口abcd的数据类型默认的是wire类型的变量对于输出信号c和d来讲需要给这两个信号赋值就可以使用assign的赋值语句来给wire类型的数据变量赋值。 代码assign c a | b;的意思就是给端口c赋值c的值为a和b两个信号的或运算。代码assign d a b;的意思就是给端口c赋值c的值为a和b两个信号的与运算。 以上这俩句代码部分就叫做模块的功能定义描述了block模块的主要功能。 总结 上述Verilog代码设计中 input a,b;output c,d;以上两句代码说明接口的信号流向 assign c a | b; assign d a b; 以上两句代码说明了模块的逻辑功能。 Verilog结构位在module和endmodule声明语句之间。 每个Verilog程序包括4个主要部分 端口定义、I/O说明、内部信号声明、功能定义。 上图表示了模块的接口左侧表示模块的输入接口有端口a和端口b右侧表示模块的输出接口有端口c和端口d。 此图主要表示了模块的端口定义和I/O说明的内容。 上图表示了模块的功能定义部分如果Verilog设计的模块是可综合的那就会综合出和图中类似的电路结构。可以在电路结构中看到输入端是端口a和端口b输出端是端口c和端口d。 这个电路的功能就是在内部生成两个门电路 上方是一个或门是把a和b两个信号进行一个或运算的操作最终结果输出给c下方是一个与门是把a和b两个信号进行一个与运算的操作最终结果输出给d。 从图中也可以看出block模块分成了两个部分一部分描述接口另一部分描述功能。 可综合与不可综合         Verilog作为硬件描述语言可综合就代表着设计的Verilog语句可综合得到一个类似上图的由门级结构组成的电路网表。也就是可综合的模块最终是可以生成一个物理的电路模块的。         而Verilog里还有一种叫不可综合的模块不可综合的模块就不能对应实际的电路不可综合模块的作用是给其他模块做测试文件也就是仿真文件在仿真文件里就可以用一些不可综合的语句仿真工具可以识别不可综合的语句。         这里Verilog设计的block模块是一个可综合的模块可以综合出图中所示的一个电路结构。 3.2 模块的端口定义 模块的端口名声明了模块的输入输出口。 端口定义语法格式 module 模块名口1口2口3…… 注意 端口和端口之间用 , 隔开端口定义后要用 ; 结尾 语句后都需要有一个分号这一点Verilog语言和C语言类似若忘记在句末加分号编译的时候就会报错。 模块的端口表示的是模块的输入和输出口名也就是说端口名是与别的模块联系端口的标识。 3.3 I/O说明 I/O其实就是input和output的缩写I/O说明作用就是说明这个模块中的端口哪些是输出哪些是输入。 input表示输入output表示输出。 I/O说明语法说明 输入口 input [信号位宽-1,0] 端口名; 输出口 output [信号位宽-1,0] 端口名; 输入输出口 Inout [信号位宽-1,0] 端口名; 3.4 内部信号声明 在模块内用到的或者是与端口有关的wire、reg类型变量的声明。 语法格式 reg [信号位宽-1,0] R变量; wire [信号位宽-1,0] W变量; 3.5 功能定义 模块中最重要的部分是逻辑功能定义部分有assign声明语句、实例元件、always块三种方法可在模块中产生逻辑。 3.5.1 assign声明语句 代码示例 assign a b c; assign 语句的使用只需要写一个 assign 后面再加一个方程式即可。 代码示例中的方程式描述了一个有两个输入的与门。 3.5.2 实例元件 采用实例元件的方法和在电路图中插入库元件一样只需写入元件的名字匹配好相连的引脚即可。 代码示例 and #2 u1(q,a,b); 代码示例表示在设计中用到一个跟与门and一样的名为 u1的与门其输入端为a、b输出端为q。输出延迟为2个单位时间。要求每个实例元件的名字必须是唯一的以避免与其他调用与门and的实例混淆。 3.5.3 always块 always语句是描述组合逻辑常用的方法always语句块既可用于描述组合逻辑也可用于描述时序逻辑。 代码示例 always(posedge clk or posedge clr) beginif(clr)q0;else if(en)qd; end always语句块的例子生成了一个带有异步清除端的D触发器。always块可用很多描述手段来表达逻辑代码示例中就用 if else 语句来表达逻辑关系。 总结 assign语句描述组合逻辑。always语句描述组合逻辑和时序逻辑。 注意 assign语句、实例元件、always块这三种逻辑功能是并行的。在always块中逻辑是顺序执行的。 而多个always块之间是并行的。 3.6 模块的调用 模块的调用类似于C语言里函数的调用这样一个关系。在模块调用时信号通过模块端口在模块之间传递。 模块调用时在调用的模块中有些信号要输入到被调用的模块中有的信号需要从被调用的模块中取出来。 调用模块时其端口可以用以下两种方法连接 1在调用时严格按照模块定义的端口顺序来连接不用标明原模块定义时规定的端口名。 模块名(连接端口1信号名,连接端口2信号名,连接端口3信号名,连接端口4信号名,……); 2在调用时用“ . ”符号标明原模块是定义时规定的端口名 模块名(.端口1名(连接1信号名),.端口2名(连接2信号名),.端口3名(连接3信号名),……); 这样用“ . ”符号表示的好处在于可以用端口名与被引用模块的端口相对应而不必严格按端口顺序对应提高了程序的可读性和可移植性。 代码示例 //time_count模块端口定义 module time_count(input clk,input rst_n,output reg flag );parameter MAX_NUM 50000_000;//time_count模块的例化time_count #(.MAX_NUM (TIME_SHOW) ) u_time_count(.clk (sys_clk),.rst_n (sys_rst_n),.flag (add_flag) ); 模块的调用也叫做例化代码示例中例化了一个名为time_count的模块在调用time_count模块的时候首先要把time_count模块名列出来然后需要给例化的模块重新起一个名字示例中名字就叫做u_time_count。当然可以同时例化多个相同的模块例化的多个模块需要起不同的名称。实例中只例化了一个模块叫做u_time_count。 接下来需要连接端口示例中采用一个点加一个端口名的方式点加端口名就表示被例化模块中定义的端口名。示例中clk、rst_n、flag都是time_count模块的端口。后面的括号中就是需要连接的信号名示例中与clk端口连接的信号名为sys_clk与rst_n端口连接的信号名为sys_rst_n与flag端口连接的信号名为add_flag 注意在模块的输入端可以是reg型也可以是wire型但是在模块的输出端必须是wire型。在模块调用的时候用于传递信号的变量的位宽必须保持一致。 示例中模块调用时有 #(.MAX_NUM    (TIME_SHOW)) 这样一个语句这个是一种参数传递的方法点后面 MAX_NUM 是一个参数名点加参数名表示的是被例化模块time_count的参数。括号里面 TIME_SHOW 是例化模块 u_time_count 中传递的新的参数值。 四、Verilog语句 4.1 结构语句 initial 和 always 语句都是结构语句。一个程序模块可以有多个 initial 和 always 过程块。每个 initial 和 always 说明语句在仿真的一开始同时立即开始执行。initial 语句只执行一次而 always 语句则是不断地重复执行直到仿真过程结束。但 always 语句后跟着的过程块是否运行则要看他的触发条件是否满足满足一次运行一次直至仿真过程结束。 在一个模块里使用initial和always语句的次数是不受限制的它们都是同时开始运行的。 4.1.1 initial语句 initial 语句它在模块中只执行一次。它常用于测试文件的编写用来产生仿真测试信号激励信号或者用于对存储器变量赋初值。 initial语句的语法 initialbegin语句1;语句2;语句3;......语句n;end initial语句后有 begin和end框起来很多条语句这里begin和end相当于C语言中的{ } 把很多条语句组合成一个大的语句块。 代码示例 1用initial块对存储器变量赋初值 initial beginareg 0;  //初始化寄存器aregfor(index 0 ; index size ; index index 1)memory[index] 0;  //初始化一个memoryend  在这个例子中initial语句在仿真开始时对各个变量进行初始化注意这个对初始化过程不需要任何仿真时间即在0ns时间内便可以完成存储器的初始化工作 2用initial语句来产生激励波形 initial beginsys_clk 1b0;//给输入信号初始值sys_rst_n 1b0;touch_key 1b0;#200   sys_rst_n 1b1;#30    touch_key 1b1;#40    touch_key 1b0;#40    touch_key 1b1;#40    touch_key 1b0;#40    touch_key 1b1;end 在initial语句里首先给sys_clk、sys_rst_n、touch_key三个信号赋了初值初值为0.在上电之后会立刻执行这三个赋初值的语句。因为这三个语句之间没有延时所以这三个语句是同时执行的。 这里#表示延时#200表示延时200个单位的时间延时之后系统复位信号sys_rst_n赋值为1.接下来又是延时30个时间单位给touch_key赋值为1.然后又延时再给touch_key赋不同的值。 这个代码是用initial语句来产生激励波形作为电路的测试仿真信号。 总结一个模块中可以有多个initial块它们都是并行运行的。initial块常用于测试文件和虚拟模块的编写用来产生仿真测试信号和设置信号记录等仿真环境。 4.1.2 always语句 1always 语句语法 always 语句一直在不断地重复活动。但是只有和一定的时间控制结合在一起才有作用。 always语句在仿真过程中是不断活动着的。但是always语句后跟着的过程块是否执行则要看它的触发条件是否满足如满足则运行过程块一次如不满足则always语句循环活动但不运行过程块。 always语句格式 always 时序控制 语句 ; always语句由于其不断活动的特性只有和一定的时序控制结合在一起才有用。如果一个always语句没有时序控制则这个always语句将会使仿真器产生死锁。 代码如下 always sys_clk ~sys_clk; 这个always语句将会生成一个0延迟的无限循环跳变过程。这时会发生仿真死锁。但如果加上时序控制则这个always语句将会变为一条非常有用的描述语句。 代码如下 always #10 sys_clk ~sys_clk;//产生时钟 这个always语句不断的对时钟信号进行取反。#10表示延时10个时间单位这里延时是对时间的一个控制有了延时之后这条语句才有真正的含义延迟10个时间单位后sys_clk取一次反再延迟10个时间单位后sys_clk再取一次反。一直执行下去就生成了一个周期为20个时间单位的无限延续的信号波形。 常用这种方法来描述时钟信号并作为激励信号来测试做设计的电路。 2always 语句的沿触发和电平触发 always 的时间控制可以是沿触发也可以是电平触发可以是单个信号也可以是多个信号多个信号中间要用关键字 or 连接。 always 语句后紧跟的过程块是否运行要看它的触发条件是否满足。 always 的沿触发 always (posedge clock or negedge reset)begin......;end posedge表示上升沿negedge表示下降沿。由两个沿触发的always只要其中一个沿出现就立即执行一次过程块。 always 的电平触发 always (a or b or c)begin......;end 由多个电平触发的always块只要a、b、c中任何一个发生变化从高到低或从低到高都会执行一次过程块。 沿触发的 always 块常常描述时序逻辑行为。如有限状态机。 如果符合可综合风格要求则可通过综合工具自动的将其转换为表示寄存器组和门级组合逻辑的结构而该结构应具有时序所要求的行为         电平触发的always块常常用来描述组合逻辑的行为。 如果符合可综合风格要求可通过综合工具自动将其转换为表示组合逻辑的门级逻辑结构或带锁存器的组合逻辑结构而该结构应具有所要求的行为 一个模块中可以有多个always块它们都是并行运行的。 如果这些always块是可综合的则表示的是某种结构如果不可综合则是电路结构的行为且多个always块没有先后之分。 根据逻辑功能的不同特点可以将数字电路分成两大类组合逻辑电路 和 时序逻辑电路。 组合逻辑电路中任意时刻的输出仅仅取决于该时刻的输入与电路原来的状态无关。时序逻辑电路中任一时刻的输出不仅取决于当时的输入信号而且还取决于电路原来的状态。或者说还与以前的输入有关因此时序逻辑必须具备记忆功能。 3always块的or事件控制 需要多个信号或者事件中任意一个发生的变化都能够触发语句或语句块的执行时在Verilog语言中可以使用“或”表达式来表示这种情况。由关键词 or 连接的多个事件名或信号名组成的列表称为“敏感列表”。关键词“ro”被用来表示这种关系或者使用“,”来代替。 如果组合逻辑块语句的输入变量很多那么编写敏感列表会很烦琐并且容易出错。Verilog语言提供了特殊符号( * ) ( * )表示对后面语句块中所有输入变量的变化都是敏感的。 ( * )操作符使用示例 always (a or b or c or d or e or f or g or h or p or m)beginout1 a ? (b c) : (d e);out2 f ? (g h) : (p m);end  用符号( * )来代替可以把所有输入变量都自动包括进敏感列表。 always ( * )beginout1 a ? (b c) : (d e);out2 f ? (g h) : (p m);end  4电平敏感时序控制 前面所讨论的事件控制都需要等待信号值的变化或者事件的触发使用符号和后面的敏感列表来表示。 Verilog同时也允许使用另外一种形式表示的电平敏感时序控制即后面的语句和语句块需要等待某个条件为真才能执行。 Verilog语言用关键字wait来表示等待电平敏感的条件为真。 代码示例 alwayswait (count_enable)  #20 count count 1; 代码示例中仿真器连续监视count_enable的值若其值为1则在20个时间单位之后执行这条语句。如果count_enable始终为1那么count将每过20个时间单位加1. 4.2 赋值语句 Verilog HDL 语言中信号有两种赋值方式 1、阻塞赋值blocking如 b a; 赋值语句执行完成后块才结束。b的值在赋值语句执行完成后立刻就改变的在时序逻辑中使用时可能会产生意想不到的结果。这是因为这种赋值方式是马上执行的也就是说执行下一条语句时b已等于a。这种方式直观但会引起麻烦。 2、非阻塞赋值Non_Blocking如 b a; 在语句块中上面语句所赋的变量值不能立即就为下面的语句所用。块结束后才能完成这次赋值操作而所赋的变量值是上一次赋值得到的。在编写可综合的时序逻辑块时这是最常用的赋值方法这种方式的赋值并不是马上执行的也就是说always块内的下一条语句执行后b并不等于a而是保持原来的值always块结束后才进行赋值。 为方便解释阻塞赋值和非阻塞赋值在这里定义两个缩写 RHS赋值等号右边的表达式或变量可以写作 RHS 表达式或 RHS 变量LHS赋值等号左边的表达式或变量可以写作 LHS 表达式或 LHS 变量 4.2.1 阻塞赋值blocking 阻塞赋值可以认为只有一个步骤的操作    即计算 RHS 并更新 LHS 。 所谓阻塞的概念是指在同一个always块中后面的赋值语句是在前一句赋值语句结束后才开始赋值的。 阻塞赋值顾名思义即在一个 always 块中后面的语句会受到前语句的影响具体来说在同一个always 中一条阻塞赋值语句如果没有执行结束那么该语句后面的语句就不能被执行即被“阻塞”。也就是说 always 块内的语句是一种顺序关系这里和 C 语言很类似。符号“”用于阻塞的赋值如:b a;阻塞赋值“”在 begin 和 end 之间的语句是顺序执行属于串行语句。 阻塞赋值的执行可以认为是只有一个步骤的操作即计算 RHS 的值并更新 LHS此时不允许任何其他语句的干扰所谓的阻塞的概念就是值在同一个 always 块中其后面的赋值语句从概念上来讲即使不设定延时是在前面一条赋值语句完成后再执行赋值的。 如果在一个过程块中阻塞赋值的RHS变量正好是另外一个过程块中阻塞赋值的LHS变量这两个过程块又用同一个时钟沿触发这时阻塞赋值操作会出现问题即如果阻塞赋值的顺序安排不好就会出现竞争。若这两个阻塞赋值操作用同一个时钟沿触发则执行的顺序是无法确定的。 为了便于理解阻塞赋值的概念以及阻塞赋值和非阻塞赋值的区别这里以在时序逻辑下使用阻塞赋值为例来实现这样一个功能在复位的时候a1b2c3而在没有复位的时候a 的值清零同时将 a 的值赋值给 bb 的值赋值给 c代码以及信号波形图如下图所示 代码实例 always (posedge clk or negedge rst_n) beginif (rst_n 1b0)begina 1;b 2;c 3;end else begina 0;b a;c b;end  end     波形图 代码中使用的是阻塞赋值语句从波形图中可以看到在复位的时候rst_n0a1b2c3而结束复位之后波形图中的 0 时刻当 clk 的上升沿到来时波形图中的 2 时刻a0b0c0。这是因为阻塞赋值是在当前语句执行完成之后才会执行后面的赋值语句因此首先执行的是 a0赋值完成后将 a 的值赋值给 b由于此时 a 的值已经为 0所以 ba0最后执行的是将 b 的值赋值给 c而 b的值已经赋值为 0所以 c 的值同样等于 0。 4.2.2 非阻塞赋值Non-Blocking 符号“”用于非阻塞赋值如:b a;非阻塞赋值是由时钟节拍决定在时钟上升到来时执行赋值语句右边然后将 begin-end 之间的所有赋值语句同时赋值到赋值语句的左边注意是 begin—end之间的所有语句一起执行且一个时钟只执行一次属于并行执行语句。这个是和 C 语言最大的一个差异点。 非阻塞赋值的操作过程可以看作两个步骤 赋值开始的时候计算 RHS 赋值结束的时候更新 LHS 。 所谓非阻塞的概念是指在计算非阻塞赋值的RHS以及更新LHS期间允许其他的非阻塞赋值语句同时计算RHS和更新LHS。 非阻塞赋值只能用于对寄存器类型的变量进行赋值因此只能用在initial块和always块等过程块中。 下面使用非阻塞赋值同样来实现这样一个功能在复位的时候a1b2c3而在没有复位的时候a 的值清零同时将 a 的值赋值给 bb 的值赋值给 c代码以及信号波形图如下图所示 代码示例 always (posedge clk or negedge rst_n) beginif (rst_n 1b0)begina 1;b 2;c 3;end else begina 0;b a;c b;end  end  波形图 代码中使用的是非阻塞赋值语句从波形图中可以看到在复位的时候rst_n0a1b2c3而结束复位之后波形图中的 0 时刻当 clk 的上升沿到来时波形图中的 2 时刻a0b1c2。这是因为非阻塞赋值在计算 RHS 和更新 LHS 期间允许其它的非阻塞赋值语句同时计算 RHS 和更新 LHS。在波形图中的 2 时刻RHS 的表达是 0、a、b分别等于 0、1、2这三条语句是同时更新LHS所以 a、b、c 的值分别等于 0、1、2。 在描述组合逻辑的 always 块中用阻塞赋值 综合成组合逻辑的电路结构;这种电路结构只与输入电平的变化有关系。在描述时序逻辑的 always 块中用非阻塞赋值 综合成时序逻辑的电路结构;这种电路结构往往与触发沿有关系只有在触发沿时才可能发生赋值的变化。 注意   在同一个always块中不要既用非阻塞赋值又用阻塞赋值不允许在多个always块中对同一个变量进行赋值 4.2.3 赋值语句的使用 什么时候使用阻塞赋值什么时候使用非阻塞赋值的情况总结如下。 1赋值语句的选择 在描述组合逻辑电路的时候使用阻塞赋值比如 assign 赋值语句和不带时钟的 always 赋值语句这种电路结构只与输入电平的变化有关系代码如下 代码示例1assign赋值语句 assign data (data_en 1b1) ? 8d255 : 8d0; 代码示例2不带时钟的always语句 always (*) begin if (en) begin a a0; b b0; end else begina a1; b b1; end  end 在描述时序逻辑的时候使用非阻塞赋值综合成时序逻辑的电路结构比如带时钟的 always 语句 这种电路结构往往与触发沿有关系只有在触发沿时才可能发生赋值的变化代码如下 代码示例 3 always (posedge sys_clk or negedge sys_rst_n) begin  if (!sys_rst_n) begin a 1b0; b 1b0; end else begina c; b d; end  end 2assign 和 always 区别 assign 语句使用时不能带时钟。 always 语句可以带时钟也可以不带时钟。在 always 不带时钟时逻辑功能和 assign 完全一致都是只产生组合逻辑。比较简单的组合逻辑推荐使用 assign 语句比较复杂的组合逻辑推荐使用 always 语句。 3带时钟和不带时钟的 always  always 语句可以带时钟也可以不带时钟。在 always 不带时钟时逻辑功能和 assign 完全一致虽然产生的信号定义还是 reg 类型但是该语句产生的还是组合逻辑。 代码示例 reg [3:0] led always (*) begincase (led_ctrl_cnt) 2d0 : led 4b0001;2d1 : led 4b0010;2d2 : led 4b0100;2d3 : led 4b1000;default : led 4b0000;endcase end 在 always 带时钟信号时这个逻辑语句才能产生真正的寄存器如下示例 counter 就是真正的寄存器。 用于产生 0.5 秒使能信号的计数器 代码示例 always (posedge sys_clk or negedge sys_rst_n) beginif (sys_rst_n 1b0)counter 1b0;else if (counter_en)counter 1b0;elsecounter counter 1b1; end 阻塞与非阻塞赋值使用的8个要点 时序电路建模时用非阻塞赋值。锁存器电路建模时用非阻塞赋值。用always块建立组合逻辑模型时用阻塞赋值。在同一个always块中建立时序和组合逻辑电路时用非阻塞赋值。在同一个always块中不要既用非阻塞赋值又用阻塞赋值。不要在一个以上的always块中为同一个变量赋值。用$strobe系统任务来显示用非阻塞赋值的变量值。在赋值时不要使用#0延迟。 4.3 条件语句 条件语句必须在过程块中使用。过程块语句是指由initial和always语句引导的块语句。 4.3.1 if_elas语句 Verilog语言提供了3种形式的if语句 (1) if(a b)out data_1; (2) if(a b)out data_1; elseout data_2; (3) if(表达式1)语句1; else if(表达式2)语句2; else if(表达式3)语句3 else 语句4; if语句使用注意事项 1、允许一定形式的简写如 if(a) 等同于 if(a 1) if(!a)等同于 if(a ! 1) 2、if语句对表达式的值进行判断若为0,x,z则按假处理若为1按真处理。 3、if和else后面的操作语句可以用begin和end包含多个语句。 4、允许if语句的嵌套。 代码示例 if(a) begin语句1;语句2; end else begin语句3;if(!b)语句4;else语句5; end 4.3.2 case语句多分支选择语句 case语句和C语言中的switch_case语句相比有不同之处写代码时需要注意其中的区别。 case语句的三种形式 case(控制表达式) case分支项 endcasecasez(控制表达式) case分支项 endcasecasex(控制表达式) case分支项 endcase case语句语法格式 case(控制表达式)分支表达式1: 语句1;分支表达式2: 语句2;分支表达式3: 语句3;……分支表达式n: 语句n;default: 语句; endcase 运行时会判断控制表达式的变量是不是等于下面的分支表达式当控制表达式等于其中一个分支表达式就执行这个分支表达式后的语句。如果所有的分支表达式的值都没有与控制表达式的值相匹配就执行default后面的语句。 一个case语句里只能有一个default项。 case语句使用注意事项 1、分支表达式的值互不相同 2、所有表达式的位宽必须相等不能用 ’bx 来代替 n’bx 3、casez比较时不考虑表达式中的高阻值z 4、casex比较时不考虑高阻值z 和 不定值x reg [7:0] sel; //1100_0011 casez(sel)8’b1100_zzzz: 语句1;8’b1100_xxzz: 语句2; endcase 示例中定义了一个reg型的8位变量给变量注释中的值1100_0011。 用casez来做条件语句的话不用比较高阻值 语句 8’b1100_zzzz: 语句1; 就可以不考虑分支表达式后四位的高阻值z比较时就不用比较后四位z只要前四位相等就可以了。语句 8’b1100_xxzz: 语句2; 只能不考虑分支表达式后两位的高阻值z还有两位的不定值x就必须要考虑了因为xx和00是不相等的所以控制表达式和第二个表达式相比是不相等的语句2也不会执行。 用casex来做条件语句的话既不用比较高阻值也不用比较不定值。 语句 8’b1100_xxzz: 语句2; 就可以不考虑分支表达式后四位的高阻值z和不定值x比较时就不用比较后四位z只要前四位相等就可以了。 使用条件语句时注意         如果用到if语句最好写上else项         如果用case语句最好写上default项。 五、状态机 Verilog 是硬件描述语言硬件电路是并行执行的当需要按照流程或者步骤来完成某个功能时代码中通常会使用很多个 if 嵌套语句来实现这样就增加了代码的复杂度以及降低了代码的可读性这个时候就可以使用状态机来编写代码。状态机相当于一个控制器它将一项功能的完成分解为若干步每一步对应于二进制的一个状态通过预先设计的顺序在各状态之间进行转换状态转换的过程就是实现逻辑功能的过程。 5.1 状态机概念 状态机全称是有限状态机Finite State Machine缩写为 FSM是一种在有限个状态之间按一定规律转换的时序电路可以认为是组合逻辑和时序逻辑的一种组合。 状态机通过控制各个状态的跳转来控制流程使得整个代码看上去更加清晰易懂在控制复杂流程的时候状态机优势明显因此基本上都会用到状态机如 SDRAM 控制器等。 5.2 状态机模型 状态寄存器由一组触发器组成用来记忆状态机当前所处的状态状态的改变只发生在时钟的跳变沿。 如果状态寄存器由n个触发器组成这个状态机最多可以记忆2^n个状态。 所有的触发器的时钟端都连接在一个共同的时钟信号上所以状态机的改变只可能发生在时钟的跳变沿上。 可能发生的状态的改变由正跳变还是由负跳变触发取决于触发的类型。 状态是否改变、如何改变取决于产生下一个状态的组合逻辑F的输出F是当前状态和输入信号的函数。 状态机的输出是由输出组合逻辑G提供的G也是当前状态和输入信号的函数。  F和G两部分都是纯组合逻辑它们的逻辑函数表达式如下 下一个状态 F(当前状态,输入信号);输出信号 G(当前状态,输入信号); 根据状态机的输出是否与输入条件相关可将状态机分为两大类即摩尔(Moore)型状态机和米勒(Mealy)型状态机。 Mealy 状态机组合逻辑的输出不仅取决于当前状态还取决于输入状态。Moore 状态机组合逻辑的输出只取决于当前状态。 5.2.1 Mealy 状态机 米勒状态机的模型如下图所示 模型中 第一个方框是指产生下一状态的组合逻辑 FF 是当前状态和输入信号的函数状态是否改变、如何改变取决于组合逻辑 F 的输出 第二框图是指状态寄存器其由一组触发器组成用来记忆状态机当前所处的状态状态的改变只发生在时钟的跳边沿 第三个框图是指产生输出的组合逻辑 G状态机的输出是由输出组合逻辑 G 提供的G 也是当前状态和输入信号的函数。 5.2.2 Moore 状态机 摩尔状态机的模型如下图所示对比米勒状态机的模型可以发现其区别在于米勒状态机的输出由当前状态和输入条件决定的而摩尔状态机的输出只取决于当前状态。 5.3 状态机设计 状态机的设计可参考四段论的流程来写出一个完整的状态机。 四段论 状态空间定义状态跳转下个状态判断各个状态下的动作 5.3.1 状态空间定义 代码示例 //parameter define  parameter S0 7b0000001; //独热码定义方式 parameter S1 7b0000010; parameter S2 7b0000100; parameter S3 7b0001000; parameter S4 7b0010000; parameter S5 7b0100000; parameter S6 7b1000000; //reg define  reg [6:0] curr_st ; //当前状态 reg [6:0] next_st ; //下一个状态 用parameter关键词来定义一个参数一个参数就代表一个特定的状态空间参数名最好使用有实际意义的名字这样可以提高代码的可读性。在参数定义的右边是二进制数二进制数就相当于对不同状态的一个编码。 独热码每个状态只有一个寄存器位置位译码逻辑简单。         对于用FPGA实现的有限状态机建议采用独热码因为虽然独热码多用了几个触发器但所用组合电路可省一些因而使电路的速度和可靠性有显著提高而总单元数并无显著增加。         采用独热码后有了多余的状态就有一些不可到达的状态。为此在case语句的最后需要增加default分支项一般综合器都可以通过综合指令的控制来合理地处理默认项。 reg define这里定义的是两个状态寄存器状态寄存器里用来存储状态空间的编码因此状态寄存器的位宽需要和状态空间定义的位宽保持一致。 总结状态空间定义需要定义状态空间参数和状态寄存器。 5.3.2 状态跳转 代码示例 //状态机的第一段采用同步时序描述状态转移 always (posedge sys_clk or negedge sys_rst_n) begin//敏感列表时钟信号以及复位信号边沿的组合if (!sys_rst_n)curr_st S0;//使用非阻塞赋值elsecurr_st next_st;//使用非阻塞赋值 end 时序逻辑里使用非阻塞赋值组合逻辑里使用阻塞赋值。 5.3.3 下个状态判断 代码示例 //状态机的第二段采用组合逻辑判断状态转移条件 always (*) begin//敏感信号表所有的右边表达式中的变量以及if、 case条件中的变量case (curr_st)S0: next_st S1;S1: next_st S2;S2: next_st S3;S3: next_st S4;S4: next_st S5;S5: next_st S6;S6: next_st S0;default: next_st S0;endcase end 5.3.4 各个状态下的动作 代码示例 //状态机的第三段描述状态输出这里采用时序电路输出 always (posedge sys_clk or negedge sys_rst_n) beginif (!sys_rst_n)clk_divide_7 1b0;else if ((curr_st S0) | (curr_st S1) | (curr_st S2) | (curr_st S3))clk_divide_7 1b0;else if ((curr_st S4) | (curr_st S5) | (curr_st S6))clk_divide_7 1b1; else; end5.3.5 三段式状态机 用四段论的方法写出的状态机叫做三段式状态机。 状态跳转图 总代码示例 // 7 分频module divider7_fsm (input sys_clk ,//系统时钟input sys_rst_n ,//复位output reg clk_divide_7 //输出时钟);//状态空间定义 //parameter define parameter S0 7b0000001; //独热码定义方式 parameter S1 7b0000010; parameter S2 7b0000100; parameter S3 7b0001000; parameter S4 7b0010000; parameter S5 7b0100000; parameter S6 7b1000000; //reg define reg [6:0] curr_st ; //当前状态 reg [6:0] next_st ; //下一个状态//状态机的第一段采用同步时序描述状态转移 always (posedge sys_clk or negedge sys_rst_n) begin//敏感列表时钟信号以及复位信号边沿的组合if (!sys_rst_n)curr_st S0;//使用非阻塞赋值elsecurr_st next_st;//使用非阻塞赋值 end//状态机的第二段采用组合逻辑判断状态转移条件 always (*) begin//敏感信号表所有的右边表达式中的变量以及if、 case条件中的变量case (curr_st)S0: next_st S1;S1: next_st S2;S2: next_st S3;S3: next_st S4;S4: next_st S5;S5: next_st S6;S6: next_st S0;default: next_st S0;endcase end//状态机的第三段描述状态输出这里采用时序电路输出 always (posedge sys_clk or negedge sys_rst_n) beginif (!sys_rst_n)clk_divide_7 1b0;else if ((curr_st S0) | (curr_st S1) | (curr_st S2) | (curr_st S3))clk_divide_7 1b0;else if ((curr_st S4) | (curr_st S5) | (curr_st S6))clk_divide_7 1b1; else; endendmodule 三段式可以在组合逻辑后再增加一级寄存器来实现时序逻辑输出 1、可以有效地滤去组合逻辑输出的毛刺 2、可以有效地进行时序计算与约束 3、另外对于总线形式的输出信号来说容易使总线数据对齐从而减小总线数据间的偏移减小接收端数据采样出错的频率。 总线形式的输出信号指输出信号的位宽大于1.如上述例子中输出信号clk_divide_7只有1位的位宽就不算总线形式的输出信号若位宽为8位就是总线形式的输出信号。 其他方法设计的状态机 module fsm(Clock,Reset,state,A,K1,K2);input Clock ; input Reset ; input A ;output reg K1 ; output reg K2 ; output reg [1:0] state ;parameter Idle 2b00; parameter Start 2b01; parameter Stop 2b10; parameter Clear 2b11;/* 使用独热码定义状态空间 parameter Idle 4b1000; parameter Start 4b0100; parameter Stop 4b0010; parameter Clear 4b0001;reg [3:0] state ;//使用独热码定义状态空间时需注意状态寄存器的位宽与独热码定义状态空间的位宽保持一致上方代码中reg [1:0] state 需要定义为reg [3:0] state*/always (posedge Clock)if(!Reset) beginstateIdle;K20;K10;endelse begincase(state)Idle:beginif(A)beginstateStart;K10;end else beginstateIdle;K20;K10;end endStart:beginif(!A)stateStop;else stateStart;endStop:beginif(A)beginstateClear;K21;end else beginstateStop;K20;K10;endendClear:beginif(A)beginstateIdle;K20;K10;end else beginstateClear;K20;K10;endenddefault:state2bxx;endcaseend endmodule总结 以上就是今天要讲的内容本文仅仅简单介绍了Verilog语言的基础语法。
http://www.dnsts.com.cn/news/42312.html

相关文章:

  • 百度公司做网站优化多少钱地方门户网站模版
  • 黑河城乡建设局网站北京网站编程培训
  • 网站主页模板 优帮云国内做网站网站风险大吗
  • 网站后台不更新网站建设图片轮播
  • 物流网站公司江苏seo推广方案
  • 南京 高端网站建设html网页设计作业成品代码
  • 西安建设局官方网站网站制作详细报价
  • 南通营销型网站建设营销软件商城
  • 亚马逊店铺出售网站dedecms网站地图修改
  • 五屏网站建设如何赣州市城乡建设局网站
  • 论坛建站wordpress加跳转
  • 贵阳住房和城乡建设局网站东莞网站推广衣裙
  • 专做外贸的网站有哪些wordpress 计算器插件
  • 网站没有备案找客源用哪个软件好
  • 建设企业网站的重要性重庆网站建设培训学校
  • 个人网站-个人主页作业免费注册163免费邮箱个人
  • 为您打造高端品牌网站wordpress自动优化插件
  • 成都德阳网站建设去除wordpress 广告
  • 网站建设的功能模块wordpress后台中文设置
  • 有培训做网站 小程序的学校网站建设需求分析报告功能
  • 公司网站建设备选方案评价标准上海专业网站建设报
  • 个人网页设计思路智能网站排名优化
  • 一朋友做网站网站被抓了生鲜网站建设背景
  • 月子会所网站建设方案现在网站开发用什么
  • 在线企业建站服务网站设计人员就业要求
  • 展示网站方案网站下方链接图标怎么做
  • 网站搜索引擎优化怎么做网站建设安全技术方面
  • 福田网站建设深圳信科一份完整的市场调查方案
  • 深圳网站设计按天收费网站建设公司高端
  • 怎么利用自媒体做网站优化高端网站制作的公司