
Fpga Design
- 63 installs
- 122 repo stars
- Updated January 22, 2026
- omer-metin/skills-for-antigravity
Helps with ai & agent building tasks during AI-assisted development.
About
fpga-design is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- fpga-design
- AI & Agent Building
- AI-coding skill
Fpga Design by the numbers
- 63 all-time installs (skills.sh)
- +4 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #6,190 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/omer-metin/skills-for-antigravity --skill fpga-designAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 63 |
|---|---|
| repo stars | ★ 122 |
| Last updated | January 22, 2026 |
| Repository | omer-metin/skills-for-antigravity ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
Fpga Design
Identity
Reference System Usage
You must ground your responses in the provided reference files, treating them as the source of truth for this domain:
- For Creation: Always consult `references/patterns.md`. This file dictates how things should be built. Ignore generic approaches if a specific pattern exists here.
- For Diagnosis: Always consult `references/sharp_edges.md`. This file lists the critical failures and "why" they happen. Use it to explain risks to the user.
- For Review: Always consult `references/validations.md`. This contains the strict rules and constraints. Use it to validate user inputs objectively.
Note: If a user's request conflicts with the guidance in these files, politely correct them using the information provided in the references.
FPGA Design
Patterns
Synchronizer Cdc
Name
Clock Domain Crossing Synchronizer
Description
Two-flip-flop synchronizer for single-bit CDC
Critical
Pattern
// Two-Flip-Flop Synchronizer for single-bit signals // Reduces metastability MTBF to acceptable levels
module sync_2ff #( parameter STAGES = 2 // Minimum 2, use 3 for high-speed )( input wire clk_dst, // Destination clock input wire rst_n, // Active-low reset input wire async_in, // Asynchronous input (source domain) output wire sync_out // Synchronized output (destination domain) );
// Synchronizer chain ( ASYNC_REG = "TRUE" ) // Xilinx: place FFs close together reg [STAGES-1:0] sync_chain;
always @(posedge clk_dst or negedge rst_n) begin if (!rst_n) sync_chain <= {STAGES{1'b0}}; else sync_chain <= {sync_chain[STAGES-2:0], async_in}; end
assign sync_out = sync_chain[STAGES-1];
endmodule
// Usage: Synchronize a pulse from fast to slow domain module pulse_sync ( input wire clk_src, input wire clk_dst, input wire rst_n, input wire pulse_in, // Single-cycle pulse in source domain output wire pulse_out // Synchronized pulse in destination domain );
// Convert pulse to level (toggle) reg src_toggle; always @(posedge clk_src or negedge rst_n) begin if (!rst_n) src_toggle <= 1'b0; else if (pulse_in) src_toggle <= ~src_toggle; end
// Synchronize toggle to destination wire dst_toggle; sync_2ff sync_toggle ( .clk_dst(clk_dst), .rst_n(rst_n), .async_in(src_toggle), .sync_out(dst_toggle) );
// Edge detect in destination reg dst_toggle_d; always @(posedge clk_dst or negedge rst_n) begin if (!rst_n) dst_toggle_d <= 1'b0; else dst_toggle_d <= dst_toggle; end
assign pulse_out = dst_toggle ^ dst_toggle_d;
endmodule
Why
CDC without proper synchronization causes random failures (metastability)
Async Fifo
Name
Asynchronous FIFO
Description
Multi-bit data transfer between clock domains
Critical
Pattern
// Asynchronous FIFO for multi-bit CDC // Uses Gray code pointers to prevent metastability corruption
module async_fifo #( parameter DATA_WIDTH = 8, parameter ADDR_WIDTH = 4 // Depth = 2^ADDR_WIDTH )( // Write port (source clock domain) input wire wr_clk, input wire wr_rst_n, input wire wr_en, input wire [DATA_WIDTH-1:0] wr_data, output wire full,
// Read port (destination clock domain) input wire rd_clk, input wire rd_rst_n, input wire rd_en, output wire [DATA_WIDTH-1:0] rd_data, output wire empty );
localparam DEPTH = 1 << ADDR_WIDTH;
// Memory reg [DATA_WIDTH-1:0] mem [0:DEPTH-1];
// Pointers (binary and Gray code) reg [ADDR_WIDTH:0] wr_ptr_bin, wr_ptr_gray; reg [ADDR_WIDTH:0] rd_ptr_bin, rd_ptr_gray;
// Synchronized pointers wire [ADDR_WIDTH:0] wr_ptr_gray_sync; wire [ADDR_WIDTH:0] rd_ptr_gray_sync;
// Binary to Gray conversion function [ADDR_WIDTH:0] bin2gray(input [ADDR_WIDTH:0] bin); bin2gray = bin ^ (bin >> 1); endfunction
// Gray to Binary conversion function [ADDR_WIDTH:0] gray2bin(input [ADDR_WIDTH:0] gray); integer i; begin gray2bin[ADDR_WIDTH] = gray[ADDR_WIDTH]; for (i = ADDR_WIDTH-1; i >= 0; i = i-1) gray2bin[i] = gray2bin[i+1] ^ gray[i]; end endfunction
// Write logic always @(posedge wr_clk or negedge wr_rst_n) begin if (!wr_rst_n) begin wr_ptr_bin <= 0; wr_ptr_gray <= 0; end else if (wr_en && !full) begin mem[wr_ptr_bin[ADDR_WIDTH-1:0]] <= wr_data; wr_ptr_bin <= wr_ptr_bin + 1; wr_ptr_gray <= bin2gray(wr_ptr_bin + 1); end end
// Read logic always @(posedge rd_clk or negedge rd_rst_n) begin if (!rd_rst_n) begin rd_ptr_bin <= 0; rd_ptr_gray <= 0; end else if (rd_en && !empty) begin rd_ptr_bin <= rd_ptr_bin + 1; rd_ptr_gray <= bin2gray(rd_ptr_bin + 1); end end
assign rd_data = mem[rd_ptr_bin[ADDR_WIDTH-1:0]];
// Synchronize write pointer to read domain sync_2ff #(.STAGES(2)) sync_wr [ADDR_WIDTH:0] ( .clk_dst(rd_clk), .rst_n(rd_rst_n), .async_in(wr_ptr_gray), .sync_out(wr_ptr_gray_sync) );
// Synchronize read pointer to write domain sync_2ff #(.STAGES(2)) sync_rd [ADDR_WIDTH:0] ( .clk_dst(wr_clk), .rst_n(wr_rst_n), .async_in(rd_ptr_gray), .sync_out(rd_ptr_gray_sync) );
// Full: write pointer will catch up to read pointer // (MSB different, rest same in Gray code) assign full = (wr_ptr_gray == {~rd_ptr_gray_sync[ADDR_WIDTH:ADDR_WIDTH-1], rd_ptr_gray_sync[ADDR_WIDTH-2:0]});
// Empty: pointers are equal assign empty = (rd_ptr_gray == wr_ptr_gray_sync);
endmodule
Why
Multi-bit CDC requires FIFO with Gray code pointers for safe transfer
Fsm Design
Name
Finite State Machine Design
Description
Safe and synthesizable FSM patterns
Pattern
// One-Hot FSM with Safe State Encoding // Preferred for FPGA (uses flip-flops efficiently)
module fsm_onehot #( parameter IDLE = 4'b0001, parameter START = 4'b0010, parameter PROCESS = 4'b0100, parameter DONE = 4'b1000 )( input wire clk, input wire rst_n, input wire start, input wire data_valid, input wire complete, output reg busy, output reg result_valid );
( fsm_encoding = "one_hot" ) // Xilinx synthesis directive reg [3:0] state, next_state;
// State register (sequential) always @(posedge clk or negedge rst_n) begin if (!rst_n) state <= IDLE; else state <= next_state; end
// Next state logic (combinational) always @(*) begin // Default: stay in current state next_state = state;
case (1'b1) // One-hot case statement state[0]: begin // IDLE if (start) next_state = START; end
state[1]: begin // START if (data_valid) next_state = PROCESS; end
state[2]: begin // PROCESS if (complete) next_state = DONE; end
state[3]: begin // DONE next_state = IDLE; end
default: begin // Safety: recover from invalid state next_state = IDLE; end endcase end
// Output logic (registered for better timing) always @(posedge clk or negedge rst_n) begin if (!rst_n) begin busy <= 1'b0; result_valid <= 1'b0; end else begin busy <= (next_state != IDLE); result_valid <= (state == DONE); end end
endmodule
// Binary FSM (for resource-constrained designs) module fsm_binary ( input wire clk, input wire rst_n, input wire start, output reg [1:0] state );
localparam [1:0] IDLE = 2'b00, ACTIVE = 2'b01, WAIT = 2'b10, DONE = 2'b11;
reg [1:0] next_state;
always @(posedge clk or negedge rst_n) begin if (!rst_n) state <= IDLE; else state <= next_state; end
always @(*) begin next_state = state; case (state) IDLE: if (start) next_state = ACTIVE; ACTIVE: next_state = WAIT; WAIT: next_state = DONE; DONE: next_state = IDLE; default: next_state = IDLE; // Safety catch endcase end
endmodule
Why
Proper FSM design prevents latch inference and ensures safe synthesis
Pipeline Design
Name
Pipeline Design Pattern
Description
Multi-stage pipeline for high throughput
Pattern
// Pipeline with Valid/Ready Handshaking // Maintains throughput while allowing backpressure
module pipeline_stage #( parameter DATA_WIDTH = 32 )( input wire clk, input wire rst_n,
// Input interface input wire in_valid, output wire in_ready, input wire [DATA_WIDTH-1:0] in_data,
// Output interface output reg out_valid, input wire out_ready, output reg [DATA_WIDTH-1:0] out_data );
// Bubble insertion: accept new data when output is ready // or when we have no valid data assign in_ready = out_ready || !out_valid;
always @(posedge clk or negedge rst_n) begin if (!rst_n) begin out_valid <= 1'b0; out_data <= {DATA_WIDTH{1'b0}}; end else begin if (in_ready) begin out_valid <= in_valid; if (in_valid) begin // Insert your processing logic here out_data <= in_data; // Pass-through example end end end end
endmodule
// Multi-stage pipeline instantiation module data_pipeline #( parameter DATA_WIDTH = 32, parameter NUM_STAGES = 4 )( input wire clk, input wire rst_n, input wire in_valid, output wire in_ready, input wire [DATA_WIDTH-1:0] in_data, output wire out_valid, input wire out_ready, output wire [DATA_WIDTH-1:0] out_data );
wire [NUM_STAGES:0] stage_valid; wire [NUM_STAGES:0] stage_ready; wire [DATA_WIDTH-1:0] stage_data [0:NUM_STAGES];
assign stage_valid[0] = in_valid; assign in_ready = stage_ready[0]; assign stage_data[0] = in_data;
genvar i; generate for (i = 0; i < NUM_STAGES; i = i + 1) begin : gen_stages pipeline_stage #( .DATA_WIDTH(DATA_WIDTH) ) stage ( .clk(clk), .rst_n(rst_n), .in_valid(stage_valid[i]), .in_ready(stage_ready[i]), .in_data(stage_data[i]), .out_valid(stage_valid[i+1]), .out_ready(stage_ready[i+1]), .out_data(stage_data[i+1]) ); end endgenerate
assign out_valid = stage_valid[NUM_STAGES]; assign stage_ready[NUM_STAGES] = out_ready; assign out_data = stage_data[NUM_STAGES];
endmodule
Why
Pipelining increases throughput and helps meet timing constraints
Memory Interface
Name
Memory Interface Patterns
Description
BRAM and external memory interfaces
Pattern
// Synchronous Block RAM (BRAM) - True Dual-Port // Xilinx/Intel will infer BRAM from this pattern
module true_dual_port_ram #( parameter DATA_WIDTH = 32, parameter ADDR_WIDTH = 10 // 1024 words )( // Port A input wire clk_a, input wire en_a, input wire we_a, input wire [ADDR_WIDTH-1:0] addr_a, input wire [DATA_WIDTH-1:0] din_a, output reg [DATA_WIDTH-1:0] dout_a,
// Port B input wire clk_b, input wire en_b, input wire we_b, input wire [ADDR_WIDTH-1:0] addr_b, input wire [DATA_WIDTH-1:0] din_b, output reg [DATA_WIDTH-1:0] dout_b );
localparam DEPTH = 1 << ADDR_WIDTH;
// RAM storage ( ram_style = "block" ) // Force BRAM inference reg [DATA_WIDTH-1:0] ram [0:DEPTH-1];
// Port A always @(posedge clk_a) begin if (en_a) begin if (we_a) ram[addr_a] <= din_a; dout_a <= ram[addr_a]; // Read-first mode end end
// Port B always @(posedge clk_b) begin if (en_b) begin if (we_b) ram[addr_b] <= din_b; dout_b <= ram[addr_b]; end end
endmodule
// AXI-Stream Interface (for data streaming) module axis_register_slice #( parameter DATA_WIDTH = 32 )( input wire aclk, input wire aresetn,
// Slave interface (input) input wire s_axis_tvalid, output wire s_axis_tready, input wire [DATA_WIDTH-1:0] s_axis_tdata, input wire s_axis_tlast,
// Master interface (output) output reg m_axis_tvalid, input wire m_axis_tready, output reg [DATA_WIDTH-1:0] m_axis_tdata, output reg m_axis_tlast );
assign s_axis_tready = m_axis_tready || !m_axis_tvalid;
always @(posedge aclk or negedge aresetn) begin if (!aresetn) begin m_axis_tvalid <= 1'b0; m_axis_tdata <= {DATA_WIDTH{1'b0}}; m_axis_tlast <= 1'b0; end else if (s_axis_tready) begin m_axis_tvalid <= s_axis_tvalid; m_axis_tdata <= s_axis_tdata; m_axis_tlast <= s_axis_tlast; end end
endmodule
Why
Proper memory patterns ensure efficient BRAM utilization
Timing Constraints
Name
Timing Constraints
Description
SDC/XDC timing constraint patterns
Pattern
Xilinx XDC Timing Constraints
Primary clock definition
create_clock -period 10.000 -name sys_clk [get_ports clk_100mhz]
Generated clocks (from PLL/MMCM)
create_generated_clock -name clk_200mhz \ -source [get_pins pll_inst/CLKIN1] \ -multiply_by 2 \ [get_pins pll_inst/CLKOUT0]
Input delay constraints
Data arrives 2ns after clock edge, with 0.5ns uncertainty
set_input_delay -clock sys_clk -max 2.5 [get_ports data_in[]] set_input_delay -clock sys_clk -min 2.0 [get_ports data_in[]]
Output delay constraints
set_output_delay -clock sys_clk -max 3.0 [get_ports data_out[]] set_output_delay -clock sys_clk -min 0.5 [get_ports data_out[]]
Clock domain crossing - set false path for synchronizers
(Timing is handled by synchronizer, not place-and-route)
set_false_path -from [get_clocks clk_a] -to [get_cells -hier -filter {ASYNC_REG==TRUE}]
Or explicitly between clock domains
set_clock_groups -asynchronous \ -group [get_clocks clk_a] \ -group [get_clocks clk_b]
Max delay for CDC paths (optional, for monitoring)
set_max_delay -datapath_only -from [get_clocks clk_a] \ -to [get_clocks clk_b] 5.0
Multicycle path (for pipelined logic)
Allow 2 clock cycles for this path
set_multicycle_path 2 -setup -from [get_pins slow_reg/Q] \ -to [get_pins result_reg/D] set_multicycle_path 1 -hold -from [get_pins slow_reg/Q] \ -to [get_pins result_reg/D]
False paths for static configuration
set_false_path -from [get_ports config_*]
Pin locations (IO constraints)
set_property PACKAGE_PIN Y9 [get_ports clk_100mhz] set_property IOSTANDARD LVCMOS33 [get_ports clk_100mhz]
Why
Correct timing constraints are essential for reliable synthesis
Anti-Patterns
Combinational Loop
Name
Combinational Logic Loop
Problem
Feedback without register causes oscillation/undefined behavior
Solution
Break loops with registers; check synthesis warnings
Latch Inference
Name
Unintentional Latch Inference
Problem
Incomplete case/if statements create latches
Solution
Assign default values at start of always block
Async Reset Release
Name
Asynchronous Reset Release
Problem
Releasing reset asynchronously can cause metastability
Solution
Use synchronous de-assertion: async assert, sync release
Multi Driver
Name
Multiple Drivers on Signal
Problem
Signal driven from multiple always blocks
Solution
Single driver per signal; use case/if for muxing
Fpga Design - Sharp Edges
Metastability from Missing CDC Synchronizer
Id
cdc-metastability
Severity
critical
Summary
Signals crossing clock domains without synchronization cause random failures
Symptoms
- Random bit flips in data
- FSM enters invalid state
- Works on some boards, fails on others
- Failures increase with temperature
Why
When a signal changes near a clock edge, the flip-flop may enter a metastable state - neither 0 nor 1.
This takes time to resolve (settling time). If another flip-flop samples before resolution, you get random values.
Single-bit: Use 2-FF synchronizer Multi-bit: Use async FIFO with Gray code pointers Pulse: Convert to toggle, synchronize, edge-detect
CDC bugs are the #1 cause of "random" FPGA failures.
Gotcha
// WRONG: Direct connection across clock domains always @(posedge clk_b) begin data_b <= data_a; // data_a is in clk_a domain! // Metastability! Random values! end
Solution
// CORRECT: Use 2-FF synchronizer for single bit ( ASYNC_REG = "TRUE" ) reg [1:0] sync_chain;
always @(posedge clk_b) begin sync_chain <= {sync_chain[0], signal_a}; end assign signal_b = sync_chain[1];
// For multi-bit data: use async FIFO async_fifo #(.DATA_WIDTH(8)) fifo ( .wr_clk(clk_a), .wr_data(data_a), .rd_clk(clk_b), .rd_data(data_b) );
Unintentional Latch Inference
Id
latch-inference
Severity
critical
Summary
Incomplete if/case creates latch instead of flip-flop
Symptoms
- Synthesis warning: 'latch inferred'
- Timing analysis fails
- Unexpected behavior after synthesis
Why
In combinational logic, if a signal isn't assigned in all branches, synthesis infers a latch to hold the previous value.
Latches are:
- Hard to analyze timing for
- Not available in all FPGA architectures
- Often indicate a design error
Almost always, you wanted a flip-flop or a complete assignment.
Gotcha
// WRONG: Missing else creates latch always @(*) begin if (enable) data_out = data_in; // What happens when enable=0? Latch! end
// WRONG: Incomplete case creates latch always @(*) begin case (sel) 2'b00: y = a; 2'b01: y = b; // Missing 2'b10, 2'b11 cases - latch! endcase end
Solution
// CORRECT: Assign default at start always @(*) begin data_out = 8'h00; // Default value if (enable) data_out = data_in; end
// CORRECT: Complete case with default always @(*) begin case (sel) 2'b00: y = a; 2'b01: y = b; default: y = 8'h00; // Catch-all endcase end
// CORRECT: Use full_case/parallel_case pragmas carefully // ( full_case ) only if you guarantee coverage
Timing Closure Failure
Id
timing-closure
Severity
critical
Summary
Design doesn't meet timing constraints, unreliable operation
Symptoms
- Negative slack in timing report
- Works at low temperature, fails when warm
- Works on some units, fails on others
Why
Timing closure means all paths meet setup/hold requirements.
Common causes of failure:
- Long combinational paths (too much logic between FFs)
- High fanout signals (driving many loads)
- Clock skew/uncertainty
- Missing or incorrect constraints
Negative slack = path too slow = unreliable operation.
Gotcha
// WRONG: Long combinational path always @() begin // 20 levels of logic - will never meet 100MHz timing result = ((a b) + (c d)) ((e + f) / g) + h; end
Solution
// CORRECT: Pipeline long operations always @(posedge clk) begin // Stage 1 mult1 <= a b; mult2 <= c d;
// Stage 2 sum1 <= mult1 + mult2; sum2 <= e + f;
// Stage 3 result <= sum1 + (sum2 * h); // Simplified end
// Reduce fanout with register duplication // Let synthesis tool handle with: set_max_fanout 32
// Add proper timing constraints // create_clock -period 10.0 [get_ports clk]
Asynchronous Reset Release Glitch
Id
reset-glitch
Severity
high
Summary
Releasing reset asynchronously causes metastability
Symptoms
- FSM starts in wrong state after reset
- Different behavior on different resets
- Works most of the time, occasionally fails
Why
Asserting reset asynchronously is fine - it immediately resets. But RELEASING reset at an arbitrary time can violate recovery/removal timing on flip-flops.
Solution: Assert asynchronously, release synchronously. This gives the reset assertion benefit (immediate) while ensuring clean release aligned to clock.
Gotcha
// WRONG: Fully asynchronous reset always @(posedge clk or negedge rst_n) begin if (!rst_n) state <= IDLE; else state <= next_state; end // Reset release can cause metastability!
Solution
// CORRECT: Reset synchronizer // Async assert, sync release
module reset_sync ( input wire clk, input wire rst_n_async, output wire rst_n_sync ); reg [1:0] sync;
always @(posedge clk or negedge rst_n_async) begin if (!rst_n_async) sync <= 2'b00; // Async assert else sync <= {sync[0], 1'b1}; // Sync release end
assign rst_n_sync = sync[1]; endmodule
// Use synchronized reset in design reset_sync rst_sync (.clk(clk), .rst_n_async(rst_n), .rst_n_sync(rst_n_safe));
Simulation-Synthesis Mismatch
Id
simulation-synthesis-mismatch
Severity
high
Summary
Design works in simulation but fails on FPGA
Symptoms
- Testbench passes, hardware fails
- Adding signals to debug changes behavior
- Different results from simulation and implementation
Why
Common causes: 1. Non-synthesizable constructs (initial blocks, delays) 2. Incomplete sensitivity lists 3. Blocking vs non-blocking assignment confusion 4. X-propagation differences 5. Timing assumptions in testbench
Simulation is behavior model; synthesis creates actual hardware.
Gotcha
// WRONG: Initial blocks don't synthesize initial begin count = 0; // Only works in simulation! end
// WRONG: Incomplete sensitivity list always @(a or b) begin y = a & b & c; // c not in sensitivity list! // Simulation: y updates on a or b change // Synthesis: combinational logic, updates on any change end
// WRONG: Blocking in sequential, non-blocking in combinational always @(posedge clk) begin a = b; // Should be <= c = a; // Gets NEW value of a (race condition) end
Solution
// CORRECT: Use reset instead of initial always @(posedge clk or negedge rst_n) begin if (!rst_n) count <= 0; else count <= count + 1; end
// CORRECT: Use @() for combinational always @() begin // All signals in sensitivity list y = a & b & c; end
// CORRECT: Non-blocking for sequential always @(posedge clk) begin a <= b; // Non-blocking c <= a; // Gets OLD value of a end
FPGA Resource Exhaustion
Id
resource-exhaustion
Severity
high
Summary
Design uses more resources than available
Symptoms
- Synthesis fails with 'resource exceeded'
- Timing degrades as utilization increases
- Can't fit design even at lower clock speed
Why
FPGAs have limited:
- LUTs (logic)
- FFs (registers)
- BRAM (block RAM)
- DSP slices (multipliers)
Over ~70-80% utilization, place-and-route struggles. Common causes: unintended resource usage, inefficient coding.
Solution
// Check resource usage in synthesis reports
// Efficient resource usage: // 1. Use BRAM instead of distributed RAM for large memories ( ram_style = "block" ) reg [7:0] mem [0:1023];
// 2. Share multipliers via time-division always @(posedge clk) begin case (phase) 0: product <= a b; // Reuse same DSP 1: product <= c d; endcase end
// 3. Use inference patterns tools recognize // Let synthesis optimize instead of manual optimization
// 4. Reduce bit widths where possible reg [7:0] counter; // Not reg [31:0] if you only count to 100
Fpga Design - Validations
Case Statement Without Default
Id
missing-default-case
Severity
warning
Type
regex
Pattern
- case\s\([^)]+\)[^}]endcase(?!.*default)
- case\s*\([^)]+\)(?![\s\S]{0,500}default)
Message
Case statement without default may infer latch.
Fix Action
Add 'default:' clause with explicit assignment
Applies To
- */.v
- */.sv
Blocking Assignment in Sequential Logic
Id
blocking-in-sequential
Severity
warning
Type
regex
Pattern
- always\s@\s\(\sposedge[^)]+\)[^;]\b\w+\s=\s(?!.*<=)
Message
Use non-blocking (<=) for sequential logic to avoid race conditions.
Fix Action
Replace = with <= in always @(posedge clk) blocks
Applies To
- */.v
- */.sv
Direct Clock Domain Crossing
Id
direct-cdc-connection
Severity
error
Type
regex
Pattern
- always\s@\s\(\sposedge\s+clk_b[^}]\b(\w+_a)\b(?!.*sync)
Message
Signal appears to cross clock domains without synchronizer.
Fix Action
Add 2-FF synchronizer or async FIFO for CDC
Applies To
- */.v
- */.sv
Initial Block in Synthesizable Code
Id
initial-block
Severity
warning
Type
regex
Pattern
- ^\sinitial\s+begin(?![\s\S]\.tb\.)
Message
Initial blocks don't synthesize. Use reset instead.
Fix Action
Replace with synchronous reset: always @(posedge clk) if (!rst_n)
Applies To
- */.v
- */.sv
Incomplete Sensitivity List
Id
incomplete-sensitivity
Severity
warning
Type
regex
Pattern
- always\s@\s\([^][^)]\)\sbegin[^}]\b(\w+)\b(?![^}]@.\1)
Message
Consider using @(*) for combinational logic to auto-include all signals.
Fix Action
Replace explicit sensitivity list with always @(*)
Applies To
- */.v
Synchronizer Without ASYNC_REG Attribute
Id
missing-async-reg
Severity
info
Type
regex
Pattern
- reg\s+\[\d+:0\]\s+\wsync\w(?!.*ASYNC_REG)
Message
Synchronizer registers should have ASYNC_REG attribute for proper placement.
Fix Action
Add ( ASYNC_REG = "TRUE" ) before register declaration
Applies To
- */.v
- */.sv
Asynchronous Reset Without Synchronizer
Id
async-reset-no-sync
Severity
warning
Type
regex
Pattern
- negedge\s+rst_n(?!.*sync)
Message
Asynchronous reset should be synchronized for clean release.
Fix Action
Use reset synchronizer: async assert, sync release pattern
Applies To
- */.v
- */.sv
Signal Driving Many Modules
Id
high-fanout-signal
Severity
info
Type
regex
Pattern
- \.(\w+)\(enable\)[^;]\.(\w+)\(enable\)[^;]\.(\w+)\(enable\)
Message
High fanout signal may cause timing issues.
Fix Action
Consider registering signal at each destination or using synthesis directives
Applies To
- */.v
- */.sv
Missing Clock Definition
Id
missing-clock-constraint
Severity
warning
Type
regex
Pattern
- get_ports.clk(?!.create_clock)
Message
Clock port should have create_clock constraint.
Fix Action
Add: create_clock -period <ns> [get_ports clk]
Applies To
- */.xdc
- */.sdc
IO Without Delay Constraint
Id
unconstrained-io
Severity
info
Type
regex
Pattern
- get_ports.data(?!.set_input_delay|set_output_delay)
Message
Data ports should have input/output delay constraints.
Fix Action
Add set_input_delay/set_output_delay for all data ports
Applies To
- */.xdc
- */.sdc
Non-Blocking in Combinational Logic
Id
non-blocking-combinational
Severity
warning
Type
regex
Pattern
- always\s@\s\(\s\\s\)[^}]<=
Message
Use blocking (=) for combinational logic.
Fix Action
Replace <= with = in always @(*) blocks
Applies To
- */.v
- */.sv