Writing SystemVerilog
Naming Conventions
- Modules:
svc_prefix (e.g.,svc_arbiter) - Clock: Always
clk - Reset: Always
rst_n(active-low) - Next-cycle signals:
_nextsuffix (e.g.,grant_valid_next) - Pipeline stages:
_p1,_p2suffixes - Interfaces:
s_for subordinate,m_for manager - Valid/ready: Use
valid/readyfor stream interfaces - Multi-cycle ops: Use
start/done
Comment Style
- NEVER use end-of-line comments - ALL comments on line above
- Use blank comment separators for sections:
//
// Write pointer logic
//
Signal Declarations
- Use
logicinstead ofwire/reg - Declare each signal on separate line, never group
- Align signal widths for readability:
logic [ ADDR_WIDTH:0] ptr;
logic [DATA_WIDTH-1:0] data;
Code Structure Order
- Localparams
- Internal signals
- Child module instantiations
- Combinational logic (
always_comb) - Sequential logic (
always_ff) - Formal assertions (if applicable)
State Machines
- Use
typedef enumwithout explicit bit width - Prefix states with
STATE_(orREAD_STATE_/WRITE_STATE_for multiple FSMs) - Separate
always_fffor transitions,always_combfor outputs
typedef enum {
STATE_IDLE,
STATE_BUSY,
STATE_DONE
} state_t;
Reset Pattern
Always use synchronous active-low reset:
always_ff @(posedge clk) begin
if (!rst_n) begin
counter <= '0;
state <= STATE_IDLE;
end else begin
counter <= counter_next;
state <= state_next;
end
end
Assignments
- Use
always_ffwith non-blocking (<=) for sequential logic - Use
always_combwith blocking (=) for combinational logic - For complex conditionals, prefer if/else over ternary operators
Unused Signals
Use the SVC_UNUSED macro:
`SVC_UNUSED({signal1, signal2, signal3});
After Writing Code
Always run:
make format- format codemake lint- check for errors
For full details see docs/style.md