Posible problema con las máquinas de estado que codifican la síntesis de vivado

0

He estado trabajando en el uso de Ethernet phy en mi DDR Nexys4 durante las últimas semanas. En los últimos días me he sentido particularmente frustrado con un problema que estaba teniendo con mi módulo rx. He pegado el código abajo. Mi módulo pasa por tres estados diferentes. Esperando el preámbulo, señalizando el inicio del cuadro y recibiendo el cuerpo del paquete. Estos tres estados se almacenan utilizando el registro estatal. El diseño funciona bien en el simulador y cuando lo probé por primera vez en la tarjeta.

Para probarlo, he estado usando chipscope y tuve un estado de registro marcado como debug. Luego quité las sondas de alcance del chip y todo comenzó a fallar. Sería señal de inicio de cuadro y luego nada más. A través de la experimentación, descubrí que cuando tengo una sonda en el registro de estado, funciona todo el diseño, pero si quito esa sonda, el diseño se desmorona. Al principio, esto parecía ser un problema de tiempo ya que las señales eth_ * provienen directamente de la red Ethernet (conduzco a la phy con un reloj 45 grados fuera de fase desde clk_mac). Agregué una etapa de canalización entre esas señales y mi lógica de combinación. Todavía estaba fallando. Ahora no creo que sea un problema de tiempo, ya que es poco probable que obtenga un preámbulo válido y un primer byte si esas señales fueran incorrectas.

Después de un poco más de experimentación, noté lo siguiente en el registro de síntesis ...

    --------------------------------------------------------------------------------------------------
                       State |                     New Encoding |                Previous Encoding 
    ---------------------------------------------------------------------------------------------------
              STATE_PREAMBLE |                                0 |                              000
                   STATE_SOF |                                1 |                              001
    ---------------------------------------------------------------------------------------------------

INFO: [Synth 8-3354] encoded FSM with state register 'state_reg' using encoding 'sequential' in module 'eth_rx'

Parece que el vivado está optimizando los bits superiores del registro estatal. (Nota: antes de que alguien lo señale, sé que probablemente debería tener solo [1: 0] en lugar de [2: 0], pero mi diseño comenzó con más estados de los que necesitaba y aún no lo he cambiado). De cualquier manera, vivado está eliminando STATE_RECV que requiere que se establezca el bit de estado [1]. Al agregar el microscopio, estaba evitando que el vivado haga lo que parece una optimización ilegal. Creo que esto es un error con el vivado. ¿Alguien más ha visto esto o hay algo malo que ves con mi verilog? Estoy usando vivado 2018.1.

'timescale 1 ns / 1 ps
module eth_rx
(
    input             clk_mac,
    input             rst_n,

    input             eth_crsdv,
    input             eth_rxerr,
    input  [1:0]      eth_rxd,

    (* mark_debug = "true" *)
    output reg        rx_vld,
    (* mark_debug = "true" *)
    output reg [7:0]  rx_dat,
    (* mark_debug = "true" *)
    output reg        rx_sof,
    (* mark_debug = "true" *)
    output reg        rx_eof,
    (* mark_debug = "true" *)
    output reg [10:0] rx_len,
    (* mark_debug = "true" *)
    output reg        rx_err
);

    'include "util.vh"

    (* mark_debug = "true" *)
    reg       eth_crsdv_b;
    (* mark_debug = "true" *)
    reg [1:0] eth_rxd_b;
    (* mark_debug = "true" *)
    reg       eth_rxerr_b;
    always @(posedge clk_mac) begin
        eth_crsdv_b <= eth_crsdv;
        eth_rxd_b   <= eth_rxd;
        eth_rxerr_b <= eth_rxerr;
    end

    (* mark_debug = "true" *)
    reg [63:0] data_buffer;
    reg [63:0] next_data_buffer;
    always @(posedge clk_mac) begin
        if(rst_n)
            data_buffer <= next_data_buffer;
        else
            data_buffer <= 0;
    end


    reg [10:0] frame_idx, next_frame_idx;
    reg [1:0]  dibit_cnt, next_dibit_cnt;
    always @(posedge clk_mac) begin
        dibit_cnt <= next_dibit_cnt;
        frame_idx <= next_frame_idx;
    end

    reg        next_rx_vld;
    reg        next_rx_sof;
    reg        next_rx_eof;
    reg [10:0] next_rx_len;
    reg [7:0]  next_rx_dat;
    reg        next_rx_err;
    always @(posedge clk_mac) begin
        rx_vld <= next_rx_vld;
        rx_dat <= next_rx_dat;
        rx_sof <= next_rx_sof;
        rx_eof <= next_rx_eof;
        rx_len <= next_rx_len;
        rx_err <= next_rx_err;
    end

    localparam STATE_PREAMBLE = 0;
    localparam STATE_SOF      = 1;
    localparam STATE_RECV     = 2;

    reg [2:0] state;
    reg [2:0] next_state;
    always @(posedge clk_mac) begin
        if(rst_n)
            state <= next_state; 
        else
            state <= STATE_PREAMBLE;
    end

    wire [31:0] crc32_code;
    crc32 crc32_inst
    (
        .clk (clk_mac),
        .rst (next_rx_sof && next_rx_vld),
        .vld (next_rx_vld && !next_rx_eof),
        .data(next_rx_dat),
        .crc (crc32_code)
    );

    always @* begin
        next_state  = state;
        next_rx_vld = 0;
        next_rx_eof = 0;
        next_rx_sof = 0;
        next_rx_err = 0; 
        next_rx_len = rx_len;
        next_rx_dat = rx_dat;

        next_frame_idx = frame_idx;
        next_dibit_cnt = dibit_cnt + 1;

        if(eth_crsdv_b && !eth_rxerr_b) 
            next_data_buffer = {eth_rxd_b, data_buffer[63:2]};
        else
            next_data_buffer = 0;

        case(state)
            STATE_PREAMBLE: begin
                next_dibit_cnt = 0;
                next_frame_idx = 0;
                if(data_buffer == 64'hd555555555555555) begin
                    next_state  = STATE_SOF;
                end
            end STATE_RECV, STATE_SOF: begin
                if(eth_rxerr_b) begin
                    next_rx_vld = 1;
                    next_rx_eof = 1;
                    next_rx_vld = 1;
                    next_state  = STATE_PREAMBLE; 
                end else if(eth_crsdv_b) begin
                    if(&next_dibit_cnt) begin
                        next_frame_idx = frame_idx + 1;
                        if(frame_idx >= 4) begin
                            next_rx_len = frame_idx - 3;
                            next_rx_vld = 1;
                            next_rx_dat = next_data_buffer[31:24];
                            next_rx_sof = state == STATE_SOF;
                            next_state  = STATE_RECV;
                        end
                    end
                end else begin
                    next_state  = STATE_PREAMBLE;
                    next_rx_eof = 1;
                    next_rx_vld = 1;
                    next_rx_err = crc32_code != bswap32(data_buffer[63:32]);
                end
            end
        endcase
    end

endmodule

ACTUALIZACIÓN: me deshice de la extracción de FSM y ahora funciona bien ...

localparam STATE_PREAMBLE = 3'b001;
localparam STATE_SOF      = 3'b010;
localparam STATE_RECV     = 3'b100;

//Override FSM because Vivado ignores STATE_RECV with auto
(* fsm_encoding = "none" *)
reg [2:0] state = STATE_PREAMBLE, next_state;
always @(posedge clk_mac) begin
    if(rst_n)
        state <= next_state; 
    else
        state <= STATE_PREAMBLE;
end
    
pregunta chasep255

1 respuesta

0

Como ha notado, el sintetizador FPGA reconocerá y optimizará automáticamente las máquinas de estado. Parte de estas optimizaciones es la eliminación de estados inalcanzables.

En este caso, creo que STATE_RECV es inalcanzable debido al if(&next_dibit_cnt) condicional. next_dibit_cnt se establece en 0 en STATE_PREAMBLE , y se incrementa durante STATE_SOF . Dado que el registro se incrementa durante ese estado, no puede ser cero.

    
respondido por el duskwuff

Lea otras preguntas en las etiquetas