123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- #!/usr/bin/env python
- # encoding: utf-8
- # waf example, builds a Xilinx FPGA bitstream
- __copyright__ = '(c) Jérôme Carretero <cJ-waf@zougloub.eu> 2012'
- """
- 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):
- self.outputs[0].write("\n".join(prj))
-
- def make_xst(self):
- self.outputs[0].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):
- self.outputs[0].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],
- )
- 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.remove(tgt)
- for x in (
- 'usage_statistics_webtalk.html',
- 'webtalk_pn.xml',
- 'webtalk.log',
- ):
- if os.path.exists(x):
- os.remove(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_', ".lock-w")) \
- or fn in (Context.DBFILE, 'config.log') \
- or fn == 'c4che':
- if os.path.isdir(fn):
- shutil.rmtree(fn)
- else:
- os.remove(fn)
|