You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
			
		
		
		
		
			
		
			
				
	
	
		
			274 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			274 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Python
		
	
| #!/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)
 | |
| 
 | |
| 
 |