当前位置:   article > 正文

Verilog学习记录(一):时序逻辑代码设计和仿真_时序逻辑电路设计入门——verilog hdl语言编程要求 根据提示,在右侧编辑器补充代

时序逻辑电路设计入门——verilog hdl语言编程要求 根据提示,在右侧编辑器补充代

本次学习的内容来自B站:Verilog零基础入门 

其他相关引用以贴上原链接

时序逻辑电路

一、计数器

1.原理及代码实现

2.Modelsim仿真

二、四级伪随机码发生器

1.原理及代码实现

2.Moselsim仿真

总结


时序逻辑电路

 时序逻辑电路是数字逻辑电路的重要组成部分,时序逻辑电路又称,主要由存储电路组合逻辑电路两部分组成。它和我们熟悉的其他电路不同,其在任何一个时刻的输出状态由当时的输入信号和电路原来的状态共同决定,而它的状态主要是由存储电路来记忆和表示的。同时时序逻辑电路在结构以及功能上的特殊性,相较其他种类的数字逻辑电路而言,往往具有难度大、电路复杂并且应用范围广的特点  。

在数字电路通常分为组合逻辑电路时序逻辑电路两大类,组合逻辑电路的特点是输入的变化直接反映了输出的变化,其输出的状态仅取决于输入的当前的状态,与输入、输出的原始状态无关,而时序电路是一种输出不仅与当前的输入有关,而且与其输出状态的原始状态有关,其相当于在组合逻辑的输入端加上了一个反馈输入,在其电路中有一个存储电路,其可以将输出的状态保持住,我们可以用下图的框图来描述时序电路的构成。(Verilog零基础入门

一、计数器

1.原理及代码实现

计数器是一种典型的时序逻辑电路,其电路图如下:

左边的加法器为组合逻辑电路,用于对输出的结果加一计数,右边为一个D触发器,在时钟的上升沿到来时触发,输出结果(因为我太久没学数电了,很多知识都遗忘了,所以这里只是用我目前的知识进行复述,不一定对),从而实现计数操作。下面我们一起来编写代码吧!

  1. //2023.4.12 Bread
  2. //计数器
  3. `timescale 1ns/1ps
  4. module counter(
  5. clk,
  6. rst,
  7. y
  8. );
  9. input clk;
  10. input rst;
  11. output[7:0] y;
  12. reg[7:0] y;
  13. wire[7:0] sum;//+1运算的结果
  14. assign sum = y+1;//组合逻辑部分
  15. always@(posedge clk or negedge rst)
  16. if(~rst)begin
  17. y<=0;
  18. end
  19. else begin
  20. y<=sum;
  21. end
  22. endmodule

这里的`timescale 1ns/1ps表示以1ns为时间单位,精度为1ps,可以根据自己的喜好设置,这是testbench需要用到的。

在代码中,clk为时钟信号,rst为复位信号,y为输出。always@里的内容为敏感变量,表示在时钟的上升沿或者复位信号的下降沿触发。在复位信号为0的时候,我们将输出值复位,置为0(这里也可以按照自己的喜欢,将复位信号的0或1用于复位,但是为了严谨还是使用D触发器原本的复位模式,因为我自己也不太清楚,所以使用的是根据老师的代码)。在这里我们就是实现了对计数器代码的编写,接下来我们来编写他的test_bench:

  1. //----testbench----
  2. module counter_tb;
  3. reg clk,rst;
  4. wire[7:0] y;
  5. counter counter(
  6. .clk(clk),
  7. .rst(rst),
  8. .y(y)
  9. );
  10. initial begin
  11. clk<=0;rst<=0;
  12. #17 rst<=1;
  13. #6000 $stop;
  14. end
  15. always #5 clk<=~clk;
  16. endmodule

testbench主要用于仿真波形,这里我们采用异名例化。编写完代码后,我们就一起使用Modelsimj进行仿真吧~ 

2.Modelsim仿真

1.打开Modelsim,找到首页的work目录,点击右上角的编译

 选择我们刚才编写好的.v文件,点击Complie进行编译

 在这里我们也可以选择更改我们的工作路径:File->Change Directory... 将工作路径放到我们自己想要的文件夹下,但是建议使用默认的路径,因为每次打开Modelsim后都会停留在默认路径下,需要每次手动更改路径,更改路径后选择编译会出现没有‘work’的情况,选择yes即可。

 之后在work目录下就会出现counter和counter_tb两个文件了,我们选择tb文件,右键,点击Simulate,就会进入我们的仿真页面了。

 

 第一次进入这里可能没有波形图的页面,我们选择View->wave就可以打开波形图界面啦

然后我们将想观察的信号导入波形图中:右击信号->Add to->Wave->Signals in Region,就可以将该页面的信号一起导入进去了

 

导入进来发现没有波形?最后我们点击右上角的Restart和Runall,我们的波形就展示出来了。 

 现在的波形看着很乱是吧?我们点击以下三个按钮可以实现对波形的观察了。

 首先点击第三个 Zoom Full按钮,可以将波形全局展示,之后再通过放大和缩小观察我们想要的波形了,我们的计数器的波形如下:

可以看到,在每一个时钟的上升沿到来的时候,输出的值就会加一,但是当加到255后又置零了,这是因为我们采用的八位计数器,可以显示的范围只有00000000——11111111。并且在这里我们使用的是无符号位表示,如果使用十进制表示,默认是有符号的,到127后就会开始变成负数了!更改表示进制可以右击信号->Radix中选择我们想要观察的进制数了(如二进制,八进制,十六进制等)。 

 以上就是计数器和Modelsim仿真观察波形图的内容了。

二、四级伪随机码发生器

1.原理及代码实现

        伪随机序列又称为伪随机码,是一种人工生成的周期序列,可以作为数字通信中的一个信号源,用于检测数字通信系统错码的概率,即误码率。

        产生伪随机码的方式有很多,通常使用线性反馈移位寄存器(LFSR)来产生。所谓线性反馈,是指反馈函数中仅包含模 2 加运算(也就是逻辑异或),而不含非线性运算。由线性反馈寄存器产生的周期最长的二进制序列称为最大长度线线性反馈寄存器序列,简称m序列。如果移位寄存器长度为n,则m序列的周期是(2^n -1),没有全0的状态。

        伪随机码发生器的初始状态由微处理器通过SEED寄存器发出。seed不能为全0的状态 ,因为0^0=0,会陷入0的死循环 。(http://t.csdn.cn/dmROL)

四级伪随机码发生器的电路图如下所示:

 通过4个D触发器以及一个模2加单元实行不断的移位与模二加,就可以得到除去0000的0001-1111即1-15的随机数了。代码如下:

  1. //2023.4.12 Bread
  2. //四级伪随机码发生器;
  3. `timescale 1ns/1ps
  4. module m_gen(
  5. clk,
  6. rst,
  7. y
  8. );
  9. input clk;
  10. input rst;
  11. output y;
  12. reg[3:0] d;
  13. assign y=d[0];
  14. always@(posedge clk or negedge rst) begin
  15. if(~rst) begin
  16. d<=4'b1111;
  17. end
  18. else begin
  19. d[2:0]<=d[3:1];//右移一位
  20. d[3]<=d[3]+d[0];//模二加
  21. end
  22. end
  23. endmodule

在这里我们使用d[2:0]<=d[3:1]的方式进行右移,将高三位的值赋给低三位。(其实verilog里面还可以用>>的方式进行移位,但是老师说尽量不要那样写,猜测可能跟位右移和逻辑右移有关?一些位溢出的问题?)

相应的testbench如下:

  1. //----testbench----
  2. module m_gen_tb;
  3. reg clk,rst;
  4. wire y;
  5. m_gen m_gen(
  6. .clk(clk),
  7. .rst(rst),
  8. .y(y)
  9. );
  10. initial begin
  11. clk<=0;rst<=0;
  12. #10 rst<=1;
  13. #600 $stop;
  14. end
  15. always #5 clk<=~clk;
  16. endmodule

这里的testbench和上面计数器的类似,就不过多叙述。接下来我们进行仿真吧。 

2.Modelsim仿真

其他的方式都和上面一样,但是要注意的是,这里的d我们并没有在testbench中注明,所以我们需要单独将其添加到波形图中:

(注意:因为我们之前添加了clk,rst,y等信号,所以这里我们仅选择Selected Signals,不然会重复添加)

最后仿真的波形如下:

 可以看到,这里的y输出值仅仅只是最后一个D触发器的输出值,我们的伪随机码是d[3:0]构成的数字,实际上,输出d更符合伪随机码的特性(1-15的随机数),但是这里的随机码是跟输入的时钟信号有关,在时间上呈现一定的周期性,并非是完全随机的。

 


总结

以上就是本文的全部内容了。本人只是一个刚入门自学的萌新,有很多不对的地方,发布这篇文章也只是记录自己的学习过程,因为自己的学习习惯很不好,从来不爱动笔只喜欢看,很快就忘记了,所以想通过这样的方式来记录。同时也提醒自己在编写代码的时候要保持良好的习惯,以及编写边检查。我在写四位伪随机码放发生器的时候因为不小心将.rst(rst)写成了.rst(clk)导致波形图一直无法更新,输出的y值一直为1,在排查了很久后也没有发现问题,编译器也没有报错。导致浪费了一个小时的时间在这里,还一直在always语句里面找问题,最后才发现!这种问题一定要注意呀,有时候参数写错了并不会报错但是结果会有很大的问题!希望能够坚持下去。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/486970
推荐阅读
相关标签
  

闽ICP备14008679号

        
cppcmd=keepalive&