# How does strength work in Verilog?

I want to create an assignment which takes care of pull-ups from a port pin. I wrote the following:

module test5;

reg value;
reg output_enable;
reg pullup_enable;

wire pullup_helper;
wire value_helper;
wire outp;

assign (highz0, pull1 ) pullup_helper = pullup_enable;
assign                   value_helper = output_enable ? value : 1'bz;
assign                           outp = value_helper  + pullup_helper;

always @(pullup_helper) $display ( "pullup_helper %b", pullup_helper ); always @(value_helper)$display ( "value_helper %b", value_helper );
always @(outp) $display ( "outp %b", outp ); initial begin$display ("Start");
pullup_enable = 0;
output_enable = 0;
value = 0;
#1
$display ("1"); output_enable = 1; #1$display ("2");
value = 1;
#1
$display ("3"); value = 0; #10$display("End");
end

endmodule


I got the output:

Start
pullup_helper z
value_helper z
1
value_helper 0
2
value_helper 1
3
value_helper 0
End


Q: Why does outp never change?

EDIT: Because the full answer is related to some comments on the given answers I will summarize the results:

As with support from Greg the answer to the problem is in two steps:

The default installation on Fedora 22 is Icarus 0.9.6. This version is buggy. As Greg tested also version 0.9.7 has the same bug. I installed the latest released version v10 (changed version conventions?)

The second part is simply let drive to assign statements into one wire.

assign (pull1,pull0)  bus = pullup_en ? 1'b1 : 1'bz;
assign                bus = output_en ? value : 1'bz;


With Icarus Verilog V10 it works as expected.

• I get a compile error with 2 simulators. I think you need to change z to 1'bz. – toolic Oct 22 '15 at 17:43
• What do you expect outp to be at what times? – toolic Oct 22 '15 at 17:47
• I expect by setting output_enable that outp becomes the state of value but I always get 'x' as undefined. I can't get any kind of wire to work which can held the value of "low", "high" and "pullup" and no idea how to deal with that. I believe that my idea of a "wire" is totally wrong. It looks that it is simply impossible to drive a wire from multiple assignments. I simply can't catch the idea how the typical way in verilog is to deal with "wires". I think in the electronic way where multiple ports of a controller can added to a network. I simply have no idea how can I write that in verilog. – Klaus Oct 23 '15 at 15:03

Verilog strengths can be a bit of complicated process understand. To get the full breath of understanding read: IEEE Std 1800-2012 § 10.3, 21.2.1.5, and 28.10 through 28.16.

To print the strength of a bit in a display message, use %v instead of %b. (§ 21.2.1.5)

Verilog mostly works in the digital logic space. Verilog strength only comes into play when two or more assignments continuously drive the same net as a from of conflict resolution. The strength value does not propagate through assignment statements. The strength value can be passed through the verilog switch primitives: nmos, pmos, tranif1, tranif0, cmos, tran, plus resistive switch primitives (which weakens the strengths on pass-through). For verilog primitives switches refer to IEEE Std 1800-2012 § 28.7 through 28.9.

assign (pull1,pull0)  bus = pullup_en ? 1'b1 : 1'bz;
assign                bus = output_en ? value : 1'bz;

assign                out = bus;
assign (weak1,weak0) outw = bus;
cmos inst_name (outs, bus, 1'b1, 1'b0);

// pullup_en output_en  |  out(%v)         outw(%v)        outs(%v)
// ---------------------+----------------------------------------------
//       0         0    |  1'bx(StX)       1'bx(WeX)       1'bz(HiZ)
//       0         1    |  value(St1,St0)  value(We1/We0)  value(St1/St0)
//       1         0    |  1'b1(St1)       1'b1(We1)       1'b1(Pu1)
//       1         1    |  value(St1,St0)  value(We1/We0)  value(St1/St0)


Pullup/pulldown logic from a standard cells libraries provide by your vendor can be used for synthesis. Some synthesizers have pragmas to indicate a pullup/pulldown on a bus. Out side of that, verilog strength is typically not synthesizable. FPGAs have limited bidirectional bus support; if any. ASICs typically try to minimize the size and use of a bidirectional buses.

• I still can't understand what is going on. If I simply assign (pull0,pull1) bus = pullup_en ? 1'b1 : 1'bz;and let pullup_en= 1; the result is bus 1 St1 displayed with (%b %v) . Why the strength results in strong and not in pull up? – Klaus Oct 23 '15 at 7:55
• What is the value of output_en? Working example on edaplayground – Greg Oct 23 '15 at 15:23
• Thanks for your example. The problem is the line 'pullup_en:1 output_en:1 value:0 :: bus:x(StX) out:x(StX) outw:x(WeX) outs:x(StX)'. My expected result is simply that the output_en anables the driver and "overwrite" the pullup with 0 as in the real world. The result should be simply "0" and not "x". – Klaus Oct 23 '15 at 16:15
• I changed both assign lines in your code with the following ones: rnmos r3( bus, 1'b1, pullup_en ); nmos p4( bus, value, output_en ); This seems to work. – Klaus Oct 23 '15 at 16:23
• Curious, what simulator are your running? – Greg Oct 23 '15 at 17:16

When I view the waveforms, I see outp is always unknown (x). outp never changes because pullup_helper is always z. pullup_helper is always z because pullup_enable is always 0. You specified highz0 for when pullup_enable is 0 in your assign statement. Refer to IEEE Std 1800-2012, section 10.3.4 "Continuous assignment strengths".

• My expectation was that setting output_enable result in value_helper becomes the value of value. And then I thought the strength of value_helper is higher and outp is set correct. But outp is never set. I still can not understand what the problem here is. – Klaus Oct 23 '15 at 6:56