imageNamaste FPGA
image
RTL Design2 min read

Vivado's RTL Linter: What's Still Missing in 2026

Vivado's inbuilt linter supports a wide variety of checks. These include width mismatch, mixing assignment operators within a single always block, misuse of clock and reset, latch inference due to incomplete if-else and case statements, multiple drivers, combinational loops, and signed-unsigned mismatch. In comparison, Verilator and commercial linters provide far more exhaustive checks than Vivado.

Vivado is progressing well with the addition of new rules in every new release. However, there are still several important rules that we expect to see in future versions of Vivado.

The first rule we wish to see is related to reading a signal before writing it which causes simulation-synthesis mismatch. e.g. if we have two expressions where one updates a variable called temp and the other uses the value of temp to generate the output, reading temp before writing it means we will always be using the previous value of temp and then updating it to the new value. This leads to completely different behavior between simulation and synthesis.

Vivado does include a check to detect missing case states. However, Vivado silently ignores if the same state is used twice or overlapping case states. This lead to creation of if-else priority logic instead of parallel logic. Therefore, a dedicated check for case overlap is must.

Vivado can detect the misuse of clock & reset when both edges are used. However, when a signal from the synchronous domain is used as an asynchronous signal inside an always block. The problem with this practice is that if a synchronous signal is used as an asynchronous reset, it will not work correctly during power-up when the clock itself is not stable.

Vivado flags a violation when unsigned and signed values are directly assigned to each other. However, if we use comparison operators and try to compare or assign unsigned to signed values (or vice versa), Vivado silently ignores it. This can lead to functional bugs that are difficult to find during debugging.

Vivado does include a rule to check whether all bits of a variable are written as well as read somewhere in the code. However, if we use the same name for a local variable inside an always block and an output variable, the local variable gets priority and gets updated, while the output variable remains unused. Although we may get an unused warning for the output, the fact that we are assigning a value inside the always block creates confusion.

Vivado detects the use of both blocking and non-blocking assignments in a single always. However, if we misuse them — for example, using blocking assignments inside a sequential always block — this is ignored by the Vivado linter.

Blog illustration
336 views