verilator / verilator

Verilator open-source SystemVerilog simulator and lint system
https://verilator.org
GNU Lesser General Public License v3.0
2.29k stars 556 forks source link

Support feedthroughs/non-ANSI complex ports (IEEE 1800-2017 23.2.2.1) #2844

Open ganghuang opened 3 years ago

ganghuang commented 3 years ago

It seems the current version of verilator doesn't support module like this:

module via (.a(w), .b(w));
inout w;
wire w;
endmodule

There was a discussion https://forums.xilinx.com/t5/Welcome-Join/synthesizable-verilog-connecting-inout-pins/td-p/284628 And as pointed out there by mcgett, this gramma is in IEEE1364-2005, in section 12.3.3: module same_port (.a(i), .b(i));

Can you attach an example that runs on other simulators? (Must be openly licensed, ideally in test_regress format.)

When I simply verilator -cc via.v I got

%Error: via1.v:16:13: syntax error, unexpected '.', expecting '['
   16 | module via (.a(w), .b(w));
      |             ^
%Error: via1.v:19:1: syntax error, unexpected endmodule
   19 | endmodule
      | ^~~~~~~~~
%Error: Exiting due to 2 error(s)

I can confirm iverilog/vivado xsim both can take that grammar and that can be synthesized by vivado.

May we assist you in trying to fix this yourself? I have not dive into the source of verilator yet, I don't think I can do it.

wsnyder commented 3 years ago

Understandable to run older modules.

This is old pre-ANSI syntax and leads to a number of including complications including the one you showed where the pin connections go to the same signals. It's therefore very unlikely Verilator will be extended to support this in even the medium term unless you or someone makes an effort to add support.

ganghuang commented 3 years ago
  1. Do you know any other syntax can implement the same feature to connecting two inout port together ? both simulatable and synthsiable
  2. If I try to dive into the source, can you help me narrow down to where will be a good place to start with? I can imagine to use iverilog as a reference to see how they handle this correctly.
wsnyder commented 3 years ago
  1. module bidi_feedthru (
    inout wire a,
    inout wire b);
    tran t1 (a, b);
    endmodule

think this is the common way, but tran isn't supported by Verilator. To support this is possible, but would require some major rework in the tristate resolution, probably take a month of work, if you can dedicate that amount of time it would be great, we can get into how to do it.

  1. "alias a = b;"

might work (untested on other simulators) but alias isn't supported by Verilator.

BUT!

If you're doing digital/RTL design you shouldn't be doing this anyways. Model it as a normal input/output going in one direction and just assign.

If you're doing analog/low level physical design this does rarely come up, but Verilator is unlikely to suite your needs for many other reasons anyways.

ganghuang commented 3 years ago

Thank you for the suggestion.

  1. Yes using verilog primitive tran can do the similar thing but that is not typically support by synthesizer. I am using vivado, and I checked the latest UG901,Jan. 28 2021, page 238 state:

Vivado synthesis does not support Verilog switch-level primitives, such as the following:cmos, nmos, pmos, rcmos, rnmos, rpmos rtran, rtranif0, rtranif1, tran, tranif0, tranif1

This confirmed by run a vivado xsim simulation on it, and I got

Primitive "tran" is not supported.

But if I really synthesis the module, it seems still accept it and do the right thing. (strange, right?)

For the net aliasing, as in UG901 page 283, the net aliasing is not supported in vivado.

So for vivado, that non-ANSI port is the only way I can run xsim simulation and synthesis as far as I know, any suggestion is welcome.

  1. I am doing RTL design, but I found this kind inout via is important for my code modularization as it can map to the hardware modules. My project typically has multiple PCB boards integrated to a system. As the fact of each board in the system constrain some pins of the chip or implement some features, while leave other pins untouched and pass it to other boards via a physical connector. In order to make the FPGA module really reusable, I map the FPGA module to the hardware one to one. For the pins going to the connector, I use this via to pass the signal through. Using this can give me a flatter design.

  2. I am not sure I can commit a month time on this now. But I guess it always good if you can point out a what and where you think is needed so I can start a little bit and also maybe other people can contribute as well? And given the vivado xsim doesn't support the tran, if you can point out what is needed to support that non-ANSI port (the one in the original question), that is also very interesting.

Thanks

quark17 commented 2 years ago

I also noticed this issue, with the following module:

module InoutConnect(
                    .X1(internal),
                    .X2(internal)
                    );
   parameter width = 1;
   inout [ width - 1 : 0 ] internal;
endmodule

that Verilator rejects:

%Error: InoutConnect.v:2:21: syntax error, unexpected '.', expecting '['
    2 |                     .X1(internal), 
      |                     ^
        mod.v:19:1: ... note: In file included from mod.v
%Error: InoutConnect.v:7:4: syntax error, unexpected inout
    7 |    inout [ width - 1 : 0 ] internal;
      |    ^~~~~
        mod.v:19:1: ... note: In file included from mod.v

Here is an example containing it (inout_connect.tar.gz). In this case, the use of connecting module is not necessary; the same example, but replacing InoutConnect with a wire, is attached to bug #3242.

I had been working with Verilog pre SystemVerilog, where I believed that this was the only notation available for expressing that two inout ports are connected. I had not considered the use of tran. In SV, maybe alias could be used?

If you don't need named ports, I believe that this form is also available in Verilog:

module InoutConnect(internal, internal);

but Verilator also rejects this:

%Error: InoutConnect.v:1:31: Duplicate declaration of port: 'internal'
    1 | module InoutConnect(internal, internal);
      |                               ^~~~~~~~
        mod.v:19:1: ... note: In file included from mod.v
        InoutConnect.v:4:28: ... Location of original declaration
    4 |    inout [ width - 1 : 0 ] internal;
      |                            ^~~~~~~~
%Error: mod.v:17:53: Duplicate pin connection: '__pinNumber2'
   17 |   InoutConnect #(.width(32'd32)) _unnamed_(recv$IN, send$OUT);
      |                                                     ^~~~~~~~
        mod.v:17:44: ... Location of original pin connection
   17 |   InoutConnect #(.width(32'd32)) _unnamed_(recv$IN, send$OUT);
      |                                            ^~~~~~~