黑金fpga整合的概念Verilog私私细语_第1页
黑金fpga整合的概念Verilog私私细语_第2页
黑金fpga整合的概念Verilog私私细语_第3页
黑金fpga整合的概念Verilog私私细语_第4页
黑金fpga整合的概念Verilog私私细语_第5页
已阅读5页,还剩78页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第1章整合的概 源码上的整 实验一:字面上的整 时钟和步骤的定 有效的使用资源(资源上的整合 实验二:资源上的整 循环保留和循环操 把C语言的好处(循环)整合进 把C语言的好处(嵌入循环)整合进 把C语言的好处(动作的关系)整合进 步骤的循环和时序的循环之间的区 实验三:串口发送模 实验四:串口发送模块 模块之间调用的延 同步数据的几个想 总 来看,意思就是提高内容的解读能力。除此以外“整合”还有把其他语言的好处,以VerilogHDL语言的特质“整合”起来.....inputinputoutputoutput[1:0]SQ_iregalways@(posedgeCLKornegedgeRSTn)if(!RSTn)C1<=elseif(C1==10-1)C1<=5'd0;C1<=C1+regregalways@(posedgeCLKornegedgeRSTnif(!RSTni<=rQ<=case(i if(C1==10-1)i<=i+ elserQ<= if(C1==10-1)i<=i+ elserQ<= if(C1==10-1)i<=i+ elserQ<= if(C1==10-1)i<=elserQ<=assignQ=rQ; assignSQ_i=assignSQ_C1=C1;71.上面是还没有进行整合的模块名为c1a_module.v。该模块的作用很简单,就是每隔100(41~43行)2(49~51行)1(45~47行)和步环,直到(其中C1==10-1代表什么?笔者先保留先。QuartusII118,2561inputinputoutputoutput[1:0]SQ_iregregregalways@(posedgeCLKornegedgeRSTn)if(!RSTn)i<=2'd0;rQ<=case(iif(C1==10-1)beginC1<=5'd0;i<=i+1'b1;elsebeginrQ<=1'b1;C1<=C1+1'b1;if(C1==10-1)beginC1<=5'd0;i<=i+1'b1;elsebeginrQ<=1'b0;C1<=C1+1'b1;if(C1==10-1)beginC1<=5'd0;i<=i+1'b1;elsebeginrQ<=1'b1;C1<=C1+1'b1;if(C1==10-1)beginC1<=5'd0;i<=i+1'b1;elsebeginrQ<=1'b0;C1<=C1+1'b1;assignQ=assignSQ_i=assignSQ_C1=c1b_module.vc1a_module.v没有什么不同,17~45QuartusII编译后,逻辑资源使用的结果同样也是“11/8,256(<1%)”。可能读者要问:“把定时器整合在操作步骤中到底有什么好处?”好处可多了。在C1寄存器是一个通用的寄存器。读者要它成为计数器它当然,,既然这个寄存器已经命名为C1(Counter1)笔者它的目的就是要它为我case(icase(i //-1if(C1==8-1)beginC1<=5'd0;i<=i+1'b1;endelseC1<=C1+1'b1;if(C1==20-1)beginC1<=5'd0;i<=i+1'b1;endelseC1<=C1+1'b1;20个时钟。感觉上,操作的范围是不是更广了?而且从理解上更直在步骤0中,C1在每一个时钟都计数,当计数到的第8个时钟就C1然后递增步骤i1中,C120个时钟。同器在操作步骤里面而已,我们可以根据不同的要求而实现不同的整合方案,只不过定时c1a_module.v和clb_module.v同样为一样的逻辑资源消耗,但是clb_module.v模块的内容比起cla_module.v来得好处。换做读者,读者会选择c1a_module.v还是,c1b_module.v就是你的选择了。是什么?笔者会在下一章节中很好解释的,放心放心!(*^^*)嘻嘻。i除了指示步骤以外i都可以显示指向时钟。唯有“一个步i为“显示指向时钟”。case(icase(ibeginrData<=rData+1'b1;i<=i+1'b1;beginrData<=4'd0;i<=i+1'b1;if(rData==5-1)rData<=4'd0;i<=i+1'b1;endelserData<=1'b1;rDatai40i0~3rData0~3的操作都作是rData,它也是以一个时钟为消耗单位。由于步骤0~4的每一个操作都以一个i有显示指向时钟的功5rData递增rData51的时候(怎么"-1"又出现了?....不怕不怕,再过不久笔者就会把它介绍了,亦即rData的结果等于4的时候,rData然后递增i以示下一个步骤。在这里我们再也不能说步骤i有显示指向时钟的能力,因为步骤5所需要的时钟消耗为5个。9T0~T3i0~30~3rData,所以在T4的时候,也是步骤4的时候,该步骤的操作是rData,所以rData的未来值是T95,ifrData4'd4T9系(有关-1是什么笔者真的会很好的解释的,请再多忍耐一会。inputinputoutputoutput[1:0]SQ_iregregregalways@(posedgeCLKornegedgeRSTn)if(!RSTn)i<=2'd0;rQ<=case(iif(C2==10)beginC2<=5'd0;i<=i+1'b1;endelsebeginrQ<=1'b1;C2<=C2+1'b1;endif(C2==10)beginC2<=5'd0;i<=i+1'b1;endelsebeginrQ<=1'b0;C2<=C2+1'b1;endif(C2==10)beginC2<=5'd0;i<=i+1'b1;endelsebeginrQ<=1'b1;C2<=C2+1'b1;endif(C2==10)beginC2<=5'd0;i<=i+1'b1;endelsebeginrQ<=1'b0;C2<=C2+1'b1;endassignQ=rQ;assignSQ_i=i;assignSQ_C2=C2;c2a_module.vc1b_module.v32c2a_module.v到底有什么问题?`timescale1ps/1regregwirewire[1:0]SQ_i;c2a_moduleU1RSTn=0;#1000RSTn=CLK=1;forever#5CLK=上面是c2a_module.v的激励文件,它没有什么特别。在第1行中了仿真用的时间刻度(时间单位)为ps。在4~9行了输入和输出,在13~20行实例化了仿真对象然后拉高,后者是10ps周期的时钟(两者都可以随便填。0ps,在光标12之间含有100ps,这也表示:100ps/(时钟周期)=100ps/10ps= T9if(C2==10)beginC2<=5'd0;i<=i+1'b1;elsebeginrQ<=1'b1;C2<=C2+1'b1;钟里都会递增,当32行的if条件成立的话(C2==10)的话,那么C2会被,然后i递1.11.2C2010但是从仿真结果上我们可以看到(1.3b12100ps,条件成立,C2被和i被递增。所以在T10的未来,C2的结果是零,i的结果是1。0Q10Q拉高,11个时钟(1~3之间的距离1.3b用了一个时钟的时间去更新C2和i寄存器的值。20Mhz10ms的话,那么多一个时钟,流水灯效果的间隔也不过是10ms+50ns而已,对于结果影响不大。c2a_module.vc2b_module.vmodule(inputinputoutputoutputoutput13. regregregalways@(posedgeCLKornegedgeRSTnif(!RSTni<=C2<=rQ<=case(i if(C2==10-1)beginC2<=5'd0;i<=i+1'b1; elsebeginrQ<=1'b1;C2<=C2+1'b1;end if(C2==10-1)beginC2<=5'd0;i<=i+1'b1; elsebeginrQ<=1'b0;C2<=C2+1'b1;end if(C2==10-1)beginC2<=5'd0;i<=i+1'b1; elsebeginrQ<=1'b1;C2<=C2+1'b1;endassignQ=rQ;assignSQ_i=i;assignSQ_C2=C2;if(C2==10-1)beginC2<=5'd0;i<=i+1'b1;endelsebeginrQ<=1'b0;C2<=C2+1'b1;endc2b_module.vc2a_module.v32,36,40,44if条件中天的苦思。在31~33行代码中,它所表达内容是:在c2a_module.v的仿真结果中(图1.3a我们知道c2a_module.v为了C2和更新i消101011个时钟。不同的是,在C2i这一个操作都考虑在步骤010个时钟之内。`timescale1ps/1moduleregCLK;regwirewire[1:0]SQ_i;RSTn=0;#1000RSTn=CLK=1;forever#5CLK=c2b_moduleU1c2b_module.v的激励文件和c2a_module.v1.3cc2b_module.v1~2之间的距离,从上图90ps92T9的时候,正好也是在步骤0。if(C2==10-1)beginC2<=5'd0;i<=i+1'b1;endelsebeginrQ<=1'b1;C2<=C2+1'b1;endif(C2==10-1)beginC2<=5'd0;i<=i+1'b1;endelsebeginrQ<=1'b0;C2<=C2+1'b1;endT10的时候,c2b_module.vi1137T10的未来Q的值更新为0。1.3c1~390ps+10ps的距离,如果换做时钟来计算的话100Q10T0~T8是无聊的计1T10,Q被拉低之前,Q010个时钟。1.3dc2b_module.v13T9Q9个时钟(T0~T8),然后再加上C2和i的更新所消耗的一个时钟(T9~T10之间)(T0~T911Q,QT100。.09110case(case(ibeginQ<=1'b1;C2<=C2+1'b1;i<=i+1'b1;beginQ<=1'b1;C2<=5'd0;i<=i+1'b1;beginQ<=1'b0;C2<=C2+1'b1;i<=i+1'b1;beginQ<=1'b0;C2<=5'd0;i<=i+1'b1;c2b_module.v01非整合的话,结果会如上面一段代码,笔者稍微的0~8,Q被拉高,i逐个步骤递增,C2只是无聊的计数而已,然后在步之间,同样的事情也会发生,不同的只是Q被拉低而已。C2好像废物那样-完全没有用处,我们之所以可以知道“在什么时钟发生什么操作”i的显示指示时钟的功能而已。但是为了更好的减少内容的行数,提高模块的表C2当做计数器,将“既分散既有共同操作性质的步骤”全部ififC29)ifC2101”这是一个很好的问题。case(case(iif(C2==9)beginC2<=5'd0;i<=i+1'b1;endelsebeginQ<=1'b1;C2<=C2+1'b1;end“在步骤0,Q被拉高,C2每一个时钟递增,在C2递增到第9个时钟的时候,C2递 还好,反之如果这个新手只会看波形图的话就像猴子看着罐头食物傻笑而已。为了更活VerilogHDL内容给人的反应“显示指示那个一个时钟发生什么事情”是很重要的。case(case(iif(C2==10-1)beginC2<=5'd0;i<=i+1'b1;endelsebeginQ<=1'b1;C2<=C2+1'b1;end“步骤0需要消耗10个时钟,步骤0在第9个时钟会C2和递增i。此外在这个10时钟里,步骤0的操作是拉低束步骤(计数器和更新i。然而else这一行就表示了步骤0的“默认操作”了。 case(i if(C2==10-1)beginrNumber<=4'd9;C2<=5'd0;i<=i+1'b1;T9 elseif(C2==10-2)beginrNumber<=4'd8;C2<=C2+1'b1;// elseif(C2==10-3)beginrNumber<=4'd7;C2<=C2+1'b1;// elseif(C2==10-4)beginrNumber<=4'd6;C2<=C2+1'b1;// elseif(C2==10-5)beginrNumber<=4'd5;C2<=C2+1'b1;// elsebeginrNumber<=4'd0;C2<=C2+1'b1;//在默认的情况下(T0~T4)rNumber都是输出4'd0;T5rNumber4'd5;T6rNumber4'd6;T7rNumber4'd7;T8rNumber输出T9rNumber4'd9,并且结束步骤。产生的时序会如同图1.4e那样。case(case(iif(C2==10-1)beginrNumber<=4'd9;C2<=5'd0;i<=i+1'b1;endelseif(C2==10-2)rNumber<=4'd8;elseif(C2==10-3)rNumber<=4'd7;elseif(C2==10-4)rNumber<=4'd6;elseif(C2==10-5)rNumber<=4'd5;elserNumber<=4'd0;C2<=C2+i来显示指示“哪一个时钟发生什么操CVerilogHDL会出现而已,举个简单的for(for(intx=0;i<8;i++{SCLK=1;Delay(100SCLK=0;Delay(100}习惯在SCLK的值更新后,都添加上延迟函数。for(for(intx=0;i<8;i++{for(inty=0;y<100;y++)SCLK=1;for(inty=0;y<100;y++)SCLK=}之VerilogHDL语言却很乐意这样作。case(case(iif(C1==100-1)beginC1<=8'd0;i<=i+1'b1;endelsebeginSCLK<=~CLK;C1<=C1+1'b1;endVerilogHDLC语言的权力呢?呵呵呵,这个问题的答案很简单,CVerilogHDL语言的时钟消耗数是可见又可自定义。这就是VerilogHDL其中之一的强大之处。for循环,值得我们在意的只有循环的操作次数和操作次序,根本就没有人会理会在forVerilogHDL语言来实现循环操作的话,C语言的一套思想就(除非无视时钟的消耗。又会令人想起循环语法。Cloopwhiledowhile还有比较有人for循环。在早期,当笔者掌握了仿顺序操作的想法以后,基本上这些循环语法都可以forfor(inti=0;i<10;i++)Act++ for循环,它始终需要一个变量用来控制循环的次数。以上述的例子为例,i变量就是用VerilogHDLforni0~910个数,也就是说在这个循环中使用了“10个实际上,在C语言的世界中,正如笔者1.4章节所说的那样。使用者仅注意“循环操作10个以上的时钟。VerilogHDL语言是富有并行性质的语言,如果不好好的利用这个好处,基本上VerilogHDL语言就没有任何模仿循环操作的目的。forinti0;i10;i动作case(case(ibeginAct<=Act+1'b1;i<=i+1'b1;这个估计是最简单了吧?啊~如果循环个数是100个的话,那么笔者既不要去见鬼了?i在“仿顺序操作”的写法中,是一个很重要的“步骤资源”,仅可以的话不要过度它(之前的笔记就是太过它了)...为此我们需要“额外”的计数器来计算循环的次数exp1_5acase(iif(if(C1==10-1)beginx<=8'd0;C1<=8'd0;i<=i+1'b1;elseC1<=C1+if(x==C1)beginx<=x+1'b1;Act<=Act+1'b1;10.上面的这段代码,笔者把for(int=0;i<10;i++)集中在一个步骤里面。笔者不再i了,C1x这个控制变量。是不是觉得这个写C1表示了计算时钟的计数器,x表示了控制循环的控制变量,if(C1==10-1)表示了循环结束(这一个步骤结束。嗯~请读者不要摆出不明白的表情,我们还是在时序图中了解这些图1.5a表示了上诉代码执行的经过。在T-1的时候是复位状态,所有的寄存器都。在,C1,x,Act行T98ifC110-1(9)并且条件成立,所ifC1xAct递增,Act的未来值是10。10。此外在T10之前(亦即T9的未来值)C1和x被,i也递增成功。在这里“循环操C1,x和i等寄存器更新所消耗的一个时钟保留在同一个步骤中,或者说C1,xi等寄存器更新所消耗的一个时钟都考虑在10次得循环操作之中。步骤0的写法在理解上也存在问题?怎么编译器会通过这样充满的写法?这到底是怎么呵呵,事实上这样的写法没有存在问题,有问题的是人类在习惯上的理解方式。在步骤T969xx1'b1x8'd0;都会069x<=x+1'b1x<=8'd0之间,编译器alwaysalways@(*if(C1==10-1)x<=elseif(x==C1)x<=x+(C1==10-1)(x==C1)x<=8'd0被执行是理09x8'd06x<=x1'b19x8'd0的优exp1_5acase(case(iif(x==C1)beginx<=x+1'b1;Act<=Act+1'b1;if(C1==10-1)beginx<=8'd0;C1<=8'd0;i<=i+1'b1;endelseC1<=C1+1'b1;beginC1<=8'd10,x<=8'd20,Act<=8'd30;i<=4'd1;笔者再添加一个步骤试一试,在T101.5b(1骤1中。的定义不同而已,所以写法也不同,但是“循环操作”的写法确实是怪了点...CVerilogHDL语言则不是。CVerilogHDL语言在时序上既有“时间forinti0;i10;iAct++;Act1010次。笔者为了有效利用时钟(时钟资源)笔者把C1,xi等寄存器更新所消耗的一个时钟,都for(for(intx=0;x<10;x++for(inty=0;y<10;y++)for循环以“时序”的形式表现出来。如果按照计算循我们可以这样写,假设x寄存器的复位值(初值)是0的话:case(case(iif(x==C1)beginx<=x+1'b1;Act<=Act+1'b1;if(C1==100-1)beginx<=8'd0;C1<=8'd0;i<=i+1'b1;endelseC1<=C1+1'b1;for循环来说,实际上是不会单单出现一个动作而已,很多时候会有多种动作出现在嵌入for循环。for(for(intx=0;x<10;x++for(inty=0;y<10;y++){Act1++;Act2++;Act1Act2看成是“独立关系”的(互不相关,所以它们可以在同一个for循环中,xy,yAct1Act2,x循环操作10次,y10次,所以Act1和Act2一共循环操作了100次。exp1_6bcase(case(iif(x==C1)beginx<=x+1'b1;Act1<=Act1+1'b1;Act2<=Act2+1'b1;if(C1==100-1)beginx<=8'd0;C1<=8'd0;i<=i+1'b1;endelseC1<=C1+1'b1;在这里(x0的话)xy,反而我们xAct1Act2是“独立关系”所以它们可以在x100if(x==C1)条件成立的时Act1Act2同时发生操作,亦即同时递增(双方没有关系100次的时候(T0~T99,xfor(for(intx=0;x<10;x++{for(inty=0;y<10;y++)}次,至于Act2会循环操作100次。case(case(iif(x==C1)beginx<=x+8'd10;Act1<=Act1+1'b1;endif(y==C1)beginy<=y+1'b1;Act2<=Act2+1'b1;endif(C1==100-1)beginx<=8'd0;y<=8'd0;C1<=8'd0;i<=i+1'b1;endelseC1<=C1+1'b1;xAct110100次的总循环操作中,x每10个时钟(每次循环操作)/x10010所以得循环操作中,x总共被更新10次,Act1被执行10次。Act2ycforxy就被100y100/100y1。 1.6a12T0~T11图1.6a表示了前12个时钟的经过,T-1表示了复位状态,所有相关的寄存器都被。T0的时候,xyC10,ifxC1)ifyC1)的条件成立,所以,Act11。但是别忘了,Act1xAct110010Act1x10。T10的时候(yAct20ifxC1判断到未来值为2,反之x被更新并且递增10,未来值为20。操作,ifxC1xC1ifT90的未来,xAct1的x10次,Act110T90~T99Act210次循环操作。100T99的时候,ifC11001)x,yC1等寄存器陆续被,然而iT99的未来,x,yC1的未来0,i1T1001。Act2y<=y+1'b1;if(x==反之Act1没有变化。1~21000ps(10ps1000ps10ps100010021如愿以偿的for(for(intx=0;x<10;x++{for(inty=0;y<10;y++)}for(for(intx=0;x<10;x++{for(inty=0;y<10;y++)}VerilogHDL100次循环操作中,Act2100次,Act1都笔者就了,C语言所用来理解“循环操作”的思想,是不适合用在理解VerilogHDL语for(for(intx=0;x<10;x++{for(inty=0;y<10;y++)Act2=Act1;}上面一段代码,Act1Act2Act1Act2有“依如何使用VerilogHDL语言来实现呢?case(case(0if(x==C1)beginx<=x+8'd10;Act1=Act1+1'b1;if(if(y==C1)beginy<=y+1'b1;Act2<=Act1;if(C1==100-1)beginx<=8'd0;y<=8'd0;C1<=8'd0;i<=i+1'b1;endelseC1<=C1+1'b1;exp1_7a的源码基本上和之前的例子没有多大的改变。xAct1,yAct2。1'b1,然而Act2每个时钟都执行一次Act2<=Act1。请问读者,在这里有发现什么奇怪篇”的朋友估计要犯傻了,是吗?笔者简单的介绍一遍:4。其外在时间点T0,x5zx的过去值,亦即2。结果在T0的未来,x的未来值是5,y的未来值是4,z的未来值是2。即即是以“即时空间中的值7”作为判断基础。if条件成立x“决定”赋值与7。T0的未来,w7x7,y8,z的未VerilogHDL语言看成是理想的语言....所以也没有这些概念,要把波形图看好需要付出更大的代价...基本上“事件点”和“即件”的区别仅此而已。case(case(0if(x==C1)beginx<=x+8'd10;Act1=Act1+1'b1;endif(y==C1)beginy<=y+1'b1;Act2<=Act1;endif(C1==100-1)beginx<=8'd0;y<=8'd0;C1<=8'd0;i<=i+1'b1;endelseC1<=C1+1'b1;有关exp1.7aAct2Act1Act1的“即时值”更作为赋值基础,而不是以该时每一次更新间隔是10个时钟。for(for(intx=0;x<10;x++{Act1=for(inty=0;y<10;y++)}forAct1Act2Act2++,换做VerilogHDL语言我们又如何是好!?case(case(iif(x==C1)beginx<=x+8'd10;Act1<=Act2;if(y==C1)beginy<=y+1'b1;Act2<=Act2+1'b1;if(C1==100-1)beginx<=8'd0;y<=8'd0;C1<=8'd0;i<=i+1'b1;endelseC1<=C1+1'b1;case(case(iif(x==C1)beginx<=x+8'd10;Act1=Act2;if(y==C1)beginy<=y+1'b1;Act2<=Act2+1'b1;if(C1==100-1)beginx<=8'd0;y<=8'd0;C1<=8'd0;i<=i+1'b1;endelseC1<=C1+1'b1;1.7e(exp1_7b仿真结果图1.7e了,基本上两段代码的效果都是一样的...为什么呢(⊙_⊙)?答案很简单因分,由于Act2的时序关系还是用图形来说话:T1表示了初始化的状态,T0~T9Act2T10Act1ifxC1的条件成立,然后执行Act1<=Act2。在这里Act1是执行时间点,所以赋予Act2是在Act1Act2Act2Act1唯有的把Act2的过去值当着赋值基础for(for(intx=0;x<10;x++{for(inty=0;y<10;y++)}case(case(0if(x==10)beginx<=8'd0;y<=8'd0;i<=i+1'b1;elseif(y==10)beginx<=x+1'b1;y<=8'd0;Act2<=Act2+1'b1;endelsebeginy<=y+1'b1;Act1<=Act1+1'b1;endfor(for(intx=0;x<10;x++{for(inty=0;y<10;y++)}case(case(0if(x=10)beginx<=8'd0;i<=i+4'd2;elsebeginAct2<=i+1'b1;x<=x+1'b1;i<=i+1'b1;if(y==10)beginy<=8'd0;i<=i-1'b1;elsebeginAct1<=Act1+1'b1;y<=y+1'b1;end;2:......for(for(intx=0;x<10;x++{for(inty=0;y<10;y++{for(intz=0;z<10;z++)}}VerilogHDLcase(case(0if(x==10)beginx<=8'd0;y<=8'd0;i<=i+1'b1;elseif(y==10)beginx<=x+1'b1;y<=8'd0;Act3<=Act3+1'b1;endelseif(z==10)beginy<=y+1'b1;z<=8'd0;Act2<=Act2+1'b1;endelsebeginAct1<=Act1+1'b1;z<=z+1'b1;endfor循环呢?”如果读者还停留在“建模篇”脚步的话,笔者不会责怪的,原因很简单~换句话说,用步骤实现的for循环,在时钟上的消耗,在时序上表现是被隐藏的。如果读者for(for(intx=0;x<10;x++{for(inty=0;y<10;y++)Act1=Act2;}case(case(0beginAct2<=Act2+1'b1;i<=i+1'b1;beginAct1<=Act1+1'b1;i<=i+1'b1;骤”来理解,亦即步骤1执行Act2++,然后步骤2执行Act1++。VerilogHDL0Act2Act21'b1;1执行Act1<=Act1+1'b1;面笔者已经,如果单个步骤仅使用1个时钟的话,那么我们可以说“步骤i有指向时钟的功能”,我们先放开“概念”不说,那么余下自然而然只有“时钟”而已。只要我们搞清楚这个简单的原理,那么VerilogHDL语言可以这样写:exp1_8acase(case(iif(x==C1)beginx<=x+8'd10;Act2<=(x!=101-1)?Act2+1'b1:Act2;endif(y+1==C1)beginy<=y+1'b1;Act1<=Act2;endif(C1==101-1)beginx<=8'd0;y<=8'd0;i<=i+1'b1;endelseC1<=C1+1'b1;exp1_7cif(C1101-1)101-1表示在x,y和i等更新是发生在最后一个时钟。xAct2,yAct1,xy均为每一个时钟更新一次。其中的(x!=101-1)表示100个时钟执行Act2+1'b1,反之就不操作。其中的(y+1==C1)表示Act1的操作延迟一个时钟。C11001C110110101个时钟?原因很简单,在这Act1Act2100个时钟基本上是不足的。所以必须加上一个延迟所消耗的时钟。乍看下Act2的执行优先级比起Act1的优先级更高,其实是Act2比起Act1早一个时钟执行罢了.......xx8'd10xx1011Act21'b11.8aexp1_8a2。在另一方面,Act11T1T1Act1Act21。for(for(intx=0;x<10;x++{for(inty=0;y<10;y++)Act1=Act2;}递增Act2Act110Act21~2x10VerilogHDLT0Act2T1~T10Act1Act210T10同一Act2Act1T11~T20Act210次。以上的执行直到101个时钟经过。嗯,读者不要用困惑的表情面着笔者呀,笔者也知道这样很难理解~没法子呀,谁叫不习惯时序的概念。顶多这样吧!笔者再绘制一段时序图给消消气:10次(Act110010Act1仅“重复赋值”Act2的值而已。在这里,读者是不是明白“为什么步骤0需要101个时钟”的原因了吧?1.8d11T90~T100Act2中有这样的一句Act2<=(x!=100-1)?Act2+1'b1Act2;这是一种扩展目的的表达式,目的是为了Act2在T100的时候再一次递增,否则就破坏了嵌入for循环的仿效了。此外,继续。当读者看到这里,是否几乎要的问:“笔者你从前几章开始就一直有完没完的用VerilogHDLfor循环,不是用[步骤]而是用[时序]。以你的性格我们知道笔者一定又在卖关子....行了!算我膜拜大人你,告诉我们吧...”(⊙o)啊!串口发送模块是建模篇一个经典实例...笔者是不是搞错了??呵呵,没有串口发送模块的“图形”还是老样子,这真的激起笔者许多的回忆呀废话少说,还是切(1/115.2k)(1/115.2k)/=(1/115200)/(1/20E+6TX_En_SiginputinputinputTX_En_Sig,outputif(!RSTni<=C1<=rData<=rPin<=isDone<=case(ibeginrData<={2'b11,TX_Data,1'b0};i<=i+1'b1;if(C1==B115K2-1)beginC1<=8'd0;i<=i+1'b1;elsebeginrPin<=rData[i-1];C1<=C1+1'b1;beginisDone<=1'b1;i<=i+1'b1;beginisDone<=1'b0;i<=4'd0;assignTX_Pin_Out=63.63.(40~4的值,这里rData<={2'b11TX_Data1'b0}表示[0]起始位;[1:8]数据位;[9]校验位;[10]步骤12~13(47~51行)是产生完成信号的步骤。n111*1742结果一个串口发送模块每一次启动需要消耗1917*50ns=95.85us。`timescale1ns/1moduleregCLK;regregTX_En_Sig;wireTX_Pin_Out;tx_moduleU1( RSTn=0;#1000RSTn=CLK=1;forever#25CLK=regalways@(posedgeCLKornegedgeRSTnif(!RSTnTX_En_Sig<=TX_Data<=i<=case(iif(TX_Done_Sig)beginTX_En_Sig<=1'b0;i<=i+1'b1;elsebeginTX_Data<= ;TX_En_Sig<=1'b1;i<=这个是激励文本,第1行是仿真的时钟单位,亦即时间刻度,在这里就填上1ns。第16~24行是实例化仿真对象。第28~32行是复位信号和时钟信号的产生和刺激,笔者近似的模仿黑金开发板的环境。也就是说复位时间是1us时钟周期是50ns。步骤0(48~50行)是启动串口发送模块发送一帧为8'b 的数据。步骤1(52~53行)是停留(有点像单片机中的while(1);)(96900.083ns-1049.99ns=96900-1050=95850ns,95.85us 1~1595.85us...⊙﹏⊙b汗!我们再整合化得功能可以非常清晰的指向时钟。1.8a(控制信号,那么咱要如何控制这个模块呢?”面笔者已经了,就是因为模块的消耗时钟无法被评估的原因,所以我们才需要使用Done_Sig控制信号来反馈模块的完成。念”的基础知识,不懂的朋友需要最好先去复习先,以免看不懂笔者在说什么...inputinputinputTX_En_Sig,inputoutput[10:0]SQ_C1regreg[10:0]C1;regregregalways@(posedgeCLKornegedgeRSTn)if(!RSTn)i<=rData<=11'd0;C1<=11'd0;x<=rPin<=elseif(TX_En_Sig)rData={2'b11,TX_Data,1'b0if(x==C1)beginx<=x+11'd174;rPin<=rData[i];i<=i+1'b1;endif(C1==1914-1)beginx<=11'd0;i<=4'd0;C1<=11'd0;endelseC1<=C1+assignTX_Pin_Out=rPin;assignSQ_C1=呵呵呵,估计有些朋友又要学马骝抓头皮了这一回的串口发送模块,笔者使用“循环操3~1313SQ_C1是仿真用的。18~2220C121行的x是用来控制循环操作的次数。-11914个时钟,“1beginx11'd0i4'd0C111'd0;191437if(x==C1)x寄存器用来控制循环操作,则x<=x+174表示每一个循环操作的间隔是174个时钟。36rData2'b11,TX_Data,1'b0};rDatarData也表示了这个串口发送模块的帧信息的配置,亦即[0]起始位[8:1]数据位[9]校验位[10]停止位,也"=",原因很简单-就是为了取得即时结果,用其他的话来说是为了节省rData更新时所消耗的一个时钟。第37行的i是用来计数,也作为rData的下标寻址。TX_En_Sig拉高的时候,就以T0开始吧,在这个瞬间rData以举得即时结果,假设C1if(x==C1)x<=x+174rPin也成rData[0][0]iT0的未来,x174,rPin是0,i是1。T174的时候,fxC1)xx174rPin也成功赋rData[1][1]iT174的未来,x348,rPin是1,i是2。T1384的时候,fx==C1)x<=x+174rPin也成功rPin是0,i是3。T522的时候,fxC1)xx174rPin也成功赋rData[3][3]2iT522的未来,x696,rPin是1,i是4。T696的时候,fxC1)xx174rPin也成功赋rData[4][4]3iT696的未来,x870,rPin是0,i是5。T870的时候,fxC1)xx174rPin也成功赋rPin是1,i是6。T1044的时候,fx==C1)x<=x+174rPin也成功rData[6][6]5iT1044的未来,x是1218,rPin是0,i是7。T1218的时候,fx==C1)x<=x+174rPin也成功rData[7][7]6iT1218的未来,x是1392,rPin是1,i是8。T1392的时候,fx==C1)x<=x+174rPin也成功rData[8][8]7iT1392的未来,x是1566,rPin是0,i是9。T1566的时候,fx==C1)x<=x+174rPin也成功rData[9][9]iT1566的未来,x1740,rPin是1,i是10。T1740的时候,fx==C1)x<=x+174rPin也成功1,i11。注意呀,从T1740之后x和i就没有作为了。rPin会拉高直到时钟的T1914,在期间T1913,C1,x和i寄存器都会,那么一帧数据`timescale1ns/1moduleregCLK;regregTX_En_Sig;regwirewire[10:0]SQ_C1;.SQ_C1(SQ_C1RSTn=0;#1000RSTn=CLK=1;forever#25CLK=regregalways@(posedgeCLKornegedgeRSTnif(!RSTni<=TX_En_Sig<=TX_Data<=C1<=case(iif(C1==1914-1)beginC1<=11'd0;i<=i+1'b1;elsebeginC1<=C1+1'b1;TX_En_Sig<=1'b1;TX_Data<=;beginTX_En_Sig<=1'b0;i<=i+1'b1;if(C1==1914-1)beginC1<=11'd0;i<=i+1'b1;elsebeginC1<=C1+1'b1;TX_En_Sig<=1'b1;TX_Data<=;if(C1==1914-1)beginC1<=11'd0;i<=i+1'b1;elsebeginC1<=C1+1'b1;TX_En_Sig<=1'b1;TX_Data<=;beginTX_En_Sig<=1'b0;i<=i+1'b1;i<=第50~71行是.vt文件对于.v文件的激励过 读者是不是觉得类似的写法很眼熟呢FIFO0:0:beginWrite_Req_Sig<=1'b1;FIFO_Write_Data<=8'hff;i<=i+1'b1;1:beginWrite_Req_Sig<=1'b0;i<=i+1'b1;01之间的经过恰恰好就是给足了FIFO一个时钟可以消耗的时钟。1.10aFIFOT0Write_Req_Sig和向FIFO_Write_Data8'hffT1Write_Req_SigT1FIFO就8'hffT1的未来8'hffFIFO存入。 根据“模块沟通”的原理,模块之间的沟通至少需要一个时钟的延 如果在“模块之....1.10b....T0Write_Req_Sig和写8'hffFIFO就会在瞬间存入数据事实上这是不可能会发生的!!!0:0:beginWrite_Req_Sig<=1'b1;FIFO_Write_Data<=8'hff;i<=i+1'b1;end1:beginWrite_Req_Sig<=1'b0;i<=i+1'b1;end2:beginWrite_Req_Sig<=1'b1;FIFO_Write_Data<=8'hee;i<=i+1'b1;3:beginWrite_Req_Sig<=1'b0;i<=i+1'b1;(0:0:beginWrite_Req_Sig<=1'b1;FIFO_Write_Data<=8'hff;i<=i+1'b1;end1:beginWrite_Req_Sig<=1'b1;FIFO_Write_Data<=8'hee;i<=i+1'b1;2:beginWrite_Req_Sig<=1'b0;i<=i+1'b1;1.10d(连续写入数据FIFO1.10d的经过。嗯~初学的同学笔者还是比较推荐使用一个深度一个深度的写入数据至此笔者依然还是喜爱一个深度一个深度的方法~解读能力高吗~(*^^*)。启动一次需要消耗消耗1914个时钟的话同样的道理,我们可以使用循环保持的方法,为TX_En_SigTX_Data19141914个时钟经过,再来拉低就是这么一回事。第61~70(步骤)行是连续启动串口发送模块,至于理解的方式和连续向FIFO写入数据一样。在代码的理解上就是这么容易,但是要在时序图中看明白,还真需要几分细心对于笔者来说更需要几分的耐心,把所有重点都表达出来...1.10e是tx_module.v的仿真初头,根据串口的协议串口发送端在闲置的状态下输出始终T0~T1之间(1~2之间,就是.vt和.v模块之间沟通的延迟。T1的时候(2).vTX_En_Sig1C1.vt的始终计数,SQ_C1.v20Mhz115.2k波特率的8700ns/50ns=觉得有点怪呢?咕~~(╯﹏╰)b...请读者了,无论是循环保留还是循环操作,笔者都和.v分开来看。12~13.vt0C1i。光标13~14.vSQ_C1xi下标寄存器。读者是不是看到其中的不同呢?就是.v文件时钟比.vt慢一个时钟。.vt13.vt01913个时钟,亦即清楚和更14.vt11TX_En_Sig,并且更新步15是指向步骤2,这个待会儿再谈。.v14.v1913个时钟,亦即清楚相关的寄存器。15.v文件停在闲置状态(15指向的同时,TX_En_Sig的过去值是低电平15~16.v16是指向第二帧数据发送的开1.10q1.vt201~2.vt.v1.10e很相似不同的是,图1.10e是第一帧发送数据发送的开始,而图1.10q是第二帧发送数据的开始。光标3~4是指向.vt步骤~的最后一个时钟,该动作是C1然后更新步骤i。在这里我们4~5是指向.vt2第三帧数据发送的启动开始。光标4~5是指向.v发送第二帧数据的最后一个时钟,该动作就是SQ_C1,x和i等寄存器。光标5是指向.v第三帧数据发送的开始。1.10s...6.vt77~8.v中在发送第三帧数据中的最后一个时钟,就是清除相关的寄存器。之后就是无限闲置中......tx_module2.v的仿真过程中,几乎一个时钟也没有被浪...tx_module.vttx_module2.v的过程中,不Start_Sig和Done_Sigtx_module2.v就FIFO的方法既然也适合用于解释本章的实验,但是Start_SigDone_Sig,毕竟用久了多少都有感情。还是那一句|Read_Req_SigFull_Sig|Empty_Sig。也就是说控制信号是双向的,不然的话要有效的控制LUT-LookUpTable就是查表的意思,早期在建模篇里任何有关图像信息的,笔者都会建立rom模块来保存。我们先举个简单的例子:信息16个信息(Rom_Addr位宽为四位)按次序写入ram模块里。ROM_Addr4'd0空间的信息对应RAM_Addr4'd0的空间。ROM_Addr4'd1空间的信息对应RAM_Addr4'd1的空间。ROM_Addr4'd2空间的信息对应RAM_Addr4'd2的空间。ROM_Addr4'd3空间的信息对应RAM_Addr4'd3的空间。ROM_Addr4'd4空间的信息对应RAM_Addr4'd4的空间。ROM_Addr4'd5空间的信息对应RAM_Addr4'd5的空间。ROM_Addr4'd6空间的信息对应RAM_Addr4'd6的空间。ROM_Addr4'd7空间的信息对应RAM_Addr4'd7的空间。ROM_Addr4'd8空间的信息对应RAM_Addr4'd8的空间。ROM_Addr4'd9空间的信息对应RAM_Addr4'd9的空间。ROM_Addr4'd10RAM_Addr4'd10的空间。ROM_Addr4'd11RAM_Addr4'd11的空间。ROM_Addr4'd12RAM_Addr4'd12的空间。ROM_Addr4'd13RAM_Addr4'd13的空间。ROM_Addr4'd14RAM_Addr4'd14的空间。ROM_Addr4'd15RAM_Addr4'd15case(case(iif(x==16)beginx<=5'd0;i<=i+1'b1;elsebeginrROM<=x;rRAM<=x;isWrite<=1'b1;x<=x+1'b1;ramrom模块中查表的,根据"模块沟通的原理rom模块的至少的结果会如图1.11b,图像发生了右移现象。1.11c。但是,这始终都是骗小孩的把戏而已~呵呵!笔者在此,再一次的强调这个骗小孩的把戏只适合用于处理图像信息而已...要完全解决在时序上被延迟的问题,我们还是得在时序上了解问题的1.11d(实验五的仿真环境在这里笔者建立用于仿真实验五的环境,exp5_env.v1.11e(rom模块中包含的图像信息inputinputinputoutputregalways@(posedgeCLKornegedgeRSTnif(!RSTnrData<=case(ROM_Addr0:rData<=1:rData<=2:rData<=3:rData<=4:rData<=5:rData<=6:rData<=7:rData<=8:rData<=9:rData<=10:rData<=11:rData<=12:rData<=13:rData<=14:rData<=15:rData<=assignROM_Data=rData; 47.了...modulemodule(inputinputinputoutputoutputoutput12. regregreg[3:0]rROM,regregalways@(posedgeCLKornegedgeRSTnif(!RSTni<=x<=rROM<=rRAM<=isDone<=elseif(Start_Sigcase(i if(x==16)beginx<=5'd0;isWrite<=1'b0;i<=i+1'b1; elsebeginrROM<=x[3:0];rRAM<=x[3:0];isWrite<=1'b1;x<=x+1'b1;end beginisDone<=1'b1;i<=i+1'b1;end beginisDone<=1'b0;i<=2'd0;end assignROM_Addr=assignRAM_Addr=assignDone_Sig=control_module.v0(35~37行)rom模块moduleexp5_envinputinputinputStart_Sig,output[7:0]ROM_Data,output[3:0]RAM_Addr,outputWrite_En_Sig,output[3:0]SQ_ROM_Addrwire.CLK(CLK.RSTn(RSTn.CLK(CLK.RSTn(RSTnassignSQ_ROM_Addr=ROM_Addr;以上是exp5_env.v...`timescale1ps/1moduleregCLK;regregStart_Sig;wire[7:0]ROM_Data;wireWrite_En_Sig;exp5_envU1( RSTn=0;#1000RSTn=CLK=0;forever#25CLK=regalways@(posedgeCLKornegedgeRSTnif(!RSTni<=case(i if(Done_Sig)beginStart_Sig<=1'b0;i<=i+1'b1; elseStart_Sig<= i<= 62. 的是时序图,亦即rom模块对于时钟的消耗“为零”作为前提。就举时钟T1来解释吧:romT1romSQ_ROM_Addr-0ROM_Data会取得“即时结果”-8'h7eRAM模块提Write_En_Sig1,RAM_Addr1。结果“rom0的数据-8'h7e就会存入ram模块中地址为0的地方。”但是仿真结果悄悄好不是如此,由于rom模块实际上会消耗掉一个时钟,所以造成了ROM_DataWrite_En_SigRAM_Addr迟了一个时钟。结果造成了这三个信号图1.11g的仿真结果是有rom模块不延迟了一个时钟所造成的意外。其中光标1指向的1.vT1.vWrite_En_Sig和输出SQ_ROM_Addr和RAM_Addr。在这里请读者稍微注意一下,光标1之前所有模块内部相关的寄存器都为,理应驱动ROMSQ_ROM_Addr0。换句话说,ROM_Data在复位的默认下的输出初值是看似这个结果和预期中的时序图很接近,实际上它存在BUG。用前面的话来说,此时ROM_Data的8'b0111_11108'b0111_1110,而不是在这个时间点里从ROM模块中的8'b0111_1110。而在这个时间点中在rom模块中所请求地址-0的数据8'b0111_1110会在下一个时间点里才有效...好了,这次的结果明显有错误了,而且非常露骨。其中ROM_Data的8'b0111_1110,是在T1rom0T18'b0111_1110T2中更T2时ROM_Data的数据应为8'b0100_0010...o(╯□╰)o......如此重复,最终头时钟发生什么事?时间点?即件?”别傻了,参考书不会告诉这一些事儿的,很多参考书都是为目的,内容的焦点都是VerilogHDL语言的性质”不说了,不说了!不然又要气火伤身了...rom模块保存的对象是图像信息的话,那么可以在图像信息的上下左右方都留如果我们无视RTL级的建模那么我们可以把rom模块设计成为组合逻 结rom模块既遵守即件而不会在时序上有任何关心。但是这个方法有许多后遗症,组合逻辑一般上可以的话都要尽量的少用,尤其是rom这般为信息为目的的模骗过读者的感 笔者真的很惭愧!第二个方法笔者也不演示了,没有任何学习的目的Bypassregister称为过路|Clockdelayregister“时钟延迟寄存器”基本上它们是同一样东西,只是在作用不同称呼也不同而已。图1.12a是经过修改的实验五,笔者从新命名为实验六至于又为Write_En_Sig和Ram_Addr加上过路寄存器。实验六的思,Write_En_SigRAM_AddrROM_AddrROM_Datamoduleexp6_envinputinputinputStart_Sig,output[7:0]ROM_Data,output[3:0]RAM_Addr,outputWrite_En_Sig,output[3:0]SQ_ROM_Addrwirewirewire(.CLK(CLK.RSTn(RSTn (.CLK(CLK.RSTn(RSTn regregalways@(posedgeCLKornegedgeRSTnif(!RSTnrBy1<=rBy2<=rBy1<=rBy2<=assignSQ_ROM_Addr=assignRAM_Addr=exp6_env.v和exp5_env.v相比只是组合模块的内容修改了一点而已。第33~34行的Write_En_Sig和RAM_Addr没有直接驱动顶层的输出口,反之是连线至U1_Write_En_SigU1_RAM_Addr49~62行的过路寄存器里。其中笔者了一位位宽的rBy1和四位

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论