Verilog Port Expressions
Q1: Why are the ports in original Verilog RTL file renamed to p1, p2, ... in the output netlist?
Verilog RTL file:
// Example of port expressions module test (datain[0], datain[0] /* same net into multiple port expression */, datain[2:1] /* part-select port expression */, /* empty port expression - nothing between the two commas */, {datain[2], datain[1], datain[1]} /* concatenation in port expression */, dataout[3], {dataout[2:0]}, /* another empty port expression due to the extra comma */ ); input [2:0] datain; output [3:0] dataout; endmodule
The items enclosed in the () after the module name are not "port names," rather, they are "port expressions." Verilog defines that the port expressions of a module CANNOT be accessed by name (only by order). This means you cannot rely on the port names to be one thing or another.
Verific chooses to not adjust any particular naming scheme for complex port expressions, which also allows us to error out if named port instantiation occurs where the language disallows it.
The original port expression of the renamed port is saved as attribute " orig_port_name" attached to the port.
key: " orig_port_name", value: port expression
Q2: Are "empty" ports Verilog-legal?
The Verilog example at the top of the page contains two "empty" port expressions (nothing between two commas or an extra comma at the end of the port expression list). This is legal as shown below:
In BNF section A.1.2 of IEEE 1800-2017 LRM:
module_nonansi_header ::= { attribute_instance } module_keyword [ lifetime ] module_identifier { package_import_declaration } [ parameter_port_list ] list_of_ports ; list_of_ports ::= ( port { , port } ) port ::= [ port_expression ] | . port_identifier ( [ port_expression ] )
"port_expression" is optional because it is enclosed within [].
In section 23.2.2.1 of the same LRM on "Non-ANSI style port declarations":
- The port expression is optional because ports can be defined that do not connect to anything internal to the module.
For the example above, the netlist output from Verific is (note the leading space character of the attribute " orig_port_name"):
// // Verific Verilog Description of module test // module test (p1, p2, p3, , p7, p11, p12, ) /* verific language=verilog, cell_name=test */ ; // test.sv(2) input p1 /* verific orig_port_name=datain[0] */ ; input p2 /* verific orig_port_name=datain[0] */ ; input [1:0]p3 /* verific orig_port_name=datain[2] datain[1] */ ; input [2:0]p7 /* verific orig_port_name=datain[2] datain[1] datain[1] */ ; output p11 /* verific orig_port_name=dataout[3] */ ; output [2:0]p12 /* verific orig_port_name=dataout[2] dataout[1] dataout[0] */ ; // Printing the identifier types // datain : input [2:0] reg : nets: datain(bus) // dataout : output [3:0] reg : nets: dataout(bus) assign p1 = p2 /* verific orig_port_name=datain[0] */ ; assign p3[1] = p7[2] /* verific orig_port_name=datain[2] */ ; assign p3[0] = p7[0] /* verific orig_port_name=datain[1] */ ; assign p7[1] = p7[0] /* verific orig_port_name=datain[1] */ ; endmodule