System verilog 状态机在信号抽头上转换为不可能状态

System verilog 状态机在信号抽头上转换为不可能状态,system-verilog,state-machine,quartus,System Verilog,State Machine,Quartus,我试图通过SPI从已知的2D阵列一次输出一位 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 fp

我试图通过SPI从已知的2D阵列一次输出一位

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
模块FPGA\u状态\u读取(
输入时钟,
输入sclk,
输入cs,//时钟启用
输入rst\u n,//异步复位有效低
输入fpgastatus_命令,
输入逻辑[3:0]组控制,
输入逻辑[7:0]环回,
输出逻辑[7:0]fpga_状态_队列[0:17],
输出逻辑dout
);
//`include“./../config\u files/rtl\u config.svh”
分配fpga_状态_队列[0]=8'h1//{组控制};
分配fpga_状态_队列[1]=8'h1//{环回};
分配fpga_状态_队列[2]=8'h1//{synth_version[0]};
分配fpga_状态_队列[3]=8'h1//{synth_version[1]};
分配fpga_状态_队列[4]=8'h1//{synth_版本[2]};
分配fpga_状态_队列[5]=8'h1//{grid_version[0]};
分配fpga_状态_队列[6]=8'h1//{grid_version[1]};
分配fpga_状态_队列[7]=8'h1//{grid_version[2]};
分配fpga_状态_队列[8]=8'h1//{pa_版本[0]};
分配fpga_状态_队列[9]=8'h1//{pa_版本[1]};
分配fpga_状态_队列[10]=8'h1//{pa_版本[2]};
分配fpga_状态_队列[11]=8'h1//{hdl_版本[0]};
分配fpga_状态_队列[12]=8'h1//{hdl_版本[1]};
分配fpga_状态_队列[13]=8'h1//{hdl_版本[2]};
分配fpga_状态_队列[14]='1;
分配fpga_状态_队列[15]='1;
分配fpga_状态_队列[16]='0;
分配fpga_状态_队列[17]='0;
逻辑位运行计数器;
逻辑位加载计数器;
逻辑[4:0]位\u当前\u值;
达到逻辑位\u计数\u;
逻辑字运行计数器;
逻辑字加载计数器;
逻辑[4:0]字\当前\值;
达到逻辑字计数;
typedef枚举逻辑[2:0]{IDLE,CS_WAIT,MISO_OUT,BIT_CHANGE,WORD_CHANGE}状态};
状态表示当前状态、下一状态;
始终\u ff@(posedge clk或NEGDEDGE rst \n)开始:向前迈出一步
如果(!rst_n)

当前状态这几乎肯定是一个时间问题。我猜
sclk
clk
不同步-可能它直接连接到设备输入引脚

问题在于这段代码:

(...)
else if (sclk)
   next_state = BIT_CHANGE;
else 
   next_state = MISO_OUT;
每当
sclk
从零变为一时,逻辑将提升与
bit\u CHANGE
对应的
next\u state
位,同时降低与
MISO\u OUT
对应的
next\u state
位。发生这种情况时,可能会有一个短暂的时刻,两个位都被设置或没有设置,这取决于哪个逻辑更快。如果您运气不好,并且此时正处于上升
clk
,您将进入您正在观察的情况,此时状态机似乎同时处于两种状态


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

状态是如何定义的?我想,18代表单词的变化。它的值是什么?为什么将
默认值
唯一大小写
语句一起使用?似乎失去了使用
unique
的所有好处。如果您取出
默认值
,工具会警告您您的状态
18'h
与任何有效状态不匹配。感谢您的回复。问题显示在最后一张图片中。其中两个状态的状态值较高。这应该是不可能的。是否有任何时间违规的报告?在通向signal tap捕获缓冲区/存储器的路径上是否设置了任何错误的路径约束?@Serge SignalTap在我的经验中总是将FSM状态转换为一个热编码,因此无论您如何定义
当前状态
,当添加到SignalTap时,它将始终以状态名称作为信号名称()。所以我不确定它是如何进入当前状态的,设置了两个位,除非合成过程中出现了一些混乱(或计时)?Sabersimon有任何警告吗?