How to Optimize Verilog Code for FPGA: Best Practices
Verilog code for FPGA, focus on writing synchronous logic with proper clock domains, use resource-efficient coding styles like finite state machines, and avoid combinational loops. Also, leverage FPGA-specific features such as block RAMs and DSP slices by coding with hardware mapping in mind.Syntax
Optimized Verilog code for FPGA typically uses synchronous logic with always @(posedge clk) blocks to ensure predictable timing. Use reg for storage elements and wire for combinational signals. Finite State Machines (FSMs) are coded with clear state definitions and transitions to control complex behavior efficiently.
module simple_fsm(
input wire clk,
input wire rst,
input wire in,
output reg out
);
typedef enum reg [1:0] {IDLE=2'b00, STATE1=2'b01, STATE2=2'b10} state_t;
state_t state, next_state;
// State register
always @(posedge clk or posedge rst) begin
if (rst)
state <= IDLE;
else
state <= next_state;
end
// Next state logic
always @(*) begin
case(state)
IDLE: next_state = in ? STATE1 : IDLE;
STATE1: next_state = in ? STATE2 : IDLE;
STATE2: next_state = IDLE;
default: next_state = IDLE;
endcase
end
// Output logic
always @(posedge clk) begin
out <= (state == STATE2);
end
endmoduleExample
This example shows a simple FSM with three states optimized for FPGA. It uses synchronous resets and clear state transitions, which help the FPGA tools map the design efficiently to hardware resources.
module counter(
input wire clk,
input wire rst,
output reg [3:0] count
);
always @(posedge clk or posedge rst) begin
if (rst)
count <= 4'b0000;
else
count <= count + 1;
end
endmoduleCommon Pitfalls
Common mistakes include using asynchronous resets unnecessarily, creating combinational loops, and writing overly complex combinational logic that increases delay. Avoid inferring latches by ensuring all branches in always blocks assign values. Also, do not use blocking assignments (=) in sequential logic; use non-blocking (<=) instead.
/* Wrong: infers latch and uses blocking assignment in sequential logic */ always @(posedge clk) begin if (enable) out = data_in; // blocking assignment end /* Correct: no latch, non-blocking assignment */ always @(posedge clk) begin if (enable) out <= data_in; else out <= 0; end
Quick Reference
- Use synchronous resets and clock edges.
- Prefer non-blocking assignments in sequential logic.
- Write clear FSMs for control logic.
- Avoid combinational loops and inferred latches.
- Leverage FPGA primitives like block RAM and DSPs by coding accordingly.
- Keep combinational logic simple and balanced.