Конечный автомат переходит в невозможное состояние при Сигнальном Сигнале - PullRequest
0 голосов
/ 24 января 2019

Я пытаюсь вывести один бит за раз через 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

Это должно перейти к WORD_CHANGE, но WORD_CHANGE и MISO_OUT для следующего состояния для текущего состояния.

Zoomed out image of waves zoomed in image of waves

1 Ответ

0 голосов
/ 08 февраля 2019

Это почти наверняка проблема времени. Я предполагаю, что sclk не синхронизирован с clk - возможно, он подключен напрямую к входному контакту устройства.

Проблема в следующем фрагменте кода:

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

Всякий раз, когда sclk переходит от нуля к единице, логика поднимает бит next_state, соответствующий BIT_CHANGE, и параллельно понижает бит next_state, соответствующий MISO_OUT. Когда это происходит, может быть короткий момент, когда оба бита установлены или биты не установлены, в зависимости от того, какая логика быстрее. Если вам не повезло и у вас в этот момент повышается clk, вы попадете в ситуацию, которую вы наблюдаете, когда конечный автомат оказывается в двух состояниях одновременно.

Решение заключается в синхронизации sclk, cs и любых других сигналов, которые определяют следующее состояние для clk. Такая синхронизация обычно выполняется путем простой отправки сигналов через два триггера.

...