Skip to content

Linter notes

Andrew Zonenberg edited this page Jan 8, 2019 · 21 revisions

Wishlist

This is a list of common Verilog coding errors, and best practices. TODO: make a similar page/section for VHDL.

The goal is to acquire a F/OSS linter which detects all of these errors and enforces these best practices. This may be done by using an existing tool (if one can be found), writing patches to improve an existing tool, or creating a new tool from scratch. The choice of which path to take will be made after this list is closer to final.

So far, this list is largely based on azonenberg's personal recollections of bugs he's found in his own code. Contributions are welcome!

The tool should support an "FPGA mode" and "ASIC mode" since some rules only make sense for one target or the other.

Best practices

These are legal according to the LRM, but poor practice. Generate warnings.

  • `timescale is required at the start of each HDL file, before any declarations
  • `default_nettype none is required at the start of each HDL file, before any declarations
  • Mixing <= and = assignments in the same always block is prohibited
  • All conditional paths in a combinatorial always block must assign all variables. Yosys can check this: select -assert-none t:$dlatch t:$dlatchsr
  • Combinatorial always blocks must use * rather than an explicit sensitivity list
  • If a reg starts at zero and is set to 1 by a clocked always block, but never set to 0, this is probably a flag somebody forgot to clear. Provide a Verilog attribute which can be attached to that wire if "sticking" is the intended behavior.
  • Use of numbered module ports (vs named) is prohibited.
  • Use of synthesis constraints in comments is prohibited.
  • (questionable, discuss): = assignments are prohibited in clocked always blocks; possibly allow in combinatorial always blocks
  • (questionable, discuss): Use of `define in source files is prohibited. Always use localparams for module-scoped constants; global macros must be defined via synthesizer arguments (f. ex specifying the device family being targeted).
  • Use of hierarchial name notation to refer to signals or parameters within a child module is prohibited.
  • (FPGA targets only): All registers must have an "initial" value.
  • (ASIC targets only): Use of "initial" values is prohibited.
  • Nested ternary ?: logic is prohibited.

Errors

These are blatantly illegal for synthesis (but possibly legal in simulation); generate an error for sure

  • Multiple always blocks driving one net
  • Multiple assign statements driving one net
  • assign to a variable of reg type
  • Use of # delays (outside sim code)
  • Setting a parameter that the module being instantiated doesn't have
  • Use of Z/X in a case statement (not casex/casez)
  • Conditionals that can never be true due to width mismatch (e.g. checking a reg[3:0] against 31)

Clock domain crossing

Just some musings here, nothing is definite...

This might be best done as a separate step (analysis on post-synthesis netlist)

  • Require all signals originating at a top-level module port to be tagged (* REFCLK = "clock_name" *)
  • If no REFCLK constraint, the signal is assumed asynchronous to all clocks in the design
  • All signals driving the input of a flipflop must be either ** Clocked by the same clock as the FF ** Tagged REFCLK = (same clock as the FF)
  • The only exception is if the load FF is tagged (* CROSS_CLOCK *), indicating this is a deliberate clock domain crossing
  • TODO: how to handle PLLs etc
  • Otherwise, flag all clock domain crossings as potential timing errors

TODO

Things that we know need discussion, but don't have a set of rules yet

  • Rules re sign extension, truncation, 32-bit implied widths, etc

Linters

This list includes both pure linters and tools which include some level of linting as one of their functions. F/OSS tools only, please.

  • Icarus Verilog
  • Verilator
  • Yosys read_verilog