diff --git a/playground/xilinx-ise/.gitignore b/playground/xilinx-ise/.gitignore
new file mode 100644
index 00000000..a4b9fd51
--- /dev/null
+++ b/playground/xilinx-ise/.gitignore
@@ -0,0 +1,44 @@
+*~
+*.bgn
+*.bit
+*.bld
+*.drc
+*.lso
+*.ncd
+*.ngc
+*.ngd
+*.ngr
+*.pad
+*.par
+*.pcf
+*.prj
+*.ptwx
+*.syr
+*.twr
+*.twx
+*.unroutes
+*.ut
+*.xpi
+*.xst
+*_bitgen.xwbt
+*_map.map
+*_map.mrp
+*_map.ncd
+*_map.ngm
+*_map.xrpt
+*_ngdbuild.xrpt
+*_pad.csv
+*_pad.txt
+*_par.xrpt
+*_summary.xml
+*_usage.xml
+*_xst.xrpt
+_ngo
+_xmsgs
+c4che
+config.log
+usage_statistics_webtalk.html
+xlnx_auto_0_xdb
+xst
+webtalk.log
+
diff --git a/playground/xilinx-ise/src/rs1.ucf b/playground/xilinx-ise/src/rs1.ucf
new file mode 100644
index 00000000..3417002e
--- /dev/null
+++ b/playground/xilinx-ise/src/rs1.ucf
@@ -0,0 +1,8 @@
+NET "DLED_2" LOC = "AB5" | IOSTANDARD = LVTTL | DRIVE = 24 ;
+NET "DLED_3" LOC = "AA5" | IOSTANDARD = LVTTL | DRIVE = 24 ;
+NET "DLED_4" LOC = "AA4" | IOSTANDARD = LVTTL | DRIVE = 24 ;
+NET "DLED_5" LOC = "AB4" | IOSTANDARD = LVTTL | DRIVE = 24 ;
+
+NET "BUTTON_1" LOC = "AA3" | IOSTANDARD = LVTTL | PULLUP ;
+NET "BUTTON_2" LOC = "Y4" | IOSTANDARD = LVTTL | PULLUP ;
+
diff --git a/playground/xilinx-ise/src/top.vhd b/playground/xilinx-ise/src/top.vhd
new file mode 100644
index 00000000..cb8d895b
--- /dev/null
+++ b/playground/xilinx-ise/src/top.vhd
@@ -0,0 +1,34 @@
+--+-------------------------------------------------------------------------------------------------+
+--|
+--| VHDL example for waf build automation tool
+--|
+--+-------------------------------------------------------------------------------------------------+
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+entity waf_demo is
+port (
+ -- buttons
+ BUTTON_1 : in std_logic;
+ BUTTON_2 : in std_logic;
+
+ -- leds
+ DLED_2 : out std_logic;
+ DLED_3 : out std_logic;
+ DLED_4 : out std_logic;
+ DLED_5 : out std_logic
+);
+end waf_demo;
+
+architecture inside of waf_demo is
+
+begin
+
+ DLED_5 <= '1';
+ DLED_4 <= BUTTON_2;
+ DLED_3 <= '0';
+ DLED_2 <= not BUTTON_1;
+
+end inside;
+
diff --git a/playground/xilinx-ise/waf_demo.xise b/playground/xilinx-ise/waf_demo.xise
new file mode 100644
index 00000000..c2fd3703
--- /dev/null
+++ b/playground/xilinx-ise/waf_demo.xise
@@ -0,0 +1,372 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/playground/xilinx-ise/wscript b/playground/xilinx-ise/wscript
new file mode 100644
index 00000000..f4dd94e9
--- /dev/null
+++ b/playground/xilinx-ise/wscript
@@ -0,0 +1,282 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# waf example, builds a Xilinx FPGA bitstream
+
+__copyright__ = '(c) Jérôme Carretero 2012'
+__license__ = 'DWTFYWPL'
+
+"""
+This script builds an FPGA bitstream in an automated fashion.
+The Xilinx ISE IDE does the same thing, but needs mouse interaction.
+
+Notes:
+
+- this is quite sad, but the Xilinx toolchain tools want to operate
+ in the source folder, so top==out
+
+- Xilinx toolchain tools generate file with timestamps,
+ so an unsignificant change can still trigger domino cascade
+ of compilations.
+
+- a "xilinx" wrapper is used; this file performs set up of the
+ PATH for Xilinx tools (not done yet by the wscript)
+
+TODO:
+
+- make a tool
+- remove hard-coded .xst / .ut data (ISE generates that from the .xise)
+- CPLD toolchain (only works for FPGA)
+
+"""
+
+top = out = "." # mandatory
+
+import os
+import shutil
+import waflib
+from lxml import etree
+
+def options(opt):
+ pass
+
+def configure(cfg):
+ pass
+
+def build(bld):
+
+ if not os.path.exists("xst/projnav.tmp"):
+ os.makedirs("xst/projnav.tmp")
+
+ nsmap={"pn": "http://www.xilinx.com/XMLSchema"}
+
+ xise = "waf_demo.xise"
+ fn = "waf_demo"
+ xml = etree.parse(xise)
+
+ def get(txt):
+ try: return xml.xpath('//pn:property[@pn:name = "%s"]/@pn:value' % txt, namespaces=nsmap)[0]
+ except: pass
+
+ device = get("Device") # or "xc3s1500"
+ package = get("Package") # or "fg456"
+ speed = get("Speed Grade") # or "-4"
+
+ # Set .prj file contents and collect HDL sources
+ hdl = []
+ prj = []
+ for x in xml.xpath('//pn:files/pn:file[@pn:type = "FILE_VHDL"]/@pn:name', namespaces=nsmap):
+ prj.append('vhdl work "%s"' % x)
+ hdl.append(x)
+ for x in xml.xpath('//pn:files/pn:file[@pn:type = "FILE_VERILOG"]/@pn:name', namespaces=nsmap):
+ prj.append('verilog work "%s"' % x)
+ hdl.append(x)
+
+ ucf = xml.xpath('//pn:files/pn:file[@pn:type = "FILE_UCF"]/@pn:name', namespaces=nsmap)[0] or "src/pci_7seg.ucf"
+
+ def make_prj(self):
+ with open(self.outputs[0].abspath(), "w") as f:
+ f.write("\n".join(prj))
+
+ def make_xst(self):
+ with open(self.outputs[0].abspath(), "w") as f:
+ fn, device, speed, package
+ f.write("""
+set -tmpdir "xst/projnav.tmp"
+set -xsthdpdir "xst"
+run
+-ifn %(fn)s.prj
+-ifmt mixed
+-ofn %(fn)s
+-ofmt NGC
+-p %(device)s%(speed)s-%(package)s
+-top %(fn)s
+-opt_mode Speed
+-opt_level 1
+-iuc NO
+-keep_hierarchy No
+-netlist_hierarchy As_Optimized
+-rtlview Yes
+-glob_opt AllClockNets
+-read_cores YES
+-write_timing_constraints NO
+-cross_clock_analysis NO
+-hierarchy_separator /
+-bus_delimiter <>
+-case Maintain
+-slice_utilization_ratio 100
+-bram_utilization_ratio 100
+-verilog2001 YES
+-fsm_extract YES -fsm_encoding Auto
+-safe_implementation No
+-fsm_style LUT
+-ram_extract Yes
+-ram_style Auto
+-rom_extract Yes
+-mux_style Auto
+-decoder_extract YES
+-priority_extract Yes
+-shreg_extract YES
+-shift_extract YES
+-xor_collapse YES
+-rom_style Auto
+-auto_bram_packing NO
+-mux_extract Yes
+-resource_sharing YES
+-async_to_sync NO
+-mult_style Auto
+-iobuf YES
+-max_fanout 500
+-bufg 8
+-register_duplication YES
+-register_balancing No
+-slice_packing YES
+-optimize_primitives NO
+-use_clock_enable Yes
+-use_sync_set Yes
+-use_sync_reset Yes
+-iob Auto
+-equivalent_register_removal YES
+-slice_utilization_ratio_maxmargin 5
+""" % locals())
+
+
+
+ def make_ut(self):
+ with open(self.outputs[0].abspath(), "w") as f:
+ fn, device, speed, package
+ f.write("""
+-w
+-g DebugBitstream:No
+-g Binary:no
+-g CRC:Enable
+-g ConfigRate:6
+-g CclkPin:PullUp
+-g M0Pin:PullUp
+-g M1Pin:PullUp
+-g M2Pin:PullUp
+-g ProgPin:PullUp
+-g DonePin:PullUp
+-g HswapenPin:PullUp
+-g TckPin:PullUp
+-g TdiPin:PullUp
+-g TdoPin:PullUp
+-g TmsPin:PullUp
+-g UnusedPin:PullDown
+-g UserID:0xFFFFFFFF
+-g DCMShutdown:Disable
+-g DCIUpdateMode:AsRequired
+-g StartUpClk:CClk
+-g DONE_cycle:4
+-g GTS_cycle:5
+-g GWE_cycle:6
+-g LCK_cycle:NoWait
+-g Match_cycle:Auto
+-g Security:None
+-g DonePipe:No
+-g DriveDone:No""")
+
+
+ bld(
+ name='prj',
+ target="%s.prj" % fn,
+ rule=make_prj,
+ source=[xise],
+ )
+
+ bld(
+ name='xst',
+ target='%s.xst' % fn,
+ rule=make_xst,
+ source=[xise],
+ )
+ bld(
+ name='ut',
+ target='%s.ut' % fn,
+ rule=make_ut,
+ source=[xise],
+ )
+
+ bld(
+ name='synth',
+ target=['%s%s' % (fn, ext) for ext in ('.syr', '.ngc', '.ngr', '.lso', '_xst.xrpt') ],
+ rule='xilinx xst -intstyle ise -ifn ${SRC[0].abspath()} -ofn ${TGT[0].abspath()}; true',
+ source=['%s.xst' % fn, '%s.prj' % fn] + hdl,
+ )
+
+ bld(
+ name='ngdbuild',
+ target=['%s%s' % (fn, ext) for ext in ('.ngd', '_ngdbuild.xrpt') ],
+ rule='xilinx ngdbuild -intstyle ise -dd _ngo -nt timestamp -uc ${SRC[1].abspath()} -p %(device)s-%(package)s%(speed)s ${SRC[0].bldpath()} ${TGT[0].bldpath()}' % locals(),
+ source=['%s.ngc' % fn, ucf],
+ )
+
+ bld(
+ name='map',
+ target=['%s%s' % (fn, ext) for ext in ('_map.ncd', '.pcf', '_map.map', '_map.mrp', '_map.ngm', '_map.xrpt', '.bld') ],
+ rule='xilinx map -intstyle ise -p %(device)s-%(package)s%(speed)s -cm area -ir off -pr b -c 100 -o ${TGT[0].bldpath()} ${SRC[0].bldpath()} ${TGT[1].bldpath()}' % locals(),
+ source=['%s.ngd' % fn],
+ )
+
+ bld(
+ name='par',
+ target=['%s%s' % (fn, ext) for ext in ('.ncd', '.pad', '.par', '.ptwx', '.unroutes', '.xpi', '_pad.csv', '_pad.txt', '_par.xrpt') ],
+ rule='xilinx par -w -intstyle ise -ol high -t 1 ${SRC[0].bldpath()} ${TGT[0].bldpath()} ${SRC[1].bldpath()}',
+ source=['%s_map.ncd' % fn, '%s.pcf' % fn],
+ )
+
+ bld(
+ name='trce',
+ target=['%s%s' % (fn, ext) for ext in ('.twx', '.twr') ],
+ rule='xilinx trce -intstyle ise -e 3 -s 4 -n 3 -xml ${TGT[0].bldpath()} ${SRC[0].bldpath()} -o ${TGT[1].bldpath()} ${SRC[1].bldpath()}; true',
+ source=['%s_map.ncd' % fn, '%s.pcf' % fn],
+ )
+
+ bld(
+ name='bitgen',
+ target=['%s%s' % (fn, ext) for ext in ('.bit', '.bgn', '.drc', '_bitgen.xwbt', '_summary.xml', '_usage.xml') ],
+ rule='xilinx bitgen -intstyle ise -f ${SRC[1].bldpath()} ${SRC[0].bldpath()} ${TGT[0].bldpath()}',
+ source=['%s.ncd' % fn, '%s.ut' % fn],
+ )
+
+ for tgen in bld.get_all_task_gen():
+ tgen.update_outputs=True
+
+ if bld.cmd == 'clean':
+ for tgen in bld.get_all_task_gen():
+ for tgt in waflib.Utils.to_list(tgen.target):
+ if os.path.exists(tgt):
+ os.unlink(tgt)
+ for x in (
+ 'usage_statistics_webtalk.html',
+ 'webtalk_pn.xml',
+ 'webtalk.log',
+ ):
+ if os.path.exists(x):
+ os.unlink(x)
+
+ for x in (
+ '_ngo',
+ '_xmsgs',
+ 'iseconfig',
+ 'xlnx_auto_0_xdb',
+ 'xst',
+ ):
+ try:
+ shutil.rmtree(x)
+ except:
+ pass
+
+def distclean(ctx):
+ import os, shutil
+ from waflib import Context
+
+ for fn in os.listdir('.'):
+ if fn.startswith('.conf_check_') or fn.startswith(".lock-w") \
+ or fn in (Context.DBFILE, 'config.log') \
+ or fn == 'c4che':
+ if os.path.isdir(fn):
+ shutil.rmtree(fn)
+ else:
+ os.unlink(fn)
+
+