HDLBits:在线学习 Verilog (二十九 · Problem 140-144)

2021-04-15 14:58:28 浏览数 (1)

本系列内容来自于知乎专栏,链接如下:https://zhuanlan.zhihu.com/c_1131528588117385216 本系列文章将和读者一起巡礼数字逻辑在线学习网站 HDLBits 的教程与习题,并附上解答和一些作者个人的理解,相信无论是想 7 分钟精通 Verilog,还是对 Verilog 和数电知识查漏补缺的同学,都能从中有所收获。

Problem 140 Serial two's complementer (Mealy FSM)

牛刀小试

本题和上一题 Serial two's complementer (Moore FSM) 一样,使用状态机实现一个二进制补码生成器,不同的是此题使用米里型状态机实现。

在本题与上一题中的米里型和摩尔型状态机最简单的区别在于:两者在输出时,摩尔型 FSM 有一个周期延迟。

米里型的输出由当前状态和输入信号的组合逻辑实现,输出信号与输入信号同步。

而摩尔型状态机的输出仅由当前状态决定,与输入信号异步,往往存在延迟。

图片来自下方链接文章,出处见水印

有关两种状态机的知识,大家可以移步下方的文章。

Power小强:FPGA菜鸟学习笔记——4、有限状态机zhuanlan.zhihu.com

书归正传,本题中给出了状态转移图,我们可以直接看图实现状态机。

存在两个状态,复位状态 A,在输入 x 为 1 后状态转移为 B,并保持在状态 B。

状态 A 中输出 z 与输入 x 相同;状态 B 中输出 z 与输入 x 相反。

简单的状态机,但这是如何实现二进制补码的呢?我们根据例子来看:

代码语言:javascript复制
输入序列为:001101000,即原码,补码通过将原码取反加 1 实现。
取反:             110010111
加 1              110011000

将原码和补码放在一起观察:

代码语言:javascript复制
001101    000
110011    000

可以发现前半部两者取反,而后半部分两者相同(均为0),两者的分界即是低位第一个 1 。所以有了上图中的状态转移图。

这里我们没有深究原理,只是从状态机的角度出发来实现该题目。(老实说一开始笔者也没想出来如何用状态机来实现这个电路 `_`)

解答与分析

代码语言:javascript复制
module top_module (
    input clk,
    input areset,    // Asynchronous active-low reset
    input x,
    output z ); 

    reg [1:0]   state;
    reg [1:0]   nxt_state;

    localparam A = 0;
    localparam B = 1;

    // State transition logic (combinational)
    always @(*) begin
        case (state)
            A:begin
                if(x)
                    nxt_state = B;
                else
                    nxt_state = A;
            end
            B:begin
                nxt_state = B;
            end
          default: begin
            nxt_state = A;
          end
        endcase
    end

    // State flip-flops (sequential)
    always @(posedge clk or posedge areset) begin
        if(areset)
            state   <=  A;
        else begin
            state   <=  nxt_state;
        end  
    end
	
    //output logic
    assign  z    =   state == A ? x:~x ;
endmodule

使用独热码的方式实现了一个双状态状态机。输出 z 取决于状态以及输入信号 x,z = x 或者 z = ~x

Problem 141 Q3a:FSM

牛刀小试

接下来一系列题目是状态机的练习题,出处应该是原作者任教学校的考试题目,适合初学者巩固状态机的编码能力。对于一定基础的学习者来说适合进行一次快速通过 Fast Through.(也适合国内高校的相关课程学习一下)

本题需要实现一个双状态状态机,状态转移并不复杂,由输入变量 s 决定。

稍显复杂的是输出逻辑,由输入变量 w 决定。当处于状态 B 时,以三个时钟为一个周期,如果三个周期中有两个周期 w 为 1,则 z 输出一个周期高电平。

值得注意的是:需要三个周期中 exactly 两个周期为 1 。

解答与分析

代码语言:javascript复制
module top_module (
    input clk,
    input reset,   // Synchronous reset
    input s,
    input w,
    output z
);

    reg [3:0]   state;
    reg [3:0]   nxt_state;

    wire        w_shft_ena;
    reg[1:0]    w_cntr;
    localparam A = 0;
    localparam B = 1;
    localparam B1 = 2;
    localparam B2 = 4;

    // State transition logic (combinational)
    always @(*) begin
        case (state)
            A:begin
                if(s)
                    nxt_state = B;
                else
                    nxt_state = A;
            end
            B:begin
                nxt_state = B1;
            end
            B1:begin
                nxt_state = B2;
            end
            B2:begin
                nxt_state = B;
            end
          default: begin
            nxt_state = A;
          end
        endcase
    end

    // State flip-flops (sequential)
    always @(posedge clk ) begin
        if(reset)
            state   <=  A;
        else begin
            state   <=  nxt_state;
        end  
    end

    always @(posedge clk ) begin
        if(reset)
            w_cntr   <=  2'b0;
        else if(state == B)begin
            w_cntr   <=  w;
        end
        else if(state == B1 || state == B2)begin
            w_cntr   <=  w_cntr   w;
        end   
    end

    assign  z    =   state == B &&  w_cntr == 2 ? 1'b1 : 1'b0;

endmodule

实现中值的注意的是,为了便于每三个时钟为一个单位检查输入 w 的值。笔者将状态 B 划分为 B1 B2 B3 三个子状态。使用计数器 w_cntr 在子状态中统计 w 为 1 的次数。

输出阶段为 B1 状态,当计数器值为 2 时输出 1,对应于 三个周期中 exactly 两个周期为 1

Problem 142 Q3b:FSM

牛刀小试

这是一道简单的根据状态转移实现状态机的题目,实现完整的三段式状态机

解答与分析

代码语言:javascript复制
module top_module (
    input clk,
    input reset,    // Asynchronous active-low reset
    input x,
    output z ); 
    
    `define STT_W 3
    `define STT_W1 `STT_W - 1

    reg [`STT_W1:0]   state;
    reg [`STT_W1:0]   nxt_state;

    localparam IDLE  = `STT_W'd0;
    localparam s_1   = `STT_W'd1;
    localparam s_10  = `STT_W'd2;
    localparam s_11  = `STT_W'd3;
    localparam s_100 = `STT_W'd4;

    // State transition logic (combinational)
    always @(*) begin
        case (state)
            IDLE:begin
                if(x)
                    nxt_state = s_1;
                else
                    nxt_state = IDLE;
            end
            s_1:begin
                if(x)
                    nxt_state = s_100;
                else
                    nxt_state = s_1;
            end
            s_10:begin
                if(x)
                    nxt_state = s_1;
                else
                    nxt_state = s_10;
            end
            s_11:begin
                if(x)
                    nxt_state = s_10;
                else
                    nxt_state = s_1;
            end
            s_100:begin
                if(x)
                    nxt_state =s_100;
                else
                    nxt_state = s_11;
            end
          default: begin
            nxt_state = IDLE;
          end
        endcase
    end

    // State flip-flops (sequential)
    always @(posedge clk ) begin
        if(reset)
            state   <=  IDLE;
        else begin
            state   <=  nxt_state;
        end  
    end

    assign  z    =   state >= s_11;

endmodule

有没有巩固自己的状态机编码能力或者 Fast Through 呢?

Problem 143 Q3c:FSM logic

牛刀小试

本题和前一题的区别在于,本题的当前状态于端口输入,只需要实现三段式中的状态跳转逻辑以及输出逻辑,不需要实现状态触发器。

我看过了,状态转移同上一题相同

解答与分析

代码语言:javascript复制
module top_module (
    input clk,
    input [2:0] y,
    input x,
    output Y0,
    output z
);
    
    `define STT_W 3
    `define STT_W1 `STT_W - 1

    wire [`STT_W1:0]   state = y;
    reg [`STT_W1:0]   nxt_state;

    localparam IDLE  = `STT_W'd0;
    localparam s_1   = `STT_W'd1;
    localparam s_10  = `STT_W'd2;
    localparam s_11  = `STT_W'd3;
    localparam s_100 = `STT_W'd4;

    // State transition logic (combinational)
    always @(*) begin
        case (state)
            IDLE:begin
                if(x)
                    nxt_state = s_1;
                else
                    nxt_state = IDLE;
            end
            s_1:begin
                if(x)
                    nxt_state = s_100;
                else
                    nxt_state = s_1;
            end
            s_10:begin
                if(x)
                    nxt_state = s_1;
                else
                    nxt_state = s_10;
            end
            s_11:begin
                if(x)
                    nxt_state = s_10;
                else
                    nxt_state = s_1;
            end
            s_100:begin
                if(x)
                    nxt_state =s_100;
                else
                    nxt_state = s_11;
            end
          default: begin
            nxt_state = IDLE;
          end
        endcase
    end
    
    assign  Y0   =   nxt_state[0];
    assign  z    =   state >= s_11;

endmodule

输入端口中的 y 输入当前状态,按照题目要求输出次状态最低位 Y0

Problem 144 Q6b:FSM next-state logic

牛刀小试

下图为状态机状态转移图。本题需要根据状态转移图以及输入的当前状态 y[3:1]实现状态跳转逻辑,输出次状态的一部分 Y2.

状态机中共有 6 个状态 A - F 分别用 000,001... 101 表示。使用二进制方式编码状态。

解答与分析

代码语言:javascript复制
module top_module (
    input [3:1] y,
    input w,
    output Y2);
    
    `define STT_W 3
    `define STT_W1 `STT_W - 1

    wire [`STT_W1:0]   state = y;
    reg [`STT_W1:0]   nxt_state;

    localparam sA  = `STT_W'd0;
    localparam sB  = `STT_W'd1;
    localparam sC  = `STT_W'd2;
    localparam sD  = `STT_W'd3;
    localparam sE  = `STT_W'd4;
    localparam sF  = `STT_W'd5;

    // State transition logic (combinational)
    always @(*) begin
        case (state)
            sA:begin
                if(w)
                    nxt_state = sA;
                else
                    nxt_state = sB;
            end
            sB:begin
                if(w)
                    nxt_state = sD;
                else
                    nxt_state = sC;
            end
            sC:begin
                if(w)
                    nxt_state = sD;
                else
                    nxt_state = sE;
            end
            sD:begin
                if(w)
                    nxt_state = sA;
                else
                    nxt_state = sF;
            end
            sE:begin
                if(w)
                    nxt_state = sD;
                else
                    nxt_state = sE;
            end
            sF:begin
                if(w)
                    nxt_state = sD;
                else
                    nxt_state = sC;
            end
          default: begin
            nxt_state = sA;
          end
        endcase
    end
 
    assign  Y2   =   nxt_state[1];
    
endmodule

值得注意的是 Y2 输出的是对应 Y[2] 的次态,但 Y 在输入时取的是 Y[3:1] ,所以 Y2 取次态 nxt_state[1] 而不是 nxt_state[2]。

0 人点赞