vivado2020.2 工程导出为tcl并rebuild(二)

张开发
2026/4/18 3:30:22 15 分钟阅读

分享文章

vivado2020.2 工程导出为tcl并rebuild(二)
这篇文档承接vivado2020.2 工程导出为tcl并rebuild一在上一篇文档中遗留一个问题就是重建后的工程中有import文件夹下面的内容为大家提供另一个解决方案。前期准备检查工程经过实验如果工程中有增量编译的文件比如.srcs/utils_1/imports/synth_1/xxxx.dcp且这个文件在工程中有这个文件处理方法如下手动从项目中删掉但是不要从路径中删掉否则后面修改了tcl文件之后会报错然后将综合和实现过程中的自动增量编译关掉不勾选图中的配置。生成了tcl之后手动删掉.dcp相关的部分后面rebuild工程之后将dcp相关的代码删掉然后生成工程后手动添加dcp文件有一个点需要注意一下就是tcl中可能有类似下面的代码可能需要把value改为0这个没试过。参考前一篇文章从vivado中生成一个用于rebuild的tcl文件将tcl文件复制到一个新的文件夹下将附件中的文件复制到新的文件夹下执行步骤执行convert_tcl.bat。执行rebuild.bat。新的工程就创建好了。代码附件convert_tcl.batecho off REM Vivado TCL 脚本转换工具 - Windows 批处理包装器 REM 双击运行自动转换当前目录下的 vivado_project.tcl REM 命令行使用convert_tcl.bat [参数] echo echo Vivado TCL 脚本转换工具 echo echo. REM 检查是否提供了参数 if not [%1][] goto :use_params REM 没有参数使用默认文件 set TARGET_FILEvivado_project.tcl goto :process :use_params REM 使用提供的参数 set TARGET_FILE%* :process echo 正在处理文件%TARGET_FILE% echo. REM 检查 Python 是否可用 where python nul 21 if %errorlevel% equ 0 ( set PYTHON_CMDpython ) else ( where py nul 21 if %errorlevel% equ 0 ( set PYTHON_CMDpy ) else ( echo [错误] 未找到 Python请先安装 Python 3.6 pause exit /b 1 ) ) echo [信息] 使用 Python 命令: %PYTHON_CMD% echo. REM 获取脚本所在目录 set SCRIPT_DIR%~dp0 set CONVERT_SCRIPT%SCRIPT_DIR%convert_import_to_add.py REM 检查转换脚本是否存在 if not exist %CONVERT_SCRIPT% ( echo [错误] 找不到转换脚本: %CONVERT_SCRIPT% pause exit /b 1 ) REM 执行转换 %PYTHON_CMD% %CONVERT_SCRIPT% %TARGET_FILE% echo. echo echo 转换完成 echo pauseconvert_import_to_add.py#!/usr/bin/env python3 # -*- coding: utf-8 -*- Vivado TCL 脚本转换工具将 import_files 转换为 add_files -norecurse 功能说明 1. 批量替换所有 import_files 命令为 add_files -norecurse 2. 删除相关的赋值语句set imported_files , set file_imported 3. 保留文件路径和参数不变 4. 支持递归处理目录或单个文件 5. 自动备份原始文件 使用方法 python convert_import_to_add.py tcl_file_or_directory [options] 选项 --backup-dir DIR 指定备份目录默认在原文件同目录创建 backup_时间戳 --recursive 递归处理目录下的所有 .tcl 文件 --dry-run 仅显示将要执行的修改不实际修改文件 --verbose 显示详细的处理信息 示例 python convert_import_to_add.py vivado_project.tcl python convert_import_to_add.py ./scripts --recursive python convert_import_to_add.py vivado_project.tcl --dry-run --verbose import os import re import sys import shutil import argparse from datetime import datetime from pathlib import Path from typing import List, Tuple class TCLConverter: Vivado TCL 脚本转换器 def __init__(self, verbose: bool False): self.verbose verbose self.stats { total_files: 0, converted_files: 0, total_replacements: 0, patterns_found: { batch_import: 0, single_import: 0, quiet_import: 0, plain_import: 0, } } def log(self, message: str, level: str INFO): 打印日志信息 if level DEBUG and not self.verbose: return prefix { INFO: [INFO], SUCCESS: [OK], WARNING: [WARN], ERROR: [ERROR], DEBUG: [DEBUG] }.get(level, ) print(f{prefix} {message}) def convert_content(self, content: str) - Tuple[str, int]: 转换 TCL 内容 replacement_count 0 # 模式 1: set imported_files [import_files -fileset name $files] pattern1 rset\simported_files\s\[import_files\s(-fileset\s\w)\s\$files\] replacement1 radd_files \1 -norecurse $files matches1 len(re.findall(pattern1, content)) if matches1 0: content re.sub(pattern1, replacement1, content) replacement_count matches1 self.stats[patterns_found][batch_import] matches1 self.log(f发现 {matches1} 处批量导入模式, DEBUG) # 模式 2: set file_imported [import_files -fileset name [list $file]] pattern2 rset\sfile_imported\s\[import_files\s(-fileset\s\w)\s\[list\s\$file\]\] replacement2 radd_files \1 -norecurse [list $file] matches2 len(re.findall(pattern2, content)) if matches2 0: content re.sub(pattern2, replacement2, content) replacement_count matches2 self.stats[patterns_found][single_import] matches2 self.log(f发现 {matches2} 处单文件导入模式, DEBUG) # 模式 3: import_files -quiet -fileset name path pattern3 rimport_files\s(-quiet\s-fileset\s\w)\s(.?)(?:\n|$) def replace_quiet(match): nonlocal replacement_count replacement_count 1 self.stats[patterns_found][quiet_import] 1 return fadd_files {match.group(1)} -norecurse {match.group(2).strip()}\n matches3 len(re.findall(pattern3, content)) if matches3 0: content re.sub(pattern3, replace_quiet, content) self.log(f发现 {matches3} 处静默导入模式, DEBUG) # 模式 4: 其他未匹配的 import_files 用法 pattern4 r(?![#\w])import_files\s remaining_matches len(re.findall(pattern4, content)) if remaining_matches 0: self.stats[patterns_found][plain_import] remaining_matches self.log(f警告: 发现 {remaining_matches} 处未处理的 import_files 用法请手动检查, WARNING) return content, replacement_count def convert_file(self, file_path: Path, backup_dir: Path None, dry_run: bool False) - bool: 转换单个 TCL 文件 try: self.log(f处理文件: {file_path}, DEBUG) with open(file_path, r, encodingutf-8) as f: original_content f.read() if import_files not in original_content: self.log(f跳过: {file_path.name} (无 import_files), INFO) return True converted_content, replacement_count self.convert_content(original_content) if replacement_count 0: self.log(f跳过: {file_path.name} (无需转换), INFO) return True self.stats[total_replacements] replacement_count self.log(f找到 {replacement_count} 处需要替换的内容, INFO) if dry_run: self.log(f[DRY RUN] 将修改: {file_path.name}, INFO) return True if backup_dir: backup_path backup_dir / file_path.name shutil.copy2(file_path, backup_path) self.log(f已备份: {backup_path}, DEBUG) # 写入无 BOM 的 UTF-8 文件 with open(file_path, w, encodingutf-8, newline) as f: f.write(converted_content) self.stats[converted_files] 1 self.log(f成功转换: {file_path.name} ({replacement_count} 处修改), SUCCESS) return True except Exception as e: self.log(f处理失败 {file_path.name}: {str(e)}, ERROR) return False def process(self, target_path: Path, recursive: bool False, backup_dir: Path None, dry_run: bool False) - dict: 处理文件或目录 self.log( * 60, INFO) self.log(Vivado TCL 脚本转换工具, INFO) self.log( * 60, INFO) self.log(f目标: {target_path}, INFO) self.log(f模式: {递归 if recursive else 单文件}, INFO) self.log(f模拟运行: {是 if dry_run else 否}, INFO) self.log(- * 60, INFO) if not dry_run and not backup_dir: timestamp datetime.now().strftime(%Y%m%d_%H%M%S) if target_path.is_file(): backup_dir target_path.parent / fbackup_{timestamp} else: backup_dir target_path / fbackup_{timestamp} backup_dir.mkdir(parentsTrue, exist_okTrue) self.log(f备份目录: {backup_dir}, INFO) tcl_files [] if target_path.is_file(): if target_path.suffix.lower() .tcl: tcl_files.append(target_path) else: self.log(f错误: {target_path} 不是 .tcl 文件, ERROR) return self.stats elif target_path.is_dir(): if recursive: tcl_files list(target_path.rglob(*.tcl)) else: tcl_files list(target_path.glob(*.tcl)) if not tcl_files: self.log(未找到任何 .tcl 文件, WARNING) return self.stats self.stats[total_files] len(tcl_files) self.log(f找到 {len(tcl_files)} 个 TCL 文件, INFO) self.log(- * 60, INFO) for file_path in tcl_files: self.convert_file(file_path, backup_dir, dry_run) self.print_summary() return self.stats def print_summary(self): 打印转换统计摘要 print(\n * 60) print(转换统计摘要) print( * 60) print(f总文件数: {self.stats[total_files]}) print(f成功转换: {self.stats[converted_files]}) print(f总替换数: {self.stats[total_replacements]}) print(\n替换模式分布:) for pattern, count in self.stats[patterns_found].items(): if count 0: pattern_names { batch_import: 批量导入 (set imported_files), single_import: 单文件导入 (set file_imported), quiet_import: 静默导入 (import_files -quiet), plain_import: 其他未匹配模式 } print(f - {pattern_names.get(pattern, pattern)}: {count}) if self.stats[patterns_found][plain_import] 0: print(\n警告: 存在未自动处理的 import_files 用法请手动检查) print( * 60) def main(): 主函数 parser argparse.ArgumentParser( descriptionVivado TCL 脚本转换工具将 import_files 转换为 add_files -norecurse, formatter_classargparse.RawDescriptionHelpFormatter ) parser.add_argument(target, typestr, help目标 TCL 文件或目录路径) parser.add_argument(--recursive, -r, actionstore_true, help递归处理目录下的所有 .tcl 文件) parser.add_argument(--backup-dir, -b, typestr, defaultNone, help指定备份目录) parser.add_argument(--dry-run, -n, actionstore_true, help仅显示将要执行的修改不实际修改文件) parser.add_argument(--verbose, -v, actionstore_true, help显示详细的处理信息) args parser.parse_args() target_path Path(args.target) if not target_path.exists(): print(f错误: 路径不存在: {target_path}) sys.exit(1) converter TCLConverter(verboseargs.verbose) backup_dir Path(args.backup_dir) if args.backup_dir else None stats converter.process( target_pathtarget_path, recursiveargs.recursive, backup_dirbackup_dir, dry_runargs.dry_run ) if stats[converted_files] 0: sys.exit(0) elif stats[total_files] 0: sys.exit(1) else: sys.exit(0) if __name__ __main__: main()rebuild.batCALL D:\Xilinx\Vivado\2020.2\bin\vivado.bat -mode batch -source vivado_project.tcl PAUSE

更多文章