6.3 同步时序逻辑电路的设计

目标:根据逻辑功能要求,设计逻辑电路图。

  1. 同步时序逻辑设计的一般步骤:

    image1

  2. 例:用D触发器设计一个8421BCD码同步十进制加计数器

    分析:实质上是对时钟脉冲计数0, 1, 2, ..., 9, 0, 1, 2, ...

    1. 列出状态表,分配状态

      image2

      4位编码对应16种状态,本例只取其中10个为有效状态,其余为无效状态。

    2. 选择触发器

      每位Q对应一个D触发器,四位对应四个D触发器。特性方程: \(Q^{n+1}=D\)

    3. 确定方程组

      \( Q_{3}^{n+1}=D_3=Q_{3}^{n}\overline{Q_{0}^{n}}+Q_{2}^{n}Q_{1}^{n}Q_{0}^{n} \)

      \( Q_{2}^{n+1}=D_2=Q_{2}^{n}\overline{Q_{1}^{n}}+Q_{2}^{n}\overline{Q_{0}^{n}}+\overline{Q_{2}^{n}}Q_{1}^{n}Q_{0}^{n} \)

      \( Q_{1}^{n+1}=D_1=Q_{1}^{n}\overline{Q_{0}^{n}}+\overline{Q_{3}^{n}Q_{1}^{n}}Q_{0}^{n} \), \( Q_{0}^{n+1}=D_0=\overline{Q_{0}^{n}} \)

    4. 绘制逻辑电路图(略)

    5. 检查自启动能力

      将6个无效状态代入电路没有简化之前的方程组,求次态

      image7

      按照该方程组得到的电路具备自启动/自校正能力。

  3. 例:设计一"011"序列检测器,每当X输入011码时,电路输出Y为1

    image8

    输入端X:串行随机信号

    输出端Y:当X出现011序列时,Y=1;否则Y=0

    1. 状态图的建立:

      image9

      image10

      状态A:开始检测/重新检测

      状态B:表示已经收到了"0"

      状态C:已经连续输入"01"

      状态D:已经连续输入"011"

    2. Verilog建模

      1. 明确输入:时钟CP、被检信号X、复位rst

      2. 输出:Y

      3. 对状态进行编码

    module SequenceDetector011(
        input cp,
        input rst,
        input x,
        output y
    );
        parameter STATE_A = 4'b0001;
        parameter STATE_B = 4'b0010;
        parameter STATE_C = 4'b0100;
        parameter STATE_D = 4'b1000;
        reg [3:0] state;
        always @(posedge cp or posedge rst) begin
            if (rst) begin
                state <= STATE_A;
            end else begin
                case (state)
                    STATE_A: 
                        if (!x)
                            state <= STATE_B;
                    STATE_B: 
                        if (x)
                            state <= STATE_C;
                    STATE_C: 
                        if (x)
                            state <= STATE_D;
                        else
                            state <= STATE_B;
                    STATE_D: 
                        if (x)
                            state <= STATE_A;
                        else
                            state <= STATE_B;
                    default: 
                        state <= STATE_A;
                endcase
            end
        end
        assign y = (state == STATE_D);
    endmodule // SequenceDetector011
    
  4. 有限状态机的设计 时序逻辑电路就是和“状态”打交道。状态机的本质就是对具有逻辑顺序时序规律的事件的一种描述方法。状态机的工作方式是控制信号根据预先设定的状态“顺序”运行的,它是纯硬件系统中的顺序控制电路。通常采用case语句设计实现。

    1. 根据功能要求,设计出状态图

      明确状态的转换关系并注明状态转换条件注明输出与状态、输入的关系

    2. 对状态进行编码

      二进制编码、格雷编码、独热码

    3. 分段设计状态机主体

      1. 第一段:采用always模块描述状态转移条件和规律

      2. 第二段:采用always或assign模块或组合逻辑描述输出

    4. 检查是否有自启动能力

      检查状态变量是否有初始值和默认值

      1. always复位语句中赋初值

      2. case分支语句中,要有default语句,将其它无效状态转到有效状态

  5. 售货机设计

    售货机能自动识别1元和0.5元的硬币,出货口和找零口,矿泉水的价格是1.5元。

    已知关系:当投入的金额等于1.5元时,出货口输出一瓶矿泉水;当投入的金额大于1.5元时(即2元,不会超过2元),出货口输出一瓶矿泉水,同时找零口输出相应余额的硬币。

    1. 明确输入输出:

      输入:按键BTN、投币M(2bit,01表示0.5元,10表示1元)

      隐性输入:clk、rst

      输出:出水W、退钱:Y(2bit,01表示0.5元,10表示1元)

    2. 画状态图

      image11

      image12

      image13

      image14

    二进制编码:

    parameter STATE_A = 4'b00;
    parameter STATE_B = 4'b01;
    parameter STATE_C = 4'b10;
    parameter STATE_D = 4'b11;
    

    独热码:

    parameter STATE_A = 4'b0001;
    parameter STATE_B = 4'b0010;
    parameter STATE_C = 4'b0100;
    parameter STATE_D = 4'b1000;
    
    `default_nettype none
    
    module FiniteStateMachineSeller(
        clk,
        rst,
        inMoney,
        btnCancel,
        water,
        outMoney
    );
    
        input wire clk;
        input wire rst;
        input wire [1:0] inMoney;       // 01---$0.5, 10---$1.0
        input wire btnCancel;           // Out Money
        output wire water;              // Out Water
        output wire [1:0] outMoney;     // 01---$0.5, 10---$1.0
    
        parameter ZERO          = 7'b0000001;    // Waiting...
        parameter HALF          = 7'b0000010;    // Get $0.5
        parameter ONE           = 7'b0000100;    // Get $1.0
        parameter ONE_AND_HALF  = 7'b0001000;    // Get $1.5
        parameter TWO           = 7'b0010000;    // Get $2.0
        parameter OUT_HALF      = 7'b0100000;    // Out $0.5
        parameter OUT_ONE       = 7'b1000000;    // Out $1.0
    
        reg [6:0] state;
    
        always @(posedge clk) begin
            if (rst) begin
                state <= ZERO;
            end else begin
                case (state)
                    ZERO:
                        if (inMoney == 2'b01)
                            state <= HALF;
                        else if (inMoney == 2'b10)
                            state <= ONE;
                    HALF:
                        if (inMoney == 2'b01)
                            state <= ONE;
                        else if (inMoney == 2'b10)
                            state <= ONE_AND_HALF;
                        else if (btnCancel)
                            state <= OUT_HALF;
                    ONE:
                        if (inMoney == 2'b01)
                            state <= ONE_AND_HALF;
                        else if (inMoney == 2'b10)
                            state <= TWO;
                        else if (btnCancel)
                            state <= OUT_ONE;
                    ONE_AND_HALF:
                        state <= ZERO;
                    TWO:
                        state <= OUT_HALF;
                    OUT_HALF:
                        state <= ZERO;
                    OUT_ONE:
                        state <= ZERO;
                    default: 
                        state <= ZERO;
                endcase
            end
        end
    
        assign water = (state == TWO) | (state == ONE_AND_HALF);
        assign outMoney = (state == OUT_ONE) ? 2'b10 : 
                        (state == OUT_HALF) ? 2'b01 : 2'b00;
    
    endmodule // FiniteStateMachineSeller