Verilog基础学习二
Verilog基础学习二
文章目录
- Verilog基础学习二
- 一、always 块
- 1.阻塞性赋值和非阻塞性赋值
- 二、条件语句
- 1.if 语句 基本用法
- 2.避免引入锁存器
- 3.case 语句
- 4.casez 语句
- 三、归约运算符(Reduction Operators)
- 四、for循环
- Problem : Combinational for-loop: 255-bit population count
- Problem : Generate for-loop: 100-bit binary adder 2
- 五、Generate 块
- Problem : Generate for-loop: 100-digit BCD adder
- 总结
一、always 块
我们知道数字电路是由导线连接的逻辑门组成,因此任何电路都可以表示为module
和assign
语句的某种组合。但是,有时候这不是描述电路最简便的方法。过程块(比如always块)提供了一种用于替代assign语句描述电路的方法。
有两种always块是可以综合出电路硬件的:
综合逻辑:always @(*)
时序逻辑:always @(posedge clk)
1.阻塞性赋值和非阻塞性赋值
在Verilog中有以下三种赋值方法:
连续赋值(assign x=y;):不能在过程块内使用;
过程阻塞性赋值(x=y;):只能在过程块中使用;
过程费阻塞性复制(x<=y):只能在过程块内使用。
在组合always块中,使用阻塞性赋值。在时序always块中,使用非阻塞性赋值。具体为什么对设计硬件用处不大,还需要理解Verilog模拟器如何跟踪事件(译者注:的确是这样,记住组合用阻塞性,时序用非阻塞性就可以了)。不遵循此规则会导致极难发现非确定性错误,并且在仿真和综合出来的硬件之间存在差异。
示例代码如下:
module top_module(input clk,input a,input b,output wire out_assign,output reg out_always_comb,output reg out_always_ff );assign out_assign = a ^ b;always@(*) out_always_comb = a ^ b;always@(posedge clk) out_always_ff <= a ^ b;endmodule
二、条件语句
1.if 语句 基本用法
基本if语句:
always @(*) beginif (condition) beginout = x;endelse beginout = y;end
end
条件(三元)运算符:
assign out = (condition) ? x : y;condition ? if_true : if_false
2.避免引入锁存器
组合电路输出必须在所有输入的情况下都有值。这意味着必须需要else子句或着输出默认值。
3.case 语句
Verilog中的case
语句几乎等同于if-else if-else
序列,它将一个表达式与其他表达式列表进行比较。它的语法和功能与C语言中的switch
语句稍有不同:
always @(*) begin // This is a combinational circuitcase (in)1'b1: begin out = 1'b1; // begin-end if >1 statementend1'b0: out = 1'b0;default: out = 1'bx;endcase
end
1、case语句以case开头,每个case项以冒号结束。而switch语句没有。
2、每个case项只执行一个语句。 *这样就不需要C语言中break来跳出switch。*但这也意味着如果您需要多个语句,则必须使用begin … end。
3、case项允许重复和部分重叠,执行程序匹配到的第一个,而C语言不允许重复的case项目。
4.casez 语句
如果case语句中的case项与某些输入无关,就可以减少列出的case项。这就是casez
的用途:它在比较中将具有值z的位视为无关项(即输入01都会匹配到)。
还有一个类似的casex,将输入的x和z都视为无关。不认为casex比casez有什么特别的好处。
(作者个人感觉没必要用casex,z和x状态的问题涉及电路的基本知识)
符号"?" 是z的同义词,所以2’bz0与2’b?0相同。
always @(*) begincasez (in[3:0])4'bzzz1: out = 0; // in[3:1]输入什么都可以4'bzz1z: out = 1;4'bz1zz: out = 2;4'b1zzz: out = 3;default: out = 0;endcase
end
同时为避免生成了不必要的锁存器,必须在所有条件下为所有的输出赋值。这可能会多打很多字,使你的代码变得冗长。 一个简单的方法是在case语句之前为输出分配一个“默认值”
除非case语句覆盖赋值,否则这种代码样式可确保在所有可能的情况下输出0。 这也意味着case的default项变得不必要。
提醒:always@(*)综合器会生成一个组合电路,其行为与代码描述的相同。硬件不会按顺序“执行”代码。
三、归约运算符(Reduction Operators)
归约运算符(Reduction Operators)可以对向量的每一位位进行AND,OR和XOR,产生一位输出:
&a [3:0] // AND:a[3]&a[2]&a[1]&a [0]相当于(a[3:0]== 4'hf)
|b [3:0] // OR: b[3]|b[2]|b[1]|b [0]相当于(b[3:0]!= 4'h0)
^c [2:0] // XOR:c[2]^c[1]^c[0]
四、for循环
for循环(组合always块或者generate块)在处理重复动作的时候很有用。
模块实例化时必须使用generate块
always@(*)beginfor (int i=0;i<=99;i=i+1)beginout[i]=in[99-i];endend
Problem : Combinational for-loop: 255-bit population count
设计电路来计算输入矢量中 ’1‘ 的个数,题目要求建立一个255bit输入的矢量来判断输入中 ’1‘ 的个数。
module top_module( input [254:0] in,output [7:0] out );integer i;always @ (*)beginout = 8'b0000_0000; //**为了后面的计数累加,此处先初始化为0.**for (i=0; i<255; i++)beginif(in[i] == 1'b1)out = out + 1'b1;elseout = out + 1'b0;endend
endmodule
- 循环里面的变量一定要初始化
Problem : Generate for-loop: 100-bit binary adder 2
通过实例化100个全加器来实现一个100bit的二进制加法器。该加法器有两个100bit的输入和cin,输出为sum与cout。为了鼓励大家使用实例化来完成电路设计,我们同时需要输出每个全加器的cout。
故cout[99]标志着全加器的最终进位。
- 有好多加法器需要实例化,可采用实例化数组或generate语句来实现。
考虑到for循环中只有cin与cout是变化的,每次计算中cout是本次计算的输出,也是下次计算的输入(cout就是下次计算的cin)。故我们先计算出cout[0]
和 sum[0]
。
assign cout[0] = a[0] & b[0] | a[0] & cin | b[0] & cin;
assign sum[0] = a[0] ^ b[0] ^ cin;
//一定要记得赋初值,然后再开始循环
代码如下
module top_module( input [99:0] a, b,input cin,output [99:0] cout,output [99:0] sum );integer i;always @(*) begin cout[0] = a[0]&b[0] | a[0]&cin | b[0]&cin;sum[0] = a[0] ^ b[0] ^ cin;for(i=1;i<100;i++) beginsum[i] = a[i] ^ b[i] ^ cout[i-1];cout[i] = a[i]&b[i] | a[i]&cout[i-1] | b[i]&cout[i-1];endend
endmodule
五、Generate 块
什么是generate
语句?
生成语句可以动态的生成verilog代码,当对矢量中的多个位进行重复操作时,或者当进行多个模块的实例引用的重复操作时,或者根据参数的定义来确定程序中是否应该包含某段Verilog代码的时候,使用生成语句能大大简化程序的编写过程。
使用关键字generate
与 endgenerate
来指定范围。generate语句有generate-for、generate-if、generate-case三种语句,本题中我们使用generate-for语句。
generate-for语句:
(1) 必须有genvar
关键字定义for
语句的变量。
(2)for语句的内容必须加begin和end**(即使就一句)**。
(3)for语句必须有个名字。
//创建一个2进制转换器Module gray2bin
#(parameter SIZE = 8)
(input [SIZE-1:0] gray,output [SIZE-1:0] bin
)Genvar gi; //在generate语句中采用genvar声明generate for (gi=0; gi<SIZE; gi=gi+1) begin : genbit //for语句必须有名字assign bin[i] = ^gray[SIZE-1:gi];endendgenerate
endmodule
Problem : Generate for-loop: 100-digit BCD adder
本题已经提供了一个名为
bcd_fadd
的BCD一位全加器,他会添加两个BCD码和一个cin,并产生一个cout和sum。
每个bcd_fadd都是含有两个四位的输入(a,b),一个四位的输出(sum)
module bcd_fadd {input [3:0] a,input [3:0] b,input cin,output cout,output [3:0] sum );
我们需要实例化100个bcd_fadd来实现100位的BCD进位加法器。该加法器应包含两个100bit的BCD码(包含在400bit的矢量中)和一个cin,
输出产生sum 和 cout。
module top_module( input [399:0] a, b,input cin,output cout,output [399:0] sum );wire [399:0] cout_temp;genvar i;bcd_fadd inst1_bcd_fadd (.a(a[3:0]),.b(b[3:0]),.cin(cin),.cout(cout_temp[0]),.sum(sum[3:0]));//与上题同理,还是先计算cout[0],我声明一个wire型的cout_temp来存放每次计算后cout的值。//类似矢量运算中赋初值,实例的初始化也是必不可少的generatefor(i=4; i<400; i=i+4)begin: bcdbcd_fadd inst_bcd_fadd(.a(a[i+3:i]), .b(b[i+3:i]), .cin(cout_temp[i-4]), //上次计算输出的cout.cout(cout_temp[i]), //本次计算输出的cout,在下次计算中变为cin.sum(sum[i+3:i]));endendgenerate assign cout = cout_temp[396]; endmodule
总结
本次学习了always 块的用法,包含里面的if、case、casez、for语句的具体用法;学习了归约运算符(Reduction Operators)的操作,简化打字量;最后学习了Generate 块的用法,今后在实践中具体操作会有更深刻的理解。
Verilog基础学习二相关推荐
- mysql用创建的用户登陆并修改表格_MySQL 基础学习二:创建一个用户表,并增删改查...
MySQL 基础学习二:创建一个用户表,并 增删改查 提示:MySQL 命令建议都用大写,因为小写运行时,还是翻译成大写的. 第一步,创建一个用户表 1,打开控制台,进入数据库 C:\Users\Ad ...
- 大数据基础学习二:在VMware虚拟机上安装Ubuntu完整步骤及需要注意的问题(以VMware Workstation 15.1.0 Pro和Ubuntu18.04.3优麒麟版为例)
大数据基础学习二:在VMware虚拟机上安装Ubuntu完整步骤及需要注意的问题 (以VMware Workstation 15.1.0 Pro for Windows和Ubuntu18.04.3优麒 ...
- python pyramid基础学习二
python pyramid基础学习二 1.前言 前面我们使用了基础命令创建pyramid项目,并运行了Hello word,万事开头难,我们知道了开发pyramid项目需要一个env文件夹,里面包 ...
- Verilog基础学习三
文章目录 一.基础门电路(Basic Gate) 1.gate 2.真值表 3.关于电路设计思路 4.门电路与向量 二.多路选择器(multiplexer) 1. 2-to-1 multiplexer ...
- 【Java进阶营】JAVA多线程基础学习二:synchronized
本篇主要介绍Java多线程中的同步,也就是如何在Java语言中写出线程安全的程序,如何在Java语言中解决非线程安全的相关问题,没错就是使用synchronized. 一.如何解决线程安全问题? 一般 ...
- Java基础学习(二十七)之IO流
1. File 1.1 File类概述和构造方法(myFile中的com.itheima_01中的FileDemo01) File:它是文件和目录路径名的抽象表示 文件和目录是可以通过File封装成对 ...
- 19-10-29-C++基础学习二
上一篇对基础部分的编译流程,输入输出,控制结构,进行了介绍,这篇主要是对里面的变量以及基本类型,标准库,类的简介 进行相关的总结: 变量: · 什么是变量? 变量提供了程序可以操作的有名字的存 ...
- 音频基础学习二——声音的波形
文章目录 前言 一.声音的基础波形 1.正弦波 2.三角波 3.锯齿波 4.方波 二.正弦波 1.什么是正弦 2.什么是正弦波和正弦曲线 三.正弦波与声音 1.角频率 2.基波和谐波 基波: 谐波: ...
- Hibernate基础学习(二)—Hibernate相关API介绍
一.Hibernate的核心接口 所有的Hibernate应用中都会访问Hibernate的5个核心接口. (1)Configuration接口: 配置Hibernate,启动Hibernate,创建 ...
最新文章
- 良心直播!看完你的Python入门基础就妥了!
- 自定义异常类: 运行期间跟编译期间的区别
- rabbitmq的整体架构一览
- Windows Server 2016-活动目录NTP时间同步
- 隔空操作之简单的模拟三种行为
- 读书笔记:黑客与画家
- 用扫地机器人楼下吵吗_扫地机器人到底好不好用?说说我两年的使用体验!
- 基于注解风格的Spring-MVC的拦截器
- 2.1)深度学习笔记:深度学习的实践层面
- C++ 的异常处理解答
- 用Binary Viewer查看H264文件中的每一帧
- 范德波振子的李雅普诺夫指数
- 常见系统中文字体的英文名
- 《了不起的我》读后感
- HTML5中weight属性的作用,css font-weight属性怎么用
- 企鹅的java游戏_那只小企鹅终究要和我们告别了,腾讯又两款游戏宣布停运
- TOP公链主网技术:多层扩容和多层分片
- turtle画了一个皮卡丘
- vim编辑器的简单使用(参考别人文章的学习笔记)
- 花了4000多的钱,领导让我去开8000多元的发票,我该怎么办??
热门文章
- 坦克世界服务器系统不更新失败怎么办,win7系统下坦克世界自动更新失败如何解决...
- U盘插入电脑提示需要格式化
- JAVA之对象的克隆
- Hyperledger Fabric 通道配置文件和容器环境变量详解
- linux原生系统_Linux的概述
- 对于Windows,GB18030是不可用的
- 硬盘装win10系统教程|不需要任何工具
- esplise自定义快捷代码补全_Ecplise更便捷的自动补全功能设置及改良
- 雇员与雇主的关系之满意度曲线
- 【每日新闻】看清小米生态链,再说它值多少钱 | 工信部:二月份查处“黑广播”违法犯罪案件206起