Tengo un ejercicio que separa la lógica de peine de la lógica secuencial en el bloque always_ff.
Sin embargo, encontré que el orden de las ejecuciones always_comb y always_ff es diferente entre los diferentes simuladores.
Por lo que sé, el bloque always_comb se ejecuta siempre que la variable en la lista de sensibilidad cambia. (Corríjame si me equivoco) y always_ff se ejecuta en el borde de la señal (por ejemplo, clk).
Desde la prospectiva de programación, el orden de ejecución de always_comb y always_ff es importante, ¿verdad? Siempre asignamos una variable de forma no bloqueable dentro de un flip flop desde una variable que es controlada por always_comb?
out_pkt_size <= pkt_size; // pkt_size is drive by always_comb
Por favor avise.
Puede verificar el código en edaplayground
always_comb begin
$display("%2g, always_comb : in_vld = %b", $time, in_vld);
if (in_vld) begin
pkt[HIBIT-:WIDTH] = in_data;
pkt_size = {<<8{pkt[HIBIT-:16]}};
end else begin
pkt = {WIDTH{1'hx}};
pkt_size = 'd0;
end
end
always_ff @(posedge clk or negedge reset_n) begin
$strobe( "%2g, always_ff(strobe) : out_pkt_size = %1d", $time, out_pkt_size);
$display("%2g, always_ff : in_vld = %b", $time, in_vld);
if (!reset_n) begin
out_pkt_size <= 1'd0;
end else begin
out_pkt_size <= pkt_size;
end
end
Ejecute el resultado desde edaplayground (usando Synopsys VCS como simulador):
Puedes ver que always_comb se ejecuta antes que always_ff.
initial ...
0, always_ff : in_vld = x
0, always_comb : in_vld = x
0, always_ff(strobe) : out_pkt_size = 0
10, always_comb : in_vld = 0
10, always_ff : in_vld = 0
10, always_ff(strobe) : out_pkt_size = 0
20, always_comb : in_vld = 1
20, always_ff : in_vld = 1
20, always_ff(strobe) : out_pkt_size = 140
30, always_comb : in_vld = 0
30, always_ff : in_vld = 0
30, always_ff(strobe) : out_pkt_size = 0
40, always_ff : in_vld = 0
40, always_ff(strobe) : out_pkt_size = 0
50, always_ff : in_vld = 0
50, always_ff(strobe) : out_pkt_size = 0
$finish called from file "testbench.sv", line 96.
$finish at simulation time 55
Resultado de ModelSim:
Puede ver que, sin embargo, always_ff siempre se ejecuta antes que always_comb. El resultado es que out_pkt_size está 1 ciclo atrás.
run
# initial ...
# 0, always_comb : in_vld = x
# 0, always_ff : in_vld = x
# 0, always_ff(strobe) : out_pkt_size = 0
# 10, always_ff : in_vld = 0
# 10, always_comb : in_vld = 0
# 10, always_ff(strobe) : out_pkt_size = 0
# 20, always_ff : in_vld = 1
# 20, always_comb : in_vld = 1
# 20, always_ff(strobe) : out_pkt_size = 0
# 30, always_ff : in_vld = 0
# 30, always_comb : in_vld = 0
# 30, always_ff(strobe) : out_pkt_size = 140
# 40, always_ff : in_vld = 0
# 40, always_ff(strobe) : out_pkt_size = 0
# 50, always_ff : in_vld = 0
run