verilog-hdl故事之刺激和激励过程_第1页
verilog-hdl故事之刺激和激励过程_第2页
verilog-hdl故事之刺激和激励过程_第3页
verilog-hdl故事之刺激和激励过程_第4页
verilog-hdl故事之刺激和激励过程_第5页
免费预览已结束,剩余50页可下载查看

下载本文档

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

文档简介

第六章刺激和激励过 精密计 实验二十一:仿真定时 刺激的各种输 实验二十二之一:虚拟按 实验二十二之二:仿真按键消抖模 实验二十三:PS2模块仿 模块相互刺 实验二十四之一:仿真串口发送模 实验二十四之二:仿真串口接收模 麻烦的IO口仿 实验二十五:仿真带有IO的模 总 精密计”。当我们开始仿真稍微复杂的模块,实验二十一:仿真定这个实验很简单,我们只要建立两个定时器,一1us产生定时,则另一个在3us产inputCLK,output_1US,output_3US,output_is1US,output_is3US,outputoutput12.parameterT1US=reg[4:0]Count_1US;regalways@(posedgeCLKornegedgeRSTn)if(!RSTn)beginCount_1US<=5'd0;is1US<=1'b0;endelseif(Count1US==T1US)beginCount_1US<=5'd0;is1US<=1'b1;beginCount_1US<=Count_1US+1'b1;is1US=1'b0;parameterT3US=6'd60;regis3US;always@(posedgeCLKornegedgeRSTn)if(!RSTn)beginCount_3US<=6'd0;is3US<=1'b0;endelseif(Count_3US==T3US)beginCount_3US<=6'd0;is3US<=1'b1;beginCount_3US<=Count_3US+1'b1;is3US<=1'b0;assign_1US=(Count_1US==T1US)?1'b1:1'b0;assign_3US=(Count_3US==T3US)?1'b1:1'b0;assign_is1US=is1US;assign_is3US=is3US;assignC1=Count_1US;assignC2=59.时器。第33行是3us的常量,第37行是3us的标志寄存器is3US。第40~46是3us501us51行是由组合逻辑驱动的3us定时标志52行是is1US标志寄存器驱动的1us定时标志53行是is3US标志寄存器驱动的3us定时标志。第54~55行则是,计数寄存器Count_1US和Count_3US的相关输出。`timescale1ns/1moduleregregwirewirewirewirewirewire(._is1US(_is1US._is3US(_is3US.C1(C1.C2(C2 RSTn=0;#1000;RSTn=CLK=0;forever#25CLK=4~8.v的输入输出一致。此外(在10~20行)都是先实例化要仿真的模块,然后(在22~26行——)再建立时钟信号和复位行,在建立虚拟环境的规4~5行表示了输入7~8行表示了输出10~20行是测试模块的实例化。第22~26行是时钟信号和复位信号,复位信号拉低1us的时间(实际情况是1us~6us),时钟信号近似了黑金开发板上的时钟频率,亦即20Mhz。一个时间周期为50ns,所以半个时钟周期为25ns。仿真结在上图仿真的仿真结果是从复位信号拉低开始到3us定时信号产生。在这里笔者建立的近似黑金开发板的虚拟环境,其中时间周期为50ns,复位时间为1us。在复位信号RSTn拉高以后,.v开始工作。上图是1us不同方式的定时结果。(Cursor省略为C)C1~C2之间表示了由组合逻辑驱动的定时标志,在还未满1us,亦T18的时候.v它“决定”拉高_1US一个时钟(C1,计数到C1~C3之间表示了由寄1us定时,在满1us产生的时候,它产生定时信上图是3us不同方式的定时结果。(Cursor省略为C)C1~C4之间表示了由组合逻辑驱动的定时标志,在还未满3us,亦3.975ns1.025ns2.95ns的时候它产生了定时信号。2.95us50ns59T0T58.v_3US一个时钟(注意:这时候的计C259T58的未来_3US被拉高一个时钟。C1~C5之间表示了由寄3us定时3us产生的时候,它产生定时信3us50ns60T0T59.v_is3US实验二十这个实验的目的不是要产密度很高的定时,实现紧密计数。在以往的实验,步骤和时钟之间的相差,都是一个又一个的时钟而已。一旦,某个模块的执行步骤是不固定,又或者时钟消耗高,我们再也不可能一个又一个去计数时钟。相反的,这时候须取得时钟和时钟相差的时间,然后再除与源时钟周期,才能取得真正的“第几个时钟数”。在实验二十一的仿真中,我T18_1US“决定”被拉高,在T19_is1US“决定”被拉T58_3US“决定”被拉高,在T59_is3US“决此外从仿真结果我们还得到几个信很多朋友常常在建立定时器的时候,假设以20Mhz的时钟频率为例。我要建立1us的定时器那么1us的常量会是20-1=19,1us的常量为什么是19!?很多朋友会回答,应为定时器从0开始算起,这是一个我们建立定时器的时候的错觉。实际的1us常量是我们先假设一个,内建定时器的流水alwaysalways@(posedgeCLKif(Count_US==T1US)Count_US<=5'd0;elseCount_US<=Counter_US+1'b1;case(i0,1,2,3,4,5,6,if(Count_US==T1US)beginLED<=(4'h01<<i);i<=i+1'b1;T1US的常量为190.95us1us。反之,T1US的常量的为20,那么流水灯的时间间隔是1us。在实验二十一中,_1US_3US定时信号时由逻辑组合驱动的。它们比起定时器驱动我们再来假设一个流水灯的1uscounter.v,流水灯效果建立在另一个单个模块led.v。output //output //parameterT1US //assign_1US=(Count_US==T1US)?1'b1:1'b0;assign_is1US=is1US;input_1US,inputcase(i0,1,2,3,4,5,6,if(_1US)beginLED_A<=(4'h01<<i);i<=i+1'b1;case(j0,1,2,3,4,5,6,if(_is1US)beginLED_B<=(4'h01<< );j<=j+1'b1;1us_is1US1us之后LED_B的流水灯效果,实1.00us+0.05us1us_1US1us前LED_A的流水灯效果是0.95us+0.05us,亦即准1us。事实上在应用中,只有完美的家伙(偏激狂)才有“完美时钟的要求”。少一个时钟还是实验二十在实验二十一中,我们实现了近似“黑金开发板”虚拟环境,用于仿真模块counter_module.v。虚拟环境在仿真中视一个非常的概念(笔者认为而已,因为我们所这里counter_module.v比较简单,笔者只是建立近似“黑金开发板”的时钟信号和复位信号而 刺激的各种输实验二十二之一:虚拟对!这就是笔者要的问题。当我们要仿真按键去抖模块的时候,我们要建立一个“虚拟按输入产生变化的时候,它就会产生8ms的“假抖动”。inputinputinputoutputregalways@(posedgeCLKornegedgeRSTnif(!RSTnF1<=F2<=F1<=F2<=parameterT8MS=18'd160000; regregalways@(posedgeCLKornegedgeRSTnif(!RSTnCount_8MS<=elseif(Count_8MS==T8MS&&isCountCount_8MS<=elseif(isCountCount_8MS<=Count_8MS+elseif(!isCountCount_8MS<=regregalways@(posedgeCLKornegedgeRSTnif(!RSTni<=isBounce<=isCount<=case(i if(F1!=F2)i<=i+ if(Count_8MS==T8MS)beginisCount<=1'b0;isBounce<=1'b0;i<=4'd8; elsebeginisCount<=1'b1;isBounce<=1'b0;i<=i+1'b1;end if(Count_8MS==T8MS)beginisCount<=1'b0;isBounce<=1'b0;i<=4'd8; elsebeginisBounce<=1'b1;i<=i+1'b1;end if(Count_8MS==T8MS)beginisCount<=1'b0;isBounce<=1'b0;i<=4'd8; elsei<= if(F1!=F2)i<=i+ if(Count_8MS==T8MS)beginisCount<=1'b0;isBounce<=1'b1;i<=4'd0; elsebeginisCount<=1'b1;isBounce<=1'b1;i<=i+1'b1;end if(Count_8MS==T8MS)beginisCount<=1'b0;isBounce<=1'b1;i<=4'd0; elsebeginisBounce<=1'b0;i<=i+1'b1;end if(Count_8MS==T8MS)beginisCount<=1'b0;isBounce<=1'b0;i<=4'd0;elsei<= 99.计数器,isCount寄存器用来使能这个计数(33行。在50~91行是该模块的功能,Q_SigisBounce寄存器用来驱动Q_Sig,所以isBounce1。0(60~61行)In_SigIn_Sigi,以示下一个步骤。步1~34~6,是执行抖动的操作。在步骤1~3,使能计数器(isCount赋值1)同时间,拉低isBounce(65行。步骤4~6,是拉高isBounce(69行。抖动产生的原理很简单,就是拉低isBounce,3个时钟,然后拉高isBounce,3个时钟。步骤7是指i返回步1(73行。在1~7if条件都在判8ms已经完成计数,8ms已经达到,那么不使能isCount(isCount赋值0),然后拉低isBounce,最后i指示步骤8(64,68,72行)。换句话,如果在步骤1~7之间,8ms的计数还没有达到的话,步骤1~7就会一直重复,isBounce会不停的拉低又拉高,从而产生出“假抖动”。8(75~76行In_SigIn_Sig的电平产生变化,就递增i以示下一步步骤。9~11和步骤12~14,同样也是执行抖动的操作。在步骤9~11,使能计数器(isCount赋值1)同时间,拉高isBounce(80行。步骤12~14,是拉低isBounce(84行。抖动产生的原理很简单,就是拉高isBounce,3个时钟,然后拉第isBounce,3个时钟。步骤15是指i返回9(88行。在步骤9~14if条件都在判断是8ms已经完成计数,如果8ms已经达到,那么不使能isCount(isCount赋值逻辑0),然后拉高isBounceii0(7983,87行)。换句话,如果在步骤9~14之间,8ms的计数还没有达到的话,步骤9~14就会一直重复,isBounce会不停的拉高又拉低,从而产生出“假抖动”。`timescale1ns/1regCLK;regregIn_Sig;wirevir_key_moduleU1( RSTn=0;#1000;RSTn=CLK=0;forever#25CLK=parameterT1MS=15'd20000; regregregregalways@(posedgeCLKornegedgeRSTnif(!RSTnCount1<=Count_MS<=elseif(isCount&&Count_MS==rTimesCount1<=Count_MS<=elseif(isCount&&Count1==T1MSCount1<=Count_MS<=Count_MS+elseif(isCountCount1<=Count1+elseif(!isCount)Count1<=15'd0;Count_MS<=10'd0;regalways@(posedgeCLKornegedgeRSTn)if(!RSTn)In_Sig<=1'b1;isCount<=1'b0;rTimes<=10'd0;i<=4'd0;case(iif(isCount&&Count_MS==rTimes)beginisCount<=1'b0;i<=i+1'b1;endelsebeginisCount<=1'b1;rTimes<=10'd1;endbeginIn_Sig<=1'b0;i<=i+1'b1;if(isCount&&Count_MS==rTimes)beginisCount<=1'b0;i<=i+1'b1;endelsebeginisCount<=1'b1;rTimes<=10'd12;endbeginIn_Sig<=1'b1;i<=4'd3;在23~26行是近似黑金开发板的时钟信号和复位信号。复位时间为1us,时钟周期为50ns。第30行是1ms的常量,39~63行是ms级的计数器。rTimes寄存器是用来寄存ms时间(36行。isCount寄存器是用来使能该计数器(37行64~94行是vir_key_module仿真的激励过程。In_Sig1(72行01ms的延迟(80~82行1是拉In_Sig(84~85行。步212ms的延迟(87~89行。步3是拉高In_Sig,然后停止动作(91~92行。12ms过后释放按键。就是这么简单。仿真结第一张仿真结果说明了,在激励过程-步骤0中,我们发呆了1ms。注意In_Sig空闲时Q_Sig是低电平触发的关系,所以同样在空闲时都是处于高电平。注意In_Sig被拉低过后不久,Q_Sig开始不稳定了(抖动开始产生了。第三张仿真图说明了,在激励过程中-步骤0~3发生的事情。我们先发呆1ms,然后按下(In_SigQ_Sig都是处于高电平。当“虚拟按键”被按下的时候,抖动开始产生了,抖动的过程大约是8ms,然后接下来是4ms的低电平。当4ms上述的结果告诉我们一个事实,由于我们在“现实中”先发呆1ms,然后按下“虚拟按键”12ms,12ms(第三张图,才会出现如此的情形。当“虚拟按键”先产生8ms的抖动,然后是4ms的低电平(这是因为我们按下“虚拟按键”12ms的关系,12ms减去8ms等于4ms。当我们释放“虚拟按键”的时候,又产生8ms的抖动,然后是的高电平(当我们释放“虚拟按键”之后,就结束动作了。实验二十二之一说5~10ms,在实验二十二之一中我们建立了近似的vir_key_module.v(如上图。vir_key_module.v8ms,然而抖505050505050ns300ns(33个时钟F=1/=1/=(...这不过这是“虚拟按键”而已,不要太介意,不要太介意,最后重要的还是抖动时间。)在激励过程冲,我们在“假现实”中先发呆1ms,然后再按下“虚拟按键”12ms,12ms过后释放“虚拟按键”,继续发呆。所以在仿真结果中出现,Q_Sig先拉高大约1ms,然后抖动大约8ms,再然后低电平4ms,过后再抖动8ms,最后保持高电平到。实验二十二之一结在这一个实验中vir_key_module.vt是vir_key_module.v的激励文件(激励过程。其中在.vt文件In_Sig拉高又拉低,它是.v文件的简单输入。但是在未来里vir_key_module.v将会是debounce_module.v的复杂输入。实验二十二之二:仿真按键消抖这个实验我们要仿真在《VerilogHDL那些事儿-建模篇》中实验三的按键消抖模块。上图显示了,虚拟按键模块和按键消抖模块组合在虚拟环境-env_debounce_module.v中。在这里,env_debounce_module.v虽然是组合模块,但是它已经不是低级建模中定我们稍微回忆一下按键消抖模块的功能:10ms然后拉低Pin_Out。inputCLK,inputIn_Sig,output10.wire.CLK(CLK.RSTn(RSTn.In_Sig(In_Sig.QSig(QSig.CLK(CLK.RSTn(RSTn.Pin_In(Q_Sig.Pin_Out(Pin_OutassignSQ_Q_Sig=Q_Sig;41.16~22行实例化了虚拟按键模块26~32行实例化了按键消抖模块。36行将虚拟(env_debounce_module.v再也不是低级建模定义中的组合模块,而是一个仿真用的虚拟`timescale1ns/1regCLK;regregIn_Sig;wireenv_debounce_module(.CLK(CLK.RSTn(RSTn.In_Sig(In_Sig RSTn=0;#1000;RSTn=CLK=0;forever#25CLK=parameterT1MS=15'd20000; regregregregalways@(posedgeCLKornegedgeRSTnif(!RSTnCount1<=Count_MS<=elseif(isCount&&Count_MS==rTimesCount1<=Count_MS<=elseif(isCount&&Count1==T1MSCount1<=Count_MS<=Count_MS+elseif(isCountCount1<=Count1+elseif(!isCountCount1<=Count_MS<=regalways@(posedgeCLKornegedgeRSTnif(!RSTnIn_Sig<=isCount<=rTimes<=i<=case(i if(isCount&&Count_MS==rTimes)beginisCount<=1'b0;i<=i+1'b1; elsebeginisCount<=1'b1;rTimes<=10'd1;end beginIn_Sig<=1'b0;i<=i+1'b1;end if(isCount&&Count_MS==rTimes)beginisCount<=1'b0;i<=i+1'b1; elsebeginisCount<=1'b1;rTimes<=10'd12;end beginIn_Sig<=1'b1;i<=4'd3;end 99.在14~21行实例化了要仿真的虚拟环境。在25~29建立了近似“黑金开发板”的和复位信号。第72~97行是激励过程,具体的过程和上一个实验一模一样。仿真结上图仿真结果显示了,按键消抖模块受到虚拟按键模块的刺激后的仿真结果。(Cursor简略为C)C1~C2,表示了当“虚拟按键”按下之后的情况,“虚拟按键”产生8ms的抖动(SQ_Q_Sig。当“虚拟按键”按下之际,按键消抖模块也检测到“虚拟按键”的Q_Sig由高变低,那么按键消抖模块开始过滤抖动10ms,C1~C3。我们知道“虚拟按键”只是产生8ms的抖动而已,然而按键消抖模块过滤抖动的时间是10ms,所以C2~C3表示了按键消抖模块余下的过滤时间。当按键消抖模块消抖时候就会拉高输出,亦即Key_Out输出高电平(C3之后。在C4的时候,“虚拟按键”被释放了,然后“虚拟按键”再一次产生8ms的抖动(SQ_Q_Sig亦即C4~C5。当“虚拟按键”释放之际,按键消抖模块也检测到了,“虚()C5~C6。当按键消抖模块过10ms之后,就拉低Key_Out(C6之后TA.vt1In_Sig,亦即按下0,检查In_Sig的变化。F1F2TAF1读取In_Sig的过去值,亦即逻辑1。在TB之际,F1In_Sig的过去值,亦即逻辑0,然而F2F1的过去值亦即逻辑1所以在TB的时候虚拟按键模块检查到In_Sig的电平产生变化,所以“它决”定产生产生抖Q_Sig的抖动时发TD之后。TDF1到Q_Sig(SQ_Q_Sig)的过去值,亦即逻辑0。在TE的时候,F1到(SQ_Q_Sig)的过去值,亦即逻辑1,F2F1的值,亦即逻辑0。按键消抖模块检测到虚拟按键的输出产生变化,变开始执行消抖10ms的工作。TA~TETA的时候,.vt在步在TA的时虚拟按键模块的F1到In_Sig的过去值是逻辑0然后在TB的时候,F1到In_Sig的过去值是逻辑1,F2F1亦即是逻辑0。在同一个时候,虚拟按In_SigTD8ms的抖动。在TE的时候,按键消抖模块的F1到虚拟按键模块Q_Sig(SQ_Q_Sig)的过去值,亦即0。然TE的时候,有虚拟按键开始产生抖动(Q_Sig产生变化,F1到Q_Sig(SQ_Q_Sig)的过去值是逻辑1,F2F1是逻辑0.在同一个时候,按键消抖模块检查到Q_Sig(SQ_Q_Sig)产生变化,便“决定”执行“过滤消抖10ms”。所以在TE之后的不九(大约2~3个时钟,按键消抖模块就开始执行消抖工作。实验二十二之二说在这个实验的仿真中,In_Sig充当虚拟按键模块的“简单输入”,虚拟按键模块的输出Q_SigQ_Sig信号称为复杂输入呢?我们虚拟按键模块是为了刺激按键消抖模块,然而“现实的按键”的输出带有抖动。笔者也,必须经过特别处理,才可以近似“现实的按输出效我们才称为“复杂输实验二十二之二结在仿真的虚拟环境里,笔者使用了建模的方法,把虚拟按键模块和按键消抖模块组合在同一个环境里。然后在激励文件中,笔者使用了综合的办法编辑激励过这里,笔者没有涉及任何和“验证”有关的语法(时钟信号和复位信号除外,全部的激励过程都是可综合一手包办。读者们可能经过这个实验之后,对仿真的认识是不是更上一层楼呢?VerilogHDL的综...在以往的时候,笔者以为仿真只是观察波形而已。但是日子久了,技术越来越成熟了,仿真的工作不是当初想VerilogHDL的基础。甚至VerilogHDL的建模来得更深不可测。如果读者没有补足好基础的话,在仿真的路实验二十三:PS2模块仿在这里,我们稍微回顾一下PS2模块的大致PS2数据一帧有11位,数据都是在时间的下降沿有效。PS2模块主要是由电平检测模块,检测PS2时钟的下降沿,然后PS2模块,用来过滤处理一帧11位的数据。该PS2模块是通码和断码通吃,但是不吃断码之后的通码。当完成一帧11位的数`timescale1ns/1regCLK;regregwire[7:0]PS2_Data;wireRSTn=0;#1000;RSTn=CLK=0;forever#25CLK=parameterT50US=10'd1000; regregalways@(posedgeCLKornegedgeRSTnif(!RSTnCount1<=elseif(isCount&&Count1==T50USCount1<=elseif(isCountCount1<=Count1+elseif(!isCountCount1<=regregregalways@(posedgeCLKornegedgeRSTnif(!RSTni<=Go<=rData<=case(i//Step(i)1~21isPS2SendFunction if(Count1==T50US)beginisCount<=1'b0;i<=i+1'b1;elsebeginisCount<=1'b1;PS2_CLK_Pin_In<=1'b1;PS2_Data_Pin_In<=rData[i>>1];if(Count1==T50US)beginisCount<=1'b0;i<=i+1'b1;elsebeginisCount<=1'b1;PS2_CLK_Pin_In<=1'b0;22://ReturntonextbeginPS2_CLK_Pin_In<=1'b1;i<=Go;beginrData<={2'b11,8'h1C,1'b0};Go<=i+1'b1;i<=6'd0;beginrData<={2'b11,8'hF0,1'b0};Go<=i+1'b1;i<=6'd0;beginrData<={2'b11,8'h1C,1'b0};Go<=i+1'b1;i<=6'd0;i<=15~23行实例化了要仿真的PS2模块。第27~31行建立了近似“黑金开发板”的环境,亦即时钟信号和复位信号。复位信号拉低1us,然而时钟的周期是50ns。第35行,定义50us39~5050us的定时器。我们知道拥有PS2接口的设备都是慢速设备,而且PS2的时钟频率大约是10KHz,亦即一个时钟周期为100us,半个时钟周期为50us。第54~95行是模仿按键A被按下后又被释放的情况。在55行了寄存器Go是用来返回步骤(仿函数需要用到。第56行了寄存器rData,是用来暂存1帧11位的数([0]开始位,[1~8]数据位,[9]校0~22行是发PS2数据的仿函数0~21(偶数-72~74行PS2时钟和设置(更新)数据数据的操作。步骤0~21(奇数-76~78行,是拉低PS2时钟,用于从机锁存()数据。步骤0~21的每一个操作,都需要等待50us的延迟。步骤22PS2Go指向的步骤(80~81行)。(注:PS2的传输时从低位开始,注意在74行rData的位寻址。)在这里稍微注意一下63i初始化23,这也是步i不是0开始而是23开始。在步23(83~84行,rData寄存{2'b11,8'h1C,1'b0},亦即A的通码,然后寄存器Go赋值i+1(表示下一个步骤,然后i赋予步骤0,以示进入PS2发送数据仿函数。([0]开始位-逻辑0,[9]校验位-如果没有特别需求可以随便,笔者就填入逻辑1,[10]停止位-1。)在这里我假设一个23,rData寄存2'b118'h1C1'b0},Goi+124i指向仿函数的如后,亦即步骤0。在步骤0,rData会从低至高被发送出去。发送过程大致如位9876543210.vt文件-11000111000.v文件PS2无无00011100无当发111位的数据会进2222会回PS2的时钟成为高(PS224~25A8'hF0,8'h1C位9876543210.vt文件-11111100000.v文件PS2无无11110000无位9876543210.vt文件-11000111000.v文件PS2无无无无无无无无无无无PS2模块不吃断码以后的通步骤26是停止操仿真结上图的C1~C2表示了PS2的时钟周期,亦即10kHz的时钟频率。读者应该知道笔者设计的PS2模块,通码和断码都是通吃,但是不吃断码以后的通码。在上图仿真结果中,当“虚拟按键A”被按下的时候,亦即在.vt的步骤23,(PS2_Done_Sig的第一个高脉冲)数据{2'b11,8'h1C,1'b0}成功被PS2模块,8'h1C被保留并输出(PS2_Data,然后产生一个完成.vt24~2{2'b11,8'hF0,0}成功被P2块8'F0被留输(PS2_Data然后据{2'11,8'1,0}会被发送,但是这一段数据是断码之后的通码,PS2模块无视,并且产生一个完成信号。所PS2_Dta的输出上,依然是输出8'hF0。实验二十env_debounce_module.v执行按键消抖的模块的仿真。然而这个实验的仿真工作,是直接在激励文件编辑,模仿“按键-A按下后又释放”的激励过程。将简单实验二十实验二十二和实验二十三相比,一个是将复杂输入建立在一个模块里(虚拟按键,一正负的关系,亦即一方为发送,另一方为接受。在仿真工作中,一方可以直接刺激另一方。模块相互刺在众多的模块中,有时候后会出现正负的关系,亦即发送和接收或者从机和主机。其中最和串口接收模块。如果要仿真串口发送模块,显然没有问题。但是,如果要仿真串口接收模块,既不是又要编辑复杂输入?实验二十四之一:仿真串口发送我们稍微回忆一下串口发送模块,大致的功能:上图是串口发送模块的图形。在不了解结构的情况下,我们只要准备数据在TX_DataTX_En_SigTX_Done_Sig产生完成信号之前,数据会以(注:这个模块是9600kbps)`timescale1ns/1moduleregCLK;regTX_En_Sig;wireTX_Pin_Out; tx_module( RSTn=0;#1000;RSTn=CLK=0;forever#25CLK=regalways@(posedgeCLKornegedgeRSTnif(!RSTnTX_En_Sig<=i<=TX_Data<=case(i if(TX_Done_Sig)beginTX_En_Sig<=1'b0;i<=i+1'b1;elsebeginTX_En_Sig<=1'b1;TX_Data<=8'h2E;end if(TX_Done_Sig)beginTX_En_Sig<=1'b0;i<=i+1'b1;elsebeginTX_En_Sig<=1'b1;TX_Data<=8'h3f;end if(TX_Done_Sig)beginTX_En_Sig<=1'b0;i<=i+1'b1;elsebeginTX_En_Sig<=1'b1;TX_Data<=8'hdd;begini<=4'd3;68.37~61行是激励过其中问答输入甚0的时(47~49行将数据发送至串口发送模块后使能串口发送模块(49然后等待串口发送模块反馈完成(51~53,(55~57步骤3(59~60行)是停止动作。仿真结上图是发送3组不同数据的仿真结果。在第一个完成信号产生,串口发送模块已经输出生,串口发送模块已经输出0xdd。0x3f发送的过程。我们知道笔者配置的串口发送模块发送的11位。[0]开始位-0,[1:8]数据位,[9]校验位-没有需要可以随便填,这里笔者填逻辑1,[10]停止位-逻辑1位9876543210.vt-00111111位0123456789.v文件-011111100110x3f的过程大致如上表。我们又知道笔者配置的串口发送模块的波特率是9600kbps,所以一个数据逗留的时间是大约104us。在仿真结果中,在B0~B1是数据[0],B1~B2是数据[1]......B10~B11是数据[10]。Bx~Bx之间的时间大约104us。实验二十四之一说在实验二十四之一的仿真中,串口发送模块在激励过程中,以问答的方式刺激该模块。实验二十四之一结该实验比较简单,我们只是要在仿真中观察串口发送模块的输出而已。在激励过程中,用问答输入刺激串口发送模块。实验二十四之二:仿真串口接收env_rx_module.v组合的串口发送模块和串口接收模块。在这TX_En_SigTX_DataTX_Done_SigRX_En_Sig,至串口接收模块,并且被串口接收模块,然后过滤。最后经过过滤的数据会输出至RX_Done_SigRX_Done_Sig。在这里笔者为串口接收模块编辑了,接收111位数据,并且波特率为9600kbps。inputCLK,inputTX_En_Sig,input[7:0]TX_Data,inputRX_En_Sig,output[7:0]RX_Data,output16.wiretx_module(.CLK(CLK.RSTn(RSTn.TX_Data(TX_Data.TX_Done_Sig(.TX_Pin_Out(TX_Pin_Outrx_module(.CLK(CLK.RSTn(RSTn.RX_Data(RX_Data.RX_Done_Sig() 51.U1TX_Pin_Out引出来(14行。46行`timescale1ns/1moduleregregregreg[7:0]TXwireregwirewirewireenv_rx_module( RSTn=0;#1000;RSTn=CLK=0;forever#25CLK=regalways@(posedgeCLKornegedgeRSTnif(!RSTni<=TX_En_Sig<=TX_Data<=case(i i<=i+ if(TX_Done_Sig)beginTX_En_Sig<=1'b0;i<=i+1'b1;elsebeginTX_En_Sig<=1'b1;TX_Data<=8'h3f;end i<= regalways@(posedgeCLKornegedgeRSTnif(!RSTnj<=RX_En_Sig<=case(j if(RX_Done_Sig)beginRX_En_Sig<=1'b0;j<=j+1'b1;elseRX_En_Sig<=1'b1; j<=89.块。在步骤j是0的时候(80~82行使能串口接收模块(82行)并且进入就绪状态,直到读完一帧数据(81行使能串口接收模块(81行然后进入步骤j的1。步骤j的1是串口接收模块“完工”操作,它什么都不干了。i0~23(55~56)i3(58~60行)8'h3f发送出去(60行4(59行i4的时候,它已经操作结束了。仿真模哇啊啊,好壮观呀。在上图仿真结果显示了,串口发送模块作为串口接收模块的刺激,的激励过程。当串口接收模块就绪以后,并且串口发送模块已经开始发送数据。(CursorC)C1~C2之间是第位帧数据的传送,C2~C3是第二位数据的传送,其他的以此类推,然和C1~C12是一帧数据11位的传送过程。注意,每个Cx~Cx之间的时间大约是104us,亦即9600kbps的波特率。在C1~C12之间,是最后一位数据的传输,亦即停止位。在这里有一个有趣的现象,当串口接收模块,接收到最后一个数据并且产生完整信号之际(注:RX_Done_Si),就(RX_En_Sig最后数据8'h3f(8'b00111111)输出至RX_Data(实际上更早之间已经输出了实验二十四之二说实验二十四之二结杂输入。除了串口模块意外,还有很多类似的情况,如:SPI从机和主机等.......麻烦IO口仿IO了,哎!IO(粤语。在建模(综合)的时候,要处理IO的引脚有两件工作,就是从IO输出和驱动IOinout IOregisOut;//输出使always@(posedgeCLKcase(i5:beginrData<=SIO;i<=i+1'b1;//6:beginisOut1'b1;rQ1'b1;ii1'b1;end//IOassignSIOisOutrQ //上面一段代码是在建模中会常常见到的IO被调用的过程。IO在的时候比较简单,它和输一样,直接调用即可。反之,IO在输出的时候比较麻烦,它得使能输出。当IO在仿真环境中出现,情况也是类似。reg IOwireIOassignSIO //上面的代码是IO在仿真中出现的样如果笔者要调用这个IO口的话过程会是如下。case(i5:begintreg_SIO1'b1;ii1'b1; //6:beginrData<=SIO;i<=i+1'b1; //在这一章中,我们要作的工作就是仿真带有IO口的模块。其中《VerilogHDL那些-建模篇》实验十三(DS1302驱动实验)中的function_module.v会是仿真对象实验二十五:仿真带IO的模function_module.vfunction_module.v是ds1302_module.v的函数模块。它包含了ds1302_module.v最基2'b01就是读操作。function_module.v可以调用的输入和输出口基本上和图形一样,其中SIO就是IO。function_module.vfunction_module.vfunction_module.vfunction_module.v已。反之,第二个字节的读操作是个问题。单单要从IO口数据,已经够麻烦了,然而现在我们还要配合function_module.v的操作步骤去执行激励过程。在这里,笔者稍微说一个故事:在很久很久以前,笔者曾经在Ourdev上发过这样一个问题:“IO的输入数据,是从哪产生”大大们说的话都是深奥,好在笔者的悟性不差。在上述的故事中某大大的意思是说,在仿真的激励过程中,如果要从IO数据。那么在另一方的激励过程中就要驱IO。用一个简单示例来说的话:case(case(ibeginrData<=SIO;case(jbegintreg_SIO<=1'b1;//case(jbegintreg_SIO=1'b1;一方激励过程中从模块的IO中数 一方激励过程中驱动IO口并且输入数上面的代码表示了,当激励过程i是1的时候从某个模块的IO数据。然后在同一个时间,另一方的激励过程j,如果按照“时间点”的概念,那么必须早一个时钟准备好要驱动的数据,亦即0的时候。反之如果无视时间点的概念,在j是1的时候可以以“阻塞式赋值”驱动IO,和激励过程i的同步。是如同作图那在激励文件中,先treg_SIO和SIO这个IO的关系。然后iSIO读jtreg_SIO驱动数据(输入基本上IO的调用在仿真是非常容易。但是唯一的问题是“一个激励过某个时候读取IO,那么另一个激励过程又该在什么时候驱动IO?”这也是众多参考书中一直避开我们再来看一看上面这一张时序图,它是function_module.v的读操作时序图。我们可“该IO口?”。这个问题和上面例子中两个激励过程不一样,在上面例但是,现在的问题是“驱动IO是在模块的外部发生”然而“模块在什么时候要IO”和“激励过程要在什么时候驱动IO”我们是不知道的。要解决问题,就必须和建模技(稍微让脑袋冷静一下吧...)elseif(Start_Sig[0]case(i0beginrSCLK<=1'b0;rData<=Words_Addr;rRST<=1'b1;isOut<=1'b1;i<=i+1'b1;1,3,5,7,9,11,13,15if(Count1==T0P5US)i<=i+elsebeginrSIO<=rData[(i>>1)];rSCLK<=1'b0;2,4,6,8,10,12,14,16if(Count1==T0P5US)i<=i+1'b1;elsebeginrSCLK<=1'b1;end17beginisOut<=1'b0;i<=i+1'b1;18,20,22,24,26,28,30,32if(Count1==T0P5US)i<=i+elsebeginrSCLK<=1'b1;19,21,23,25,27,29,31,33if(Count1==T0P5US)begini<=i+1'b1;elsebeginrSCLK<=1'b0;rData[(i>>1)-9]<=SIO;34beginrRST<=1'b0;isOut<=1'b1;i<=i+1'b1;35beginisDone<=1'b1;i<=i+1'b1;36beginisDone<=1'b0;i<=6'd0;上面的代码是functon_modul.v命令为2b01i从0~16是第一个字节的写操作,我们可以无视。重点就是在于从步骤17开始,亦即步骤18~33的读操作。如果我们要知道该模块要在什么时候,那么既是步骤18~33。又如果我们要知道该模块在什么时候,需要“哪一个位”数据,那么步骤18(第零位),20(第一位),22(第二位),24(第三位),26(第四位),28(第五位),30(第六位),32(第七位(DS1302的传输时从SB,亦即最低位开始)为什么是步骤18,20,22,24,26,28,30,32而不是步骤19,21,23,25,27,29,31,33呢?我们知道DS1302在读操作的时候,第二个字节读数据是SCLK“下降(更新)SCLK18,20,22,24,26,28,30,32是上升沿的操作。function_module.vi引出来即可知道“该模块要在什么时候IO”。(CLK, inputinputinputinputinputoutputoutputoutputoutputinoutoutputparameterT0P5US=4'd9; regalways@(posedgeCLKornegedgeRSTnif(!RSTnCount1<=elseif(Count1==T0P5USCount1<=elseif(Start_Sig[0]==1'b1||Start_Sig[1]==1'b1Count1<=Count1+Count1<=regregregregregregregalways@(posedgeCLKornegedgeRSTnif(!RSTni<=rData<=rSCLK<=rRST<=rSIO<=isOut<=isDone<=elseif(Start_Sig[1]case(i 0 beginrSCLK<=1'b0;rData<=Words_Addr;rRST<=1'b1;isOut<=1'b1;i<=i+1'b1;end 1,3,5,7,9,11,13,15 if(Count1==T0P5US)i<=i+ elsebeginrSIO<=rData[(i>>1)];rSCLK<=1'b0;end 2,4,6,8,10,12,14,16 if(Count1==T0P5US)i<=i+ elsebeginrSCLK<=1'b1;end 17 beginrData<=Write_Data;i<=i+1'b1;end 18,20,22,24,26,28,30,32 if(Count1==T0P5US)i<=i+ elsebeginrSIO<=rData[(i>>1)-9];rSCLK<=1'b0;end 19,21,23,25,27,29,31,33 if(Count1==T0P5US)i<=i+ elsebeginrSCLK<=1'b1;end 34 beginrRST<=1'b0;i<=i+1'b1;end 35 beginisDone<=1'b1;i<=i+1'b1;end 36 beginisDone<=1'b0;i<=6'd0;endcase(i 0 beginrSCLK<=1'b0;rData<=Words_Addr;rRST<=1'b1;isOut<=1'b1;i<=i+1'b1;end 1,3,5,7,9,11,13,15 if(Count1==T0P5US)i<=i+ elsebeginrSIO<=rData[(i>>1)];rSCLK<=1'b0;end 2,4,6,8,10,12,14,16 if(Count1==T0P5US)i<=i+ elsebeginrSCLK<=1'b1;end 17 beginisOut<=1'b0;i<=i+1'b1;end 18,20,22,24,26,28,30,32 if(Count1==T0P5US)i<=i+ elsebeginrSCLK<=1'b1;end 19,21,23,25,27,29,31,33 if(Count1==T0P5US)begini<=i+1'b1; elsebeginrSCLK<=1'b0;rData[(i>>1)-9]<=SIO;end 34 beginrRST<=1'b0;isOut<=1'b1;i<=i+1'b1;end 35 beginisDone<=1'b1;i<=i+1'b1;end 36 beginisDone<=1'b0;i<=6'd0;end assignRead_Data=assignDone_Sig=assignRST=assignSCLK=assignSIO=isOut?rSIO:assignSQ_i= 的具体功能笔者就不重复了,在《VerilogHDL那些事儿-建模篇》骤i引出的过程。`timescale1ns/1regCLK;regreg[1:0]reg[7:0]reg[7:0]wirewirewireRST;wireregwire[5:0]SQ_i;function_module( RSTn=0;#1000;RSTn=CLK=0;forever#25CLK=regalways@(posedgeCLKornegedgeRSTnif(!RSTni<=Start_Sig<=case(i if(Done_Sig)beginStart_Sig<=2'b00;i<=i+1'b1; elsebeginStart_Sig<=2'b10;Words_Addr<=8'hf0;Write_Data<=8'hf2;end if(Done_Sig)beginStart_Sig<=2'b00;i<=i+1'b1;i<=reg[7:0]DS1302_Data;always@(posedgeCLKornegedgeRSTn)if(!RSTn)treg_SIO<=1'b0;DS1302_Data<=8'h33;elseif(Start_Sig==2'b01)case(SQ_i)18:treg_SIO<=20:treg_SIO<=22:treg_SIO<=24:treg_SIO<=26:treg_SIO<=28:treg_SIO<=30:treg_SIO<=106.17~19SIOtreg_SIO51~75i,它主要0(64~66行的时function_module.v写操作,写入的Words_Addr8'hf0Write_Data8'hf2,这点不重要。在步骤1的时候(68~70行)是命令function_module.v读操作(这才是重点,其中第一个字节的写数据8'hf0我们可以无视。function_module.v如果是读操作,当第一个字节被写入以后,tion_module.v接下来的操作是读一个字节的数据,亦即按不同的SCLK时钟,从IO读书数在同一个时间79~99行是激励过j,它主要是用来驱动IO。第79行的寄存器DS1302_DataIO驱动的数据,8'h3387行表示了,该激励过function_module.v(2'b01)88~99行是根据,function_module.v被引出来的步骤iIO驱动。第行是18,既是读操作的第一个上升沿,驱的数据为寄存器第[0]位值第行是20,既是读操作的第二个上升沿,驱的数据为寄存器第[1]位值第行是22,既是读操作的第三个上升沿,驱的数据为寄存器第[2]位值第行是24,既是读操作的第四个上升沿,驱的数据为寄存器第[3]位值第行是26,既是读操作的第五个上升沿,驱的数据为寄存器第[4]位值第行是28,既是读操作的第六个上升沿,驱的数据为寄存器第[5]位值第行是30,既是读操作的第七个上升沿,驱的数据为寄存器第[6]位值第97行,SQ_i是32,既是读操作的第八个上升沿,驱动IO的数据为寄存器第[7]仿真结在这里读者要注意一点,由于笔者的不给力的关系,在IO的输出上,如果是1是红线,事实上它不是悬空,而是逻1。反之,如果IO上输出逻0的话,就能正常显示。(从IO数据,不受影响)无论如何,仿真结果不会受到影响,只是2'b10(Start_Sig),Words_Addr的数据时8'hf0,Write_Data8'hf2function_module.v这个时候在仿真的虚拟环境里,只是对IO(SIO)输出数据而已(CursorC)C1~C9Words_Addr的数据8'hf0SIO上的输出。C1~C2之间是Words_Addr的第[0]位值在SIO的数据,其余的以此类推。C9~C17是Wrte_Data的数据8'hf2SIO上的输出。C9~C10是Write_Data的第[0]值在SIO的数据其它的也是以此类推(注意DS1302的传输是低位开始结束)上图仿真结果是激励过程i,在步骤1对function_module.v执行的读操作。读操作2'b01(Start_Si8'hf0SIO上的输(写操作其中是发生在function_module.v的步1~1(SQ_

温馨提示

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

评论

0/150

提交评论