Research test chip projects are typically severely time constrained.
Therefore, it is important to use an RTL development approach that is 1) efficient, 2) minimizes bugs, and 3) is supported by front-to-back EDA tool flows.
While less verbose than VHDL, the earlier Verilog RTL standards such as Verilog'95 and Verilog-2001 offer very limited compile-time checking, which can lead to a large number of trivial bugs.
Although this can be overcome by the use of lining tools and strict coding guidlines, it is generally slow.
In recent years, there has been a significant research effort exploring new hardware design languages, such as Chisel, PyMTL, MyHDL etc, as well as high-level synthesis (HLS) from C++/SystemC languages.
However, in either case, there is a translation step of varying complexity required to generate Verilog for the EDA tools to consume.
We use SystemVerilog (SV) for most of our RTL design, which is mature, natively supported by EDA tools, and relatively well supported in open source projects.
SV includes a number of more advanced language features that prevent a whole class of common issues with older Verilog standards.
This document outlines some coding guidelines for writing bug-free RTL in SV.
More generally, we offer advice for arranging RTL projects.
## SystemVerilog Coding Style
SV is a very large language with many verification-oriented features that are not relevant to writing synthesizable RTL.
Therefore, we use a strict RTL coding style, which can be summarized in the following directives:
***Separate logic and registers.**
Makes RTL easier to parse and pipelining easier to modify.
Forces designers to think about where registers exist in the design.
Also typically also it easier to modify pipelines.
***Use rising-edge registers with active-low async reset.**
Simplifies functional debug, validation and timing constraint development.
***Only one clock and reset signal in a module.**
This guideline drastically reduces bugs related to clocking and reset.
The vast majority of RTL modules do not require more than one clock and reset.
Any logic that *requires* multiple clocks should be careful contained in a special module.
***Use the `logic` type exclusively.**
Replaces both the older \texttt{wire} and (very confusing) \texttt{reg} types.
Provides compile-time checking for multiple drivers.
***Use the `always_comb` keyword for logic.**
Provides compile-time checking for unintended latches or registers.
***Use the ``always_ff`` keyword to infer registers.**
Provides compile-time checking for unintentional latches.
In addition to these guidelines, we also recommend the strict use of a pre-processor macro for register inference.
This has a number of advantages, including: 1) significant reduction in lines of code, 2) removes the risk of poor inference style, e.g. embedded logic, 3) enforces use of a rising-edge, async active-low reset, 4) allows the register inference template to be changed to suit ASIC or FPGA.
A macro is used instead of a module to reduce simulation overhead.
The CHIPKIT RTL header file (`RTL.svh`) includes a macro definition `\`FF()` for this purpose, which replaces the traditional inference template, as shown in the snippet below.
When using FPGAs with an RTL codebase, this macro can be easily redefined to infer a synchronous reset, which is more common.
```systemverilog
// Include file contains flip-flop inference macro
Physical IP such as SRAMs, IO cells, clock oscillators, and synchronizers need to be instantiated in the RTL.
It's worth remembering that various versions of these cells may be required over the lifetime of the IP or full-chip, including RTL functional models as well as various ASIC and FPGA libraries.
Therefore, it is helpful to wrap instantiated components inside a module, which can then be easily switched.
Each set of wrapped component instantiation modules is stored in a different directory for each library, with the correct directory included at compile time.
%This allows the developer to swap out RTL models with ASIC or FPGA models or inference templates at both simulation and implementation time.
TODO
add intro on importance of coding guidelines and explain not much currently around
add examples of common gotchas, especially with Verilog (and how SV helps)