SCOORE Coding Style
From Vlsiwiki
Contents
Coding Rules
- Try to use active high always (no active low like reset_N)
- Avoid latches
- Code must be synthesizable for FPGA and ASIC. Only testbenches can use behavioral.
- Do not use timing delays
- Use for command if and only if the loop conditions are constants.
- No initialization assignments. Use reset signal when necessary
Compact begin/end indentation
if (a) begin ... end else begin ... end
- Try to have less than 1000 lines per file
- File name equals module name: Each module has its own file
- Do not use hardcoded numeric values. Use defines or parameters
- Use connection by name when instantiating a submodule. Ex:
pipe fe(.clk(clk) ,.reset(reset) ,.foo(foo));
- Declare modules following the Verilog-2001 new specification
module idStage ( input BoolType clk ,input FooType nCommited ,output BarType var);
- Use case stmts, avoid ifs stms whenever possible. If no priority is required, make sure that the different cases are mutually exclusive (parallel case) and that all the options are covered (full case).
- All cases covered. Always cover all input patterns, either by specifying them or using a default case. Place assertions on non-possible cases
- Synopsys dc_shell checks:
- No latches: Run “all_registers -level_sensitive” to list latches
- Check design: run “check_design”. It is OK to have warnings if you understand them.
- no threestate: “all_threestate -cells” should have an empty list
- full/parallel: dc_shell should automatically recognize all the case statements as full/parallel. If not, add a comment explaining why. E.g. output from dc_shell
=============================================== | Line | full/ parallel | =============================================== | ??? | auto/auto | ===============================================
Variable/Type Naming
- Always use big endian. E.g. logic [n:0].
- Create a typedef for each of your variables classes:
typedef struct packed { BoolType msb; logic [29-1:0] mid; BoolType lsb; } DataType;
- All the variables should have a type ending with Type. E.g.: FooType
- you should ONLY do assignments to a variable that finish either with _comb or _next.
- Correct assignment examples:
// _next variables have a flop (foo1_next has a foo1 flop output) foo1_next = bar1; foo2_next = bar2_next; // May be too slow foo3_next = bar3_comb; // May be too slow // _comb variables are "wires" in real logic foo4_comb = bar4; foo5_comb = bar5_next; // May be too slow foo6_comb = bar6_comb; // May be too slow
- Incorrect assignment example:
foo1 = ...;
Comments
- Do not overuse comments. Never comment “how” is done, comment “why” is done. The code explains the “how”, if it is not clear, re-structure. Code should be clean enough to understand it without comments. There are 3 keywords for comments:
- FIXME is used for functionality not working (should be fix as soon as possible)
- TODO is an improvement not implemented due to lack of time
- WARNING is for very weird behavior in a section of code
FSM Rules
- Avoid tricks with encoding (one-hot, gray...). Let the tool choose. To do so, declare states as parameter:
parameter [2:0] // synopsys enum my_states IDDLE = 3’d0, S1 = 3’d1, ... logic [2:0] /* synopsys enum my_states */ state; logic [2:0] /* synopsys enum my_states */ state_next;
- Remember that always @(posedge clk) are not allowed. Use flop_r as follows:
flop_r #(.Size(3), .Reset_Value(IDDLE) f1 (.clk (clk), .reset (reset), .din (state_next), .q (state));
- Big FSMs (>500LoC) should be implemented as separate module
System Verilog
Not all the System Verilog constructions are allowed (classes, unions, interfaces...). The code should constraint to:
- Use const (avoid defines and ifdefs)
- No more include files (*.h)
- Use $bits(FooType) to know number of bits is data type.
- Avoid reg/wire syntax. Use your custom types with logic.
- Only use always_comb (no always @...)
- Check System Verilog LRM for detailed System Verilog documentation.
Creating New Files
- When creating a new file, add the same copyright notice (GPL2). Add a module description, and the file name to the xml file
- Try to have only one module per Verilog file. The module name should match the Verilog file name
- All file names must be lowercase
- Before creating a new file check that the same functionality is not already implemented
Module Input/Output
- All the clocked modules must be a “Synchronous Moore Machine”
- We use flops and pulse triggered latches. To make it transparent, use the “Synchronous Moore Machine” from the flops library
- All the inputs and outputs in the module are wires. The outputs are registered using the flops library
- Flip-flops library available (storage/rtl/flop.v)
- flop: posedge flip-flop without reset
- flop_r: posedge flip-flop with reset. Reset_Value parameter can change the default reset value
- cgflop: posedge flip-flop with clock gating (enable)
- cgflop_r: posedge flip-flop with clock gating (enable) and reset
- Modules without clock signal are assumed to be combinational logic only.
- Port ordering: Declare one port per line. Use the following order:clock,reset, input (enable/busy, control, data), output (enable/busy, control data)
Clock/Reset
- Clock properties:
- flip-flops use the posedge of the clock
- Computer resets on high reset signal. Reset signal will be high for at least 32K full clock cycles. If you need to clear a table, iterate on different clock cycles (reset high)
- Do not use any @(posedge ...) statement. If you need to use flip-flops use the flop library
flop #(.Size($bits(YourType))) f1 (.clk(clk), .din(your_in), .q(your_out));
- Use reset signal if necessary for functionality. Not all the modules have reset signal. RAM-like structures do not have reset signal. External state machine should clear the values if necessary.
- No logic should use clock as input. Clock is only passed to structures in storage library
Blocking/Non-Blocking
- Only use blocking assignments (=)
- Combinational blocks only use blocking assignments (=). Synchronous blocks only use non-blocking assignments (<=). Since we do not have synchronous block. We only use non-blocking assignments on low level libraries like flops & memory_bank
- Use always_comb on the sensitivity list. Do not add list of parameters.
always_comb begin case (sel) // 1'b0: y = a; 1'b1: y = b; default: y = 1'bx; endcase end
- Assign to the same variable in a single always block. Group together in the same always.
Emacs Verilog Mode
- Do not use tabs, write spaces instead of tabs (tab stop is 2). If you use the emacs formating parameters found at the end of this document, this will be done automatically. The reason for not having tabs is that each person has a different setup
- Column width. Do not to go over 80 columns (at least it should be very rare)
- Use the following style for module instantiation (spacing)
mod_name (.clk (clk) ,.reset (reset) ...
- If you use emacs get verilog-mode.el and copy it to
your .emacs.d directory. Then, set this options (.emacs) ("Library/Preferences/Aquamacs Emacs/Preferences.el" for Aquamacs).
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Load verilog mode only when needed (autoload 'verilog-mode "verilog-mode" "Verilog mode" t ) ;; Any files that end in .v should be in verilog mode (setq auto-mode-alist (cons '("\\.v\\'" . verilog-mode) auto-mode-alist)) ;; Any files in verilog mode should have their keywords colorized (add-hook 'verilog-mode-hook '(lambda () (font-lock-mode 1))) (add-hook 'verilog-mode-hook '(lambda () (add-hook 'local-write-file-hooks (lambda() (untabify (point-min) (point-max)))))) (setq verilog-indent-level 2 verilog-indent-level-module 2 verilog-indent-level-declaration 2 verilog-indent-level-behavioral 2 verilog-indent-level-directive 1 verilog-case-indent 2 verilog-auto-newline t verilog-auto-indent-on-newline t verilog-tab-always-indent t verilog-auto-endcomments nil verilog-minimum-comment-distance 40 verilog-indent-begin-after-if t verilog-auto-lineup '(all))
Work Methodology Rules of Thumb (SVN)
This section describes basic working methodology that you should try to follow:
- Synthesize frequently. Optimize area for FPGA and maintain the ASIC frequency target.
- Use SVN frequently: Update every day, commit frequently
- “svn update” before and after editing a file
- “svn commit” every time that a change compiles
- “svn add <file>” whenever you create a new file
- Always use the following commit keywords:
- Design phase:
- CODING ...
- Describe basic design code for module implementation
- OPTIMIZATION ...
- Describe feature added AFTER current module passes complete synthesis with minimum spec
- INCORRECT SPEC ...
- An incorrect spec is found and corrected
- CODING ...
- Solving bugs without integrating with other modules:
- BUG SOLVED ...
- Describe bug and how fixed
- BUG FOUND ...
- Describe bug and how to reproduce (if solved use BUG SOLVED)
- BUG SOLVED ...
- Final integration bugs (nobody should be doing this as we still do not talk between blocks)
- INTEGRATION SOLVED ...
- Bug solved during integration testing
- INTEGRATION FOUND ...
- Bug found during integration testing
- INTEGRATION SOLVED ...
- Design phase:
- Do not work more than 8 hours without a commit
- Design peer review: You should explain your design to someone else before starting implementation. The explanation should include all the modules, inputs, outputs.
- Write assertions as you code. Do not add them latter
- After finding a bug, add an assertion to protect against it
- Write testbenches for big components. Ex: IF0, cache
- Refactor whenever you see something ugly
VPI Techbench
Most of the testbenches in SCOORE use VPI and share infrastructure across tests.
- The testbenches are compiled with c++ (even if it is plain c code).
- Each typedef System Verilog class has an equivalent C++ class to simplify passing parameters between Verilog and C++ testbench. The C++ class is defined in the rtl directory with a _tb.h extension E.g: the C++ VPI specification scoore/common/rtl/dinst_tb.h is the equivalent to the System Verilog scoore/common/rtl/dinst.v.