2
\$\begingroup\$

In my experience, driving a net from two separate processes (or always blocks) is a bad idea and will result in a multi-driver error in the tools.

However, one of my acquaintances claims that if the signal assignments are contained within if statements that never assert at the same time, it should be possible to drive one signal from two always blocks.

As a test, I did this in Vivado 2014.4. Here is my very trivial test code:

// always block one
always @ (posedge clk) begin 
   if (rst) begin 
      RegA <= 0;
   end 
   else begin 
      if (RegA_in_valid_1) begin 
         RegA <= RegA_in_1;
      end 
   end 
end 

// Always block two
always @ (posedge clk) begin
   if (rst == 0) begin
      if (!RegA_in_valid_1 && RegA_in_valid_2)
        RegA <= RegA_in_2;
   end
end

As I expected, Vivado does produce errors:

[Synth 8-3352] multi-driven net RegA_out_OBUF[31] with 1st driver pin 'RegA_reg[31]__0/Q' 
...

After this test, said acquaintance still claims that this code would synthesize in previous versions of Vivado without errors. This got me thinking - what does the synthesis tool use to determine if a net is multi driven? Does it use the respective sensitivity lists, or is this mechanism feasible (using conditional statements). I see my version of Vivado doesn't work, but what is the consensus in general?

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

If some branches in the process are not explicitly assigning some net, it is implicitly assigned with the previous value with an inferred latch. So there is no situation the process won't drive this signal (unless explicitly assigning hi-Z to it..).

Update:
The possible solution, as states, is to mutually disable the driven net (put it in tri-state) in two processes:
The following code is tested with Xilinx ISE:

module test_two_drv (select, q);
  input      select;
  output reg     q;

  always @(*)
  begin
    if (select) begin
      q <= 1'b1;
    end else begin
      q <= 1'b0;
    end
  end

  always @(*)
  begin
    if (!select) begin
      q <= 1'b1;
    end else begin
      q <= 1'b0;
    end
  end

endmodule

It is compiling, but the synthesis tool is complaining about two drivers. When replacing by the following code:

module test_two_drv (select, q);
  input      select;
  output reg     q;

  always @(*)
  begin
    if (select) begin
      q <= 1'b1;
    end else begin
      q <= 1'bZ;    // <---- Change
    end
  end

  always @(*)
  begin
    if (!select) begin
      q <= 1'b1;
    end else begin
      q <= 1'bZ;   // <---- Change
    end
  end

endmodule

The module is synthesized without errors, and generating the following RTL schematic: enter image description here

\$\endgroup\$
6
  • \$\begingroup\$ So, if you write your each of your processes to drive the net to Z for all circumstances except for the explicit non-Z situations for each process, then what the author proposes is possible? It sounds like it should be, just like a tri-state on a pin. \$\endgroup\$
    – Jotorious
    Commented Mar 25, 2015 at 15:44
  • \$\begingroup\$ Yep. I just did that and it works. It's not a great solution because then it's not really a register anymore. The latching behaviour is required. \$\endgroup\$
    – stanri
    Commented Mar 25, 2015 at 15:59
  • \$\begingroup\$ I am checking it now, and will update the answer with an example \$\endgroup\$
    – Eugene Sh.
    Commented Mar 25, 2015 at 16:00
  • \$\begingroup\$ See the update. \$\endgroup\$
    – Eugene Sh.
    Commented Mar 25, 2015 at 16:26
  • \$\begingroup\$ Modern FPGAs don't have internal tristate buffers anymore (still have for IOs, obviously), I think Xilinx dropped them for the Spartan-3. This may work, but is anything but recommended. \$\endgroup\$ Commented Mar 25, 2015 at 17:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.