当前位置:   article > 正文

FPGA学习笔记(一)——12-19_assign和always的区别

assign和always的区别

一.阻塞与非阻塞:

      1.阻塞赋值的执行可以认为是只有一个步骤的操作,即计算RHS的值并更新LHS,此时不允许任何其他语句的干扰。符号=    
      2.非阻塞赋值是由时钟节拍决定,在时钟上升到来时,执行赋值语句右边,然后将begin-end之间的所有赋值语句同时赋值到赋值语句的左边。

 

assign语句与always的区别
           assign语句使用时不能带时钟。
           always语句可以带时钟,也可以不带时钟。在always不带时钟时,逻辑功能和assign完全 一致,都是只产生组合逻辑。比较简单的组合逻辑推荐使用assign语句,比较复杂的组合逻辑 推荐使用always语句。

 

 latch是指锁存器
          一种对脉冲电平敏感的存储单元电路。锁存器和寄存器都是基本存 储单元,锁存器是电平触发的存储器,寄存器是边沿触发的存储器。两者的基本功能是一样的, 都可以存储数据。锁存器是组合逻辑产生的,而寄存器是在时序电路中使用,由时钟触发产生的。
latch的主要危害是会产生毛刺(glitch),在设计中,应尽量避免latch的使用。
        代码里面出现latch的两个原因是在组合逻辑中,if或者case语句不完整的描述,比如if缺少else分支,case缺少default分支,导致代码在综合过程中出现了latch。解决办法就是if必须带else分支,case必须带default分支。
        需要注意下,只有不带时钟的always语句if或者case语句不完整才会产生latch,带时钟的语句if或者case语句不完整描述不会产生latch。
 

状态机

Mealy 状态机:组合逻辑的输出不仅取决于当前状态,还取决于输入状态。
Moore 状态机:组合逻辑的输出只取决于当前状态。
三段式状态机:
       一段式:整个状态机写到一个always模块里面,在该模块中既描述状态转移,又描述状态的输入和输出。不推荐采用这种状态机,因为从代码风格方面来讲,一般都会要求把组合逻辑和时序逻辑分开;从代码维护和升级来说,组合逻辑和时序逻辑混合在一起不利于代码维护和 修改,也不利于约束。
        二段式:用两个always模块来描述状态机,其中一个always模块采用同步时序描述状态转 移;另一个模块采用组合逻辑判断状态转移条件,描述状态转移规律以及输出。不同于一段式状态机的是,它需要定义两个状态,现态和次态,然后通过现态和次态的转换来实现时序逻辑。
        三段式:在两个always模块描述方法基础上,使用三个always模块,一个always模块采用同步时序描述状态转移,一个always采用组合逻辑判断状态转移条件,描述状态转移规律,另一个always模块描述状态输出(可以用组合电路输出,也可以时序电路输出)。
       三段式状态机的基本格式是:
            第一个always语句实现同步状态跳转;
            第二个always语句采用组合逻辑判断状态转移条件;
            第三个always语句描述状态输出(可以用组合电路输出,也可以时序电路输出)。
            在开始编写状态机代码之前,一般先画出状态跳转图,这样在编写代码时思路会比较清晰
下面以一个7分频为例
 
  1. 1 module divider7_fsm (
  2. 2 //系统时钟与复位
  3. 3 input sys_clk ,
  4. 4 input sys_rst_n ,
  5. 5
  6. 6 //输出时钟
  7. 7 output reg clk_divide_7
  8. 8 );
  9. 9
  10. 10 //parameter define
  11. 11 parameter S0 = 7'b0000001; //独热码定义方式
  12. 12 parameter S1 = 7'b0000010;
  13. 13 parameter S2 = 7'b0000100;
  14. 14 parameter S3 = 7'b0001000;
  15. 15 parameter S4 = 7'b0010000;
  16. 16 parameter S5 = 7'b0100000;
  17. 17 parameter S6 = 7'b1000000;
  18. 18
  19. 19 //reg define
  20. 20 reg [6:0] curr_st ; //当前状态
  21. 21 reg [6:0] next_st ; //下一个状态
  22. 22
  23. 23 //*****************************************************
  24. 24 //** main code
  25. 25 //*****************************************************
  26. 26
  27. 27 //状态机的第一段采用同步时序描述状态转移
  28. 28 always @(posedge sys_clk or negedge sys_rst_n) begin
  29. 29 if (!sys_rst_n)
  30. 30 curr_st <= S0;
  31. 31 else
  32. 32 curr_st <= next_st;
  33. 33 end
  34. 34
  35. 35 //状态机的第二段采用组合逻辑判断状态转移条件
  36. 36 always @(*) begin
  37. 37 case (curr_st)
  38. 38 S0: next_st = S1;
  39. 39 S1: next_st = S2;
  40. 40 S2: next_st = S3;
  41. 41 S3: next_st = S4;
  42. 42 S4: next_st = S5;
  43. 43 S5: next_st = S6;
  44. 44 S6: next_st = S0;
  45. 45 default: next_st = S0;
  46. 46 endcase
  47. 47 end
  48. 48
  49. 49 //状态机的第三段描述状态输出(这里采用时序电路输出)
  50. 50 always @(posedge sys_clk or negedge sys_rst_n) begin
  51. 51 if (!sys_rst_n)
  52. 52 clk_divide_7 <= 1'b0;
  53. 53 else if ((curr_st == S0) | (curr_st == S1) | (curr_st == S2) | (curr_st == S3))
  54. 54 clk_divide_7 <= 1'b0;
  55. 55 else if ((curr_st == S4) | (curr_st == S5) | (curr_st == S6))
  56. 56 clk_divide_7 <= 1'b1;
  57. 57 else
  58. 58 ;
  59. 59 end
  60. 60
  61. 61 endmodule

模块化设计
        一般采用自顶向下的设计方式
 
在顶层TOP文件中  可以 例化子模块     
          上图左边为子模块的定义、各种输入输出接口
          上图右侧对应的就是顶层模块的例化     分别包含子模块名   例化模块名(可随意书写,我们一般命名为 u_+子模块名)                子模块端口需要与子模块的函数单口一致,后面的例化模块端口与TOP层的端口定义一致,也就是进行对应连接
 
参数的例化,参数的例化是在模块例化的基础上,增加了对参数的信号定义,如下图所示:
   

     
在对参数进行例化时,在模块名的后面加上“#”,表示后面跟着的是参数列表。计时模块定义 的 MAX_NUM 和 顶 层 模 块 的 TIME_SHOW 都 是 等 于 25000_000 , 当 在 顶 层 模 块 定 义 TIME_SHOW=12500_000时,那么子模块的MAX_NUM的值实际上是也等于12500_000。当然即使子模块包含参数,在做模块的例化时也可以不添加对参数的例化,这样的话,子模块的参数值等 于该模块内部实际定义的值。
 
Verilog语法中的localparam代表的意思同样是参数定义,用法和parameter基本一致,区别在于parameter定义的参数可以做例化,而localparam定义的参数是指本地参数,上层模块不可以对localparam定义的参数做例化
                                       
 

 


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

闽ICP备14008679号