Keep It Simple, Stupid! Verilog has how many ways to replicate logic?
One of the tenets held most firmly by TL-X.org is simplicity. We value a minimal set of features because we recognize that every feature is a burden to the next wave of capabilities.
An excess of features also leads to differences in coding style. Often the first thing a designer does when inheriting someone else's Verilog code is to rewrite it stylistically, which only provides an opportunity to introduce bugs. Organizations often institute coding standards (with difficulty) to improve uniformity. This introduces the need for linting tools to enforce the local standards, which leads to issues with external IP and leveraged code and in the end results in more headache than it is worth.
The complexity in Verilog isn't necessary. Growing up my family was baffled when a T intersection in the middle of nowhere was replaced with the one pictured to the right. We referred to it as "Committee Junction". That's Verilog.
Let's look specifically at replication -- n copies of some logic. It can be anything from the 64 registers in a register file to 16 CPU cores on a die.
So how many constructs are there for replication in Verilog? I count five:
- arrayed module instantiation
- generate for loop
- procedural for loop
- unpacked arrays
- packed arrays
These constructs are largely overlapping, but each has its own unique restrictions and nuances. For example, an unpacked array of bits cannot be referenced as a vector. As a more obscure example, it is not possible to reference a signal within a generate loop from outside the loop by indexing into the loop using a signal as the index.
TL-Verilog provides a single form of replication. When it was introduced, I thought of it as a shorthand notation for a for loop. Now I realize it offers much more -- or much less, as the case may be.
We should not undervalue the fact that in the process of adding powerful new transaction-level capabilities, more constructs are deprecated by TL-Verilog than are introduced.
New TL-X constructs (in TL-X 1a):
These new constructs obviate the need for the following:
- always blocks (always @, always_comb, always_latch, always_ff)
- sensitivity lists
- posedge/negedge triggering
- generate blocks and genvars
- for loops and generate for loops
- blocking vs. non-blocking assignments
- reg vs. wire
- bit vs. logic
- packed vs. unpacked
- signals, in fact
Just like Java introduced simpler and safer mechanisms versus C++, TL-Verilog simplifies Verilog. The analogy isn't entirely fitting, however. While Java sacrifices performance for simplicity, TL-Verilog gives up nothing and eases the effort of optimizing performance. And, TL-Verilog, while introducing abstraction and preserving detail, actually reduces code size. Verilog really is that bloated.