1#------------------------------------------------------------------------------- 2# This script takes an xml file which describes hardware options and produces 3# header files in the target directory which are used by the embedded 4# software. 5#------------------------------------------------------------------------------- 6 7import datetime 8import os 9import os.path 10import xml.etree.ElementTree as ET 11import sys 12from pathlib import Path 13 14 15# -------------------------------------------------------------------------------------------- 16# mpfs_configuration_generator.py version 17# 18# 0.6.4 Added the following generated files: 19# hw_mssio_mux_alternate.h 20# hw_nvm_map.h 21# 0.6.3 target folder name change from "fpga_config" -> fpga_design config, filename 22# hw_platform.h changed to fpga_design_config.h , 23# bug fix related to multiple xml file selection and added libero design information 24# constants in fpga_design_config.h/ removed date,version and design information from all the files 25# except fpga_design_config.h 26# 27# 0.6.2 added support for multiple xml file found in input folder 28# /empty xml file check/ xml filename arg in current folder/ 29# if multiple files are there then the file with the latest time stamp will 30# be selected. 31# 0.6.1 changed target folder name from soc_config to fpga_config 32# 33# 0.5.2 Aries Embedded Feedback: remove trailing spaces. 34# 0.5.1 Added check that the source XML document is more recent than content of already existing 35# SoC configuration files. 36# 37# 0.4.2 Allowed to only specify the folder where the input XML 38# file is located. Use file ending with _mss_cfg.xml if one exists, any other .xml file in 39# the input folder otherwise. 40# 41# 0.4.1 Modified the arguments to allow specifying 42# the folder where the soc_config folder should be generated. 43# 44# 0.3.4 fixed comment formatting bug in hw_memory.h generation 45# 0.3.3 updated copyright format 46# 0.3.2 removed leading zeros from decimal values ( clock rates) 47# ------------------------------------------------------------------------------------------------------- 48def get_script_ver(): 49 ''' 50 This changes anytime anytime the mpfs_configuration_generator.py script 51 changes. This does not necessarily mean the xml format has been updated in 52 get_xml_ver() 53 :return: script version 54 ''' 55 return "0.6.4" 56 57 58 59 60# ----------------------------------------------------------------------------- 61# xml file to parse 62# Also an xml files listing tags used for reference 63# ----------------------------------------------------------------------------- 64reference_xml_file = \ 65 ('hardware_des_xml,src_example,mpfs_hw_ref_defaults.xml,default', 66 'hardware_des_xml,src_example,mpfs_hw_ref_ddr3_100Mhz_ext_clk.xml,ddr3_100Mhz_ref') 67 68xml_tag_file = 'hardware_des_xml,src_example,mpfs_hw_tag_reference.xml' 69 70 71# ----------------------------------------------------------------------------- 72# xml tags, the structure here should follow the readme.md description 73# contained in the root folder for tags 74# Please note: The tag in the first column ( mss_xxx) is the same as the 75# directory name (/fpga_design_config/mss_xxx) 76# the fourth item lets program know how to format info in header file 77# fm_reg - appears as reg with fields 78# fm_define - appears as define with value, no fields 79# the six item lets program know how to format value, decimal or hex 80# ----------------------------------------------------------------------------- 81xml_tags = ('mss_memory_map,map,mem_elements,fm_define,none,hex', 82 'mss_memory_map,apb_split,registers,fm_struct,none,hex', 83 'mss_memory_map,cache,registers,fm_struct,none,hex', 84 'mss_memory_map,pmp_h0,registers,fm_struct,HART0_,hex64', 85 'mss_memory_map,pmp_h1,registers,fm_struct,HART1_,hex64', 86 'mss_memory_map,pmp_h2,registers,fm_struct,HART2_,hex64', 87 'mss_memory_map,pmp_h3,registers,fm_struct,HART3_,hex64', 88 'mss_memory_map,pmp_h4,registers,fm_struct,HART4_,hex64', 89 'mss_memory_map,mpu_fic0,registers,fm_struct,FIC0_,hex64', 90 'mss_memory_map,mpu_fic1,registers,fm_struct,FIC1_,hex64', 91 'mss_memory_map,mpu_fic2,registers,fm_struct,FIC2_,hex64', 92 'mss_memory_map,mpu_crypto,registers,fm_struct,CRYPTO_,hex64', 93 'mss_memory_map,mpu_gem0,registers,fm_struct,GEM0_,hex64', 94 'mss_memory_map,mpu_gem1,registers,fm_struct,GEM1_,hex64', 95 'mss_memory_map,mpu_usb,registers,fm_struct,USB_,hex64', 96 'mss_memory_map,mpu_mmc,registers,fm_struct,MMC_,hex64', 97 'mss_memory_map,mpu_scb,registers,fm_struct,SCB_,hex64', 98 'mss_memory_map,mpu_trace,registers,fm_struct,TRACE_,hex64', 99 'mss_memory_map,nvm_map,registers,fm_define,none,decimal', 100 'mss_io,io_mux,registers,fm_reg,none,hex', 101 'mss_io,io_mux_alt,registers,fm_reg,none,hex', 102 'mss_io,hsio,registers,fm_reg,none,hex', 103 'mss_sgmii,tip,registers,fm_reg,none,hex', 104 'mss_ddr,options,registers,fm_reg,none,hex', 105 'mss_ddr,io_bank,registers,fm_reg,none,hex', 106 'mss_ddr,mode,registers,fm_reg,none,hex', 107 'mss_ddr,off_mode,registers,fm_reg,none,hex', 108 'mss_ddr,segs,registers,fm_reg,none,hex', 109 'mss_ddr,ddrc,registers,fm_reg,none,hex', 110 'mss_clocks,clocks,registers,fm_define,none,decimal', 111 'mss_clocks,mss_sys,registers,fm_define,MSS_,hex', 112 'mss_clocks,mss_pll,registers,fm_define,MSS_,hex', 113 'mss_clocks,sgmii_pll,registers,fm_reg,SGMII_,hex', 114 'mss_clocks,ddr_pll,registers,fm_reg,DDR_,hex', 115 'mss_clocks,mss_cfm,registers,fm_reg,MSS_,hex', 116 'mss_clocks,sgmii_cfm,registers,fm_reg,SGMII_,hex', 117 'mss_general,mss_peripherals,registers,fm_reg,none,hex',) 118 119 120# ----------------------------------------------------------------------------- 121# Header files to generate 122#------------------------------------------------------------------------------ 123header_files = ('fpga_design_config,memory_map,hw_memory.h', 124 'fpga_design_config,memory_map,hw_apb_split.h', 125 'fpga_design_config,memory_map,hw_cache.h', 126 'fpga_design_config,memory_map,hw_pmp_hart0.h', 127 'fpga_design_config,memory_map,hw_pmp_hart1.h', 128 'fpga_design_config,memory_map,hw_pmp_hart2.h', 129 'fpga_design_config,memory_map,hw_pmp_hart3.h', 130 'fpga_design_config,memory_map,hw_pmp_hart4.h', 131 'fpga_design_config,memory_map,hw_mpu_fic0.h', 132 'fpga_design_config,memory_map,hw_mpu_fic1.h', 133 'fpga_design_config,memory_map,hw_mpu_fic2.h', 134 'fpga_design_config,memory_map,hw_mpu_crypto.h', 135 'fpga_design_config,memory_map,hw_mpu_gem0.h', 136 'fpga_design_config,memory_map,hw_mpu_gem1.h', 137 'fpga_design_config,memory_map,hw_mpu_usb.h', 138 'fpga_design_config,memory_map,hw_mpu_mmc.h', 139 'fpga_design_config,memory_map,hw_mpu_scb.h', 140 'fpga_design_config,memory_map,hw_mpu_trace.h', 141 'fpga_design_config,memory_map,hw_nvm_map.h', 142 'fpga_design_config,io,hw_mssio_mux.h', 143 'fpga_design_config,io,hw_mssio_mux_alternate.h', 144 'fpga_design_config,io,hw_hsio_mux.h', 145 'fpga_design_config,sgmii,hw_sgmii_tip.h', 146 'fpga_design_config,ddr,hw_ddr_options.h', 147 'fpga_design_config,ddr,hw_ddr_io_bank.h', 148 'fpga_design_config,ddr,hw_ddr_mode.h', 149 'fpga_design_config,ddr,hw_ddr_off_mode.h', 150 'fpga_design_config,ddr,hw_ddr_segs.h', 151 'fpga_design_config,ddr,hw_ddrc.h', 152 'fpga_design_config,clocks,hw_mss_clks.h', 153 'fpga_design_config,clocks,hw_clk_sysreg.h', 154 'fpga_design_config,clocks,hw_clk_mss_pll.h', 155 'fpga_design_config,clocks,hw_clk_sgmii_pll.h', 156 'fpga_design_config,clocks,hw_clk_ddr_pll.h', 157 'fpga_design_config,clocks,hw_clk_mss_cfm.h', 158 'fpga_design_config,clocks,hw_clk_sgmii_cfm.h', 159 'fpga_design_config,general,hw_gen_peripherals.h') 160 161MAX_LINE_WIDTH = 80 162 163 164# ----------------------------------------------------------------------------- 165# Read the xml file into ET 166# ----------------------------------------------------------------------------- 167def read_xml_file(s): 168 file_dir = os.path.join(*s) 169 tree = ET.parse(file_dir.strip()) 170 root = tree.getroot() # type: object 171 return root 172 173 174# ----------------------------------------------------------------------------- 175# Routine to make a folder 176# ----------------------------------------------------------------------------- 177def safe_make_folder(i): 178 '''Makes a folder (and its parents) if not present''' 179 try: 180 os.makedirs(i) 181 except: 182 pass 183 184 185# ----------------------------------------------------------------------------- 186# Create the directory structure 187# ----------------------------------------------------------------------------- 188def create_hw_dir_struct(root_folder, TOP): 189 '''Creates directory structure off root, subdirectories passed in a tupple''' 190 for folder in TOP: 191 safe_make_folder(root_folder + '/' + folder) 192 193 194# ----------------------------------------------------------------------------- 195# Generate the copyright notice at the top of the header file 196# ----------------------------------------------------------------------------- 197def WriteCopyright(root, theFile, filename, creator): 198 ''' 199 generate copyright notice based on the following: 200 #/******************************************************************************* 201 # * Copyright 2019-2020 Microchip FPGA Embedded Systems Solutions. 202 # * 203 # * SPDX-License-Identifier: MIT 204 # * 205 # * MPFS HAL Embedded Software 206 # * 207 # */ 208 :param root: 209 :param theFile: 210 :param filename: 211 :param creator: 212 :return: 213 ''' 214 theFile.write('/**********************************************************' 215 '*********************\n') 216 theFile.write(" * Copyright 2019-" + str(datetime.datetime.now().year) + " Microchip FPGA Embedded Systems Solutions.\n") 217 theFile.write(' *\n') 218 theFile.write(' * SPDX-License-Identifier: MIT\n') 219 theFile.write(' *\n') 220 theFile.write(" * @file " + filename + "\n") 221 theFile.write(" * @author " + creator + "\n") 222 theFile.write(' *\n') 223 if theFile.name == "fpga_design_config\fpga_design_config.h": 224 for child in root: 225 if child.tag == "design_information": 226 for child1 in child: 227 if child1.tag == "design_name": 228 theFile.write(' * Libero design name: ' + child1.text.strip() + "\n") 229 if child1.tag == "libero_version": 230 theFile.write(' * Generated using Libero version: ' + child1.text.strip() + "\n") 231 if child1.tag == "mpfs_part_no": 232 theFile.write(' * MPFS part number used in design: ' + child1.text.strip() + "\n") 233 if child1.tag == "creation_date_time": 234 theFile.write(' * Date generated by Libero: ' + child1.text.strip() + "\n") 235 if child1.tag == "xml_format_version": 236 theFile.write(' * Format version of XML description: ' + child1.text.strip() + "\n") 237 theFile.write(' * PolarFire SoC Configuration Generator version: ' + get_script_ver() + "\n") 238 239 strings = ('', ' Note 1: This file should not be edited. If you need to modify a parameter',\ 240 ' without going through regenerating using the MSS Configurator Libero flow ' ,' or editing the associated xml file',\ 241 ' the following method is recommended: \n',\ 242 ' 1. edit the following file ',' boards/your_board/platform_config/mpfs_hal_config/mss_sw_config.h\n',\ 243 ' 2. define the value you want to override there.',' (Note: There is a commented example in the platform directory)\n',\ 244 ' Note 2: The definition in mss_sw_config.h takes precedence, as',\ 245 ' mss_sw_config.h is included prior to the generated header files located in', ' boards/your_board/fpga_design_config'\ 246 ) 247 for string in strings: 248 theFile.write(' *' + string + "\n") 249 theFile.write(' *\n */\n') 250 251 252# ----------------------------------------------------------------------------- 253# the header start define 254# ----------------------------------------------------------------------------- 255def start_define(theFile, filename): 256 filename = filename[:-2] # remove .h from file name 257 theFile.write('\n#ifndef ' + filename.upper() + '_H_') 258 theFile.write('\n#define ' + filename.upper() + '_H_\n\n') 259 260 261# ----------------------------------------------------------------------------- 262# start c plus define 263# ----------------------------------------------------------------------------- 264def start_cplus(theFile, filename): 265 theFile.write('\n#ifdef __cplusplus\n') 266 theFile.write('extern ' + ' \"C\"' + ' {\n') 267 theFile.write('#endif\n\n') 268 269 270# ----------------------------------------------------------------------------- 271# end define associated with header start define 272# ----------------------------------------------------------------------------- 273def end_define(theFile, filename): 274 filename = filename[:-2] # remove .h from file name 275 theFile.write('\n#endif /*' + ' #ifdef ' + filename.upper() + '_H_ */\n\n') 276 277 278# ----------------------------------------------------------------------------- 279# end c++ define 280# ----------------------------------------------------------------------------- 281def end_cplus(theFile, filename): 282 theFile.write('\n#ifdef __cplusplus\n}\n#endif\n\n') 283 284 285# ----------------------------------------------------------------------------- 286# write line, break into chunks 287# ----------------------------------------------------------------------------- 288def write_line(headerFile , reg_description): 289 ''' write line, break into chunks ''' 290 word_list = reg_description.split() # list of words 291 sentence = word_list[0] + ' ' 292 word_list.pop(0) 293 for word in word_list: 294 if (len(sentence + word + ' ') > MAX_LINE_WIDTH): 295 headerFile.write(sentence.rstrip() + '\n') 296 sentence = word + ' ' 297 else: 298 sentence = sentence + word + ' ' 299 if len(sentence) > 0: 300 headerFile.write(sentence.rstrip() + '\n') 301 302 303# ----------------------------------------------------------------------------- 304# Iterate through registers and produce header file output 305# ----------------------------------------------------------------------------- 306def generate_register(headerFile, registers, tags): 307 ''' 308 Parse registers tag for register tags and print to header file 309 :param headerFile: header file to print to 310 :param registers: registers in a tag 311 :param tags: Some tags used to determine print format 312 :return: 313 ''' 314 for register in registers: 315 # if tag 4 is set, pre-append register name with tag[4] value 316 if tags[4] != 'none': 317 pre_append = tags[4] 318 name = 'LIBERO_SETTING_' + pre_append + register.get('name') 319 else: 320 name = 'LIBERO_SETTING_' + register.get('name') 321 name_of_reg = name 322 description = register.get('description') 323 name_gap = 15 324 if len(name) > 15: 325 name_gap = len(name) 326 s = '#define' + ' ' + name.ljust(name_gap, ' ') 327 name = register.get('name') + "_OFF_MODE" 328 name_gap = 15 329 if len(name) > 15: 330 name_gap = len(name) 331 stest1 = '#define' + ' ' + name.ljust(name_gap, ' ') 332 field_list = [] 333 reg_value = 0 334 reg_value_default = 0 335 for field in register: 336 if field.tag == "field": 337 gap = 30 338 if len(field.get('name')) > gap: 339 gap = len(field.get('name')) + 4 340 sfield = ' /* ' + field.get('name').ljust(gap, ' ') 341 stemp = ' [' + field.get('offset') + ':' + field.get('width') + ']' 342 stemp = stemp.ljust(12, ' ') 343 sfield += stemp 344 sfield += field.get('Type') 345 if (field.get('Type') == 'RW'): 346 sfield += ' value= ' + field.text.strip() 347 temp_val = ((int(field.text.strip(), 16)) << int(field.get('offset'))) 348 reg_value += temp_val 349 sfield += ' */\n' 350 # add the field to list of fields 351 field_list.extend([sfield]) 352 if tags[5] == 'decimal': 353 value = format(reg_value, '01X') 354 default_value = format(reg_value_default, '08X') 355 elif tags[5] == 'hex64': 356 value = '0x' + format(reg_value, '016X') + 'ULL' 357 default_value = '0x' + format(reg_value_default, '08X') 358 else : 359 value = '0x' + format(reg_value, '08X') + 'UL' 360 default_value = '0x' + format(reg_value_default, '08X') 361 name_gap = 4 362 if len(s) >= name_gap: 363 name_gap = len(s) + 4 364 s = s.ljust(name_gap, ' ') + value + '\n' 365 reg_description = '/*' + description + ' */\n' 366 headerFile.write('#if !defined ' + '(' + name_of_reg + ')\n') 367 # Write out the register description, max chars per line 80 368 write_line(headerFile , reg_description) 369 headerFile.write(s) 370 for x in range(len(field_list)): 371 headerFile.write(field_list[x]) 372 headerFile.write('#endif\n') 373 374 375# ----------------------------------------------------------------------------- 376# Iterate through tag mem_elements looking for mem elements produce header file 377# output 378# ----------------------------------------------------------------------------- 379def generate_mem_elements(headerFile, mem_elements, tags): 380 ''' 381 Parse registers tag for mem tags and print to header file 382 :param headerFile: 383 :param registers: 384 :return: 385 ''' 386 for mem in mem_elements: 387 name = 'LIBERO_SETTING_' + mem.get('name') 388 name_of_reg = name 389 name_size = name + '_SIZE' 390 description = mem.get('description') 391 name_gap = 15 392 if len(name) > 15: 393 name_gap = len(name) 394 s = '#define' + ' ' + name.ljust(name_gap, ' ') 395 s1 = '#define' + ' ' + name_size.ljust(name_gap, ' ') 396 # get the values 397 mem_value = mem.text.strip() 398 mem_size = mem.get('size') 399 # make sure space between name and value 4 spaces 400 name_gap = 4 401 if len(s) >= name_gap: 402 name_gap = len(s) + 4 403 # make sure space between name and value 4 spaces 404 name_size_gap = 4 405 if len(s1) >= name_size_gap: 406 name_size_gap = len(s1) + 4 407 # create the strings for writing 408 s = s.ljust(name_gap, ' ') + mem_value + '\n' 409 reg_description = '/*' + description + ' */\n' 410 s1 = s1.ljust(name_size_gap, ' ') + mem_size \ 411 + ' /* Length of memory block*/ \n' 412 headerFile.write('#if !defined ' + '(' + name_of_reg + ')\n') 413 headerFile.write(reg_description) 414 headerFile.write(s) 415 headerFile.write(s1) 416 headerFile.write('#endif\n') 417 418 419# ----------------------------------------------------------------------------- 420# generate a header file 421# ----------------------------------------------------------------------------- 422def generate_header( file, real_root, root, file_name, tags): 423 creator = "Microchip-FPGA Embedded Systems Solutions" 424 with open(file, 'w+') as headerFile: 425 # write the copyright header 426 WriteCopyright(real_root, headerFile, file_name, creator) 427 start_define(headerFile, file_name) 428 start_cplus(headerFile, file_name) 429 if tags != None : 430 for child in root: 431 if child.tag == "registers": 432 generate_register(headerFile, child, tags) 433 if child.tag == "mem_elements": 434 generate_mem_elements(headerFile, child, tags) 435 for child2 in child: 436 if child2.tag == "registers": 437 generate_register(headerFile, child2, tags) 438 else: 439 headerFile.write('/* No content from MSS Configurator generated for this file. */\n') 440 headerFile.write('/* An older version of MSS Configurator has been used. */\n') 441 end_cplus(headerFile, file_name) 442 end_define(headerFile, file_name) 443 444 445# ----------------------------------------------------------------------------- 446# fpga_design_config.h header file generation. 447# ----------------------------------------------------------------------------- 448 449def write_libero_config_info(root,theFile): 450 script_version = get_script_ver().split('.') 451 tags_dic = {"design_name":"LIBERO_SETTING_DESIGN_NAME","libero_version":"LIBERO_SETTING_MSS_CONFIGURATOR_VERSION","mpfs_part_no" :"LIBERO_SETTING_MPFS_PART "\ 452 ,"creation_date_time":"LIBERO_SETTING_GENERATION_DATE","xml_format_version":"LIBERO_SETTING_XML_VERSION"} 453 454 #max constant name size + some extra buffer space 455 max_gap = max([len(v) for k,v in tags_dic.items()]) + 8 456 457 fixed_gap = 12 458 xml_version = [] 459 for child in root: 460 if child.tag == "design_information": 461 for child1 in child: 462 if child1.tag in tags_dic: 463 gap = max_gap - (len(tags_dic[child1.tag])) 464 theFile.write('#define '+ tags_dic[child1.tag].ljust(4,' ') + " "*(gap + fixed_gap) + "\"" + child1.text.strip() + "\"" + "\n") 465 if child1.tag == "xml_format_version": 466 xml_version = child1.text.strip().split('.') 467 468 const = {"LIBERO_SETTING_XML_VERSION_MAJOR": xml_version[0],"LIBERO_SETTING_XML_VERSION_MINOR":xml_version[1],"LIBERO_SETTING_XML_VERSION_PATCH":xml_version[2], "LIBERO_SETTING_HEADER_GENERATOR_VERSION":'.'.join(script_version),"LIBERO_SETTING_HEADER_GENERATOR_VERSION_MAJOR":script_version[0],"LIBERO_SETTING_HEADER_GENERATOR_VERSION_MINOR":script_version[1],"LIBERO_SETTING_HEADER_GENERATOR_VERSION_PATCH":script_version[2]} 469 470 # write hard coded constants in the fpga_design_config.h file. 471 for k,v in const.items(): 472 gap = max_gap - len(k) 473 if k == "LIBERO_SETTING_HEADER_GENERATOR_VERSION": 474 theFile.write('#define '+ k.ljust(4,' ') + " "*(gap + fixed_gap) + "\"" + v + "\"" + "\n") 475 else: 476 theFile.write('#define '+ k + " "*(gap + fixed_gap) + v + "\n") 477 #new line 478 theFile.write("\n") 479 480 481def generate_reference_header_file(ref_header_file, root, header_files): 482 creator = "Embedded Software" 483 # itemName ="io_mux configuration" 484 s = ref_header_file.split(',') 485 file = os.path.join(*s) 486 file_name = s[-1] 487 with open(file, 'w+') as headerFile: 488 # write the copyright header 489 490 WriteCopyright(root, headerFile, file_name, creator) 491 # add exclusive define 492 start_define(headerFile, file_name) 493 # include all the headers 494 495 #define Libero design information constants 496 write_libero_config_info(root,headerFile) 497 index = 0 498 for child in header_files: 499 c = header_files[index].split(',') 500 c.remove('fpga_design_config') 501 # include_file = os.path.join(*c) 502 # as we need formatting correct for linux and windows 503 include_file = c[0] + '/' + c[1] 504 headerFile.write('#include \"' + include_file + '\"\n') 505 index += 1 506 # add the c++ define 507 start_cplus(headerFile, file_name) 508 # no content in this case 509 comment = '/* No content in this file, used for referencing header */\n' 510 headerFile.write(comment) 511 # end the c++ define 512 end_cplus(headerFile, file_name) 513 end_define(headerFile, file_name) 514 515 516# ----------------------------------------------------------------------------- 517# Generate all the header files, passed in output_header_files 518# ----------------------------------------------------------------------------- 519def generate_header_files(output_header_files, input_xml_file, input_xml_tags): 520 # read in an xml file 521 s = input_xml_file.split(',') 522 523 root = read_xml_file(s) 524 index = 0 525 while index < len(input_xml_tags): 526 ref_tags = input_xml_tags[index].split(',') 527 s = output_header_files[index].split(',') 528 file_name = s[-1] 529 dir_name = s[-2] 530 file_dir = os.path.join(*s) 531 found_match = 0 532 for child in root: 533 if child.tag == 'mss_' + dir_name: 534 for child1 in child: 535 if child1.tag == ref_tags[1]: 536 found_match = 1 537 break 538 # 539 # Next, create file based on xml content 540 # 541 if found_match == 1: 542 generate_header(file_dir, root, child1, file_name, ref_tags) 543 else: 544 generate_header(file_dir, root, child1, file_name, None) 545 index += 1 546 547 ''' 548 generate a header which references all the generated headers 549 ''' 550 file_name = 'fpga_design_config,fpga_design_config.h' 551 generate_reference_header_file(file_name, root, output_header_files) 552 553 554# ----------------------------------------------------------------------------- 555# Return absolute path created from working directory location and relative 556# path passed as argument. Handles path to an XML file and path to a folder. 557# ----------------------------------------------------------------------------- 558def get_full_path(in_path): 559 print(in_path) 560 cwd = os.getcwd() 561 print(cwd) 562 filename = '' 563 temp = in_path 564 if in_path.endswith('.xml'): 565 path_comp = in_path.split('/') 566 last = len(path_comp) - 1 567 filename = path_comp[last] 568 569 in_path = in_path.replace(filename, '') 570 print(in_path) 571 if in_path == '': 572 filename = temp 573 in_path = os.getcwd() 574 print(in_path) 575 else: 576 xml_list = [] 577 dir_entries = os.listdir(in_path) 578 for dir_entry in dir_entries: 579 580 if dir_entry.endswith('.xml'): 581 xml_list.append(dir_entry) 582 else: 583 if dir_entry.endswith('_mss_cfg.xml'): 584 xml_list.append(dir_entry) 585 break 586 #This section will sort the xml file by the latest timestamp 587 if len(xml_list) > 1: 588 589 xml_list = sort_by_timestamp(xml_list,in_path) 590 filename = xml_list[-1] 591 #prompt the selected filename 592 print("selected xml file is : {}".format(filename)) 593 else: 594 if len(xml_list) != 0: 595 filename = xml_list[0] 596 597 print(in_path) 598 599 try: 600 print("trying to change directory") 601 os.chdir(in_path) 602 full_path = os.getcwd() 603 except IOError: 604 print("caught IO error ") 605 sys.exit() 606 607 os.chdir(cwd) 608 full_path = full_path + '/' + filename 609 if is_empty_file(full_path): 610 print("\nxml File is empty") 611 sys.exit() 612 else: 613 return full_path 614 615 616# ------------------------------------------------------- 617# check is fpath is a file and empty 618# ------------------------------------------------------- 619def is_empty_file(fpath): 620 return os.path.isfile(fpath) and os.path.getsize(fpath) == 0 621 622# ------------------------------------------------------- 623# sort file names on the basis of time stamp 624# ------------------------------------------------------- 625def sort_by_timestamp(file_name,file_path): 626 cwd = os.getcwd() 627 try : 628 os.chdir(file_path) 629 path = os.getcwd() 630 except IOError : 631 print("not a valid folder name--------------") 632 sys.exit() 633 634 635 Files = [path + '/' + file_name[i] for i in range(len(file_name))] 636 Files.sort(key=os.path.getmtime) 637 s_file_name = [] 638 for i in range(len(Files)): 639 s_file_name.append(Files[i].split('/')[-1]) 640 641 print("sorted list of files\n",s_file_name) 642 os.chdir(cwd) 643 return s_file_name 644 645# ----------------------------------------------------------------------------- 646# helper for showing help information 647# ----------------------------------------------------------------------------- 648def show_help(): 649 print ('no of args you entered = ' + str(len(sys.argv) - 1)) 650 print ('mpfs_configuration_generator.py :') 651 print (' This program reads xml hardware definition, outputs: header files') 652 print \ 653 (' Usage: python3 mpfs_configuration_generator.py [xml file path] [output folder path] ') 654 print('path can be absolute as well as relative \n') 655 input(' Please run again with correct arguments') 656 657 658# ----------------------------------------------------------------------------- 659# main function 660# todo: add options from the command line 661# ----------------------------------------------------------------------------- 662def main_config_generator(): 663 ''' 664 This script takes an xml file which describes hardware options and produces 665 header files in the target directory which are used by the embedded 666 software. 667 Currently there are Two command line arguments 668 arg0: path to the folder containing xml file. 669 arg1: path of the folder where the fpga_design_config will be generated. 670 Note - If multiple xml files are present then the one with the latest time stamp 671 will be selected. 672 673 ''' 674 675 # 676 # check/parse arguments 677 # 678 nb_arguments = len(sys.argv) - 1 679 if nb_arguments < 2: 680 show_help() 681 sys.exit() 682 fullCmdArguments = sys.argv 683 # - further arguments 684 argumentList = fullCmdArguments[1:] 685 input_xml_file = argumentList[0] 686 input_xml_file = get_full_path(input_xml_file) 687 688 if nb_arguments >= 2: 689 output_folder_name = argumentList[1] 690 output_folder_name = get_full_path(output_folder_name) 691 os.chdir(output_folder_name) 692 693 debug_reg_csv = False 694 if nb_arguments >= 4: 695 if argumentList[3] == 'debug_regs': 696 debug_reg_csv = True 697 if nb_arguments >= 3: 698 if argumentList[2] == 'generate_refernce_xml': 699 gen_xml = True 700 else: 701 gen_xml = False 702 # 703 # Check version of python interpreter, helps debugging 704 # Currently runs on python version 2 and 3 705 # 706 print ('python interpreter details:',sys.version_info) 707 if sys.version_info > (3, 0): 708 # # Python 3 code in this block 709 print ('python interpreter running is version 3') 710 else: 711 # # Python 2 code in this block 712 print ('python interpreter running is version 2') 713 714 # Create directory structure for the header files 715 # 716 root_folder = 'fpga_design_config' 717 TOP = ['clocks', 'ddr', 'io', 'memory_map', 'sgmii', 'general'] 718 create_hw_dir_struct(root_folder, TOP) 719 # 720 # Next, read in XML content and create header files 721 # 722 generate_header_files(header_files, input_xml_file, xml_tags) 723 print('Hardware configuration header files created in directory:', os.path.join(output_folder_name, 'fpga_design_config')) 724 725if __name__ == "__main__": 726 main_config_generator() 727 728 729