Skip to content
Back to skills

Fpga Patterns

ASecurity

Synthesizable Verilog patterns for MCU-FPGA designs on Artix-7 and Cyclone V: register bank with strobes, two-flop clock domain crossing, PWM generator, Vivado block design Tcl, and ILA or SignalTap capture. Use when writing FPGA logic that an MCU drives or debugging it in hardware.

  • 50 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 1, 2026
ai-agentsdebugging

Security analysis

A100/100

Scanned October 1, 2026

npx -y skills add HermeticOrmus/LibreEmbed-Claude-Code --skill fpga-patterns --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Fpga Patterns?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Fpga Patterns
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/hermeticormus-fpga-patterns/badge)](https://www.skillsdirectory.com/skills/hermeticormus-fpga-patterns)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: "fpga-patterns"
description: "Synthesizable Verilog patterns for MCU-FPGA designs on Artix-7 and Cyclone V: register bank with strobes, two-flop clock domain crossing, PWM generator, Vivado block design Tcl, and ILA or SignalTap capture. Use when writing FPGA logic that an MCU drives or debugging it in hardware."
---

# fpga-patterns

## Knowledge Base

Synthesizable Verilog patterns for FPGA-MCU integration. Targeting Xilinx Artix-7 and Intel Cyclone V.

---

## Pattern 1: Register Bank with Read/Write Strobe

Simpler than AXI-Lite for SPI-connected FPGAs:

```verilog
/* 8 x 32-bit register file with address/data/write-enable interface */
module reg_bank (
    input  wire        clk,
    input  wire        rst_n,
    input  wire [2:0]  addr,
    input  wire [31:0] wdata,
    input  wire        wen,
    output reg  [31:0] rdata,
    /* Application outputs */
    output wire [31:0] reg0_out,
    output wire [31:0] reg1_out,
    input  wire [31:0] reg4_in,   /* Read-back from hardware */
    input  wire [31:0] reg5_in
);
    reg [31:0] regs [0:7];

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            regs[0] <= 32'h0; regs[1] <= 32'h0;
            regs[2] <= 32'h0; regs[3] <= 32'h0;
        end else if (wen) begin
            regs[addr] <= wdata;
        end
    end

    /* Read: hardware status registers override software writes */
    always @(*) begin
        case (addr)
            3'd4:    rdata = reg4_in;
            3'd5:    rdata = reg5_in;
            default: rdata = regs[addr];
        endcase
    end

    assign reg0_out = regs[0];
    assign reg1_out = regs[1];
endmodule
```

---

## Pattern 2: Clock Domain Crossing — 2FF Synchronizer

Signals crossing from one clock domain to another must be synchronized to avoid metastability.

```verilog
/* 2-flipflop synchronizer for a single control bit */
module sync_2ff (
    input  wire dst_clk,
    input  wire rst_n,
    input  wire sig_in,      /* Asynchronous input */
    output reg  sig_out      /* Synchronized output */
);
    reg ff1;

    (* ASYNC_REG = "TRUE" *) reg sync_ff1;   /* Vivado: keep close in placement */
    (* ASYNC_REG = "TRUE" *) reg sync_ff2;

    always @(posedge dst_clk or negedge rst_n) begin
        if (!rst_n) begin
            sync_ff1 <= 0; sync_ff2 <= 0;
        end else begin
            sync_ff1 <= sig_in;
            sync_ff2 <= sync_ff1;
        end
    end
    assign sig_out = sync_ff2;
endmodule
```

For multi-bit data: use a dual-clock FIFO or handshaking with acknowledgment.

---

## Pattern 3: Pulse Width Modulation (PWM) Generator

```verilog
module pwm_gen #(
    parameter integer CNT_WIDTH = 16    /* 100MHz / 65536 ≈ 1.5kHz */
)(
    input  wire                  clk,
    input  wire                  rst_n,
    input  wire [CNT_WIDTH-1:0]  duty,  /* 0=0%, 65535=100% */
    output reg                   pwm_out
);
    reg [CNT_WIDTH-1:0] cnt;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            cnt     <= 0;
            pwm_out <= 0;
        end else begin
            cnt     <= cnt + 1;
            pwm_out <= (cnt < duty) ? 1'b1 : 1'b0;
        end
    end
endmodule
```

MCU sets `duty` register via SPI/AXI. Frequency = clk / (2^CNT_WIDTH).

---

## Pattern 4: Xilinx Block Design Tcl Automation

```tcl
# Create Vivado project from Tcl (for version control of block design)
create_project myproject ./myproject -part xc7a100tcsg324-1

# Add HDL sources
add_files -norecurse {src/spi_slave.v src/reg_bank.v}

# Create block design with Zynq PS
create_bd_design "system"
create_bd_cell -type ip -vlnv xilinx.com:ip:processing_system7:5.5 ps7

# Apply Zynq preset (board-specific)
set_property CONFIG.preset {ZedBoard} [get_bd_cells ps7]

# Connect AXI-Lite custom IP
create_bd_cell -type module -reference axi_lite_regs axi_regs_0
apply_bd_automation -rule xilinx.com:bd_rule:axi4 \
    -config {Master "/ps7/M_AXI_GP0" Clk "Auto"} [get_bd_intf_pins axi_regs_0/S_AXI]

# Save and generate
save_bd_design
generate_target all [get_files system.bd]
```

---

## Pattern 5: SignalTap / ILA In-Logic Analyzer

Add debug capture to synthesized netlist (no external pins needed):

```tcl
# Vivado: create ILA debug core via Tcl
create_debug_core u_ila ila
set_property C_DATA_DEPTH  1024 [get_debug_cores u_ila]
set_property C_TRIGIN_EN  false [get_debug_cores u_ila]

# Connect signals to probe
set_property port_width 8 [get_debug_ports u_ila/probe0]
connect_debug_port u_ila/probe0 [get_nets spi_rx_byte]

set_property port_width 1 [get_debug_ports u_ila/probe1]
connect_debug_port u_ila/probe1 [get_nets spi_rx_valid]

implement_debug_core
```

Or instantiate directly in Verilog:
```verilog
ila_0 u_ila (
    .clk    (clk),
    .probe0 (spi_rx_byte),   /* 8 bits */
    .probe1 (spi_rx_valid)   /* 1 bit  */
);
```

---

## Anti-Patterns

- **Combinational loops**: any feedback path without a register causes simulation mismatch and synthesis failure. Add a register.
- **Missing `(* ASYNC_REG = "TRUE" *)` on CDC synchronizers**: Vivado placement optimizer separates the two FFs, increasing metastability risk.
- **Inferring RAM with `initial` blocks**: synthesis ignores `initial`; use reset logic or external initialization.
- **Blocking assignments in sequential blocks**: use non-blocking (`<=`) for clocked logic. Mixing causes simulation/synthesis mismatch.

## References

- Xilinx UG901: Vivado Design Suite User Guide - Synthesis
- Xilinx PG209: AXI4-Lite Interface
- Intel AN 433: Constraining and Analyzing Source Synchronous Interfaces (Quartus)
- Cummings, "Simulation and Synthesis Techniques for Asynchronous FIFO Design" (SNUG 2002)

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…