Using a continous assignment in a Verilog procedure?
It is called procedural continuous assignment. It is the use of an assign
or force
(and their corresponding counterparts deassign
and release
) within procedural block. A new continuous assignment process is created when the line is reached in the procedural block. assign
can be applied to register types such as reg
, integer
, and real
. force
can be applied to registers and nets (i.e. wire
s). It has been part of the LRM since 1364-1995.
- IEEE Std 1364-1995 § 9.3
- IEEE Std 1364-2001 § 9.3
- IEEE Std 1364-2005 § 9.3
- IEEE Std 1800-2005 § 25.3
- IEEE Std 1800-2009 § 10.6
- IEEE Std 1800-2012 § 10.6
Procedural continuous assignments are synthesizable, by most tools. However it is recommend to limit the use to behavior modeling of an analog block, test bench files, or fixing RTL<->gate functional mismatches.
-
always @* assign data_in = Data;
is functional the same asalways @* data_in = Data;
-
always @(posedge clk) assign data_in = Data;
is functional the same as:always @(posedge clk) enable = 1; always @* if (enable==1) data_in = Data;
A valid use of procedural continuous assignment would be should be applited to the following:
always @(posedge clk or negedge rst_n, negedge set_n) begin
if (!rst_n) q <= 1'b0;
else if (!set_n) q <= 1'b1;
else q <= d;
end
It will synthesize to a flop with an asynchronous set and reset with priority to reset. In simulation however the model is inaccurate if rst_n
and set_n
are both low then rst_n
goes high. q
should go to 1 the the asynchronous set is still enabled, but nothing to trigger in in the sensitivity list. This is a well documented issue with Verilog. It is the one case procedural continuous assignment are allowed in RTL when used with the translate off keyword your synthesizer. The release
/deassign
allows the the register/wire to be assigned in the usual manner.
// translate_off
always @(rst_n or set_n)
if (rst_n && !set_n) force q = 1'b1;
else release q;
// translate_on
OR (currently valid but discouraged)
// translate_off
always @(rst_n or set_n)
if (rst_n && !set_n) assign q = 1'b1;
else deassign q;
// translate_on
Using assign
/deassign
in this manner is being considered to be depreciated in future IEEE 1800 release. IEEE Std 1800-2005 § 25.3, IEEE Std 1800-2009 § C.4.2 and IEEE Std 1800-2012 § C.4.2 recognizes assign
used this way causes confusion and is the source of errors. Use force
/release
if procedural continuous assignment as needed.
In generate using procedural continuous assignment (with force
/release
) should only be used if absolutely necessary. Alternative approaches are more reliable.
Misuse of procedural continuous assignment and solutions:
-
Combinational logic on
reg
:always @(sel) if (sel) assign reg1 = func1(x,y,z); else assign reg1 = func2(a,b,c);
-
Solution:
always @* // <- IEEE Std 1364-2001 construct if (sel) reg1 = func1(x,y,z); else reg1 = func2(a,b,c);
-
-
Combinational logic on
wire
:always @(sel) if (sel) force wire1 = func1(x,y,z); else force wire1 = func2(a,b,c);
-
Solution:
assign wire1 = sel ? func1(x,y,z) : func2(a,b,c);
-
-
Sequential logic:
always @(posedge clk) if (sel) assign reg2 = func1(x,y,z); else assign reg2 = func2(a,b,c);
-
Solution (assuming original functionality is wrong):
always @(posedge clk) if (sel) reg2 <= func1(x,y,z); // Non-blocking assignment !!! else reg2 <= func2(a,b,c);
-
Solution (assuming original functionality is correct):
reg flop_sel; always @(posedge clk) flop_sel <= sel; // Non-blocking assignment !!! always @* if (flop_sel) reg2 = func1(x,y,z); // Blocking assignment !!! else reg2 = func2(a,b,c);
-