FPGA Targets Guide

MIRR generates vendor-specific constraint files and build scripts for six FPGA target families. This enables one-command synthesis-to-bitstream workflows for prototyping safety-critical hardware monitors on real FPGA development boards.


Table of Contents

  1. Overview
  2. Supported FPGA families
  3. Constraint file formats
  4. Build script generation
  5. Yosys and nextpnr integration
  6. Example usage
  7. Target-specific details
  8. DSP mapping
  9. Resource bounds

Overview

When you compile a MIRR module, the compiler generates SystemVerilog (.sv) output. To place that design onto a real FPGA, you need two additional artifacts:

  1. Constraint file -- maps logical signal names to physical pins on your FPGA board and defines clock timing.
  2. Build script -- invokes the vendor synthesis, place-and-route, and bitstream generation tools in the correct order.

The MIRR FPGA scaffold generator (src/emit/fpga_scaffold.rs and src/emit/fpga_target.rs) produces both artifacts for your chosen target family. All generated files contain PLACEHOLDER pin assignments that you must fill in for your specific board.


Supported FPGA families

MIRR supports six FPGA targets plus a generic fallback:

Target nameFamilyVendorBuild toolDefault part
genericGeneric--Yosys--
xilinx-7Xilinx 7-SeriesAMD/XilinxVivadoxc7a35tcpg236-1
xilinx-usXilinx UltraScale+AMD/XilinxVivadoxcku5p-ffvb676-2-e
intel-cycloneCyclone V/10Intel/AlteraQuartus5CSEBA6U23I7
lattice-ice40iCE40Latticenextpnr-ice40iCE40-HX8K-CT256
lattice-ecp5ECP5Latticenextpnr-ecp5LFE5U-85F-6BG381C
lattice-nexusNexus/CrossLink-NXLatticenextpnr-nexusLIFCL-40-9BG400C

CLI name aliases

Several aliases are accepted for convenience:

Canonical nameAlso accepts
xilinx-7xilinx7
xilinx-usultrascale
intel-cyclonecyclone
lattice-ice40ice40
lattice-ecp5ecp5
lattice-nexusnexus, crosslink-nx

Constraint file formats

Each FPGA family uses a different constraint file format. MIRR generates the appropriate format based on the selected target.

PCF -- Lattice iCE40

Physical Constraints Format. Used by nextpnr-ice40.

# Auto-generated PCF constraints for neonatal_respirator
# Fill in pin numbers for your board.

set_io respirator_enable PLACEHOLDER
set_io clamp_valve PLACEHOLDER
set_io airway_pressure[0] PLACEHOLDER
set_io airway_pressure[1] PLACEHOLDER
...

Each signal gets a set_io line mapping it to a physical pin. Multi-bit signals are expanded bit-by-bit.

LPF -- Lattice ECP5

Lattice Preference File. Used by nextpnr-ecp5.

# Auto-generated LPF constraints for neonatal_respirator (Lattice ECP5)
# Fill in LOC values for your board.

FREQUENCY NET "clk" 100.000000 MHz;

LOCATE COMP "respirator_enable" SITE "PLACEHOLDER";
IOBUF PORT "respirator_enable" IO_TYPE=LVCMOS33;
...

LPF files include I/O type specifications (defaulting to LVCMOS33) and a frequency constraint for the clock net.

PDC -- Lattice Nexus

Physical Design Constraints. Used by nextpnr-nexus.

# Auto-generated PDC constraints for neonatal_respirator (Lattice Nexus)
# Fill in pin assignments for your board.

create_clock -name {clk} -period 10.000 [get_ports clk]

ldc_set_location -site {PLACEHOLDER} [get_ports {respirator_enable}]
...

PDC files use Tcl-like syntax with ldc_set_location commands.

XDC -- Xilinx 7-Series and UltraScale+

Xilinx Design Constraints. Used by Vivado.

## Auto-generated XDC constraints for neonatal_respirator (Xilinx 7-Series)
## Fill in PACKAGE_PIN values for your board.

create_clock -period 10.000 -name clk [get_ports clk]
# set_property PACKAGE_PIN {PLACEHOLDER} [get_ports respirator_enable]
# set_property IOSTANDARD LVCMOS33 [get_ports respirator_enable]
...

XDC constraints are generated as comments (prefixed with #) so they do not cause errors before you fill in the pin assignments. Each port gets a PACKAGE_PIN and IOSTANDARD property.

SDC -- Intel Cyclone and Generic

Synopsys Design Constraints. Used by Quartus and as the generic format.

## Auto-generated SDC constraints for neonatal_respirator (Intel Cyclone)
## Fill in pin assignments for your board.

create_clock -period 10.000 -name clk [get_ports clk]
derive_pll_clocks
derive_clock_uncertainty

set_input_delay -clock clk 2.000 [get_ports respirator_enable]
set_input_delay -clock clk 2.000 [get_ports airway_pressure]
set_output_delay -clock clk 2.000 [get_ports clamp_valve]

SDC files include input/output delay constraints relative to the clock.


Build script generation

MIRR generates complete build scripts for each target family. All scripts are clearly marked as auto-generated scaffolding.

Vivado Tcl (Xilinx)

For Xilinx 7-Series and UltraScale+ targets, MIRR generates a Vivado Tcl build script:

# Auto-generated Vivado build script for neonatal_respirator
create_project neonatal_respirator ./build -part xc7a35tcpg236-1 -force
add_files neonatal_respirator.sv
add_files -fileset constrs_1 neonatal_respirator.xdc
launch_runs synth_1 -jobs 4
wait_on_run synth_1
launch_runs impl_1 -to_step write_bitstream -jobs 4
wait_on_run impl_1

Run with: vivado -mode batch -source build.tcl

Quartus Tcl (Intel)

For Intel Cyclone targets:

# Auto-generated Quartus build script for neonatal_respirator
project_new neonatal_respirator -overwrite
set_global_assignment -name FAMILY "Cyclone V"
set_global_assignment -name DEVICE 5CSEBA6U23I7
set_global_assignment -name SYSTEMVERILOG_FILE neonatal_respirator.sv
set_global_assignment -name SDC_FILE neonatal_respirator.sdc
execute_flow -compile
project_close

Run with: quartus_sh -t build.tcl

Shell scripts (Lattice and Generic)

For Lattice targets and the generic target, MIRR generates bash scripts that invoke the open-source Yosys/nextpnr toolchain.

iCE40 example:

#!/usr/bin/env bash
# Auto-generated build script for neonatal_respirator (Lattice iCE40)
set -euo pipefail

# NOTE: Use --strip-sva when generating neonatal_respirator.sv for synthesis
yosys -p "read_verilog -sv neonatal_respirator.sv; synth_ice40 -top neonatal_respirator -json neonatal_respirator.json"
nextpnr-ice40 --hx8k --package ct256 --json neonatal_respirator.json --pcf neonatal_respirator.pcf --asc neonatal_respirator.asc
icepack neonatal_respirator.asc neonatal_respirator.bin
echo "Bitstream ready: neonatal_respirator.bin"

ECP5 example:

#!/usr/bin/env bash
set -euo pipefail
yosys -p "read_verilog -sv module.sv; synth_ecp5 -top module -json module.json"
nextpnr-ecp5 --85k --package CABGA381 --json module.json --lpf module.lpf --textcfg module.config
ecppack module.config module.bit
echo "Bitstream ready: module.bit"

Nexus example:

#!/usr/bin/env bash
set -euo pipefail
yosys -p "read_verilog -sv module.sv; synth_nexus -top module -json module.json"
nextpnr-nexus --device LIFCL-40-9BG400C --json module.json --pdc module.pdc --fasm module.fasm
prjoxide pack module.fasm module.bit
echo "Bitstream ready: module.bit"

Yosys and nextpnr integration

The Lattice targets and the generic target use the open-source oss-cad-suite toolchain:

ToolPurposeUsed by
YosysRTL synthesis (Verilog to netlist)All Lattice targets, Generic
nextpnr-ice40Place and route for iCE40lattice-ice40
nextpnr-ecp5Place and route for ECP5lattice-ecp5
nextpnr-nexusPlace and route for Nexuslattice-nexus
icepackBitstream packing for iCE40lattice-ice40
ecppackBitstream packing for ECP5lattice-ecp5
prjoxideBitstream packing for Nexuslattice-nexus
icetimeStatic timing analysis (iCE40)lattice-ice40 (optional)

SVA stripping

SystemVerilog Assertions (SVA) generated by the MIRR compiler's property blocks are not synthesizable. When targeting synthesis, use the --strip-sva flag to generate clean RTL without assertion blocks. The generated build scripts include a reminder comment about this.

Yosys synthesis commands

Each target uses a target-specific Yosys synthesis command:

TargetYosys command
lattice-ice40synth_ice40
lattice-ecp5synth_ecp5
lattice-nexussynth_nexus
xilinx-7 / xilinx-ussynth_xilinx
intel-cyclonesynth_intel
genericsynth

Example usage

Step 1: Compile to SystemVerilog

cargo run --bin mirr-compile -- --emit verilog my_monitor.mirr > my_monitor.sv

Step 2: Generate FPGA scaffold

The scaffold generator is available through the Rust API:

use mirr::emit::fpga_scaffold::{emit_constraints, emit_build_script};
use mirr::emit::fpga_target::FpgaTarget;

let target = FpgaTarget::from_str_name("lattice-ice40").unwrap();

// Generate constraint file
let constraints = emit_constraints(&pipeline_result, &target);
std::fs::write("my_monitor.pcf", &constraints)?;

// Generate build script
let build_script = emit_build_script(&pipeline_result, &target);
std::fs::write("build.sh", &build_script)?;

Step 3: Fill in pin assignments

Open the generated constraint file and replace every PLACEHOLDER with the actual pin name from your board's datasheet or schematic.

For example, on a Lattice iCE40-HX8K breakout board:

# Before:
set_io clk PLACEHOLDER

# After:
set_io clk J3

Step 4: Run the build

chmod +x build.sh
./build.sh

This produces a bitstream file (.bin, .bit, or similar) that can be loaded onto your FPGA.


Target-specific details

Clock primitives

Each FPGA family has a different PLL/clock primitive:

TargetClock primitive
GenericPLL
Xilinx 7-SeriesMMCME2_BASE
Xilinx UltraScale+MMCME4_ADV
Intel Cyclonealtpll
Lattice iCE40SB_PLL40_CORE
Lattice ECP5EHXPLLL
Lattice NexusOSCA

Default clock period

All generated constraint files assume a 100 MHz clock (10 ns period). Adjust the create_clock or FREQUENCY directive if your board uses a different oscillator.

I/O standards

  • Xilinx targets default to LVCMOS33.
  • Lattice ECP5 targets default to LVCMOS33 via IOBUF directives.
  • Other targets leave I/O standards to be configured by the engineer.

DSP mapping

MIRR emits vendor-specific synthesis attributes to map multiply operations to hardware DSP blocks when possible:

TargetDSP primitiveAttributeMax input width
Xilinx 7-SeriesDSP48E1(* use_dsp48 = "yes" *)25 bits
Xilinx UltraScale+DSP48E2(* use_dsp48 = "yes" *)27 bits
Intel Cyclonecyclonev_mac(* multstyle = "dsp" *)27 bits
Lattice iCE40SB_MAC16(* use_dsp = "yes" *)16 bits
Lattice ECP5ALU54B(* use_dsp = "yes" *)18 bits
Lattice NexusMULT18X18(* use_dsp = "yes" *)18 bits
Generic--(* use_dsp = "yes" *)18 bits

If a multiply operand exceeds the DSP block's maximum input width, the synthesis tool will infer logic-based multiplication instead.


Resource bounds

The scaffold generator enforces the following NASA Power-of-10 bounds:

ConstantValuePurpose
MAX_CONSTRAINT_LINES256Maximum lines in a generated constraint file
MAX_SYNC_STAGES4Maximum clock-domain synchronizer stages

Multi-bit signals are expanded bit-by-bit in constraint files. If the total line count reaches MAX_CONSTRAINT_LINES, generation stops to prevent unbounded output.


See Also