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