input 赋值_FPGA基础设计:Verilog行为级建模(过程赋值)

来源:CSDN文章

使用逻辑门和连续赋值对电路建模,是相对详细的描述硬件的方法。使用过程块可以从更高层次的角度描述一个系统,称作行为级建模(behavirol modeling)。

1. 过程赋值

阻塞赋值和非阻塞赋值的区别都很熟悉了。这里记录两个特性。

1.1 特性1

绝大多数情况下,非阻塞赋值都是一个时间点处最后执行的赋值语句。看下面的示例代码:

module test
(
input clk,
output reg a, b
);
always @ (posedge clk) begin
a = 0;
b = 1;
a <= b;
b <= a;
end
endmodule

非阻塞赋值可以认为包括两步:
(1)求值和调度(evaluate and schedule),先得到非阻塞赋值等式右侧的值,并将这次赋值安排在当前时间点的结束时刻。
(2)当前时间点结束时,更新左侧的值。因此这段代码的结果是 a = 1,b = 0。

1.2 特性2

如果过程块内,有针对同一个变量的多个非阻塞赋值,那么这些非阻塞赋值会按顺序执行(但我认为不能简单地说过程块内是“顺序执行的”,容易造成误导,应该说具有一定的“顺序性”特点)。

看下面的示例代码:

module test
(
input clk,
output reg a, b
);
always @ (posedge clk) begin
a <= 0;
a <= 1;
end
endmodule

always块内有两条对于变量a的赋值语句,但由于顺序性特点,a的赋值结果应该是1。利用这个特性,会经常见到下面这种代码写法:

always @ (posedge clk) begin
a <= 0;
if (flag == 1)
a <= 1;
end

只有当flag=1时,a才为1。

2. 过程连续赋值

这种赋值方式允许在过程块中连续地驱动网络或变量。但这种建模方法不可综合,因此这里只简单记录一下两种过程连续赋值方式的作用。

assign和deassign:assign连续赋值会优先占用一个变量,让其它对这个变量进行赋值的过程块无效。deassign连续赋值会解除占用关系。

看下面的示例代码:

`timescale 1ns / 1ps
module sim();
reg clk = 0, rst_n = 0, d = 1;
reg q;
//test i1
//(
// .clk (clk),
// .rst_n(rst),
// .q(q),
// .d(d)
//);
always @ (rst_n)
if (!rst_n) assign q = 0;
else deassign q;
always @ (posedge clk)
q <= d;
always #5 clk <= ~clk;
initial begin
#50 rst_n = 1;
end
endmodule

当rst_n=0时,asssign连续赋值占用了q,q的值恒为0;当rst_n=1时,deassign解除了占用,q的值由其它过程赋值决定,在clk上升沿随d变化而变化。

force和release:功能和assign、deassign相同,只是赋值对象可以是变量也可以是网络。force过程赋值的对象为网络时,会使其它所有对该网络的驱动无效。

3. case语句

case语句的default分支不是必须的,只要设计者清楚设计意图即可。记录一下case两个比较少见但有时候特别有用的用法。

3.1 do-not-cares

包括两种:
  •  casez表示不关心高阻状态(z);
  •  casex表示不关心高祖状态(z)和未知状态(x)。

在不关心的bit位上使用“?”表示要更加方便。casex和casez完全是可以综合的,例如下面的代码可以实现优先编码器:

module test
(
input clk,
input [3:0] d,
output reg [15:0] q
);
always @ (posedge clk)
casez (d)
4'b1??? : q <= 1;
4'b01?? : q <= 2;
4'b001? : q <= 3;
4'b0001 : q <= 4;
endcase
endmodule

如果想使用casex和casez,还是要从“设计上”能否综合的角度考虑一下,并且做好综合后的仿真。

比如上面的代码,使用case语句+16条分支可以实现同样的效果,这个设计完全是可以综合实现的。使用casez更多还是起到简化代码设计的作用。

3.2 常数case

case语句中可以使用常数表达式,这个常数会和每个分支中的表达式进行比较。如下面的代码:

module test
(
input clk,
input [3:0] d,
output reg [15:0] q
);
always @ (posedge clk)
casez (1)
d[0] : q <= 1;
d[1] : q <= 2;
d[2] : q <= 3;
d[3] : q <= 4;
endcase
endmodule

可以实现,根据d中的哪个bit为1,执行相应的代码。如果d中多个bit同时为1,此时多条分支同时满足,会执行顺序最前面的一条。总之还是要清楚设计意图,做好仿真工作。

4. 循环语句

forever 和 repeat 是完全不可综合的,只用于仿真文件的设计。

循环语句 for 和 while 并不是完全不能综合的,但因为Verilog是对硬件进行建模,for和while的使用肯定不像在软件编程语言中使用一样灵活。还是上面的老话,要从“设计上”能否综合的角度进行考虑。

如果循环语句的使用出现问题,综合工具会给出提示,如Vivado的提示信息如下:

[Synth 8-3380] loop condition does not converge after 2000 iterations

用好循环,可以简化代码设计。一个寄存器链的示例如下(使用for也能达到同样的效果):

module test
(
input clk, rst_n,
input [15:0] d,
output reg [15:0] q
);
integer i;
(* keep = "true" *)reg [15:0] mem [7:0];
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
i = 0;
while(i < 8) begin
mem[i] <= 0;
i = i + 1'b1;
end
end
else begin
i = 0;
mem[0] <= d;
while(i < 7) begin
mem[i+1] <= mem[i];
i = i + 1'b1;
end
end
q <= mem[7];
end
endmodule

相应的RTL原理图如下 :

82143d5bec6056c7031206214eaa1bb1.png

按软件编程思维考虑,循环语句是一条一条执行的一个过程。而从上面的设计结果来说,显然while循环中的所有语句是“同时”执行的,代码只是将很多具有重复性特点的赋值语句改用 while/for 的形式来编写。

5. 过程块

过程块(procedure)包括四种:initial结构、always结构、任务(task)、函数(function)。这里只记录两个不太熟悉的特性。

5.1 零延迟无限循环

always块在仿真文件中,都要与一些时序控制配合使用。如果always块中没有任何推动仿真时间的控制,仿真会卡在一个时间点。比如经常用如下语句创建时钟信号:

always #10 clk = ~clk;

如果写成了如下的形式:

always clk = ~clk;

相当于形成了一个零延迟的无限循环,仿真时间会卡在0s无法前进。如果运行这个代码,轻则程序卡死,重则系统奔溃只能重启。

5.2 initial用于初始化

initial块是可以综合的,只不过不能添加时序控制语句,因此作用有限,一般用于变量的初始化。如下面代码:

reg [15:0] mem [7:0];
integer i;
initial begin
for (i = 0; i < 8; i=i+1)
mem[i] = i;
end

6. 过程块时序控制

此特性主要用于仿真文件中,部分在硬件设计中也会涉及。Verilog有两种明确的时序控制类型:延时控制和事件表达式。仿真时间正是靠过程块中的延时控制、事件控制以及wait语句来推动的。

6.1 延时控制

用于控制语句的执行时间,比如描述激励的波形。延迟值可以是表达式,比如“#d rega = regb;”,这条赋值语句会在延迟d个时间单位后执行。
(1)如果d的计算结果是高阻(z)或未知(x),则当作0处理;
(2)如果d的计算结果为负数,也会将其视作无符号数来看待,如下面的代码:

parameter [7:0] delay = -50;
initial begin
rst_n = 0;
#(-delay) rst_n = 1;
#delay rst_n = 0;
end

rst_n先延迟50个时钟后变为1;由于8bit -50的二进制补码当作无符号数看时值为206,因此在延时206个时钟后,rst_n值又变为0。

6.2 事件表达式

直到某些仿真事件发生时,语句才会只执行。网络或变量的值发生变化,称作隐式事件(implict event);设计者设置一些命名事件,可能会由其它过程块触发,称作显式事件(explicit event)。

值的变化、或变化的方向(上升沿posedge或下降沿negedge)都是隐式事件。虽然在硬件设计中经常和always配合使用(比如 always @ (posedge clk) ),但在仿真文件中有更多灵活的使用方法。看下面的代码示例:

// example1:clk上升沿,语句执行
reg [7:0] delay = 0;
initial begin
forever @(posedge clk) delay = delay + 1'b1;
end
// example2:clk的值发生变化,语句执行
reg [7:0] delay = 0;
always begin
@(clk) delay = delay + 1'b1;
end

如果 posedge 和 negedge 检测的对象是一个表达式或多位宽的数据,则只会检测LSB上的边沿变化。如下:

// example3
reg [2:0] cnt = 0;
always @ (posedge clk)
cnt <= cnt + 1'b1;
reg [7:0] delay = 0;
always begin
@(posedge cnt) delay = delay + 1'b1;
end

检测3bit变量cnt的上升沿,相当于检测cnt[0]的边沿事件。

事件(event) 是除了变量和网络外Verilog中的另一种数据类型,如果一个标识符被申明为事件类型,则称作“命名事件”,需要显示地触发。虽然事件是一种数据类型,但它本身又没有任何“数据”。如下面的示例:

event trig;        // 命名事件申明
reg [2:0] cnt = 0;
always @ (posedge clk) begin
cnt <= cnt + 1'b1;
if (cnt == 7) -> trig; // 事件显示触发
end
reg [7:0] delay = 0;
always begin
@(trig) delay = delay + 1'b1; // 事件捕获
end

使用命名事件可以有效的实现多个过程块之间的通信和同步。

如果过程块语句的执行同时对多个事件敏感,可以使用事件的逻辑或特性。在事件敏感列表中使用 “or” 或 “,”(这两个符号含义等价),如“always @ (posedge clka or posedge clkb, trig)”。

还有一个特性称作隐式事件表达式,符号为“@*”,会把过程时序控制语句中所有读取的变量和网络添加到事件表达式中

6.3 wait语句

上面的事件控制方法都是边沿敏感型的。还可以使用wait语句控制过程块的时序,直到某项条件为true时才执行相应语句,这种方法称作电平敏感型。

如果wait中的条件为false,则过程块会一直阻塞,直到条件变为真时,才会执行后面的语句。比如下面的代码:

reg [7:0] cnta = 0, cntb = 0;
initial begin
wait(en) #10 cnta <= 60;
#10 cntb <= 70;
end

对于begin…end(顺序块) 而言,wait会阻止顺序块的执行,直到en为1时,cnta和cntb的两条赋值语句才会执行。如果使用fork…join(并行块),则上述代码中的wait只会对cnta的赋值语句有效,此时最好也为wait语句加上块声明(begin…end或fork…join)。

6.4 赋值间(Intra-assignment)时序控制

赋值间延迟和事件控制是另一种时序控制方法,如

 a = #5 b;

与“ #5 a = b; ”不同,赋值语句右边的表达式会马上求值,延迟和事件只是控制这个值赋值给赋值语句左边的时间。比如上面的代码等效于:

begin
temp = b;
#5 a = temp;
end

利用赋值间时序控制的特性,可以巧妙地完成一些行为建模。比如下面的代码可以避免赋值语句间的“竞争”,达到数据交换的效果:

fork       // 并行块,存在竞争
#5 a = b;
#5 b = a;
join
fork // 数据交换
a = #5 b;
b = #5 a;
join

赋值间延迟之前会先求等式右边的值,延迟后才会把这个值赋到左边,因此上面代码相当于交换了a和b的值。很多工具在实现Verilog的赋值间时序控制这个特性时,都会使用临时存储来存放右边表达式的值。

也可以用事件控制:

a = @(posedge clk) b;
//等效于
begin
temp = b;
@(posedge clk) a = temp;
end

赋值间时序控制还有一个特点是可以用repeat来控制延迟或事件执行的次数,如:

a = repeat(3) @(posedge clk) b;
//等效于
begin
temp = b;
@(posedge clk);
@(posedge clk);
@(posedge clk); a = temp;
end

要注意如果采用变量的形式 “ repeat (num) ”:

  •   若num是无符号数:当num为负数时,相当于二进制补码对应的无符号数。比如num = -1,repeat(num) 相当于 repeat(7) 。

  •   若num是带符号数:当num为0或负数时,这条语句将永远不会被执行。

7. 块(block)

块(block)是一些赋值语句的组合,包括:

  •   顺序块begin-end:块中语句按照给定的顺序执行,因此块中的延迟、事件控制相当于起到了隔断的作用。顺序块的开始时间是第一条语句开始执行的时刻,结束时间是最后一条语句执行完的时刻。

  •   并行块fork-join:块中语句同时执行,即所有语句的开始时间相同。并行块的结束时间是所有语句都执行完的时刻。

7.1 嵌套块

通常要使用多个块的嵌套实现更复杂的控制逻辑,因此最好要理解各个块的开始时间和结束时间。下面给出几个例子:

// Example1
begin
fork
@Aevent;
@Bevent;
join
areg = breg;
end

由于fork-join的并行性,A和B两个事件可以以任意的顺序出现,fork-join块结束后执行赋值语句 areg = breg。

// Example2
begin
begin
@Aevent;
@Bevent;
end
areg = breg;
end

如果换成begin-end,事件的触发必须按照给定的顺序。如果B事件先出现,再出现A,那么内部嵌套的begin-end还要再等待B事件的发生。

// Example3
fork
@Aevent;
begin #ta wa = 0; #ta wa = 1; end
@Bevent;
begin #tb wb = 1; #tb wb = 0; end
join

fork-join中的两个顺序块的执行分别受到两个事件的控制。由于fork-join的并行性,两个begin-end的触发和执行同样也是并行的。

7.2 命名块

每个块都可以在begin和fork后面为其附加名字,称为命名块。其它语句可以通过这个名字来引用命名块,最常见的是“命名块+disable”的用法。

disable语句可以终止命名块的运行,一般用于处理异常情况,比如下面的代码:

begin : block_name
...
if (a == 0)
disable block_name;
...
end

当满足a == 0时,begin-end块会终止运行。disable会终止整个命名块的运行,包括命名块中的其它所有块和已调用的任务。利用这个特性可以实现两个功能:
  •   中止一个循环语句(相当于C语言中的break)
  •   跳过循环中的某些状态(相当于C语言中的continue)

虽然Verilog没有直接提供类似于C语言中break和continue的关键词,但可以使用“命名块+disable”来实现此特性。看下面的示例代码:

reg [7:0] cnt = 0;
always @ (posedge clk) cnt <= cnt + 1'b1;
reg [7:0] data;
integer i;
initial begin : break
for (i = 0; i < 100; i = i + 1) begin : continue
@(posedge clk)
if (cnt == 5)
disable break;
data <= cnt;
end
end

for循环中,当满足一定条件时," disable break; "会终止initial之后的begin-end块的执行,整个循环也就终止了。

如果改成" disable continue; ",当满足条件时,会终止for之后的begin-end块的执行,这样只会终止当前的循环状态,而不会影响循环的下一次迭代。

原文链接:https://bestfpga.blog.csdn.net/article/details/102784167

‧  END  

68961e7acb00d446c66d7326215243fc.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/266265.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

本地配置DNS服务器(MAC版)

转自https://www.cnblogs.com/skylor/p/7483959.html作为一个前端开发者&#xff0c;会遇到使用cookie的情况&#xff0c;常见的如&#xff1a;登录&#xff0c;权限控制&#xff0c;视频播放&#xff0c;图形验证码等&#xff0c;这时候本地开发者在PC上会使用修改hosts的方式…

mme设备内部错误_华为拟安装“俄版安卓”;百度回应内部贪腐;Android Studio 3.5 RC2 发布 | 极客头条...

快来收听极客头条音频版吧&#xff0c;智能播报由标贝科技提供技术支持。「CSDN 极客头条」&#xff0c;是从 CSDN 网站延伸至官方微信公众号的特别栏目&#xff0c;专注于一天业界事报道。风里雨里&#xff0c;我们将每天为朋友们&#xff0c;播报最新鲜有料的新闻资讯&#x…

[spring mvc]Hello World入门

1.新建项目 File->New->Other,选择Dynamic web project&#xff1a; 项目建好之后&#xff0c;目录结构如下&#xff1a; 2.WEB-INF/web.xml 中配置 dispatcherServlet <?xml version"1.0" encoding"UTF-8"?> <web-app xmlns:xsi"ht…

Mysql日期函数使用大全

为什么80%的码农都做不了架构师&#xff1f;>>> 1.1 获得当前日期时间&#xff08;date time&#xff09;函数&#xff1a;now() 除了 now() 函数能获得当前的日期时间外&#xff0c;MySQL 中还有下面的函数&#xff1a; current_timestamp() current_timestamp …

input点击事件不能用_用js简单写一个计算器

嗨&#xff0c;大家好&#xff0c;今天给大家带来的是一个计算器首先要知道我们常用的计算器都有哪些按键&#xff0c;有0~9&#xff0c; , - , *, /&#xff0c;还有 和.&#xff0c;基本是这些按键&#xff0c;然后我们去创建一些按键。之后我们去设置样式&#xff0c;设置完…

php判断信用卡,php校验信用卡卡号代码

[php]代码库// This function will take a credit card number and check to make sure it// contains the right amount of digits and uses the Luhn Algorithm to// weed out made up numbersfunction validateCreditcard_number($credit_card_number){// Get the first dig…

python list长度_python的入门阶段 编程思维100题 我跟罗志祥没关系

"""python的入门阶段 编程思维100题&#xff08;适合学习了1周--1个月的新人&#xff09; 第五题&#xff1a;我跟罗志祥没关系 朋友圈大家每天都看&#xff0c;那用python如何实现它那&#xff1f; 很简单&#xff0c;朋友的信息&#xff08;名字&#xff0c;头…

Android ----中文Api 百度地图

Android中文API最新中文版 [复制链接] kupekupe当前离线在线时间1 小时e望0 点最后登录2011-2-17注册时间2011-2-17积分12阅读权限10UID1341171 主题 0 好友 12 积分No.1 开发小菜鸟 No.1 开发小菜鸟, 积分 12, 距离下一级还需 88 积分升级 12% 当前用户组为 No.1 开发小菜鸟 …

android之多媒体篇(一)

2019独角兽企业重金招聘Python工程师标准>>> Android 4.0.3(Api Level 15&#xff09;支持的多媒体格式。 注意&#xff1a;有些设备可能支持其他的文件格式。 1.Audio AAC LC/LTP、HE-AACv1(AAC)、AMR-NB、AMR-WB、MP3、MIDI、Ogg Vorbis、PCM/WAVE、FLAC&#…

java定时器_拾遗Timer定时器

一 Timer 介绍在开发中我们经常会遇到一些简单定时任务的需求&#xff0c;而不需要量级较重的定时任务就可以采取java定时器&#xff1b;java.util.Timer工具类中的Timer 是定时器&#xff0c;但定时任务写在java.util.TimerTask 中&#xff0c;由 Timer 执行 TimerTask &#…

逻辑门电路的知识点归纳

1.半导体二极管与MOS管的开关特性 二极管&#xff1a;正向导通&#xff0c;反向截止&#xff0c;但是要注意的是从反向截止到正向导通的时间极其短&#xff0c;但是从正向导通到反向截止要经过反向恢复&#xff08;电荷存储效应&#xff09;的过程&#xff0c;这个过程实际上就…

善心

2019独角兽企业重金招聘Python工程师标准>>> 一个穷苦学生郝武德.凯礼&#xff0c;为了付学费&#xff0c;挨家挨户地推销货品。 到了晚上&#xff0c;发现自己的肚子很饿&#xff0c;而口袋里只剩下一个小钱。他在大街上犹豫徘徊了半天&#xff0c;终于鼓起勇气&a…

python 清屏_Python学前准备如果你知道要去哪,那么全世界都给你让路

一、Python 已来 AI 不远在当今&#xff0c;人工智能已经渗透到了智能手机、网络搜索&#xff0c;广告分发&#xff0c;人脸识别&#xff0c;语音识别&#xff0c;自动驾驶&#xff0c;智能医疗&#xff0c;无人银行等日常生活领域。人工智能的生活化是不可避免的&#xff0c;它…

js判断用户是否离开当前页面

简介 VisibilityChange 事件&#xff1b;用于判断用户是否离开当前页面 Code // 页面的 visibility 属性可能返回三种状态 // prerender&#xff0c;visible 和 hidden let pageVisibility document.visibilityState; // 监听 visibility change 事件 document.addEventLi…

记一次B站答题经历

第一题部分&#xff1a;社区规范卷 --------- ------------ 第二题&#xff1a;社区规范第二部分 -------------------- 第三部分自由选择题 ---------------------- -------------------------------- 最后答题成绩得分 -------------- ------------- 答完题后的感受&#xff…

linux 安装程序丢失链接动态库,Linux安装软件过程中提示缺少动态链接库.so的解决方法...

Linux在安装软件的时候有时会出现错误&#xff0c;提示缺少动态链接库.so&#xff0c;该问题是由什么原因导致的呢?情况分析&#xff1a;1.缺少动态连接库.so-cannot open shared object file:No such file or directory2.缺少动态连接库.so.0-cannot open shared object file…

yaf(5) smarty

2013年4月6日 13:41:37 参考: http://www.oschina.net/question/812776_71817 http://yaf.laruence.com/manual/yaf.class.dispatcher.setView.html 这两者都是在bootstrap.php中写_initSmarty()函数来重新实现yaf的视图接口 这中方案默认的是存放模版文件的上级文件夹名字必须…

Hibernate(三) - hibernate 表操作-多对多配置

Hibernate 的一对多关联映射 之前在学习 Hibernate 的时候&#xff0c;其实都是单表的操作。在实际的开发当中&#xff0c;比如做一个商城&#xff0c;就需要好多张数据库表&#xff0c;表与表之间是有关系的。之前些做一些关联查询或者是一些基本的查询操作的时候&#xff0c;…

vb treeview 展开子节点_详解最长公共子序列问题,秒杀三道动态规划题目

学算法认准 labuladong后台回复进群一起力扣?读完本文&#xff0c;可以去力扣解决如下题目&#xff1a;1143.最长公共子序列(Medium)583. 两个字符串的删除操作(Medium)712.两个字符串的最小ASCII删除和(Medium)好久没写动态规划算法相关的文章了&#xff0c;今天来搞一把。不…

linux查看数据积压,查看kafka消息队列的积压情况

创建topickafka-topics --create --zookeeper master:2181/kafka2 --replication-factor 2 --partitions 3 --topic mydemo5列出topickafka-topics --list --zookeeper master:2181/kafka2描述topickafka-topics --describe --zookeeper master:2181/kafka2 --topic mydemo5生产…