aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Selkirk <paul@psgd.org>2017-09-21 09:20:21 -0400
committerPaul Selkirk <paul@psgd.org>2017-09-21 09:20:21 -0400
commita4e91b6221f75045dd1d97362e9d12c590ebc15a (patch)
tree04dc1fbaaca17585754aaa624db08e0dad491a38
parent74415e8d386b5080aaf7270a2d5356ed4f533859 (diff)
Separate FMC test from mainline top-level module.
-rw-r--r--build/Makefile8
-rw-r--r--build/Makefile.test49
-rw-r--r--rtl/alpha_fmc_test.v227
-rw-r--r--rtl/alpha_fmc_top.v69
-rw-r--r--ucf/alpha_fmc_test.ucf199
5 files changed, 481 insertions, 71 deletions
diff --git a/build/Makefile b/build/Makefile
index 763ad5e..4e3a9bb 100644
--- a/build/Makefile
+++ b/build/Makefile
@@ -25,10 +25,10 @@ all: $(project).bit
CONFIG = $(CORE_TREE)/platform/common/config
CONFIG_BOARD = alpha
CONFIG_PROJECT = hsm
-CONFIG_GEN = $(CONFIG)/core_config.py -c $(CONFIG)/core.cfg -b $(CONFIG_BOARD) -p $(CONFIG_PROJECT)
+CONFIG_GEN = $(CONFIG)/core_config.py -c $(CONFIG)/core.cfg -b $(CONFIG_BOARD)
core_selector.v core_vfiles.mk:
- $(CONFIG_GEN)
+ $(CONFIG_GEN) -p $(CONFIG_PROJECT)
# Build some different configurations
@@ -56,6 +56,10 @@ hsm:
$(CONFIG_GEN) -p hsm
$(MAKE) project=$(project)_hsm ucf=$(ucf)
+hsm-super:
+ $(CONFIG_GEN) -p hsm-super
+ $(MAKE) project=$(project)_hsm-super ucf=$(ucf)
+
# Verilog files that always go with builds on this platform.
vfiles = \
diff --git a/build/Makefile.test b/build/Makefile.test
new file mode 100644
index 0000000..7243bd5
--- /dev/null
+++ b/build/Makefile.test
@@ -0,0 +1,49 @@
+# Localize all the relative path awfulness in one variable.
+
+CORE_TREE := $(abspath ../../..)
+
+# Figure out what the native word size is on the build host, because
+# the XiLinx tools care for some reason.
+
+WORD_SIZE := $(shell python -c 'from struct import pack; print len(pack("L", 0)) * 8')
+
+# Parameters to xilinx.mk.
+
+project ?= alpha_fmc_test
+vendor = xilinx
+family = artix7
+part = xc7a200tfbg484-3
+top_module = alpha_fmc_top
+isedir = /opt/Xilinx/14.7/ISE_DS
+xil_env = . $(isedir)/settings$(WORD_SIZE).sh
+ucf ?= ../ucf/$(project).ucf
+
+all: $(project).bit
+
+# Verilog files that always go with builds on this platform.
+
+vfiles = \
+ $(CORE_TREE)/platform/alpha/rtl/alpha_fmc_test.v \
+ $(CORE_TREE)/platform/alpha/rtl/alpha_regs.v \
+ $(CORE_TREE)/platform/alpha/rtl/alpha_clkmgr.v \
+ $(CORE_TREE)/platform/alpha/rtl/clkmgr_mmcm.v \
+ $(CORE_TREE)/comm/fmc/src/rtl/cdc_bus_pulse.v \
+ $(CORE_TREE)/comm/fmc/src/rtl/fmc_arbiter_cdc.v \
+ $(CORE_TREE)/comm/fmc/src/rtl/fmc_arbiter.v \
+ $(CORE_TREE)/comm/fmc/src/rtl/fmc_d_phy.v \
+ $(CORE_TREE)/comm/fmc/src/rtl/fmc_indicator.v \
+ $(CORE_TREE)/comm/fmc/src/rtl/fmc_regs.v
+
+include xilinx.mk
+
+# 'clean' target collects files by project name, and we just broke that
+# by adding configurations
+
+junk += *.bgn *.bit *.bld *.cfi *.drc *.lso *.map *.mcs *.mrp *.ncd *.ngc \
+ *.ngd *.ngm *.pcf *.post_map.twr *.post_map.twx *.prj *.prm *.psr \
+ *.scr *.srp *.twr *.twx *_bd.bmm *_bitgen.xwb *_bitgen.xwbt \
+ *_err.twr *_err.twx *_par.grf *_par.ncd *_par.pad *_par.par \
+ *_par.ptwx *_par.unroutes *_par.xpi *_par_pad.csv *_par_pad.txt \
+ *_summary.xml *_usage.xml
+
+distclean: clean
diff --git a/rtl/alpha_fmc_test.v b/rtl/alpha_fmc_test.v
new file mode 100644
index 0000000..182911e
--- /dev/null
+++ b/rtl/alpha_fmc_test.v
@@ -0,0 +1,227 @@
+//======================================================================
+//
+// alpha_test.v
+// ------------
+// Top module for the Cryptech Alpha FPGA framework. This design
+// allow us to run the FMC interface at one clock and cores including
+// core selector with the always present global clock.
+//
+//
+// Author: Pavel Shatov
+// Copyright (c) 2016, NORDUnet A/S All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// - Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// - Neither the name of the NORDUnet nor the names of its contributors may
+// be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//======================================================================
+
+`timescale 1ns / 1ps
+
+module alpha_fmc_top
+ (
+ input wire gclk_pin, // 50 MHz
+
+ input wire ct_noise, // cryptech avalanche noise circuit
+
+ input wire fmc_clk, // clock
+ input wire [23: 0] fmc_a, // address
+ inout wire [31: 0] fmc_d, // data
+ input wire fmc_ne1, // chip select
+ input wire fmc_noe, // output enable
+ input wire fmc_nwe, // write enable
+ input wire fmc_nl, // latch enable
+ output wire fmc_nwait,// wait
+
+ output wire mkm_sclk,
+ output wire mkm_cs_n,
+ input wire mkm_do,
+ output wire mkm_di,
+
+ output wire [3: 0] led_pins // {red, yellow, green, blue}
+ );
+
+
+ //----------------------------------------------------------------
+ // Clock Manager
+ //
+ // Clock manager is used to generate SYS_CLK from GCLK
+ // and implement the reset logic.
+ // ----------------------------------------------------------------
+ wire sys_clk;
+ wire sys_rst_n;
+
+ alpha_clkmgr #
+ (
+ .CLK_OUT_MUL (20.0), // 2..64
+ .CLK_OUT_DIV (20.0) // 1..128
+ )
+ clkmgr
+ (
+ .gclk (gclk_pin),
+
+ .sys_clk (sys_clk),
+ .sys_rst_n (sys_rst_n)
+ );
+
+
+ //----------------------------------------------------------------
+ // BUFG
+ //
+ // FMC clock must be routed through the global clocking backbone.
+ // ----------------------------------------------------------------
+ wire fmc_clk_bug;
+
+ BUFG BUFG_fmc_clk
+ (
+ .I (fmc_clk),
+ .O (fmc_clk_bufg)
+ );
+
+
+
+ //----------------------------------------------------------------
+ // FMC Arbiter
+ //
+ // FMC arbiter handles FMC access and transfers it into
+ // `sys_clk' clock domain.
+ //----------------------------------------------------------------
+
+ wire [23: 0] sys_fmc_addr; // address
+ wire sys_fmc_wren; // write enable
+ wire sys_fmc_rden; // read enable
+ wire [31: 0] sys_fmc_dout; // data output (from STM32 to FPGA)
+ reg [31: 0] sys_fmc_din; // data input (from FPGA to STM32)
+
+ fmc_arbiter #
+ (
+ .NUM_ADDR_BITS(24) // change to 26 when Alpha is alive!
+ )
+ fmc
+ (
+ .fmc_clk(fmc_clk_bufg),
+ .fmc_a(fmc_a),
+ .fmc_d(fmc_d),
+ .fmc_ne1(fmc_ne1),
+ .fmc_nl(fmc_nl),
+ .fmc_nwe(fmc_nwe),
+ .fmc_noe(fmc_noe),
+ .fmc_nwait(fmc_nwait),
+
+ .sys_clk(sys_clk),
+
+ .sys_addr(sys_fmc_addr),
+ .sys_wr_en(sys_fmc_wren),
+ .sys_rd_en(sys_fmc_rden),
+ .sys_data_out(sys_fmc_dout),
+ .sys_data_in(sys_fmc_din)
+ );
+
+
+ //----------------------------------------------------------------
+ // LED Driver
+ //
+ // A simple utility LED driver that turns on the Alpha
+ // board LED when the FMC interface is active.
+ //----------------------------------------------------------------
+ fmc_indicator led
+ (
+ .sys_clk(sys_clk),
+ .sys_rst_n(sys_rst_n),
+ .fmc_active(sys_fmc_wren | sys_fmc_rden),
+ .led_out(led_pins[0])
+ );
+
+
+ //----------------------------------------------------------------
+ // Dummy Register
+ //
+ // General-purpose register to test FMC interface using STM32
+ // demo program instead of core selector logic.
+ //
+ // This register is a bit tricky, but it allows testing of both
+ // data and address buses. Reading from FPGA will always return
+ // value, which is currently stored in the test register,
+ // regardless of read transaction address. Writing to FPGA has
+ // two variants: a) writing to address 0 will store output data
+ // data value in the test register, b) writing to any non-zero
+ // address will store _address_ of write transaction in the test
+ // register.
+ //
+ // To test data bus, write some different patterns to address 0,
+ // then readback from any address and compare.
+ //
+ // To test address bus, write anything to some different non-zero
+ // addresses, then readback from any address and compare returned
+ // value with previously written address.
+ //
+ //----------------------------------------------------------------
+ reg [31: 0] test_reg;
+
+
+
+ //
+ // Noise Capture Register
+ //
+ reg [31: 0] noise_reg;
+
+ always @(posedge sys_clk)
+ //
+ noise_reg <= {noise_reg[30:0], ct_noise};
+
+
+
+ always @(posedge sys_clk)
+ //
+ if (sys_fmc_wren) begin
+ //
+ // when writing to address 0, store input data value
+ //
+ // when writing to non-zero address, store _address_
+ // (padded with zeroes) instead of data
+ //
+ test_reg <= (sys_fmc_addr == {24{1'b0}}) ? sys_fmc_dout : {{8{1'b0}}, sys_fmc_addr};
+ //
+ end else if (sys_fmc_rden) begin
+ //
+ // always return current value, ignore address
+ //
+ sys_fmc_din <= (sys_fmc_addr == {24{1'b1}}) ? noise_reg : test_reg;
+
+ // when reading from address 0, return the current value
+ // when reading from other addresses, return the address
+ //sys_fmc_din <= (sys_fmc_addr == {22{1'b0}}) ? test_reg : {{10{1'b0}}, sys_fmc_addr};
+ //
+ end
+
+
+ //
+ // Dummy assignments to bypass unconnected outpins pins check in BitGen
+ //
+
+ assign led_pins[3:1] = 3'b000;
+
+
+endmodule
diff --git a/rtl/alpha_fmc_top.v b/rtl/alpha_fmc_top.v
index 79bfba8..03c2802 100644
--- a/rtl/alpha_fmc_top.v
+++ b/rtl/alpha_fmc_top.v
@@ -108,17 +108,12 @@ module alpha_fmc_top
// FMC arbiter handles FMC access and transfers it into
// `sys_clk' clock domain.
//----------------------------------------------------------------
- //`define test
wire [23: 0] sys_fmc_addr; // address
wire sys_fmc_wren; // write enable
wire sys_fmc_rden; // read enable
wire [31: 0] sys_fmc_dout; // data output (from STM32 to FPGA)
-`ifdef test
- reg [31: 0] sys_fmc_din; // data input (from FPGA to STM32)
-`else
wire [31: 0] sys_fmc_din; // data input (from FPGA to STM32)
-`endif
fmc_arbiter #
(
@@ -160,69 +155,6 @@ module alpha_fmc_top
);
-`ifdef test
- //----------------------------------------------------------------
- // Dummy Register
- //
- // General-purpose register to test FMC interface using STM32
- // demo program instead of core selector logic.
- //
- // This register is a bit tricky, but it allows testing of both
- // data and address buses. Reading from FPGA will always return
- // value, which is currently stored in the test register,
- // regardless of read transaction address. Writing to FPGA has
- // two variants: a) writing to address 0 will store output data
- // data value in the test register, b) writing to any non-zero
- // address will store _address_ of write transaction in the test
- // register.
- //
- // To test data bus, write some different patterns to address 0,
- // then readback from any address and compare.
- //
- // To test address bus, write anything to some different non-zero
- // addresses, then readback from any address and compare returned
- // value with previously written address.
- //
- //----------------------------------------------------------------
- reg [31: 0] test_reg;
-
-
-
- //
- // Noise Capture Register
- //
- reg [31: 0] noise_reg;
-
- always @(posedge sys_clk)
- //
- noise_reg <= {noise_reg[30:0], ct_noise};
-
-
-
- always @(posedge sys_clk)
- //
- if (sys_fmc_wren) begin
- //
- // when writing to address 0, store input data value
- //
- // when writing to non-zero address, store _address_
- // (padded with zeroes) instead of data
- //
- test_reg <= (sys_fmc_addr == {24{1'b0}}) ? sys_fmc_dout : {{8{1'b0}}, sys_fmc_addr};
- //
- end else if (sys_fmc_rden) begin
- //
- // always return current value, ignore address
- //
- sys_fmc_din <= (sys_fmc_addr == {24{1'b1}}) ? noise_reg : test_reg;
-
- // when reading from address 0, return the current value
- // when reading from other addresses, return the address
- //sys_fmc_din <= (sys_fmc_addr == {22{1'b0}}) ? test_reg : {{10{1'b0}}, sys_fmc_addr};
- //
- end
-
-`else // !`ifdef test
//----------------------------------------------------------------
// Core Selector
//
@@ -248,7 +180,6 @@ module alpha_fmc_top
.mkm_do(mkm_do),
.mkm_di(mkm_di)
);
-`endif
//
diff --git a/ucf/alpha_fmc_test.ucf b/ucf/alpha_fmc_test.ucf
new file mode 100644
index 0000000..34b2072
--- /dev/null
+++ b/ucf/alpha_fmc_test.ucf
@@ -0,0 +1,199 @@
+#======================================================================
+#
+# alpha_fmc.ucf
+# -------------------
+# Constraint file for implementing the Cryptech Alpha base
+# for the Xilinx Artix-7 200T on the Alpha.
+#
+#
+# Author: Pavel Shatov
+# Copyright (c) 2016, NORDUnet A/S All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# - Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# - Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# - Neither the name of the NORDUnet nor the names of its contributors may
+# be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#======================================================================
+
+
+#--------------------------------------------------------------------------------
+# GCLK Timing (fixed at 50 MHz)
+#--------------------------------------------------------------------------------
+NET "gclk_pin" TNM_NET = TNM_gclk;
+TIMESPEC TS_gclk = PERIOD TNM_gclk 20 ns HIGH 50%;
+
+
+#-------------------------------------------------------------------------------
+# FMC_CLK Timing (can be up to 90 MHz)
+#-------------------------------------------------------------------------------
+NET "fmc_clk" TNM_NET = TNM_fmc_clk;
+TIMESPEC TS_fmc_clk = PERIOD TNM_fmc_clk 90 MHz HIGH 50%;
+
+
+#-------------------------------------------------------------------------------
+# FPGA Pinout
+#-------------------------------------------------------------------------------
+#
+NET "led_pins<0>" LOC = "U3";
+NET "led_pins<1>" LOC = "T1";
+NET "led_pins<2>" LOC = "W22";
+NET "led_pins<3>" LOC = "AA20";
+#
+NET "led_pins<*>" IOSTANDARD = "LVCMOS33";
+NET "led_pins<*>" SLEW = SLOW;
+NET "led_pins<*>" DRIVE = 8;
+#
+NET "gclk_pin" LOC = "D17" | IOSTANDARD = "LVCMOS33" ;
+#
+NET "fmc_clk" LOC = "W11" | IOSTANDARD = "LVCMOS33" ;
+NET "fmc_ne1" LOC = "V5" | IOSTANDARD = "LVCMOS33" ;
+NET "fmc_noe" LOC = "W16" | IOSTANDARD = "LVCMOS33" ;
+NET "fmc_nwe" LOC = "AA6" | IOSTANDARD = "LVCMOS33" ;
+NET "fmc_nl" LOC = "W17" | IOSTANDARD = "LVCMOS33" ;
+NET "fmc_nwait" LOC = "Y6" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+#
+NET "fmc_a<0>" LOC = "Y17" | IOSTANDARD = "LVCMOS33" ;
+NET "fmc_a<1>" LOC = "AB16" | IOSTANDARD = "LVCMOS33" ;
+NET "fmc_a<2>" LOC = "AA16" | IOSTANDARD = "LVCMOS33" ;
+NET "fmc_a<3>" LOC = "Y16" | IOSTANDARD = "LVCMOS33" ;
+NET "fmc_a<4>" LOC = "AB17" | IOSTANDARD = "LVCMOS33" ;
+NET "fmc_a<5>" LOC = "AA13" | IOSTANDARD = "LVCMOS33" ;
+NET "fmc_a<6>" LOC = "AB13" | IOSTANDARD = "LVCMOS33" ;
+NET "fmc_a<7>" LOC = "AA15" | IOSTANDARD = "LVCMOS33" ;
+NET "fmc_a<8>" LOC = "AB15" | IOSTANDARD = "LVCMOS33" ;
+NET "fmc_a<9>" LOC = "Y13" | IOSTANDARD = "LVCMOS33" ;
+NET "fmc_a<10>" LOC = "AA14" | IOSTANDARD = "LVCMOS33" ;
+NET "fmc_a<11>" LOC = "Y14" | IOSTANDARD = "LVCMOS33" ;
+NET "fmc_a<12>" LOC = "AB10" | IOSTANDARD = "LVCMOS33" ;
+NET "fmc_a<13>" LOC = "V2" | IOSTANDARD = "LVCMOS33" ;
+NET "fmc_a<14>" LOC = "AB12" | IOSTANDARD = "LVCMOS33" ;
+NET "fmc_a<15>" LOC = "AB8" | IOSTANDARD = "LVCMOS33" ;
+NET "fmc_a<16>" LOC = "AA9" | IOSTANDARD = "LVCMOS33" ;
+NET "fmc_a<17>" LOC = "AA8" | IOSTANDARD = "LVCMOS33" ;
+NET "fmc_a<18>" LOC = "Y7" | IOSTANDARD = "LVCMOS33" ;
+NET "fmc_a<19>" LOC = "AB21" | IOSTANDARD = "LVCMOS33" ;
+NET "fmc_a<20>" LOC = "AB22" | IOSTANDARD = "LVCMOS33" ;
+NET "fmc_a<21>" LOC = "AB20" | IOSTANDARD = "LVCMOS33" ;
+NET "fmc_a<22>" LOC = "Y21" | IOSTANDARD = "LVCMOS33" ;
+NET "fmc_a<23>" LOC = "Y22" | IOSTANDARD = "LVCMOS33" ;
+#NET "fmc_a<24>" LOC = "AB18" | IOSTANDARD = "LVCMOS33" ;
+#NET "fmc_a<25>" LOC = "AA19" | IOSTANDARD = "LVCMOS33" ;
+#
+NET "fmc_d<0>" LOC = "AB7" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<1>" LOC = "AB6" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<2>" LOC = "U1" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<3>" LOC = "U2" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<4>" LOC = "AB11" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<5>" LOC = "AA11" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<6>" LOC = "Y11" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<7>" LOC = "Y12" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<8>" LOC = "Y18" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<9>" LOC = "AA21" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<10>" LOC = "W20" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<11>" LOC = "N15" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<12>" LOC = "U20" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<13>" LOC = "AA1" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<14>" LOC = "AB1" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<15>" LOC = "AB2" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<16>" LOC = "AB3" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<17>" LOC = "Y3" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<18>" LOC = "AA3" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<19>" LOC = "AA5" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<20>" LOC = "AB5" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<21>" LOC = "Y4" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<22>" LOC = "AA4" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<23>" LOC = "V4" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<24>" LOC = "W10" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<25>" LOC = "R4" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<26>" LOC = "W12" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<27>" LOC = "W14" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<28>" LOC = "V20" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<29>" LOC = "V18" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<30>" LOC = "R21" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+NET "fmc_d<31>" LOC = "P21" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 8;
+
+NET "ct_noise" LOC = "W19" | IOSTANDARD = "LVCMOS33" ;
+
+#-------------------------------------------------------------------------------
+# FMC Input Timing
+#-------------------------------------------------------------------------------
+#
+# The following timing values were derived from pages 173-175 of the STM32F429
+# datasheet. Control signals NE1, NL and NWE all have different timing values.
+# Instead of writing individual constraints for every control signal, the most
+# strict constraint is applied to all control signals. This should not cause
+# any P&R issues, since Spartan-6 (and Artix-7) can handle 90 MHz easily.
+#
+# NOE signal is not constrained, since it drives "T" input of IOBUF primitive.
+#
+# Data and Address buses also have different timings, with Data bus timing being
+# more strict. The same approach is used here, i.e. timing for Data bus is
+# applied to Address bus too.
+#
+# Oh, and stupid datasheet doesn't explicitly specify hold time for the data bus!
+#
+
+NET "fmc_d<*>" TNM = "TNM_FMC_IN_DATA" ;
+NET "fmc_a<*>" TNM = "TNM_FMC_IN_ADDR" ;
+
+NET "fmc_ne1" TNM = "TNM_FMC_IN_CONTROL" ;
+NET "fmc_nl" TNM = "TNM_FMC_IN_CONTROL" ;
+NET "fmc_nwe" TNM = "TNM_FMC_IN_CONTROL" ;
+
+TIMEGRP "TNM_FMC_IN_DATA" OFFSET = IN 3.0 ns VALID 6.0 ns BEFORE "fmc_clk" RISING ;
+TIMEGRP "TNM_FMC_IN_ADDR" OFFSET = IN 3.0 ns VALID 6.0 ns BEFORE "fmc_clk" RISING ;
+TIMEGRP "TNM_FMC_IN_CONTROL" OFFSET = IN 5.0 ns VALID 10.0 ns BEFORE "fmc_clk" RISING ;
+
+#-------------------------------------------------------------------------------
+# FMC Output Timing
+#-------------------------------------------------------------------------------
+#
+# NWAIT signal is not constrained, since it is polled by STM32.
+#
+
+NET "fmc_d<*>" TNM = "TNM_FMC_OUT_DATA" ;
+
+TIMEGRP "TNM_FMC_OUT_DATA" OFFSET = OUT 16.7 ns AFTER "fmc_clk" FALLING;
+
+
+#-------------------------------------------------------------------------------
+# CDC Paths
+#-------------------------------------------------------------------------------
+INST "fmc/fmc_cdc/cdc_fmc_sys/src_ff" TNM = "TNM_from_fmc_clk";
+INST "fmc/fmc_cdc/cdc_fmc_sys/src_latch*" TNM = "TNM_from_fmc_clk";
+INST "fmc/fmc_cdc/cdc_fmc_sys/ff_sync*" TNM = "TNM_to_sys_clk";
+INST "fmc/fmc_cdc/cdc_fmc_sys/dst_latch*" TNM = "TNM_to_sys_clk";
+
+INST "fmc/fmc_cdc/cdc_sys_fmc/src_ff" TNM = "TNM_from_sys_clk";
+INST "fmc/fmc_cdc/cdc_sys_fmc/src_latch*" TNM = "TNM_from_sys_clk";
+INST "fmc/fmc_cdc/cdc_sys_fmc/ff_sync*" TNM = "TNM_to_fmc_clk";
+INST "fmc/fmc_cdc/cdc_sys_fmc/dst_latch*" TNM = "TNM_to_fmc_clk";
+
+TIMESPEC "TS_fmc_clk_2_sys_clk" = FROM "TNM_from_fmc_clk" TO "TNM_to_sys_clk" TIG;
+TIMESPEC "TS_sys_clk_2_fmc_clk" = FROM "TNM_from_sys_clk" TO "TNM_to_fmc_clk" TIG;
+
+#======================================================================
+# EOF alpha_fmc.ucf
+#======================================================================