• SPI程序的一些总结


    1、电平敏感量触发/边沿触发敏感量问题(阻塞赋值与非阻塞赋值的问题):详细程序参看Verilog数字系统设计教程 夏宇闻 【第二版】第14章 深入理解阻塞和非阻塞赋值的不同

      (1)、原则1:时序电路建模时,用非阻塞赋值

           原则2:锁存器电路建模时,用非阻塞赋值

      (2)、原则3:用always快描述组合逻辑时,应采用阻塞赋值语句

      (3)、原则4:在同一个always快中描述时序和组合逻辑混合电路时,用非阻塞赋值

      (4)、原则5:不要再同一个always快中同时使用阻塞和非阻塞赋值

      (5)、原则6:严禁在多个always块中对同一个变量赋值

      (6)、原则7:用$系统任务来显示,应该用非阻塞赋值的变量值

    RHS——表示赋值等号右边的表达式或变量;LHS——表示赋值等号左边的表达式或变量;

    1.1

      阻塞赋值操作符(即=):阻塞赋值的执行可以认为是只有一个步骤的操作,即计算RHS并更新LHS,此时不允许有来自任何其他Verilog语句的干扰。所谓阻塞的概念是指在同一个always快中,其后面的赋值语句从概念上是在前一句赋值语句结束后在开始进行赋值的。

      如果一个过程块中阻塞赋值的RHS变量正好是另一个过程快中阻塞赋值的LHS变量这两个过程快又用同一个时钟沿触发

      参看例子中的y1,y2,若复位信号已从1到0,(1)若always块的又消失中沿比下面的always块的有效时钟沿早到几个皮秒(由时钟偏差造成的),则先计算y1=y2,此时y2的值为复位前的值1,则y1=1,当下一个always块执行的时候,y2=y1,此时y1=1,则y2=1;(2)同理可分析得到当下面的always块的有效时钟沿早到几个皮秒,则y1,y2都会取0,这说明这个Verilog模块是不稳定的,必定会产生冒险和竞争的情况。

    1.2

      非阻塞赋值操作符(即<=),非阻塞赋值的操作过程可以看做下面两个步骤:(1)在赋值开始时刻,计算非阻塞赋值RHS表达式;(2)在赋值结束时刻,更新非阻塞赋值LHS表达式。非阻塞赋值操作只能用于寄存器类型变量进行赋值,因此只能用在“initial”块和“always”块等过程快中,且不能用于连续赋值。

      参看例子中的y3,y4,若复位信号已从1到0,无论哪一个always块的有效沿先到,两个always块中的非阻塞赋值都在赋值开始时刻计算RHS表达式,而在结束时刻才更新LHS表达式。实质上y1被赋值y2的值是有rst正跳变沿确定的,y2被赋值y1的值也是由正跳变沿去诶的那个的(若以后rst继续保持为0,时钟信号不断重复,则每次被赋值的y1和y2都是有上一个周期的时钟有效沿确定的)。从用户的角度看这两个非阻塞赋值好像是并行执行的。

    例子1:

      

    BlockAndNonblock
     1 `timescale 1ns/1ns
    2 `define clk_cycle 5
    3 module BlockAssignment;
    4 reg clk;
    5 reg rst;
    6 reg y1;
    7 reg y2;
    8 reg y3;
    9 reg y4;
    10 always #`clk_cycle clk=~clk;
    11 initial
    12 begin
    13 clk=0;
    14 rst=0;
    15 #10 rst=1;
    16 #10 rst=0;
    17 end
    18
    19 /* BlockAssignment */
    20 always @(posedge clk or posedge rst)
    21 begin
    22 if(rst)
    23 y1=0;
    24 else
    25 y1=y2;
    26 end
    27 always @(posedge clk or posedge rst)
    28 begin
    29 if(rst)
    30 y2=1;
    31 else
    32 y2=y1;
    33 end
    34
    35 /* NONBlockAssignment */
    36 always @(posedge clk or posedge rst)
    37 begin
    38 if(rst)
    39 y3<=0;
    40 else
    41 y3<=y4;
    42 end
    43 always @(posedge clk or posedge rst)
    44 begin
    45 if(rst)
    46 y4<=1;
    47 else
    48 y4<=y3;
    49 end
    50
    51 endmodule

    仿真波形:(此处时序逻辑中阻塞赋值没有达到想要的逻辑关系,非阻塞可以达到预想的逻辑关系)

    例子2:

     

    例子2
     1 module a04(y,a,b,c,d);
    2 output y;
    3 input a,b,c,d;
    4 reg y,temp1,temp2;
    5 always@(a or b or c or d)
    6 begin
    7 temp1<=a&b;
    8 temp2<=c&d;
    9 y<=temp1|temp2;
    10 end
    11 endmodule
    12 //由于非阻塞赋值语句在LHS更新前计算RHS的值,因此tmp1和tmp2仍是进入该
    13
    14 //always快是的值,而不是在该步仿真结束时将更新的值。输出y是刚进入always块
    15
    16 //时tmp1和tmp2的值,而不是在always块中经计算后得到的值。
    17
    18 module a04(y,a,b,c,d,tmp1,tmp2);
    19 output y;
    20 input a,b,c,d;
    21 reg y,temp1,temp2;
    22 always@(a or b or c or d)
    23 begin
    24 temp1<=a&b;
    25 temp2<=c&d;
    26 y<=temp1|temp2;
    27 end
    28 endmodule
    29 //将tep1和tmp2加入敏感列表中后,现在输出的y是正确的,但是一个always块中有多次参数的传递,由此降低了仿真器的性能,只有在没有其他合理的方式的采用此方法

    30 module a04(y,a,b,c,d);
    31 output y;
    32 input a,b,c,d;
    33 reg y,temp1,temp2;
    34 always@(a or b or c or d)
    35 begin
    36 temp1=a&b;
    37 temp2=c&d;
    38 y=temp1|temp2;
    39 end
    40 endmodule
    41
    42 //保证了经一次数据传输y的值是正确的,又提高了仿真效率

    1.3 时序和组合的混合逻辑使用非阻塞赋值

      

    例子
     1 module nbex2(q,a,b,clk,rst_n);
    2 output q;
    3 input clk ,rst_n;
    4 input a,b;
    5 reg q;
    6 always @(posedge ckl or negecge rst_n)
    7 if(!rst_n)
    8 q<=1'b0;//时序逻辑
    9 else
    10 q<=a^b;//异或,为组合逻辑
    11 endmodule
    12
    13 /*采用两个always块实现以上逻辑也可以*/
    14 module nbex2(q,a,b,clk,rst_n);
    15 output q;
    16 input clk ,rst_n;
    17 input a,b;
    18 reg q,y;
    19 always @(a or b)
    20 y=a^b;//组合逻辑
    21 always @(posedge ckl or negecge rst_n)
    22 if(!rst_n)
    23 q<=1'b0;//时序逻辑
    24 else
    25 q<=y;//时序逻辑
    26 endmodule


     

    2、分频(倍频)问题

      (1)、对clk进行二分频,得到control_pulse,在always(negedge clk)中检测control_pulse实现对control_pulse电平中间位置处采样,如图,同样也可作为门控时钟

                                      

      (2)、锁相环倍频

       (3)、奇数倍/偶数倍分频(来自互联网)

    clk_divide
     1 `timescale 1ns/1ns
    2 `define clk_cycle 5
    3 `define N 11
    4
    5 module m1k;
    6 // module m1k(rst_n,clk,k,clkk);
    7 // input rst_n;
    8 // input clk;
    9 // input [3:0] k;//k分频
    10 // reg clk1;
    11 // reg clk2;
    12
    13 // output clkk;
    14 // reg [3:0] k1;
    15 // reg [3:0] k2;
    16
    17 reg rst_n;
    18 reg clk;
    19 reg [3:0] k;
    20 //wire sys_clk;
    21 wire clkk;
    22 //wire clk_point;
    23
    24 reg clk1;
    25 reg clk2;
    26 //reg clk_point1;
    27 //reg clk_point2;
    28 //reg trigger_clk;
    29 reg [3:0] k1;
    30 reg [3:0] k2;
    31 //reg [3:0] clk_point_count1;
    32 //reg [3:0] clk_point_count2;
    33 //assign sys_clk=clk;
    34 initial
    35 begin
    36 rst_n=1;
    37 clk=0;
    38 k=11;
    39 clk1=0;
    40 clk2=0;
    41 k1=0;
    42 k2=0;
    43 #20 rst_n=0;
    44 #20 rst_n=1;
    45 end
    46 always #`clk_cycle clk=~clk;
    47
    48 always@(negedge rst_n or posedge clk)
    49 begin
    50 if(~rst_n)
    51 begin
    52 k1 <= 4'b0;
    53 clk1 <= 1'b0;
    54 end
    55 else
    56 begin
    57 if(k1==(k-1))
    58 clk1 <= ~clk1;
    59 if(k1==((k>>1)-1'b1))//移位运算,此处相当于是k/2-1
    60 clk1 <= ~clk1;
    61
    62 if(k1==k-1)
    63 k1 <= 4'b0000;
    64 else
    65 k1 <= k1+4'b0001;
    66
    67
    68 end
    69
    70 end
    71
    72 always@(negedge rst_n or negedge clk)
    73 begin
    74 if(~rst_n)
    75 begin
    76 k2 <= 4'b0;
    77 clk2 <= 1'b0;
    78 end
    79 else
    80 begin
    81 if(k2 == k-1)
    82 k2 <= 4'b0000;
    83 else
    84 k2 <= k2+4'b0001;
    85 if(k2==k-1)
    86 clk2 <= ~clk2;
    87 if(k2==((k>>1)-1'b1))
    88 clk2 <= ~clk2;
    89 end
    90
    91 end
    92 assign clkk = (k%2)?clk1&clk2:clk1;
    93 endmodule

    仿真波形如下:

    3、门控时钟问题

    4、状态机问题

       用可综合的Verilog模块设计复杂的多输出状态机时常用的方法

    复杂状态机常用方法
     1 module fsm(Clock, Reset, A, K2, K1);
     2     input   Clock, Reset, A;
     3     output  K2, K1;
     4     reg     K2, K1;
     5     reg [1:0]   state, nextState;
     6 
     7     parameter
     8         Idle = 2'b00,
     9         Start = 2'b01,
    10         Stop = 2'b10,
    11         Clear = 2'b11;
    12         //---每一个时钟沿产生一次可能的状态变化-----
    13 
    14     always @(posedge Clock)
    15         if (!Reset)
    16             state <= Idle;
    17         else
    18             state <= nextState;
    19 
    20         //-----产生下一状态的组合逻辑-------
    21         always @(state or A)//由当前状态和当前输入决定下一个状态
    22             case (state)
    23                 Idle:
    24                     if (A)
    25                         nextState = Start;
    26                     else
    27                         nextState = Idle;
    28                 Start:
    29                     if (!A)
    30                         nextState = Stop;
    31                     else
    32                         nextState = Start;
    33                 Stop:
    34                     if (A)
    35                         nextState = Clear;
    36                     else
    37                         nextState = Stop;
    38                 Clear:
    39                     if (!A)
    40                         nextState = Idle;
    41                     else
    42                         nextState = Clear;
    43                 default:
    44                     nextState = 2'bxx;
    45             endcase
    46 
    47         //----产生输出K1的组合逻辑--------
    48         always @(state or Reset or A)//由当前状态和当前输入决定K1的输出
    49             if (!Reset) K1 = 0;
    50             else 
    51                 if (state == Clear && !A)   //...
    52                     K1 = 1;
    53                 else
    54                     K1 = 0;
    55 
    56         //----产生输出K2的组合逻辑--------
    57         always @(state or Reset or A)//由当前状态和当前输入决定K2的输出
    58             if (!Reset) K2 = 0;
    59             else
    60                 if (state == Stop && A)      //...
    61                     K2 = 1;
    62                 else
    63                     K2 = 0;
    64 
    65 endmodule

    5、触发器问题

      5.1 D触发器

      

      5.1.1 边沿检测中用到的D触发器(来之CrazyBingo的博客)

        5.1.11

      wps_clip_image-28203

      

        

        正常工作,没有复位的情况下,工作流程如下:

        (1)D触发器经过时钟clk的触发,输出trigger信号,保存了t0时刻的信号。

        (2)同时由trigger通过非门输出信号,保留了当前时刻t1的触发信号

        (3)经过与门输出信号pos_edge,neg_edge

           a) 只有t0时刻为高,且t1时候为低的时候,与门输出高,此时为下降沿。

         b) 只有to时候为低,且t1时候为高的时候,与门输出高,此时为上升沿。

         当然,在复位的时刻,DFF被复位,无法检测触发信号。

         5.1.22

          一般为了防止触发信号的波动,加几级触发器,消除抖动,使得信号更稳定。

         此例程中,相对于上图多了触发器。其用触发器对信号打慢两拍,使得触发信号然后在进行相关的处理;再来检测边沿的上升沿,下降沿。

    wps_clip_image-4666

      

    (2)用verilog代码实现

    edge_tech_design.v代码如下所示:

    /*****************************************************

    * Module Name : edge_tech_design.v

    * Engineer : Crazy Bingo

    * Target Device : EP2C8Q208C8

    * Tool versions : Quartus II 11.0

    * Create Date : 2011-6-25

    * Revision : v1.0

    * Description :  

    *****************************************************/

    module edge_tech_design

    (

    input clk,

    input rst_n,

    input trigger,

    output pos_edge,

    output neg_edge

    );

    //Capture the rising_endge & falling_edge

    reg trigger_r0,trigger_r1,trigger_r2;

    always@(posedge clk or negedge rst_n)

    begin

    if(!rst_n)

    begin

    trigger_r0 <= 1'b0;

    trigger_r1 <= 1'b0;

    trigger_r2 <= 1'b0;

    end

    else

    begin

    trigger_r0 <= trigger;

    trigger_r1 <= trigger_r0;

    trigger_r2 <= trigger_r1;

    end

    end

    assign pos_edge = trigger_r1 & ~trigger_r2;

    assign neg_edge = ~trigger_r1 & trigger_r2;

    endmodule

    5.1.33没有十全十美的东西,也没有十全十美的电路、代码;本章节中所介绍的边沿检测技术亦如此。有如下缺陷:

    (1)增大CLK信号可以增强边沿检测的效率,但不能滤去跳变的杂波。

    (2)减少CLK可以有效滤去跳变的杂波,但不能及时检测到边沿跳变。

    (3)增加DFF能更好的滤除杂波,寄存信号,但同时检测延时大。

    6、算术运算问题

      (1)、k=1010,k1=k>>1;k=1*2^3+0*2^2+1*2^1+0*2^0;k1=1*2^2+0*2^1+1*2^0;故由此分析,k1=k/2(当k为奇数的时候k1=k/2+1),即向右移动一位缩小两倍,同理,向左移动一位,扩大两倍

  • 相关阅读:
    ARM汇编指令
    Linux系统里如何彻底的清空终端屏幕?
    Linux命令(16)压缩,解压文件
    Linux命令(18)查看当前用户who、whoami、who am i
    Linux命令(17)du 查看文件和目录磁盘使用情况
    Mongodb(3)插入文档,更新文档,删除文档
    Mongodb(2)创建数据库,删除数据库,创建集合,删除集合,显示文档内容
    Mongodb(1)如何存储以及简介
    Linux命令(15)查看系统版本信息
    Python 结巴分词(2)关键字提取
  • 原文地址:https://www.cnblogs.com/lanlingshan/p/2371467.html
Copyright © 2020-2023  润新知