Logical Coding

Logical Coding

Python programmers have a concept they call "pythonic."  In Python, as in many programming languages, there are often multiple ways of accomplishing the same thing.  The pythonic one is the one that uses the Python language elegantly and properly.  It makes best use of the language features and uses conventions and idioms that are well accepted in the Python community.  These are considered good practices.  There is no fixed set of rules listing what is pythonic; there is no document describing what pythonic code looks like. Often what is considered pythonic is as much an aesthetic judgement as a technical one. If you are an experienced Python programmer you know pythonic code when you see it.

In SystemVerilog there are conventions, norms, best practices, and even aesthetics that are generally well accepted, but until now, no one has provided a name for them. I offer the term SVlogical.  "SystemVerilogic" is a bit clumsy with too many syllables.  It does not roll off the tongue in the same way that "pythonic" does. SVlogic kind of works but somehow seems abrupt. "Logical" being part of SVlogical implies that the coding style is logical -- that is, the way to code is written just makes sense.  And that's what we're trying to get across.  Code that is SVlogical is sensible, well constructed, good looking code.

What are some coding idioms or conventions that we could consider as SVlogical?  Here are a few that come to mind (in no particular order).

  • A parameterized class should be extended from a non-parameterized base class.  Preferably, the base class contains a pure virtual interface.
     
  • Avoid using more than two or three class parameters.  For any more than that consider some other means of making parametric information available to a class.
     
  • Avoid $cast whenever possible. There are some circumstances where its use is unavoidable, however, most of the time you can get away with not using it.
     
  • CAPITALIZE macros. Macros defined using lower case identifiers can easily be confused for functions or variables. Macro invocations can get lost among other code. The corollary is do not CAPITALIZE other (non-macro) identifiers. Identifiers could begin with or have capital letters in them (e.g CamelCase) but should not be entirely capitalized.  This makes it easy to distinguish between macro identifiers and non-macro identifiers.
     
  • Put code in packages.  All your classes should be in a package or spread across several packages and imported where needed.  This avoids (awkward) `include files and minimizes compile-time dependencies.
     
  •  Since everything is in a package, those of you using include guards can stop doing that. You know who you are. Include guards make a lot of sense in C++, but not so much in SystemVerilog.
     
  • Use wires when constructing interfaces.  This will make it a lot easier to connect to port lists on modules.  Use modports if you need to enforce directionality.
     
  • Speaking of interfaces, use aliases instead of continuous assignments to bind modules to interfaces.  You will save yourself a lot of time debugging the directionality of the assignments.
     
  • Don't use the "this" handle unless you really need it.  Code like the following is not recommended. You are better off using different names (e.g. m_a, m_b) to disambiguate than using the "this" handle.
    this.a = a;
    this.b = b;
  • Use push_front(), push_back(), pop_front(), and pop_back() functions for queue operations.  Don't use expressions such as {a,q}, {q,a}, q[1:$], q[0:$-1] to do the same things.  The named functions are easier to read and I doubt there is any performance difference in using the named functions versus the expressions.
     
  • Use '0, '1, 'x, or 'z to initialize bit strings.  A lot of people use fixed-length initialization values, things like 32'h00000000. This is fine until next year when your company moves to a 64 bit bus or a 36-bit address space.  Now you have to go and change all those 32s to 64'h0000000000000000 or whatever. Eek. For bit strings whose size is self-determined, '0 means fill all bits with 0. Same with '1, 'x, and 'z.
     
  • Feel free to rely on the fact that non-static variables (class members and local variables in tasks and functions) are initialized to 0 or null for you (see table 6-7 in the IEEE-1800-2012 LRM) and that the garbage collector will pick up memory that is no longer referenced. These things are considered poor practice in other languages, but they are fine in SystemVerilog.
     
  • Don't use program blocks.  If you are relying on a program block to resolve a race condition you are just fooling yourself.  The race still exists, now you've just covered it up. It will come back to haunt you later. Also, you have to spend time figuring out about which events occur in the active region and which occur in the observed or reactive regions.  Without any good debugging tools to tell you which is which this can be very difficult.
     
  • Make sure you choose the appropriate comparison operator (==, !=, ===, !==, ==?, !=?) for each situation.  Using the wrong one could be the cause of a very subtle bug.
     
  • Take advantage of the static initialization phase to do consistency checking, initialize data structures and variables, or any other housekeeping that needs to be done before time zero.  The example below uses some_bit to cause initialize() to be called at static initialization time.  Initialize() is a function that returns a bit. Initialize() is a function with useful side-effects.
    static bit some_bit = initialize();
  • Be very careful with the use of the `timescale directive.  Generally, testbench code should be independent of timescale.  If you do need to specify the timescale, do so in the fewest places possible, preferably no more than one.
     
  • Do not use while(1) to create an infinite loop.  That's a C++ idiom. Use the forever keyword instead.

These are not hard and fast rules and this is hardly an exhaustive list. In fact, they are just my opinion.  Your opinion of what is SVlogical may differ.  However you define it, you should continually strive to write good quality, well constructed code that uses the SystemVerilog language elegantly. What things do you consider to be SVlogical?

C++ ... Really?

C++ ... Really?

Assumptions

Assumptions