【问题标题】:State machine transitions to impossible state on Signal Tap状态机在 Signal Tap 上转换为不可能的状态
【发布时间】:2019-06-17 17:56:00
【问题描述】:

我试图通过 SPI 从已知的二维数组一次输出一位。

logic [7:0] fpga_status_queue [0:17],

我的状态机由于某种原因进入了一个奇怪的状态。

18'h

这是我的代码:

module FPGA_STATUS_READ (
     input clk,
    input sclk, 
    input cs, // Clock Enable
    input rst_n,  // Asynchronous reset active low
    input fpgastatus_command,
    input logic [3:0] group_control,
    input logic [7:0] loopback,
    output logic [7:0] fpga_status_queue [0:17],
    output logic dout
);

    // `include "../../config_files/rtl_config.svh"

    assign fpga_status_queue[ 0] = 8'h1;//{group_control};
    assign fpga_status_queue[ 1] = 8'h1;//{loopback}; 
    assign fpga_status_queue[ 2] = 8'h1;//{synth_version[0]}; 
    assign fpga_status_queue[ 3] = 8'h1;//{synth_version[1]}; 
    assign fpga_status_queue[ 4] = 8'h1;//{synth_version[2]}; 
    assign fpga_status_queue[ 5] = 8'h1;//{grid_version[0]}; 
    assign fpga_status_queue[ 6] = 8'h1;//{grid_version[1]}; 
    assign fpga_status_queue[ 7] = 8'h1;//{grid_version[2]}; 
    assign fpga_status_queue[ 8] = 8'h1;//{pa_version[0]}; 
    assign fpga_status_queue[ 9] = 8'h1;//{pa_version[1]}; 
    assign fpga_status_queue[10] = 8'h1;//{pa_version[2]}; 
    assign fpga_status_queue[11] = 8'h1;//{hdl_version[0]}; 
    assign fpga_status_queue[12] = 8'h1;//{hdl_version[1]}; 
    assign fpga_status_queue[13] = 8'h1;//{hdl_version[2]};     
    assign fpga_status_queue[14] = '1;
    assign fpga_status_queue[15] = '1;
    assign fpga_status_queue[16] = '0;
    assign fpga_status_queue[17] = '0;

    logic bit_run_counter;
    logic bit_load_counter;
    logic [4:0] bit_current_value;
    logic bit_count_reached;

    logic word_run_counter;
    logic word_load_counter;
    logic [4:0] word_current_value;
    logic word_count_reached;

    typedef enum logic [2:0] {IDLE, CS_WAIT, MISO_OUT, BIT_CHANGE, WORD_CHANGE} status_states;
    status_states current_state, next_state;

    always_ff @(posedge clk or negedge rst_n) begin : step_forward
        if(!rst_n)
            current_state                        <= IDLE;
        else 
            current_state                        <= next_state;
    end : step_forward

    always_comb begin : set_next_state
        next_state = IDLE;
        case (current_state)
            IDLE       : next_state = fpgastatus_command ? CS_WAIT : IDLE;
            CS_WAIT    : next_state = ~cs ? MISO_OUT : CS_WAIT;
            MISO_OUT   : begin//next_state = sclk ? bit_count_reached ? word_count_reached ? IDLE: WORD_CHANGE : BIT_CHANGE: MISO_OUT;
                if (sclk && bit_count_reached && word_count_reached) 
                    next_state = IDLE;
                else if (sclk && bit_count_reached) 
                    next_state = WORD_CHANGE;
                else if (sclk)
                    next_state = BIT_CHANGE;
                else 
                    next_state = MISO_OUT;
            end
            BIT_CHANGE : next_state = MISO_OUT;
            WORD_CHANGE: next_state = MISO_OUT;
            default : next_state = IDLE;
        endcase
    end

    always_comb begin : cntr_logic
        bit_run_counter           = '0;
        bit_load_counter          = '0;
        word_run_counter          = '0;
        word_load_counter         = '0;
        dout                      = '0;
        unique case (current_state)
            IDLE       :begin 
                bit_load_counter  = '1;
                word_load_counter = '1;
            end 
            CS_WAIT    :begin 
                bit_load_counter  = '1;
                word_load_counter = '1;
            end 
            MISO_OUT   :begin 
                dout              = fpga_status_queue[word_current_value][bit_current_value];
            end
            BIT_CHANGE :begin 
                bit_run_counter   = '1;
            end 
            WORD_CHANGE:begin 
                word_run_counter  = '1;
                bit_load_counter  = '1;
            end 
            default : dout        = '0;
        endcase
    end

    up_down_counter #(
            .ABSOLUTE_DATA_WIDTH(4)
        ) inst_bit_counter (
            .clk           (clk),
            .run_counter   (bit_run_counter),
            .rst_n         (rst_n),
            .count_value   (5'h7),
            .load_counter  (bit_load_counter),
            .up_counter    ('0),
            .current_value (bit_current_value),
            .count_reached (bit_count_reached)
        );

    up_down_counter #(
            .ABSOLUTE_DATA_WIDTH(5)
        ) inst_word_counter (
            .clk           (clk),
            .run_counter   (word_run_counter),
            .rst_n         (rst_n),
            .count_value   (5'h11),
            .load_counter  (word_load_counter),
            .up_counter    ('0),
            .current_value (word_current_value),
            .count_reached (word_count_reached)
        );

endmodule

它应该转到WORD_CHANGE,但WORD_CHANGEMISO_OUT 都是当前状态的下一个状态。

【问题讨论】:

  • 状态是如何定义的?我猜,18 代表 WORD_CHANGE。它的价值是什么?
  • 为什么使用defaultunique case 语句?似乎失去了使用unique 的所有好处。如果您取出default,工具会警告您您的状态18'h 不匹配任何有效状态。
  • 感谢您的回复。问题显示在最后一张图片中。两个州的状态值都很高。这应该是不可能的。
  • 是否报告了任何时序违规?在通往信号抽头捕获缓冲区/存储器的路径上是否设置了任何错误的路径约束?
  • @Serge SignalTap 以我的经验总是将 FSM 状态转换为 one-hot 编码,所以无论你如何定义 current_state,当添加到 SignalTap 时,它总是会在每个状态中生成 1 位name 作为信号名称 (stackoverflow.com/questions/29308500/…)。所以我不确定它是如何到达current_state 设置两个位的,除非在综合中可能(或时间)搞砸了? @Sabersimon 有任何警告吗?

标签: system-verilog state-machine quartus


【解决方案1】:

这几乎可以肯定是时间问题。我猜sclkclk 不同步——可能它直接连接到设备输入引脚。

问题是这段代码:

(...)
else if (sclk)
   next_state = BIT_CHANGE;
else 
   next_state = MISO_OUT;

每当sclk 从零转换为一时,逻辑将提高对应于BIT_CHANGEnext_state 位,同时降低对应于MISO_OUTnext_state 位。发生这种情况时,可能会有一个短暂的时刻,两个位都被设置或没有位被设置,这取决于哪个逻辑更快。如果你不走运并且在这个确切的时刻有一个加注clk,你将进入你正在观察的情况,状态机似乎同时处于两种状态。

解决方案是将sclkcs 以及确定下一个状态的任何其他信号同步到clk。这种同步通常通过简单地通过两个触发器发送信号来完成。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-27
    • 1970-01-01
    • 2020-04-07
    • 1970-01-01
    • 2015-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多