verilog做小游戏需要的fpga板(FPGA基础设计Verilog行为级建模)
verilog做小游戏需要的fpga板(FPGA基础设计Verilog行为级建模)
2024-06-26 10:47:44  作者:慢摇废鞋  网址:https://m.xinb2b.cn/sport/aqh478665.html

蓝字verilog做小游戏需要的fpga板(FPGA基础设计Verilog行为级建模)(1)关注我们

版权声明:本文为CSDN博主「FPGADesigner」的原创文章

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

使用逻辑门和连续赋值对电路建模,是相对详细的描述硬件的方法。使用过程块可以从更verilog做小游戏需要的fpga板(FPGA基础设计Verilog行为级建模)(2)高层次的角度描述一个系统,称作行为级建模(behavirol modeling)。

1. 过程赋值

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

1.1 特性1

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

module test(input clk,output reg a, b);always @ (posedge clk) begina = 0;b = 1;a <= b;b <= a;endendmodule

非阻塞赋值可以认为包括两步:

(1)求值和调度(evaluate and schedule),先得到非阻塞赋值等式右侧的值,并将这次赋值安排在当前时间点的结束时刻。

(2)当前时间点结束时,更新左侧的值。因此这段代码的结果是 a = 1,b = 0。

1.2 特性2

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

看下面的示例代码:

module test(input clk,output reg a, b);always @ (posedge clk) begina <= 0;a <= 1;endendmodule

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

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

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

2. 过程连续赋值

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

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

看下面的示例代码:

`timescale 1ns / 1psmodule 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;endendmodule

当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;endcaseendmodule

如果想使用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;endcaseendmodule

可以实现,根据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) beginif (!rst_n) begini = 0;while(i < 8) beginmem[i] <= 0;i = i 1'b1;endendelse begini = 0;mem[0] <= d;while(i < 7) beginmem[i 1] <= mem[i];i = i 1'b1;endendq <= mem[7];endendmodule

相应的RTL原理图如下 :

verilog做小游戏需要的fpga板(FPGA基础设计Verilog行为级建模)(3)

按软件编程思维考虑,循环语句是一条一条执行的一个过程。而从上面的设计结果来说,显然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 beginfor (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 beginrst_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 beginforever @(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上的边沿变化。如下:

// example3reg [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) begincnt <= cnt 1'b1;if (cnt == 7) -> trig; // 事件显示触发endreg [7:0] delay = 0;always begin@(trig) delay = delay 1'b1; // 事件捕获end

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

如果过程块语句的执行同时对多个事件verilog做小游戏需要的fpga板(FPGA基础设计Verilog行为级建模)(4)敏感,可以使用事件的逻辑或特性。在事件verilog做小游戏需要的fpga板(FPGA基础设计Verilog行为级建模)(5)敏感列表中使用 “or” 或 “,”(这两个符号含义等价),如“always @ (posedge clka or posedge clkb, trig)”。

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

6.3 wait语句

上面的事件控制方法都是边沿verilog做小游戏需要的fpga板(FPGA基础设计Verilog行为级建模)(6)敏感型的。还可以使用wait语句控制过程块的时序,直到某项条件为true时才执行相应语句,这种方法称作电平verilog做小游戏需要的fpga板(FPGA基础设计Verilog行为级建模)(7)敏感型。

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

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

对于begin…end(顺序块) 而言,wait会阻止顺序块的执行,直到en为1时,cnta和cntb的两条赋值语句才会执行。如果使用fork…join(并行块),则上述代码中的wait只会对cnta的赋值语句有效,此时最好也为wait语句verilog做小游戏需要的fpga板(FPGA基础设计Verilog行为级建模)(8)加上块声明(begin…end或fork…join)。

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

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

a = #5 b;

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

begintemp = b;#5 a = temp;end

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

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

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

也可以用事件控制:

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

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

a = repeat(3) @(posedge clk) b;//等效于begintemp = 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 嵌套块

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

// Example1beginfork@Aevent;@Bevent;joinareg = breg;end

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

// Example2beginbegin@Aevent;@Bevent;endareg = breg;end

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

// Example3fork@Aevent;begin #ta wa = 0; #ta wa = 1; end@Bevent;begin #tb wb = 1; #tb wb = 0; endjoin

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 : breakfor (i = 0; i < 100; i = i 1) begin : continue@(posedge clk)if (cnt == 5)disable break;data <= cnt;endend

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

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

  • 张鲁一胡歌对比张一山(胡歌同时演4个人)
  • 2024-06-27胡歌同时演4个人看电视剧的时候,我们经常会发现一部剧中演员饰演多个角色的情况,比如演一个角色的前世今生,同一张面孔更容易记住,在仙剑三中杨幂同时出演雪见和夕瑶两个角色;再比如演父子母子,同一个面孔更让人亲切,还珠格格。
  • 东京喰种里面最恶心的角色(最悲催的搜查官)
  • 2024-06-27最悲催的搜查官东京喰种中搜查官是与喰种战斗的第一线人员,他们背负着与喰种作战的使命,被称为“鸽子”,有这么一个搜查官最为悲催,复仇不成反被杀!女儿最后嫁给独眼喰种!真户吴绪,这是在第二季中出现的一个搜查官,外边看上。
  • 谷歌离线地图导航怎么用(谷歌地图离线功能于下半年推出)
  • 2024-06-27谷歌地图离线功能于下半年推出众人关注的谷歌I/O大会已于凌晨0:30在美国旧金山正式开启,值得一提的是,谷歌地图将支持离线地图及导航功能,具体什么情况呢?我们一起来看一下据了解,谷歌地图是2005年推出的,现在全球用户已超过10。
  • 无法定义标题(没有标题)
  • 2024-06-27没有标题现在延迟退休政策还没出台,各种消息到处是延迟退休应该是事业单位延迟,企业正常退休三年疫情连国企都在减员增效,我们企业三、四千多人的单位,享受科级待遇的就有一千六百多号人单位一把手找个评估机构找本选科把。
  • 春天花开唯美诗词(8首唯美春风诗词)
  • 2024-06-278首唯美春风诗词8首唯美春风诗词:爱惜芳心莫轻吐,且教桃李闹春风1、《雨晴后步至四望亭下鱼池上遂自乾明寺前东冈》苏轼高亭废已久,下有种鱼塘暮色千山入,春风百草香市桥人寂寂,古寺竹苍苍鹳鹤来何处,号鸣满夕阳暮色千山入,。
  • ups不间断电源正确使用方法(UPS不间断电源工作原理)
  • 2024-06-27UPS不间断电源工作原理UPS不间断电源当电网电压正常时,市电电压通过UPS稳压后供应给负载使用,性能好的UPS不间断电源本身就是良好的交流稳压器,同时改善电源质量;同时它还对机内的电池进行充电,储存后备能源;当电网电压异常。
  • 承德到石家庄直达大巴(承德至石家庄客车今日起通车运营)
  • 2024-06-27承德至石家庄客车今日起通车运营承德至石家庄的客车今日起全部恢复运营啦!每日两个班次客车,分别是9:30和14:30,由承德汽车客运东站始发,开往石家庄客运总站详情咨询电话:2123588有出行计划的朋友们可以安排啦~一定要做好防护。
  • 十大香辣鸡翅煲(鸡翅虾煲味道绝了)
  • 2024-06-27鸡翅虾煲味道绝了By给舅娘的目录用料大虾350g鸡翅根6只土豆一个甜玉米一个葱姜蒜适量八角茴香二个小红辣椒二个豆豉酱一勺生抽二勺白糖一勺耗油一勺做法步骤1、焯水2、鸡翅和虾煎3、葱蒜爆香4、放配菜5、调料6、焖15分。
  • 最好看的古代电影大全(12部大片感受国粹无穷魅力)
  • 2024-06-2712部大片感受国粹无穷魅力1月12日正在直播关注1905电影网APP直播剧场365天佳片有约每天24小时联播不见不散↓↓↓↓↓12部京剧相关电影带你感受唱念做打皆是戏光影定格梨园情《大红灯笼高高挂》从《红娘》《苏三起解》到《御。
  • 家庭养肉狗需要注意什么(想养肉狗的看过来)
  • 2024-06-27想养肉狗的看过来嗨大家好,我们又见面了,我是你们的老朋友,农民大张感谢大家一直以来对我的支持和鼓励,有了你们的支持,我的写作之路才能走得更长远,我才能持续不断的给大家带来更多有用的好资讯,老规矩,今天我们继续来聊聊农。
  • 必看十部泰剧高甜(超越甜茶封神之作)
  • 2024-06-27超越甜茶封神之作近年来泰国腐剧泛滥是能够填补国内腐女观众没得看国内男演员卖腐的心理空缺的,毕竟卖腐就是容易火啊,近年搞擦边球把卖腐改编为社会主义兄弟情的《镇魂》《陈情令》,火了多少演员你说擦边球这种东西因为改编过度剧。
  • 关晓彤和白敬亭同框过吗(关晓彤和白敬亭恋爱)
  • 2024-06-27关晓彤和白敬亭恋爱最近95后小花关晓彤可是火得不要不要的,各种花式上热搜,这一次竟然是因为恋情哦!豆瓣八组网友曝料白敬亭和关晓彤在一起了,还列出了不少两个人在微博上的暧昧互动证据起因是关晓彤发了一组写真带上了冷漠狗的表。