I have structured a design into 2 blocks where the 2 blocks could independently work and the code needs to be synthesized. However when the ports have enumerated types and though the package for each module contains the same definition of the enumerated type when I simulate the top-level the simulator complains that this is an issue because SV is strongly typed. Is there an elegant way to do this besides declaring some kind of common package that holds a single definition of the enumerated type. The pieces of code sits in different directories and I would prefer not to employ a common package. Here’s and example and I used initial and display only for the example and does not exist in the design. color_mode_t is the same for both packages but the top-level connectivity complains because color in top comes from one of the packages but color is used to bind between 2 different packages holding the same definition.
package a;
typedef enum logic [1:0] { RED, BLUE, GREEN } color_mode_t;
endpackage
package b;
typedef enum logic [1:0] { RED, BLUE, GREEN } color_mode_t;
endpackage
module aa(input a::color_mode_t color);
initial
#5 $display ("color is %p\n", color);
endmodule
module bb(output b::color_mode_t color);
import b::*;
initial
color = RED;
endmodule
module top ();
import a::*;
color_mode_t color;
aa aa (.color (color));
bb bb (.color (color));
endmodule
Strong types like enums must be in a common package if they are to be shared amongst multiple modules. You can either add additional import statements, or can use the export package construct to make them appear as if they are defined separately in each package.
package common;
typedef enum logic [1:0] { RED, BLUE, GREEN } color_mode_t;
endpackage
package a;
import common::*;
export common::color_mode_t;
endpackage
package b;
import common::*;
export common::color_mode_t;
export common::RED;
endpackage
module aa import a::*;(input color_mode_t color);
initial
#5 $display ("color is %p\n", color);
endmodule
module bb import b::*; (output color_mode_t color);
initial
color = RED;
endmodule
module top ();
import a::*; // or common::*
color_mode_t color;
aa aa (.color (color));
bb bb (.color (color));
endmodule
Thanks Dave. Why cant the entire common package be exported instead of the specific type? And when I do that it still doesn’t recognize RED so I still need to export RED. This is puzzling because I though export of the package would export all contents and I would not have to specifically export RED.
There are two separate issues related to your question.
A wildcard import pkg::* doesn’t import anything until there’s an actual reference to an undeclared identifier; it only creates a list of candidates for imports. When it sees an undeclared identifier, it searches the list of candidates for a match. Upon finding a match, it makes that identifier visible from the package.
The import statement never moves an identifier definition into the scope doing the import, it just makes it visible for referencing without an explicit package scope reference (a:: color_mode_t). The export statement propagates or chains the visibility of the imported identifier. But the identifier needs to have an actual reference for the import visibility to get propagated. There is no “import all package identifiers” construct in SystemVerilog. That’s why the packages need and explicit reference to color_mode_t and RED somewhere in the package to be propagated. It could be explicitly in the import, export, or any other piece of code within the package.
And the reason that uppercase read RED needs to appear explicitly along with color_mode_t is because enumerated label names are at the same scope level as the enumerated data type declaration. They are not a subscope. That is why you cannot do the following in the same scope:
typedef enum { RED, BLUE, GREEN } color_mode1;
typedef enum { RED, ORANGE, YELLOW } color_mode2; // RED already declared!!
int RED; // RED already declared!!