wscript 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. #!/usr/bin/env python
  2. # encoding: utf-8
  3. # waf example, builds a Xilinx FPGA bitstream
  4. __copyright__ = '(c) Jérôme Carretero <cJ-waf@zougloub.eu> 2012'
  5. """
  6. This script builds an FPGA bitstream in an automated fashion.
  7. The Xilinx ISE IDE does the same thing, but needs mouse interaction.
  8. Notes:
  9. - this is quite sad, but the Xilinx toolchain tools want to operate
  10. in the source folder, so top==out
  11. - Xilinx toolchain tools generate file with timestamps,
  12. so an unsignificant change can still trigger domino cascade
  13. of compilations.
  14. - a "xilinx" wrapper is used; this file performs set up of the
  15. PATH for Xilinx tools (not done yet by the wscript)
  16. TODO:
  17. - make a tool
  18. - remove hard-coded .xst / .ut data (ISE generates that from the .xise)
  19. - CPLD toolchain (only works for FPGA)
  20. """
  21. top = out = "." # mandatory
  22. import os
  23. import shutil
  24. import waflib
  25. from lxml import etree
  26. def options(opt):
  27. pass
  28. def configure(cfg):
  29. pass
  30. def build(bld):
  31. if not os.path.exists("xst/projnav.tmp"):
  32. os.makedirs("xst/projnav.tmp")
  33. nsmap={"pn": "http://www.xilinx.com/XMLSchema"}
  34. xise = "waf_demo.xise"
  35. fn = "waf_demo"
  36. xml = etree.parse(xise)
  37. def get(txt):
  38. try: return xml.xpath('//pn:property[@pn:name = "%s"]/@pn:value' % txt, namespaces=nsmap)[0]
  39. except: pass
  40. device = get("Device") # or "xc3s1500"
  41. package = get("Package") # or "fg456"
  42. speed = get("Speed Grade") # or "-4"
  43. # Set .prj file contents and collect HDL sources
  44. hdl = []
  45. prj = []
  46. for x in xml.xpath('//pn:files/pn:file[@pn:type = "FILE_VHDL"]/@pn:name', namespaces=nsmap):
  47. prj.append('vhdl work "%s"' % x)
  48. hdl.append(x)
  49. for x in xml.xpath('//pn:files/pn:file[@pn:type = "FILE_VERILOG"]/@pn:name', namespaces=nsmap):
  50. prj.append('verilog work "%s"' % x)
  51. hdl.append(x)
  52. ucf = xml.xpath('//pn:files/pn:file[@pn:type = "FILE_UCF"]/@pn:name', namespaces=nsmap)[0] or "src/pci_7seg.ucf"
  53. def make_prj(self):
  54. self.outputs[0].write("\n".join(prj))
  55. def make_xst(self):
  56. self.outputs[0].write("""
  57. set -tmpdir "xst/projnav.tmp"
  58. set -xsthdpdir "xst"
  59. run
  60. -ifn %(fn)s.prj
  61. -ifmt mixed
  62. -ofn %(fn)s
  63. -ofmt NGC
  64. -p %(device)s%(speed)s-%(package)s
  65. -top %(fn)s
  66. -opt_mode Speed
  67. -opt_level 1
  68. -iuc NO
  69. -keep_hierarchy No
  70. -netlist_hierarchy As_Optimized
  71. -rtlview Yes
  72. -glob_opt AllClockNets
  73. -read_cores YES
  74. -write_timing_constraints NO
  75. -cross_clock_analysis NO
  76. -hierarchy_separator /
  77. -bus_delimiter <>
  78. -case Maintain
  79. -slice_utilization_ratio 100
  80. -bram_utilization_ratio 100
  81. -verilog2001 YES
  82. -fsm_extract YES -fsm_encoding Auto
  83. -safe_implementation No
  84. -fsm_style LUT
  85. -ram_extract Yes
  86. -ram_style Auto
  87. -rom_extract Yes
  88. -mux_style Auto
  89. -decoder_extract YES
  90. -priority_extract Yes
  91. -shreg_extract YES
  92. -shift_extract YES
  93. -xor_collapse YES
  94. -rom_style Auto
  95. -auto_bram_packing NO
  96. -mux_extract Yes
  97. -resource_sharing YES
  98. -async_to_sync NO
  99. -mult_style Auto
  100. -iobuf YES
  101. -max_fanout 500
  102. -bufg 8
  103. -register_duplication YES
  104. -register_balancing No
  105. -slice_packing YES
  106. -optimize_primitives NO
  107. -use_clock_enable Yes
  108. -use_sync_set Yes
  109. -use_sync_reset Yes
  110. -iob Auto
  111. -equivalent_register_removal YES
  112. -slice_utilization_ratio_maxmargin 5
  113. """ % locals())
  114. def make_ut(self):
  115. self.outputs[0].write("""
  116. -w
  117. -g DebugBitstream:No
  118. -g Binary:no
  119. -g CRC:Enable
  120. -g ConfigRate:6
  121. -g CclkPin:PullUp
  122. -g M0Pin:PullUp
  123. -g M1Pin:PullUp
  124. -g M2Pin:PullUp
  125. -g ProgPin:PullUp
  126. -g DonePin:PullUp
  127. -g HswapenPin:PullUp
  128. -g TckPin:PullUp
  129. -g TdiPin:PullUp
  130. -g TdoPin:PullUp
  131. -g TmsPin:PullUp
  132. -g UnusedPin:PullDown
  133. -g UserID:0xFFFFFFFF
  134. -g DCMShutdown:Disable
  135. -g DCIUpdateMode:AsRequired
  136. -g StartUpClk:CClk
  137. -g DONE_cycle:4
  138. -g GTS_cycle:5
  139. -g GWE_cycle:6
  140. -g LCK_cycle:NoWait
  141. -g Match_cycle:Auto
  142. -g Security:None
  143. -g DonePipe:No
  144. -g DriveDone:No""")
  145. bld(
  146. name='prj',
  147. target="%s.prj" % fn,
  148. rule=make_prj,
  149. source=[xise],
  150. )
  151. bld(
  152. name='xst',
  153. target='%s.xst' % fn,
  154. rule=make_xst,
  155. source=[xise],
  156. )
  157. bld(
  158. name='ut',
  159. target='%s.ut' % fn,
  160. rule=make_ut,
  161. source=[xise],
  162. )
  163. bld(
  164. name='synth',
  165. target=['%s%s' % (fn, ext) for ext in ('.syr', '.ngc', '.ngr', '.lso', '_xst.xrpt') ],
  166. rule='xilinx xst -intstyle ise -ifn ${SRC[0].abspath()} -ofn ${TGT[0].abspath()}; true',
  167. source=['%s.xst' % fn, '%s.prj' % fn] + hdl,
  168. )
  169. bld(
  170. name='ngdbuild',
  171. target=['%s%s' % (fn, ext) for ext in ('.ngd', '_ngdbuild.xrpt') ],
  172. 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(),
  173. source=['%s.ngc' % fn, ucf],
  174. )
  175. bld(
  176. name='map',
  177. target=['%s%s' % (fn, ext) for ext in ('_map.ncd', '.pcf', '_map.map', '_map.mrp', '_map.ngm', '_map.xrpt', '.bld') ],
  178. 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(),
  179. source=['%s.ngd' % fn],
  180. )
  181. bld(
  182. name='par',
  183. target=['%s%s' % (fn, ext) for ext in ('.ncd', '.pad', '.par', '.ptwx', '.unroutes', '.xpi', '_pad.csv', '_pad.txt', '_par.xrpt') ],
  184. rule='xilinx par -w -intstyle ise -ol high -t 1 ${SRC[0].bldpath()} ${TGT[0].bldpath()} ${SRC[1].bldpath()}',
  185. source=['%s_map.ncd' % fn, '%s.pcf' % fn],
  186. )
  187. bld(
  188. name='trce',
  189. target=['%s%s' % (fn, ext) for ext in ('.twx', '.twr') ],
  190. 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',
  191. source=['%s_map.ncd' % fn, '%s.pcf' % fn],
  192. )
  193. bld(
  194. name='bitgen',
  195. target=['%s%s' % (fn, ext) for ext in ('.bit', '.bgn', '.drc', '_bitgen.xwbt', '_summary.xml', '_usage.xml') ],
  196. rule='xilinx bitgen -intstyle ise -f ${SRC[1].bldpath()} ${SRC[0].bldpath()} ${TGT[0].bldpath()}',
  197. source=['%s.ncd' % fn, '%s.ut' % fn],
  198. )
  199. if bld.cmd == 'clean':
  200. for tgen in bld.get_all_task_gen():
  201. for tgt in waflib.Utils.to_list(tgen.target):
  202. if os.path.exists(tgt):
  203. os.remove(tgt)
  204. for x in (
  205. 'usage_statistics_webtalk.html',
  206. 'webtalk_pn.xml',
  207. 'webtalk.log',
  208. ):
  209. if os.path.exists(x):
  210. os.remove(x)
  211. for x in (
  212. '_ngo',
  213. '_xmsgs',
  214. 'iseconfig',
  215. 'xlnx_auto_0_xdb',
  216. 'xst',
  217. ):
  218. try:
  219. shutil.rmtree(x)
  220. except:
  221. pass
  222. def distclean(ctx):
  223. import os, shutil
  224. from waflib import Context
  225. for fn in os.listdir('.'):
  226. if fn.startswith(('.conf_check_', ".lock-w")) \
  227. or fn in (Context.DBFILE, 'config.log') \
  228. or fn == 'c4che':
  229. if os.path.isdir(fn):
  230. shutil.rmtree(fn)
  231. else:
  232. os.remove(fn)