One aspect of RTL design, foreign to the software developers, is the widths and ranges:
Every signal or register may have any width, not just 8 * 2k. The indices don't always start from 0 or 1, but the start index is explicitly given. And the order of the indices may be as ascending (e.g.
[0:7]) as descending (e.g.
Meanwhile the range limits are inclusive, so to define an empty array or bit-vector (say as a general case of the configuration) you'd have to use ranges like "descending from n - 1 to n", but Verilog may as well interpret it as 2-elenment array/bit-vector with ascending order of indices instead of 0-element array/bit-vector with descending indices… that's why VHDL distinguishes
downto in the range.
Moreover in Verilog there are index ranges to the left and to the right of the declared identifier, it boils down to the distinction between packed and unpacked (padded for alignment) values. For example, an array
logic [7:0] arrgh [0:3] can't be seen as just
logic [0:31] bv or
logic ar [0:31], And even if the concatenation of a signals should have the same width, the translator will still complain that width doesn't match (without specifying what the widths are BTW, good luck guessing it for yourself).
To replicate typical constructions over multiple indices, you're supposed to use the "for"-"loop", which isn't a loop of course but essentially a templating directive. This expression is very picky about the types of the index variables, the ranges, and how you use the variable in the index range. Basically it's just a parody on the for-loops in C. If the variable needs to linearly affect as the upper as the lower index of an array/bit-vector in the body, you can't do that, only in special cases you can utilize the
+: delimiters, if the distance between the indices is fixed.
Concatenation (of e.g. bit-vectors), doesn't have a parametric generalization, so you'd need to rewrite it "for" assigning to individual bits.
In SV there are also "genvar" + "generate" constructions used when just "for" doesn't suffice. Where to apply which is a mystery. Just another redundant syntax perhaps.
To recap: it's even easier to introduce subtle bugs in Verilog than in JS, and most hardware is probably full of it. I really don't have much respect to this language or it's authors, and nobody should write it directly, if it can't be avoided. While VHDL seems fine.
@amiloradovsky The "generate" statement is also available in plain Verilog. Generate will actually "instantiate" new constructs within it. So if you have a generate for loop with an instance of Module(), you will have the same number of Module() instances as you do loop iterations (of course same applies to wires etc). The names of module instances and wires defined in the loop are all scoped to the generate for loop. I've used that construct quite a bit over time in different scenarios.
@cstanhope Ordinary "for" (not within a "generate") will also generate so many instances of the body, but is indexed by a variable indistinguishable from a signal/register, which in fact is meta-syntax one and is more like "genvar". What isn't clear is where to use "for" without "generate", or why they ever kept the two constructions.
"genvar"s are also untyped AFAICT, prone to errors.
@amiloradovsky I'm not sure. I've definitely used implementations of Verilog (not SystemVerilog) which would not let me create instances of modules or wires outside of generate blocks. I tend to think of generate blocks as a kind of weak templating system or slightly weird C macro system. Of course, what you say about types are true. Although plain Verilog has so few types anyway. ;)
@amiloradovsky Thinking about it, whenever I am working, I tend to be targeting at least two implementations of Verilog: the toolchain used to generate a bitstream and the toolchain used to simulate. Often these disagree about what Verilog is. So I end up writing to the subset of the language they both can agree to, which is hopefully a useful subset. 😆
@cstanhope It's probably the subset which the specification is unambiguous about…
Either way, the point is to use not as much of the specification but as little of it as possible, generating Verilog from a decent language (Koika, BlueSpec, (n)Mingen, etc.).
Not to say that I used any extensively any of those, but that's what to aspire to.
OTOH, I'm not super fond of the proliferation of intermediate forms, and perhaps modern VHDL+OSVVM would be preferable in most cases.
@amiloradovsky I do want to try one of the languages you refer to. Probably Mingen to start. I've stayed away from it for work because it is much easier to find people who can work in Verilog and VHDL than other languages. In a pinch, a contractor can be brought in and they could probably easily get to work. I'll have to explore these options in my own time (like always).
The social network of the future: No ads, no corporate surveillance, ethical design, and decentralization! Own your data with Mastodon!