LJgibbs · 2020年10月30日

HDLBits:在线学习 Verilog (三十 · Problem 145-149)

转载自:知乎
作者:ljgibbs

首先附上传送门:Exams/m2014 q6c - HDLBits首先附上传送门:

Exams/m2014 q6c - HDLBits​hdlbits.01xz.net图标

Problem 145 Q6c FSM one-hot next-state logic

牛刀小试

本题和前一题的状态转移图相同,但使用独热码来为状态机编码。

状态机编码

状态机编码主要可以分为独热码(one-hot code) 编码以及二进制编码两类。

独热码为每个状态分配 1 个比特位,该位为 1'b1 置起时表示状态机处于该状态。使用独热码的好处在于状态判断时不需要组合逻辑,判断对应状态的触发器输出即可。

举个栗子,state = 3'b1 表示状态 A, 3'b2 表示状态 B,3'b4 表示状态 C ,使用独热码编码。判断是否为状态 A 时,只需要判断 state[0] 是否为 1'b1; 状态 B C 同理。

如果使用二进制码编码,好处在于更少的触发器。只需要使用 2 个触发器,即 2 bit 就可以表示 3 个状态。但判断状态 A 时需要使用组合逻辑 ~state[1] && state[0] 。组合逻辑会增加时序路径长度,降低系统最大工作频率。

所以在触发器资源较为丰富的 FPGA 应用中一般使用独热码而不是二进制来对状态编码。

言归正传,本题使用 6 bit 来表示 6 个状态,为 000001 表示状态 A,000010 表示状态 B,等等依次类推。

和上一题一样,本题要求输出次状态 nxt\_state 的一部分即 Y2,Y4.

注意:在这道练习中,为了判断读者是否使用独热码来编码,以及使用独热码的方式来处理状态跳变。本题 testbench 会输入一些不存在的状态。如果使用二进制编码,这些不存在的状态都会使状态机跳转到 default 分支,从而引发输出错误(尽管逻辑正确)

使用独热码,因为是分别对每一 bit 进行状态跳转判断,所以每一比特仍然会分别进入正常状态的分支。(但其实此时状态是错误的,本题如此设置是出于考察独热码的使用。)

比如输入一个不存在的状态 6'b000011,二进制编码时进入 default 分支,状态固定为复位状态。但独热码应用中,最低位和次低位同时为 1,分别判断为状态 A 或是状态 B,进行跳转。testbench 会分别检查这些跳转。

解答与分析

module top_module (
    input [6:1] y,
    input w,
    output Y2,
    output Y4);

    `define STT_W 6
    `define STT_W1 `STT_W - 1

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

    localparam sA  = `STT_W'd1;
    localparam sB  = `STT_W'd2;
    localparam sC  = `STT_W'd4;
    localparam sD  = `STT_W'd8;
    localparam sE  = `STT_W'd10;
    localparam sF  = `STT_W'd20;

    // State transition logic (combinational)
    always @(*) begin
        nxt_state[0]    <=  w ? state[0] || state[3] : 1'b0;
        nxt_state[1]    <=  w ? 1'b0 : state[0];
        nxt_state[2]    <=  w ? 1'b0 : state[5] || state[1];
        nxt_state[3]    <=  w ? state[1] || state[2] || state[4] || state[5]: 1'b0;
        nxt_state[4]    <=  w ? 1'b0 : state[4] || state[2];
        nxt_state[5]    <=  w ? 1'b0 : state[3];
    end
 
    assign  Y2   =   nxt_state[1];
    assign  Y4   =   nxt_state[3];
    
endmodule

根据题意输出次状态的一部分 Y2 Y4,由于输入的是 y[6:1] ,所以 Y2 对应于解答中的 nxt\_state[1],Y4 同理。

Problem 146 Q6 FSM

牛刀小试

本题的状态转移图和上一题相同,但此题需要实现一个完整的状态机,并根据图中的标识产生正确的输出 z 。

解答与分析

module top_module (
    input clk,
    input reset,     // synchronous reset
    input w,
    output z);

    
    `define STT_W 6
    `define STT_W1 `STT_W - 1

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

    localparam sA  = `STT_W'd1;
    localparam sB  = `STT_W'd2;
    localparam sC  = `STT_W'd4;
    localparam sD  = `STT_W'd8;
    localparam sE  = `STT_W'd10;
    localparam sF  = `STT_W'd20;

    // State transition logic (combinational)
    always @(*) begin
        nxt_state[0]    <=  w ? state[0] || state[3] : 1'b0;
        nxt_state[1]    <=  w ? 1'b0 : state[0];
        nxt_state[2]    <=  w ? 1'b0 : state[5] || state[1];
        nxt_state[3]    <=  w ? state[1] || state[2] || state[4] || state[5]: 1'b0;
        nxt_state[4]    <=  w ? 1'b0 : state[4] || state[2];
        nxt_state[5]    <=  w ? 1'b0 : state[3];
    end

    always @(posedge clk ) begin
        if(reset)
            state   <=  sA;
        else begin
            state   <=  nxt_state;
        end  
    end
 
    assign  z   =   state[4] || state[5];  
endmodule

Problem 147 Q2a FSM

牛刀小试

本题仍然似乎是一道原作者任教学校的测试题。编写 Verilog 代码实现下图中的状态机。这道测试题要求分别使用两个 always 块来实现状态跳转以及状态触发器逻辑。输出逻辑可以使用 assign 连续赋值也可以使用 always 块实现,随你的便。状态编码方式也随你的便。

但请 注意 这里的图和上题中的状态转移图有所 不同
(来自一个一开始没发现的人。。。)

注意这里的图和上题中的图不同

解答与分析

逻辑和上一题没有不同,不再赘述代码,注意根据状态转移图实现正确的状态转移逻辑。

Problem 148 Q2b One-hot FSM equations

牛刀小试

本题和此前的题目类似,使用独热码编码方式来描述上题中的状态机。如果在此前的题目中搭建了完善的状态机框架,那么稍稍修改就能够应对此题。这里就不再赘述了。

Problem 149 Q2a FSM (Exams/2013 q2afsm)

牛刀小试

本题需要实现一个如下图的状态机。

本状态机扮演一个仲裁电路,控制三个设备对于某种资源的访问权限。

每个设备通过置起 r[i] 信号为 1'b1 来表示对这种资源的请求。r[1],r[2].r[3]分别对应三个设备的请求信号。三个请求信号作为 FSM 的输入信号。

FSM 在没有任何请求时处于状态 A。当出现了一个或多项请求时,由 FSM 决定哪台设备获得资源的,并向其发出许可信号 g[i],置为 1'b1。g[i] 信号是 FSM 的输出信号。

本系统存在优先级,设备 1 拥有最高权限,设备 2 次之,设备 3 的权限最低。因此设备 3 只能在系统处于状态 A 的情况下才能获得资源访问权限。一旦设备获得 FSM 给出的许可信号后,将持续持有资源直至其将请求信号置低为止,请求信号为高期间不能被打断。

编写 Verilog 代码实现这个 FSM。分别使用两个 always 块来实现状态跳转以及状态触发器逻辑。输出逻辑可以使用 assign 连续赋值也可以使用 always 块实现,随你的便。状态编码方式也随你的便。

解答与分析

module top_module (
    input clk,
    input resetn,    // active-low synchronous reset
    input [3:1] r,   // request
    output [3:1] g   // grant
); 
    `define STT_W 4
    `define STT_W1 `STT_W - 1

    wire [2:0] ri = r;
    wire [2:0] go;

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

    localparam sidle    = 0;
    localparam sd1      = 1;//devive 1 
    localparam sd2      = 2;
    localparam sd3      = 3;

    // State transition logic (combinational)
    always @(*) begin
        nxt_state[sidle]    <=  (state[sidle] && ~(|ri)) 
                             || (state[sd1]   && ~ri[0]) 
                             || (state[sd2]   && ~ri[1]) 
                             || (state[sd3]   && ~ri[2]);

        nxt_state[sd1  ]    <=  (state[sidle] && ri[0])
                             || (state[sd1  ] && ri[0]);

        nxt_state[sd2  ]    <=  (state[sidle] && ~ri[0] && ri[1])
                             || (state[sd2  ] && ri[1]);

        nxt_state[sd3  ]    <=  (state[sidle] && ~ri[0] && ~ri[1] && ri[2])
                             || (state[sd3  ] && ri[2]);
        
    end

    // State flip-flops (sequential)
    always @(posedge clk ) begin
        if(~resetn)
            state   <=  `STT_W'b1;
        else begin
            state   <=  nxt_state;
        end  
    end

    //output logic
    assign      go[0]   =   state[sd1  ];
    assign      go[1]   =   state[sd2  ];
    assign      go[2]   =   state[sd3  ];
    assign      g       =   go;

endmodule

若从题目所给的状态转移图来描述这个状态机是比较容易的。我们可以从中学习使用状态机实现一个优先级系统的思路。最好能够不依赖于状态转移图,根据请求与许可信号来描述这个 FSM 系统。

推荐阅读

关注此系列,请关注专栏FPGA的逻辑
推荐阅读
关注数
10614
内容数
577
FPGA Logic 二三事
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息