A well known SystemVerilog limitation is that the same literal cannot appear in more enumerated types within a package (or more precisely within a scope).
Unfortunately many synthesis tools simply barf when they see the class keyword, so using a class to create a scope, or create a parameterised function (as per http://stackoverflow.com/a/22711967/579887) doesn’t work.
Sadly with SystemVerilog we seem to have ended up with a language that combines “design” and “verification” but where nobody knows which parts they are supposed to ignore…
Interesting point. I usually write the posts from a verification perspective, so I don’t really think about synthesis tools. All the more reason then for a standard update.
Regarding mixing in design and verification in the same language, the only thing I think is actually useful is being able to specify assertions side-by-side with the verification code. Everything else is just marketing mumbo jumbo.
SystemVerilog comes close to enabling quite a decent level of abstraction for synthesis, however many of the capabilities are unusable (despite being theoretically synthesisable) because the tool vendors assume they are just for verification.
One of my biggest gripes with SystemVerilog is the confusion caused by trying to cram so much into it. It would have been much better if they’d enabled functionality by relaxing rules instead of adding new features. For example the capabilities provided by interfaces could be achieved by allowing module and package instances to be passed around as first class objects, which would also enable many other use models that are currently prohibited.
Sadly the industry has instead created a complex monstrosity of a language and invested huge amount of effort implementing the tools. In practice all we’ve actually achieved is bringing Verilog up to a par with VHDL for synthesis and created a new and rather poor domain specific software language for verification.
On the verification front - if UVM really is the best we can come up with then I despair. It’s ultimately just a collection of macros and helper factories required to work around the fact that SystemVerilog simply isn’t a very good language for writing software.
The vendors now need to re-coup their investments in SV and of course it’s the users who will pay for this inefficiency. We’re therefore stuck with SV for both design and verification for the foreseeable future.
We missed an opportunity to actually raise the abstraction for synthesis and we’ll have to wait another decade for the next round of innovation unless something like OpenCL manages to disrupt things.
I’m not clear on what is wrong with creating a package for each (I mean, given what we have to work with). You should never do an import package_name::* (if you are familiar with C++ that’s the same as saying don’t do using namespace namespace_name;) and so you will consistently use the scope operator before your enum member name (just like you did with your class). You mentioned work library pollution as a downside to creating packages, why is that a problem?
Your class solution is clever, but it seems unnecessarily complicated when packages exist and can do essentially the same thing.
And now I will admit that I have almost given up on using enums altogether because of issues like this. Python doesn’t have enums, so maybe my SystemVerilog doesn’t need them either. Strings FTW!
Either wrapping in a package or in a class results in an extra level of hierarchy, but IMO the class is nicer because it’s better encapsulated. I know it’s not nice to use pkg::* (saving this for a different blog post), but that doesn’t mean others won’t use it, so the class forces a little more discipline.
Also, regarding classes, something one could add is nice utility methods such as from_string() which converts from a string to the enum literal. I found the idea on Verilab - Blog (also look at the comments). I was thinking of a nice way to integrate it with defining the enum inside the class, that’s why it didn’t make the cut. Again, something for a future post.
One of the main reasons for using classes instead of packages, in my opinion, is that in a modern TB, you are already going to have a class that encapsulates the information that the enum pertains to. I.e. in case of NOP, ADD, SUB, you will certainly have an “instruction”-like class where this enum naturally belongs.
You now get two benefits – namespace protection for your enum, and you get to refer to it without class_name::value construct within your instruction class which should, presumably, be the place where the enum is used the most.
I consider this technique a part of a proper coding standard for SV TBs :).
UVM 1.2 has added a uvm_enum_wrapper#(T) class that provides the ability to convert strings to enums. It’s more or less the same code as the one from the quoted 2007 verilab post :).
Welcome to VGM! Thanks for pointing out the uvm_enum_wrapper class. The functionality of this class is still orthogonal to a “wrapper” class that defines the enum inside it, as it takes the enum type as a parameter.
My idea was that since we anyway wrap the enums in a class, we could somehow also define the utility methods inside those classes. The only way I can think up now is by having some instance of the utility class (uvm_enum_wrapper) inside the class that defines the enum do the work or maybe even better, a mixin.
+1 with Chiggs. IMO we need a well-designed language for unified verification and design. SV/UVM are not good candidates. I wonder if we can use a general-purpose language like JavaScript or Python someday.
@Debamitro I’m a big fan of Python for verification (hence developing Cocotb). There is also the option of MyHDL for design/verification using Python although I don’t personally use it.
I tried a load of these options and none of them were great. Using a package means you can’t have the same scope name for the enum and the package. In other words you end up with this:
import FooPkg::Foo;
var Foo = FooPkg::A;
When you really want
var Foo = Foo::A;
Packages are also limited to the top level which is unfortunate. Also (like many things) Yosys doesn’t support it.
Using classes sounds equally horrible (and probably poorly supported too). In the end I gave up and just used poor mans namespacing:
typedef enum {
Foo_A,
Foo_B
} Foo;
The only downsides are:
You can’t import the members. Generally you shouldn’t do this anyway but in some instances it may be appropriate.
It looks a bit weird with _ instead of ::, and if the name already has _ in it it may be unclear where the scope separator lies. I think this is a fairly minor flaw though.
It’s probably the simplest and most reliable solution IMO.
PS:
@chiggs_ifb Python was a terrible choice IMO. I mean it’s amazing compared to TCL and SV, but I wish some software engineers could slap some sense into the EDA industry.