博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
HDLBits 系列(38)值得一看的状态机设计题目
阅读量:2027 次
发布时间:2019-04-28

本文共 6939 字,大约阅读时间需要 23 分钟。

目录


 


背景

这是这个系列中的一个状态机的题目,但是相比于给了你完整状态转移图之类的题目,这个题目还是稍微有点难的,我实在不知道该怎么给这个博客起个什么名字?

我在线等一个简单的方式去解决今天的问题,而如题所说,我用最无能的方式来解决这个问题,但简单的方式一定存在。

2019/12/16更新

今天一个帅兄弟给了我一个答案,很巧妙,这里十分感谢。我把它放到后面来给出。

原题复现

Consider a finite state machine with inputs s and w. Assume that the FSM begins in a reset state called A, as depicted below. The FSM remains in state A as long as s = 0, and it moves to state B when s = 1. Once in state B the FSM examines the value of the input w in the next three clock cycles. If w = 1 in exactly two of these clock cycles, then the FSM has to set an output z to 1 in the following clock cycle. Otherwise z has to be 0. The FSM continues checking w for the next three clock cycles, and so on. The timing diagram below illustrates the required values of z for different values of w.

Use as few states as possible. Note that the s input is used only in state A, so you need to consider just the w input.

我的方案

状态转移图

我的解决方案,有点无奈,多加了一些状态:

我的设计

根据此状态转移图给出我的设计:

module top_module (    input clk,    input reset,   // Synchronous reset    input s,    input w,    output z);        localparam A = 0, B = 1, S0 = 3, S1 = 4, S2 = 5, S3 = 6, S4 = 7, S5 = 8, S6 = 9, S7 = 10, S8 = 11, S9 = 12, S10 = 13, S11 = 14;    reg [3:0] state, next_state;    always@(*) begin        case(state)            A: begin                if(s) next_state = B;                else next_state = A;            end            B: begin                if(w) next_state = S1;                else next_state = S0;            end            S0: begin                if(w) next_state = S2;                else next_state = S4;            end            S1: begin                if(w) next_state = S9;                else next_state = S6;            end            S2: begin                if(w) next_state = S3;                else next_state = S5;            end            S3: begin                if(w) next_state = S1;                else next_state = S0;            end            S4: begin                next_state = S5;            end            S5: begin                if(w) next_state = S1;                else next_state = S0;            end            S6: begin                if(w) next_state = S7;                else next_state = S8;            end            S7: begin                if(w) next_state = S1;                else next_state = S0;            end            S8: begin                if(w) next_state = S1;                else next_state = S0;            end            S9: begin                if(w) next_state = S11;                else next_state = S10;            end            S10: begin                if(w) next_state = S1;                else next_state = S0;            end            S11: begin                if(w) next_state = S1;                else next_state = S0;            end            default: begin                next_state = A;            end                     endcase            end    always@(posedge clk) begin        if(reset) state <= 0;        else state <= next_state;    end    assign z = (state == S10 || state == S7 || state == S3) ? 1 : 0;                endmodule

测试成功。


更新方案

今天群里的大佬给了一种简单的方法,状态转移图确实简单了,但是理解起来呢?

我之前用的方案是在B之后的三个周期内,列举w的值,取值情况有8种,然后添加更多的状态去解决这个问题,不得不说状态转移图看起来复杂很多,也绝对不是推荐的方案。

我等待的确实是今天的这个方案,通过计数,不需要添加更多的状态,这也是我一开始就想用的方法,只是计数的时序当时没有搞定,今天很感谢,群里的一位兄弟。

直接给出设计,通过代码就应该能看出来设计的思路:

module top_module (    input clk,    input reset,   // Synchronous reset    input s,    input w,    output z);    parameter A = 1'b0, B = 1'b1;    reg current_state;    reg next_state;        always@(posedge clk)begin        if(reset)begin            current_state <= A;        end        else begin            current_state <= next_state;        end    end        always@(*)begin        case(current_state)            A:begin                next_state = s ? B : A;            end            B:begin                next_state = B;            end        endcase    end    reg w_reg1;    reg w_reg2;    always@(posedge clk)begin        if(reset)begin            w_reg1 <= 1'b0;            w_reg2 <= 1'b0;        end        else if(next_state == B)begin            w_reg1 <= w;            w_reg2 <= w_reg1;        end        else begin            w_reg1 <= 1'b0;            w_reg2 <= 1'b0;        end    end        always@(posedge clk)begin        if(reset)begin            z <= 1'b0;        end        else if(next_state == B && counter == 2'd0)begin            if(~w & w_reg1 & w_reg2 | w & ~w_reg1 & w_reg2 | w & w_reg1 & ~w_reg2)begin                z <= 1'b1;            end            else begin                z <= 1'b0;            end        end        else begin            z <= 1'b0;        end    end           reg [1:0] counter;    always@(posedge clk)begin        if(reset)begin            counter <= 2'd0;        end        else if(counter == 2'd2)begin            counter <= 2'd0;        end        else if(next_state == B)begin            counter <= counter + 1'b1;        end    endendmodule

巧妙之处在于将输入w延迟两拍之后进行判断,如果有两个w为1,则在下一个周期将输出z置位.

有的朋友,也许在状态机的设计中,习惯将第三段使用组合逻辑来实现,这个题目的第三段也可以使用组合逻辑,但是呢?确实也没有必要,因为状态机的第三段本身既可以使用组合逻辑,也可以使用时序逻辑,如果使用时序逻辑。

下面给出组合逻辑的方案:

module top_module (    input clk,    input reset,   // Synchronous reset    input s,    input w,    output reg z);    parameter A = 1'b0, B = 1'b1;    reg current_state;    reg next_state;        always@(posedge clk)begin        if(reset)begin            current_state <= A;        end        else begin            current_state <= next_state;        end    end        always@(*)begin        case(current_state)            A:begin                next_state = s ? B : A;            end            B:begin                next_state = B;            end        endcase    end    reg w_reg1;    reg w_reg2;    always@(posedge clk)begin        if(reset)begin            w_reg1 <= 1'b0;            w_reg2 <= 1'b0;        end        else if(next_state == B)begin            w_reg1 <= w;            w_reg2 <= w_reg1;        end        else begin            w_reg1 <= 1'b0;            w_reg2 <= 1'b0;        end    end        reg z_mid;    always@(*)begin        if(reset)begin            z_mid <= 1'b0;        end        else if(current_state == B && counter == 2'd0)begin            if(~w & w_reg1 & w_reg2 | w & ~w_reg1 & w_reg2 | w & w_reg1 & ~w_reg2)begin                z_mid <= 1'b1;            end            else begin                z_mid <= 1'b0;            end        end        else begin            z_mid <= 1'b0;        end    end        always@(posedge clk)begin        if(reset)begin            z <= 1'b0;        end        else begin            z <= z_mid;        end    end            reg [1:0] counter;    always@(posedge clk)begin        if(reset)begin            counter <= 2'd0;        end        else if(counter == 2'd2)begin            counter <= 2'd0;        end        else if(next_state == B)begin            counter <= counter + 1'b1;        end    endendmodule

只需要将第三段改为组合逻辑,但是输出需要延迟一拍,为什么?看时序图。

FPGA/IC群推荐

有幸在这个群里认识了诸多俊杰,让我欣慰。

 

 

 

 

 

转载地址:http://xdcaf.baihongyu.com/

你可能感兴趣的文章
bash 命令执行环境
查看>>
bash 作业控制
查看>>
物理内存的管理
查看>>
高效能人士的七个习惯——由内而外全面造就自己
查看>>
为什么精英都是清单控(笔记)——工作清单
查看>>
怦然心动的人生整理魔法(笔记)——物品类别整理
查看>>
让人生发生戏剧性变化的整理魔法(笔记)
查看>>
按物品类别整理的心动收纳法(笔记)
查看>>
番茄工作图解——序(笔记)
查看>>
每天最重要的2小时——序(笔记)
查看>>
29.开源项目--git远程仓库的概念
查看>>
36.开源项目--git搭建本地Git服务器
查看>>
01.创新与企业家精神——创新实践
查看>>
17.创新与企业家精神——攻其软肋
查看>>
14.openssl编程——错误处理
查看>>
29.openssl编程——PKCS7
查看>>
openssl passwd
查看>>
openssl pkeyutl
查看>>
02.规划过程组表格-责任分配矩阵
查看>>
02.规划过程组表格-质量管理计划
查看>>