KB 05: Synthesizable Coding of Verilog
The synthesis is to convert the description language into a circuit that can be implemented in hardware. However, most Verilog courses do not tell us whether you have to consider that the code is synthesizable or not, while you use Verilog to design the system.
When you use Verilog to describe your circuit, keep in mind the following:
- Do not use the initialization block.
- Do not use delay statements.
- Do not use statements with uncertain loop times, such as: forever, while, etc.
- Use synchronous methods to design the circuit as possible.
- Use behavioral modeling to design the circuit as possible.
- When using an always block describes the combinational circuit, all the inputs should be listed in the sensitivity list.
- All the User-Defined Primitives (UDP) are not synthesizable.
- The repeat, wait, fork/join, deassign, event, force/release statements are not supported by synthesis tools.
- Hierarchical references of registers and nets inside the modules are not supported.
module my_module;
assign my_net = top.my_module1.my_net;
endmodule
Synthesizable Verilog
Not all kinds of Verilog constructs can be synthesized. Only a subset of Verilog constructs can be synthesized and the code containing only this subset is synthesizable.
The following of the Verilog codes are synthesizable.
- Verilog Basis:
- parameter declarations
- wire, wand, wor declarations
- reg declarations
- input, output, inout
- continuous assignment (assign)
- module instructions
- gate instructions
- always blocks
- task statement
- function definitions
- for, while loop
- Synthesizable Verilog primitives cells
- and, or, not, nand, nor, xor, xnor
- buffif0, buffif1, notif0, notif1
- Operators
- Concatenation ( {}, {{}} )
- Unary reduction ( !, ~, &, |, ^ )
- 2's complement arithmetic ( +, -, * )
- Logic shift ( >>, <<)
- Relational ( >, <, >=, <=)
- Equality ( ==, != )
- Binary bit-wise ( &, |, ^%, ~^ )
- Logical (&&, || )
- Conditional ( ? : )
The following Verilog code can not be used for the synthesis
- ===, !==
- delay, initial, repeat, forever, wait, fork, join, event
Coding Style
On the premise of meeting the functional and performance goals, a good coding style can improve the readability and portability of the code. Before developing an FPGA project, the most important thing is to create a naming convention and acronym lists, and document them. All the designers on the team must strictly follow the code when writing the process.
The general principles of good coding style are summarized as follows:
- Use lowercase for all signal names, variable names, and port names; uppercase for constant names and user-define types. Most industries follow these rules.
- Use meaningful signal names, port names, function names, and argument names.
- The signal name should not be too long.
- For the clock signal, use clk as the signal name. If there are multiple clocks in the design, use clk as the prefix of the clock signal.
- Use the same name for the signals from the same drive source in different sub-modules. Defining the name of the connection between the top module and submodules should be done in the design stage. Whenever possible, use the same name for the port and port connection signals.
- Active low signals should be indicated by an underscore (_) followed by a lowercase letter b or n. Note: In the same design, use the same lowercase letter to indicate active low signals.
- Use rst as the signal name for the reset signal. If the reset signal is active low, it is recommended to use rst_n.
- When describing multi-bit buses, use a consistent bit-order. For Verilog, it is recommended to use little-endian bit order, which format is [msb:lsb]. For example, databus[15:0].
- Try to follow some conventions used in the industry. For example, *_r indicates the register output, *_a indicates the asynchronous single, *_pn indicates the signal used in the nth cycle of the multi-cycle path, *_nxt indicates the signal before latching, *_z indicates the tri-state signal, etc.
- Add a file header at the beginning of the source files. Usually, the file header contains the following items: file name, author, module function overview, key feature description, file creation, and modification date and modified content, etc.
- Use appropriate comments to explain all always procedures, functions, port definitions, signal meanings, variable meanings or signal groups, variable array meanings, etc. The comment should be placed near the code it annotates, and it should be concise, as long as it is sufficient to explain the design intent and avoid being too complicated.
- Each statement is written on a separate line, and the length of each line is less than or equal to 72 characters, which can improve the readability and maintainability of the code. Although, Verilog allowed multiple statements can be written on a single line, but it is not recommended.