Si usted es principalmente un ingeniero de software, puede pensar que Verilog utiliza copias internas de las variables asignadas dentro del bloque siempre. En términos de implementación, las "variables internas" no están realmente ahí , pero nunca es la mejor manera de visualizar cómo funciona.
Considere el siguiente código:
wire a, b;
always @ (posedge clk) begin
a = a + 1;
if (a) ...
end
always @ (posedge clk) begin
b <= b + 1;
if (b) ...
end
Esto se realiza efectivamente como:
wire a, b;
always @ (posedge clk) begin
var a_int = a;
a_int = a_int + 1;
if (a_int) ...
a = a_int;
end
always @ (posedge clk) begin
var b_int = b;
b_int = b + 1;
if (b) ...
b = b_int;
end
Observe cómo las instrucciones de no bloqueo provocan que se realicen cálculos en la variable externa (global si lo desea). Sin embargo, las instrucciones de bloqueo hacen que los cálculos se realicen utilizando la variable interna (local).
Al final del bloque siempre, el valor resultante de la variable interna se asigna de nuevo a la externa.
En su caso, está utilizando asignaciones no bloqueadas para el recuento, por lo que sus cálculos utilizarán la variable externa, que contendrá el valor "antiguo", y no el valor incrementado "nuevo".
A medida que te familiarizas, comienzas a pensar en términos de hardware como describe @Oldfart.
Nota al margen: esta es la razón por la que es una mala idea combinar el bloqueo y el no bloqueo. Terminas calculando una combinación impredecible de valores internos y externos, lo que puede dar como resultado resultados de simulación frente a síntesis muy diferentes.