├── .gitignore ├── License.txt ├── README.md ├── checkin.tcl ├── checkout.tcl ├── config.ini ├── git_vivado.py └── templates ├── hw.gitignore ├── post_build.tcl └── project_info.tcl /.gitignore: -------------------------------------------------------------------------------- 1 | # Blacklist everything 2 | /* 3 | 4 | # Whitelist this stuff 5 | !License.txt 6 | !config.ini 7 | !*.tcl 8 | !*.py 9 | !*README.md 10 | !*.gitignore 11 | !templates 12 | !templates/* -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Digilent 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Digilent Vivado Scripts 2 | 3 | ## Introduction 4 | This repository contains a set of scripts for creating, maintaining, and releasing git repositories containing minimally version-controlled Vivado projects. A Python 3.6.3 (or newer) installation is required to use the Python frontend for these scripts. As of time of writing, no additional Python modules are depended on. 5 | 6 | ---------------- 7 | ## Quick Guide 8 | 9 | This guide covers only what is required to gain access to and build demo project sources. For more in-depth details on these steps, and for information on how to push changes to a demo repository or build a release, see the **Workflows** section of this document, below. 10 | 11 | ### Prerequisites 12 | - You must have the URL for a demo repository that uses digilent-vivado-scripts as a submodule. 13 | 14 | For the purposes of this guide, any time that the text `` appears, you should replace it with the name of your chosen demo, as it appears at the end of the URL. For example, for the [Zybo Z7-20 HDMI demo](https://github.com/Digilent/Zybo-Z7-20-HDMI), `` should be replaced with `Zybo-Z7-20-HDMI`. 15 | - Make sure that [Git](https://git-scm.com/) and a console application that can use it are installed on your computer. Most Linux systems will already have git installed. Windows users are recommended to use the Git Bash shell available through https://gitforwindows.org. 16 | - Make sure you have the version of Vivado targeted by your chosen demo repository installed on your computer. The README for your chosen demo will describe which version of these tools it can be used with. Installation instructions can be found in the [Installing Vivado, Xilinx SDK, and Digilent Board Files](https://reference.digilentinc.com/vivado/installing-vivado/start) guide on the Digilent Wiki. FIXME update link 17 | ### Getting Demo Sources 18 | 1. Open your git-compatible console or terminal application. 19 | 1. Change directory (using the `cd` command) to the folder that you wish to put the demo sources into. **Note:** *Take note of which directory you are in, it will be used again later* 20 | 1. Clone the chosen demo repository. Since the demo repository uses submodules, you should specify the --recursive flag when cloning: 21 | 22 | `git clone --recursive https://github.com/Digilent/` 23 | 1. *Only if* the chosen demo repository uses multiple branches to contain multiple demos - which is described in the repository's README - then use the steps below to get the correct sources for that branch. 24 | 1. Change the working directory to the folder the repo was cloned into: 25 | 26 | `cd ` 27 | 1. If you don't know if your chosen demo repository contains multiple demo branches, or if you don't know the name of the demo branch you want to check out, the following command can be used to list all available branches: 28 | 29 | `git branch -a` 30 | 1. Check out the branch for the demo you wish to access: 31 | 32 | `git checkout ` 33 | 1. When checking out a branch, make sure to run the following commands. This will make sure that the correct versions are used for any sources that are included in the demo as submodules. 34 | 35 | `git submodule init` 36 | 37 | `git submodule update` 38 | ### Initializing and Building the Vivado Project 39 | 1. Launch the version of Vivado that your chosen demo targets. 40 | 1. Once Vivado is open, open the TCL Console at the bottom of the screen. 41 | 1. To initialize and open the Vivado project, run the following command in the TCL console, changing `` to match the location of the directory that you noted down in Step 2 of the *Getting Demo Sources* section: 42 | 43 | `set argv ""; source //scripts/checkout.tcl` 44 | 1. At this point you now have access to the Vivado Project and all of its sources. The project can be viewed, changes can be made, a bitstream can be generated, and Xilinx shell architecture file (XSA) can be generated for handoff to Vitis. 45 | ### Final Notes 46 | At this point, you have access to a working copy of the demo repository. The chosen demo's README or wiki page will contain instructions on how to use this demo once it is programmed onto your board. 47 | 48 | For technical support, please visit the [Digilent Forums](https://forum.digilentinc.com/forum/4-fpga). 49 | 50 | This concludes the *Quick Guide*. The remainder of this document discusses the implementation of the digilent-vivado-scripts repository and how to use the scripts in more technical detail. 51 | 52 | ---------------- 53 | ## Python Frontend 54 | A front-end script, git_vivado.py, is provided to parse command line arguments and call into Vivado at the command line. This script has three subcommands: "checkout", "checkin", and "release". Each of these subcommands has its own help menu, which explains the arguments that can be passed to the script, as well as show what the default values of each of these arguments will be. All paths passed to the script are assumed to be relative to the current working directory. 55 | 56 | **Note**: *Each script can instead be manually sourced within the TCL console in Vivado. When doing so, take care to properly set the `argv` variable, as described in each scripts' Example Usage subsection* 57 | 58 | -------------- 59 | ## Commands / Scripts 60 | ### Checkout 61 | #### Description 62 | This subcommand calls into checkout.tcl in order to create a Vivado project, in the form of an XPR file, using the sources and scripts contained in the project repository. 63 | #### Optional Arguments 64 | 1. `-r `: Path to the repository directory. Default: `/..` 65 | 1. `-x `: Path to the project .xpr file the repo is to be checked out into. Default: `/proj/.xpr` 66 | 1. `-v `: Vivado version number. Default contained in config.ini. (Python only) 67 | 1. `-b`: Build project after its checked out. Depending on post_build script, may also export files to hw_handoff and/or release directories. 68 | 1. `-no-block`: If -b is specified, exit the script as soon as the build is started. Not available in the Python script. 69 | **Note**: *All paths passed as arguments must either be absolute or relative to the current working directory.* 70 | #### Example Usage 71 | ##### Python: 72 | > `python3 git_vivado.py checkout -r D:/Github/Zybo-Z7/hw` 73 | 74 | ##### TCL: 75 | > `set argv "-r D:/Github/Zybo-Z7/hw"` 76 | 77 | > `source checkout.tcl` 78 | 79 | ----------- 80 | ### Checkin 81 | #### Description 82 | This subcommand calls into checkin.tcl in order to collect sources and generate needed scripts from a Vivado project into the repository structure described below. Files required for checkout *that are not already present* in the repository (such as project_info.tcl and gitignores), are automatically created. These files are not overwritten if they already exist. 83 | #### Optional Arguments 84 | 1. `-r `: Path to the repository directory. Default: `/..` 85 | 1. `-x `: Path to the project .xpr file to be processed for checkin. Default: `/proj/*.xpr` 86 | 1. `-v `: Vivado version number. Default contained in config.ini. (Python only) 87 | 88 | **Note**: *All paths passed as arguments must either be absolute or relative to the current working directory.* 89 | #### Example Usage 90 | ##### Python: 91 | > `python3 git_vivado.py checkin -r D:/Github/Zybo-Z7/hw` 92 | 93 | ##### TCL: 94 | > `set argv "-r D:/Github/Zybo-Z7/hw"` 95 | 96 | > `source checkin.tcl` 97 | 98 | ------------------------------------ 99 | ## Other Files and Overall Structure 100 | ### Configuration File 101 | The digilent-vivado-scripts repository contains a file named `config.ini`. This file contains several values used by the Python frontend to determine what the default arguments for the different subcommands should be. It has not yet been decided how this file should be managed/version-controlled. See *Known Issues* at the bottom of this document for a little more information. 102 | 103 | ### Repository Structure 104 | In order to ensure that any changes to this repository do not break the projects that use them, it is expected that this repository will be used as a submodule of each project repository that is intended to use them. 105 | 106 | * `/scripts`: Submodule containing the scripts described by this document. 107 | * `/hw_handoff`: Used to contain the hardware handoff file. 108 | * `/proj`: Used to contain a checked-out Vivado project, and cached generated sources. 109 | * `/release`: Contains temporary files necessary to generate a release zip archive. 110 | * `/repo`: Contains local IP, IP submodules. 111 | * `/src`: Contains source files for the Vivado Project. 112 | * `/src/bd`: Contains a TCL script used to re-create a block design. 113 | * `/src/constraints`: Contains XDC constraint files. 114 | * `/src/hdl`: Contains Verilog and VHDL source files. 115 | * `/src/ip`: Contains XCI files describing IP to be instantiated in non-IPI projects. 116 | * `/src/others`: Contains all other required sources, such as memory initialization files. 117 | * `/.gitignore`: File describing which sources should be version controlled. Template is generated by the checkin process. 118 | * `/.gitmodules`: File describing submodules of the repository. Automatically maintained by the `git submodule` command. 119 | * `/project_info.tcl`: Script generated by first-time checkin used to save and re-apply project settings like board/part values. This can be modified after initial creation to manually configure settings that are not initially supported. **Note**: *This script should be deleted and recreated when porting a project from one board to another.* 120 | * `/post_build.tcl`: Script generated by first-time checkin that is run after checkout builds. Intended to be used to export handoff and release files. 121 | * `/README.md`: Markdown file describing the project and the process needed to use it, from downloading the release archive, to programming the FPGA. 122 | 123 | ------------ 124 | ## Workflows 125 | 126 | ### 1. Cloning a Repo that uses this Submodule 127 | In a console, first change the working directory (`cd`) to the location you wish to place the local version of the repo you will be cloning. 128 | 129 | Clone the repository from github, using the `--recursive` flag, in order to pick up this and any other submodules installed in the repo. 130 | 131 | * `git clone --recursive ` 132 | 133 | **Important:** *Further example commands in this document assume that the working directory of the console you are running them in has been set to the cloned repo directory: `cd `* 134 | 135 | If the repo was cloned non-recursively, the repo's submodules must be initialized from a console: 136 | 137 | * `git submodule init` 138 | 139 | #### Vivado 140 | Once the repo exists locally, the Vivado project can be checked out from source. To do this, use the following command: 141 | 142 | * `python3 ./digilent-vivado-scripts/git_vivado.py checkout` 143 | 144 | Alternatively, the project can be checked out from within Vivado, by calling the following command in the TCL console: 145 | 146 | * `set argv ""; source ./digilent-vivado-scripts/checkout.tcl` 147 | 148 | Both of these commands create a Vivado project within the repository's `proj` folder. In the case of the Python command, the project then needs to be opened from within Vivado. 149 | 150 | ### 2. Creating a New Project 151 | 1. Create a folder on your computer to hold the project repository. Use the naming convention `--` (for example: `Zybo-Z7-20-DMA`). This folder will be referred to as the "local repo" 152 | 153 | 2. Create a repository on GitHub for your project with Digilent as the owner. Name it the same as the local repo folder. Do not have Github create a README, gitignore file, or license for you. This repository will be referred to as the "remote repo". 154 | 155 | 3. In a command line interface (git bash is recommended) cd into the local repo. Call the following set of commands, in order to initialize the repository, add these scripts to it, and set its remote. 156 | * `git init` 157 | * `git submodule add https://github.com/Digilent/digilent-vivado-scripts` 158 | * `git remote add origin ` 159 | 160 | 4. While creating and developing your project using Vivado, there are a few guidelines to follow: 161 | * When creating the project, make sure to place the Vivado project in a folder named `proj` in the local repo. 162 | * When exporting hardware, make sure to export to the folder named `hw_handoff` in the local repo. 163 | * If IPs or interfaces from [vivado-library](https://github.com/Digilent/vivado-library) are required, create a folder called `repo` in the local repo, and add vivado-library as a submodule within that folder. 164 | 165 | 5. Call the command below. This command can be called from anywhere in your filesystem, with relative paths changed as required. Missing required folders and files are automatically created, including gitignores. **Note:** *Invoking the script in this way uses all default arguments, which assume that the local repo directory structure is used. See* Creating a Repo from a Local Project, *below, for an alternate method.* 166 | * `python3 ./digilent-vivado-scripts/git_vivado.py checkin` 167 | 168 | 6. Create a README for the repo that specifies what the project is supposed to do and how to use a release archive for it. See *Using a Release Archive*, below, and the file `template_README.md` in digilent-vivado-scripts for more information. 169 | 170 | 7. Add, commit, and push your changes to the remote repo: 171 | 172 | * `git add .` 173 | * `git commit -m "Initial Commit"` 174 | * `git push origin master` 175 | 176 | 8. Create and upload a release ZIP to Github - see *Creating a Release Archive* below. 177 | 178 | ---- 179 | ### 3. Creating a Repo from a Local Project 180 | If your new project was not created following the directory structure described in *Creating a New Project*, above, this is the workflow to follow. This flow is a little more in depth. It assumes that a project has already been created. 181 | 182 | 1. Create a repository on GitHub for your project with Digilent as the owner. Name it the same as the local repo folder. Do not have Github create a README, gitignore file, or license for you. This repository will be referred to as the "remote repo". Clone this repository to your computer - the folder where the repository is placed will be referred to as the "local repo". 183 | * `cd ` 184 | * `git clone --recursive ` 185 | 186 | 2. In a command line interface (git bash is recommended) cd into the local repo. Call the following command in order add these scripts to the repository. 187 | * `git submodule add https://github.com/Digilent/digilent-vivado-scripts` 188 | 189 | 3. Use the checkin command of git_vivado.py to check the local project into the local repo, adding required folders, required files, and the projects sources: 190 | * `cd digilent-vivado-scripts` 191 | * `python3 git_vivado.py checkin -x ` 192 | * `cd ..` 193 | 194 | 4. If any changes need to be made to the project during the checkout process, the project_info.tcl generated by the checkin command should be manually edited. 195 | 196 | 5. Create a README for the repo that specifies what the project is supposed to do and how to use a release archive for it. See *Using a Release Archive*, below, and the file `template_README.md` in digilent-vivado-scripts for more information. 197 | 198 | 6. Add, commit, and push your changes to the remote repo: 199 | * `git add .` 200 | * `git commit -m "Initial Commit"` 201 | * `git push origin master` 202 | 203 | 7. Create and upload a release ZIP to Github - see *Creating a Release Archive* below. 204 | 205 | 206 | ---- 207 | ### 4. Making Changes to a Project that uses this Submodule 208 | 1. Clone the Vivado project to be changed. **Note**: *Pull the repo instead, if you already have a local instance of the project.* 209 | * `git clone --recursive ` 210 | 211 | 2. In a command line interface (git bash is recommended for Windows) cd into the local project. 212 | 213 | **NOTE**: Steps 3, 4, and 5 are only required if changes to the Vivado project are required. 214 | 215 | 3. Call the command below. This command can be called from anywhere in your filesystem, with the relative path to git_vivado. This will also create a gitignore file for the repository. Default arguments will create the XPR at `/proj/.xpr`. 216 | * `python3 /git_vivado.py checkout` 217 | 218 | 4. Open the project in Vivado and make any changes necessary (perhaps upgrading IP or fixing a bug). Build the project. Do NOT export hardware yet. 219 | 220 | 5. Call the command below. This command can be called from anywhere in your filesystem, with the relative path to git_vivado changed as required. Default arguments are fine, as they assume the use of the `proj` folder. 221 | * `python3 /git_vivado.py checkin` 222 | 223 | 7. Make sure to update the repo's README as required. 224 | 225 | 8. Add, commit, and push your changes. 226 | * `git add .` 227 | * `git commit -m "Write an informative message here"` 228 | * `git push origin master` 229 | 230 | 9. Export the hardware platform from Vivado into the local repo's `hw_handoff` folder. Commit and push it with the commit message "Export Hardware". 231 | 232 | 10. Create and upload a release ZIP to GitHub - see *Creating a Release Archive* below. 233 | 234 | ---- 235 | ### 5. Creating a Release Archive 236 | 1. If a README has not been created for the repo, first create one. 237 | 238 | 2. Use Vivado's File > Project > Archive menu option to create a release ZIP file for the project. This will package all sources depended on by the project, including IP and board files into a single ZIP, allowing it to be used on a system that does not have these sources previously installed. 239 | 240 | 3. Take the new ZIP archive, and add a minor version number to its name, such that the name follows the pattern: `--.zip` (for example, `Zybo-Z7-20-DMA-2018.2-3.zip`). 241 | 242 | 4. Draft a new release on Github and upload the ZIP to it. Give the release a descriptive title including the name of the project and the tool version number it supports. Use the format `v-` (for example, `v2018.2-3`) for the version tag. Add text specifying the name of the ZIP that the user must download to the release's description field. 243 | 244 | 5. If the project has a software component, review appropriate documentation to release it as well. 245 | 246 | ---- 247 | ### 6. Using Simulations 248 | The checkout script now supports basic checkout of simulation sources. Manual checkin is required. Each set of simulation sources, representing a single simulation and testbench, receives its own folder under the `/src/sim` folder. Any source files, including Verilog, VHDL, and Vivado simulator waveform configuration file (.wcfg), loaded into this folder will be added exclusively to the simulation fileset represented by that folder. All project design sources are available to each simulation set. Importantly, the top module for the simulation fileset is automatically selected based on the suffix "_tb" (like "my_simulation_tb.v") showing up in one of the source file names in the simulation set folder - only one source file should include this suffix per simulation. 249 | 250 | Once checked out, to run any particular simulation: 251 | 252 | - In Vivado, navigate to the Sources tab's Simulation Sources dropdown. 253 | - Right-click on the dropdown for the simulation set of interest (for example, `sim_1`), and select "Make Active". 254 | - In the Flow Navigator, select "Run Simulation >> Run Behavioral Simulation". 255 | - Use simulation controls to navigate through the generated waveforms. 256 | - To run another simulation, simply set it as active and use "Run Behavioral Simulation" again. Once a simulation has been started, it can be rerun using "Relaunch Simulation" in the top bar. 257 | 258 | ---- 259 | ## Known Issues 260 | * Each developer may need their own version of the configuration file, config.ini, for each project they are working on. The configuration file should be moved to somewhere outside of the repo submodule to accomodate this, in a predictable location on Linux and Windows. The Python script will need to be updated to accomodate this, a location and less generic name will need to be chosen for the configuration file. Additional note, requiring that a single Xilinx install directory containing all versions to be used be included in the path may be a better solution. 261 | * There is some danger that modifications to Digilent's board files may break existing projects, it may be worth considering adding the vivado-boards repository as a submodule to project repositories. 262 | * `close_project -delete` does not remove the .sim project directory while simulations are open - to fully clear a `proj` directory for checkout, simulations either need to be manually closed before project deletion, or the leftover files manually deleted after. 263 | -------------------------------------------------------------------------------- /checkin.tcl: -------------------------------------------------------------------------------- 1 | # Note: argument order does not matter when setting argv; all arguments are optional 2 | # Usage (No Defaults): 3 | # set argv "-r -x -v " 4 | # source digilent_vivado_checkin.tcl 5 | # Usage (All Defaults): 6 | # set argv "" 7 | # source digilent_vivado_checkin.tcl 8 | # TODO: add debug flag for argument checking 9 | 10 | set script_dir [file normalize [file dirname [info script]]] 11 | 12 | foreach arg $argv { 13 | puts $arg 14 | } 15 | 16 | # Collect local sources, move them to ../src/ 17 | 18 | # Handle repo_path argument 19 | set idx [lsearch ${argv} "-r"] 20 | if {${idx} != -1} { 21 | set repo_path [glob -nocomplain [file normalize [lindex ${argv} [expr {${idx}+1}]]]] 22 | } else { 23 | # Default 24 | set repo_path [file normalize [file join [file dirname [info script]] ..]] 25 | } 26 | 27 | # Handle xpr_path argument 28 | set idx [lsearch ${argv} "-x"] 29 | if {${idx} != -1} { 30 | set xpr_path [glob -nocomplain [file normalize [lindex ${argv} [expr {${idx}+1}]]]] 31 | } else { 32 | # Default 33 | set xpr_path [glob -nocomplain "${repo_path}/proj/*.xpr"] 34 | } 35 | if {[llength ${xpr_path}] != 1} { 36 | puts "ERROR: XPR not found" 37 | } else { 38 | set xpr_path [lindex ${xpr_path} 0] 39 | } 40 | 41 | # Handle vivado_version argument 42 | set idx [lsearch ${argv} "-v"] 43 | if {${idx} != -1} { 44 | set vivado_version [lindex ${argv}] 45 | } else { 46 | set vivado_version [version -short] 47 | } 48 | 49 | set vivado_version [lindex $argv 2]; # unused 50 | 51 | # Other variables 52 | set force_overwrite_info_script 0; # included for possible argument support in future 53 | set proj_file [file tail $xpr_path] 54 | set proj_dir [file dirname $xpr_path] 55 | set proj_name [file rootname [file tail $proj_file]] 56 | 57 | puts "INFO: Checking project \"$proj_file\" into version control." 58 | set already_opened [get_projects -filter "DIRECTORY==$proj_dir && NAME==$proj_name"] 59 | if {[llength $already_opened] == 0} { 60 | open_project $xpr_path 61 | } else { 62 | current_project [lindex $already_opened 0] 63 | } 64 | 65 | 66 | 67 | set required_dirs [list \ 68 | $repo_path/proj \ 69 | $repo_path/hw_handoff \ 70 | $repo_path/src \ 71 | $repo_path/src/bd \ 72 | $repo_path/src/constraints \ 73 | $repo_path/src/ip \ 74 | $repo_path/src/hdl \ 75 | $repo_path/src/other \ 76 | $repo_path/repo \ 77 | $repo_path/repo/local \ 78 | ] 79 | set required_files [list \ 80 | $repo_path/proj/.keep \ 81 | $repo_path/hw_handoff/.keep \ 82 | $repo_path/src/bd/.keep \ 83 | $repo_path/src/constraints/.keep \ 84 | $repo_path/src/ip/.keep \ 85 | $repo_path/src/hdl/.keep \ 86 | $repo_path/src/other/.keep \ 87 | $repo_path/repo/local/.keep \ 88 | ] 89 | set files [list] 90 | 91 | # Create any missing required directories and files 92 | foreach d $required_dirs { 93 | if {[file exists $d] == 0} { 94 | file mkdir $d 95 | } 96 | } 97 | foreach f $required_files { 98 | if {[file exists $f] == 0} { 99 | close [open $f "w"] 100 | } 101 | } 102 | 103 | # Save source files, including block design tcl script 104 | # WARNING: This script does not capture any non-xdc files for block-design projects 105 | set bd_files [get_files -filter "NAME=~*.bd && NAME!~*/bd/*/ip/*"] 106 | if {[llength $bd_files] > 1} { 107 | puts "ERROR: This script cannot handle projects containing more than one block design!" 108 | } elseif {[llength $bd_files] == 1} { 109 | set bd_file [lindex $bd_files 0] 110 | open_bd_design $bd_file 111 | set bd_name [file tail [file rootname [get_property NAME $bd_file]]] 112 | set script_name "$repo_path/src/bd/${bd_name}.tcl" 113 | puts "INFO: Checking in ${script_name} to version control." 114 | write_bd_tcl -force -no_ip_version -make_local $script_name 115 | # TODO: Add support for "Add Module" IPI features (check in hdl files included in sources_1, but not any ip fileset) 116 | } else { 117 | foreach source_file [get_files -of_objects [get_filesets sources_1]] { 118 | set origin [get_property name $source_file] 119 | set skip 0 120 | if {[file extension $origin] == ".vhd"} { 121 | set subdir hdl 122 | } elseif {[file extension $origin] == ".v"} { 123 | set subdir hdl 124 | } elseif {[file extension $origin] == ".sv"} { 125 | set subdir hdl 126 | } elseif {[file extension $origin] != ".bd" && [file extension $origin] != ".xci"} { 127 | set subdir other 128 | } else { 129 | set skip 1 130 | } 131 | 132 | foreach ip [get_ips] { 133 | set ip_dir [get_property IP_DIR $ip] 134 | set source_length [string length $source_file] 135 | set dir_length [string length $ip_dir] 136 | if {$source_length >= $dir_length && [string range $source_file 0 $dir_length-1] == $ip_dir} { 137 | set skip 1 138 | } 139 | } 140 | 141 | if {$skip == 0} { 142 | puts "INFO: Checking in [file tail $origin] to version control." 143 | set target $repo_path/src/$subdir/[file tail $origin] 144 | if {[file exists $target] == 0} { # TODO: this may not be safe; remind users to make sure to delete any unused files from version control 145 | file copy -force $origin $target 146 | } 147 | } 148 | } 149 | 150 | #Convert each core container back to its original format 151 | foreach ip [get_ips] { 152 | set ip_core_cont [get_property IP_CORE_CONTAINER $ip] 153 | if {[llength ${ip_core_cont}] != 0} { 154 | puts "INFO: Found $ip_core_cont for $ip" 155 | puts "Convert $ip currently in the core container format into the expanded form of the non-core container format" 156 | convert_ips -force -from_core_container [get_files [get_property ip_file $ip]] 157 | } 158 | } 159 | foreach ip [get_ips] { 160 | set origin [get_property ip_file $ip] 161 | set ipname [get_property name $ip] 162 | set dir "$repo_path/src/ip/$ipname" 163 | if {[file exists $dir] == 0} { 164 | file mkdir $dir 165 | } 166 | set target $dir/[file tail $origin] 167 | puts "INFO: Checking in [file tail $origin] to version control." 168 | if {[file exists $target] == 0} { 169 | # TODO: this may not be safe; remind users to make sure to delete any unused files from version control 170 | file copy -force $origin $target 171 | } 172 | } 173 | # TODO: foreach file in /src/ip, if it wasn't just checked in, delete it 174 | } 175 | foreach constraint_file [get_files -of_objects [get_filesets constrs_1]] { 176 | set origin [get_property name $constraint_file] 177 | set target $repo_path/src/constraints/[file tail $origin] 178 | puts "INFO: Checking in [file tail $origin] to version control." 179 | if {[file exists $target] == 0} { # TODO: this may not be safe; remind users to make sure to delete any unused files from version control 180 | file copy -force $origin $target 181 | } 182 | } 183 | # TODO: foreach file in /src/constraints, if it wasn't just checked in, delete it 184 | 185 | # Save project-specific settings into project_info.tcl 186 | # TODO: will break if multiple projects are open 187 | # project_info.tcl will only be created if it doesn't exist - if it has been manually deleted by the user, or if this is the first time this repo is checked in 188 | if {[file exists $repo_path/project_info.tcl] == 0 || $force_overwrite_info_script != 0} { 189 | set proj_obj [get_projects [file rootname $proj_file]] 190 | 191 | set board_part [current_board_part -quiet] 192 | set part [get_property part $proj_obj] 193 | set default_lib [get_property default_lib $proj_obj] 194 | set simulator_language [get_property simulator_language $proj_obj] 195 | set target_language [get_property target_language $proj_obj] 196 | set directives "#Custom directives for synthesis and implementation" 197 | 198 | #Fetch non-default synthesis and implementation settings 199 | foreach prop [list_property [get_runs synth_1] STEPS.*.ARGS.*] { 200 | set Dval [list_property_value -default $prop [get_runs synth_1]] 201 | set val [get_property $prop [get_runs synth_1]] 202 | if {$Dval!=$val} { 203 | append directives "\n\tset_property " $prop " " $val " \[get_runs synth_1\]" 204 | }} 205 | 206 | foreach prop [list_property [get_runs impl_1] STEPS.*.ARGS.*] { 207 | set Dval [list_property_value -default $prop [get_runs impl_1]] 208 | set val [get_property $prop [get_runs impl_1]] 209 | if {$Dval!=$val} { 210 | append directives "\n\tset_property " $prop " " $val " \[get_runs impl_1\]" 211 | }} 212 | 213 | puts "INFO: Checking in project_info.tcl to version control." 214 | 215 | set var_map [list $part \ 216 | $default_lib \ 217 | $simulator_language \ 218 | $target_language \ 219 | $directives \ 220 | ] 221 | 222 | # Even if current_board_part is empty, the replacement must be made, otherwise placeholder will be considered a board name upon checkout 223 | lappend var_map $board_part 224 | 225 | set file_name $repo_path/project_info.tcl 226 | set dfid [open $file_name "w"] 227 | set sfid [open $script_dir/templates/project_info.tcl "r"] 228 | 229 | while { [gets $sfid line] >= 0 } { 230 | puts $dfid [string map $var_map $line] 231 | } 232 | 233 | close $dfid 234 | close $sfid 235 | } 236 | 237 | # if post_build script does not exist, create it 238 | set post_build_script [file join ${repo_path} post_build.tcl] 239 | if {[file exists ${post_build_script}] == 0} { 240 | puts "WARNING: This repository does not contain a post_build script. creating one now." 241 | set target ${post_build_script} 242 | set origin [file join ${script_dir} templates post_build.tcl] 243 | file copy -force ${origin} ${target} 244 | } 245 | 246 | # if .gitignore does not exist, create it 247 | set master_gitignore [file join $repo_path .gitignore] 248 | if {[file exists $master_gitignore] == 0} { 249 | puts "WARNING: This repository does not contain a master gitignore. creating one now." 250 | set target $master_gitignore 251 | set origin $script_dir/templates/hw.gitignore 252 | file copy -force $origin $target 253 | } 254 | 255 | puts "INFO: Project $proj_file has been checked into version control" 256 | -------------------------------------------------------------------------------- /checkout.tcl: -------------------------------------------------------------------------------- 1 | # Note: argument order does not matter when setting argv; all arguments are optional 2 | # Usage (No Defaults): 3 | # set argv "-r -x -v -b -no-block" 4 | # source digilent_vivado_checkout.tcl 5 | # Usage (All Defaults): 6 | # set argv "" 7 | # source digilent_vivado_checkout.tcl 8 | # TODO: add debug flag for argument checking 9 | 10 | # Handle repo_path argument 11 | set idx [lsearch ${argv} "-r"] 12 | if {${idx} != -1} { 13 | set repo_path [glob -nocomplain [file normalize [lindex ${argv} [expr {${idx}+1}]]]] 14 | } else { 15 | # Default 16 | set repo_path [file normalize [file dirname [info script]]/..] 17 | } 18 | 19 | # Handle xpr_path argument 20 | set idx [lsearch ${argv} "-x"] 21 | if {${idx} != -1} { 22 | set xpr_path [file normalize [lindex ${argv} [expr {${idx}+1}]]] 23 | } else { 24 | # Default 25 | set xpr_path [file join ${repo_path} proj [file tail $repo_path]].xpr] 26 | } 27 | 28 | # Handle vivado_version argument 29 | set idx [lsearch ${argv} "-v"] 30 | if {${idx} != -1} { 31 | set vivado_version [lindex ${argv} [expr {${idx}+1}]] 32 | } else { 33 | # Default 34 | set vivado_version [version -short] 35 | } 36 | 37 | # Handle build flag 38 | set idx [lsearch ${argv} "-b"] 39 | if {${idx} != -1} { 40 | set build_when_checked_out 1 41 | } else { 42 | # Default 43 | set build_when_checked_out 0 44 | } 45 | 46 | # Handle no block flag 47 | set idx [lsearch ${argv} "-no-block"] 48 | if {${idx} != -1} { 49 | set wait_on_build 0 50 | } else { 51 | # Default 52 | set wait_on_build 1 53 | } 54 | 55 | # Other variables 56 | set vivado_year [lindex [split $vivado_version "."] 0] 57 | set proj_name [file rootname [file tail $xpr_path]] 58 | 59 | puts "INFO: Creating new project \"$proj_name\" in [file dirname $xpr_path]" 60 | 61 | # Create project 62 | create_project $proj_name [file dirname $xpr_path] 63 | 64 | source $repo_path/project_info.tcl 65 | 66 | # Capture board information for the project 67 | puts "INFO: Capturing board information from $repo_path/project_info.tcl" 68 | set_project_properties_post_create_project $proj_name 69 | set obj [get_projects $proj_name] 70 | set part_name [get_property "part" $obj] 71 | 72 | # Uncomment the following 3 lines to greatly increase build speed while working with IP cores (and/or block diagrams) 73 | puts "INFO: Configuring project IP handling properties" 74 | set_property "corecontainer.enable" "0" $obj 75 | set_property "ip_cache_permissions" "read write" $obj 76 | set_property "ip_output_repo" "[file normalize "$repo_path/proj/cache"]" $obj 77 | 78 | # Create 'sources_1' fileset (if not found) 79 | if {[string equal [get_filesets -quiet sources_1] ""]} { 80 | puts "INFO: Creating sources_1 fileset" 81 | create_fileset -srcset sources_1 82 | } 83 | 84 | # Create 'constrs_1' fileset (if not found) 85 | if {[string equal [get_filesets -quiet constrs_1] ""]} { 86 | puts "INFO: Creating constrs_1 fileset" 87 | create_fileset -constrset constrs_1 88 | } 89 | 90 | # Capture project-specific IP settings 91 | puts "INFO: capturing IP-related settings from $repo_path/project_info.tcl" 92 | set_project_properties_pre_add_repo $proj_name 93 | 94 | # Set IP repository paths 95 | puts "INFO: Setting IP repository paths" 96 | set obj [get_filesets sources_1] 97 | set_property "ip_repo_paths" "[file normalize $repo_path/repo]" $obj 98 | 99 | # Refresh IP Repositories 100 | puts "INFO: Refreshing IP repositories" 101 | update_ip_catalog -rebuild 102 | 103 | # Add hardware description language sources 104 | puts "INFO: Adding HDL sources" 105 | add_files -quiet -norecurse [glob -nocomplain $repo_path/src/hdl/*.v] 106 | add_files -quiet -norecurse [glob -nocomplain $repo_path/src/hdl/*.vhd] 107 | add_files -quiet -norecurse [glob -nocomplain $repo_path/src/hdl/*.sv] 108 | 109 | # Add IPs 110 | # TODO: handle IP core-container files 111 | puts "INFO: Adding XCI IP sources" 112 | add_files -quiet [glob -nocomplain $repo_path/src/ip/*/*.xci] 113 | 114 | # Add constraints 115 | puts "INFO: Adding constraints" 116 | add_files -quiet -norecurse -fileset constrs_1 [glob -nocomplain $repo_path/src/constraints/*.xdc] 117 | 118 | # Recreate block design 119 | # TODO: handle multiple block designs 120 | set ipi_tcl_files [glob -nocomplain "$repo_path/src/bd/*.tcl"] 121 | set ipi_bd_files [glob -nocomplain "$repo_path/src/bd/*/*.bd"] 122 | if {[llength $ipi_tcl_files] > 1} { 123 | # TODO: quit and log the error 124 | puts "ERROR: This script cannot handle projects containing more than one block design! More than one tcl script foudn in src/bd" 125 | } elseif {[llength $ipi_tcl_files] == 1} { 126 | # Use TCL script to rebuild block design 127 | puts "INFO: Rebuilding block design from script" 128 | # Create local source directory for bd 129 | if {[file exist "[file rootname $xpr_path].srcs"] == 0} { 130 | file mkdir "[file rootname $xpr_path].srcs" 131 | } 132 | if {[file exist "[file rootname $xpr_path].srcs/sources_1"] == 0} { 133 | file mkdir "[file rootname $xpr_path].srcs/sources_1" 134 | } 135 | if {[file exist "[file rootname $xpr_path].srcs/sources_1/bd"] == 0} { 136 | file mkdir "[file rootname $xpr_path].srcs/sources_1/bd" 137 | } 138 | # Force Non-Remote BD Flow 139 | set origin_dir [pwd] 140 | cd "[file rootname $xpr_path].srcs/sources_1" 141 | set run_remote_bd_flow 0 142 | if {[set result [catch { source [lindex $ipi_tcl_files 0] } resulttext]]} { 143 | # remember global error state 144 | set einfo $::errorInfo 145 | set ecode $::errorCode 146 | catch {cd $origin_dir} 147 | return -code $result -errorcode $ecode -errorinfo $einfo $resulttext 148 | } 149 | cd $origin_dir 150 | } elseif {[llength $ipi_bd_files] > 1} { 151 | # TODO: quit and log the error 152 | puts "ERROR: This script cannot handle projects containing more than one block design! More than one bd file foudn in src/bd" 153 | } elseif {[llength $ipi_bd_files] == 1} { 154 | # Add block design from .bd file and sources 155 | puts "INFO: Rebuilding block design from BD fileset" 156 | add_files -norecurse -quiet -fileset sources_1 [glob -nocomplain $repo_path/src/bd/*/*.bd] 157 | open_bd_design [glob -nocomplain $repo_path/src/bd/*/*.bd] 158 | set design_name [get_bd_designs] 159 | set file "$repo_path/src/bd/$design_name/$design_name.bd" 160 | set file [file normalize $file] 161 | set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] 162 | if { ![get_property "is_locked" $file_obj] } { 163 | set_property "synth_checkpoint_mode" "Hierarchical" $file_obj 164 | } 165 | } 166 | 167 | # Make sure IPs are upgraded to the most recent version 168 | foreach ip [get_ips -filter "IS_LOCKED==1"] { 169 | upgrade_ip -vlnv [get_property UPGRADE_VERSIONS $ip] $ip 170 | export_ip_user_files -of_objects $ip -no_script -sync -force -quiet 171 | } 172 | 173 | # Generate the wrapper for the root design 174 | catch { 175 | # catch block prevents projects without a block design from erroring at this step 176 | set bd_name [get_bd_designs -of_objects [get_bd_cells /]] 177 | set bd_file [get_files $bd_name.bd] 178 | set wrapper_file [make_wrapper -files $bd_file -top -force] 179 | import_files -quiet -force -norecurse $wrapper_file 180 | 181 | set obj [get_filesets sources_1] 182 | set_property "top" "${bd_name}_wrapper" $obj 183 | } 184 | 185 | # Create 'synth_1' run (if not found) 186 | if {[string equal [get_runs -quiet synth_1] ""]} { 187 | puts "INFO: Creating synth_1 run" 188 | create_run -name synth_1 -part $part_name -flow {Vivado Synthesis $vivado_year} -strategy "Vivado Synthesis Defaults" -constrset constrs_1 189 | } else { 190 | set_property strategy "Vivado Synthesis Defaults" [get_runs synth_1] 191 | set_property flow "Vivado Synthesis $vivado_year" [get_runs synth_1] 192 | } 193 | puts "INFO: Configuring synth_1 run" 194 | set obj [get_runs synth_1] 195 | set_property "part" $part_name $obj 196 | 197 | # Set the current synth run 198 | puts "INFO: Setting current synthesis run" 199 | current_run -synthesis [get_runs synth_1] 200 | 201 | # Create 'impl_1' run (if not found) 202 | if {[string equal [get_runs -quiet impl_1] ""]} { 203 | puts "INFO: Creating impl_1 run" 204 | create_run -name impl_1 -part $part_name -flow {Vivado Implementation $vivado_year} -strategy "Vivado Implementation Defaults" -constrset constrs_1 -parent_run synth_1 205 | } else { 206 | set_property strategy "Vivado Implementation Defaults" [get_runs impl_1] 207 | set_property flow "Vivado Implementation $vivado_year" [get_runs impl_1] 208 | } 209 | puts "INFO: Configuring impl_1 run" 210 | set obj [get_runs impl_1] 211 | set_property "part" $part_name $obj 212 | 213 | # Set the current impl run 214 | puts "INFO: Setting current implementation run" 215 | current_run -implementation [get_runs impl_1] 216 | 217 | # Capture project-specific IP settings 218 | puts "INFO: capturing run settings from $repo_path/project_info.tcl" 219 | set_project_properties_post_create_runs $proj_name 220 | 221 | # Import source files for simulation 222 | set sim_dirs [glob -nocomplain -type d $repo_path/src/sim/*] 223 | foreach sim_dir $sim_dirs { 224 | set sim_name [file tail $sim_dir] 225 | # Note: sim_1 already exists in a fresh project, testing for existance and only creating when a name is not found helps avoid an error 226 | if {[get_fileset $sim_name] == ""} { 227 | puts "INFO: Simulation set $sim_name does not exist, creating it" 228 | create_fileset -simset $sim_name 229 | } 230 | set_property SOURCE_SET sources_1 [get_filesets $sim_name] 231 | set top_found 0 232 | foreach source_file [glob -nocomplain -type f $sim_dir/*] { 233 | add_files -quiet -fileset $sim_name -norecurse $source_file 234 | set module_name [file tail [file rootname $source_file]] 235 | puts "INFO: Imported $source_file for $sim_name" 236 | if {[string range $module_name end-2 end] == "_tb"} { 237 | update_compile_order -fileset $sim_name 238 | set_property top $module_name [get_filesets $sim_name] 239 | puts "INFO: Picked $module_name as top-level testbench for $sim_name" 240 | set top_found 1 241 | } 242 | } 243 | if {$top_found == 0} { 244 | puts "WARNING: No testbench (identified by suffix _tb) found in simulation set $sim_name" 245 | } 246 | set_property top_lib xil_defaultlib [get_filesets $sim_name] 247 | update_compile_order -fileset $sim_name 248 | } 249 | 250 | # Get the post_build script path 251 | set post_build_script_path [file join ${repo_path} post_build.tcl] 252 | set post_build_script [glob -nocomplain ${post_build_script_path}] 253 | 254 | # Launch a build if -b was specified 255 | if {${build_when_checked_out}} { 256 | launch_runs -to_step write_bitstream impl_1 257 | # Wait until the project has been built if -no-block wasn't specified 258 | if {${wait_on_build}} { 259 | wait_on_run impl_1 260 | puts "INFO: Build complete" 261 | 262 | # If it exists, run the post_build script. This can be used to export 263 | if {${post_build_script} ne ""} { 264 | source ${post_build_script} 265 | } else { 266 | puts "INFO: No post_build script found" 267 | } 268 | } else { 269 | if {${post_build_script} ne ""} { 270 | puts "WARNING: Build launched but ${post_build_script} has not been run" 271 | puts " After the bitstream has been generated, run the command 'source ${post_build_script}'" 272 | } else { 273 | puts "INFO: No post_build script found" 274 | } 275 | } 276 | } 277 | 278 | puts "INFO: Project created: [file tail $proj_name]" 279 | puts "INFO: Exiting digilent_vivado_checkout" -------------------------------------------------------------------------------- /config.ini: -------------------------------------------------------------------------------- 1 | [Windows] 2 | VivadoInstallPath = D:/Xilinx/Vivado 3 | VivadoVersion = 2020.1 4 | XsctFile = xsct.bat 5 | [Linux] 6 | VivadoInstallPath = /opt/Xilinx/Vivado 7 | VivadoVersion = 2020.1 8 | XsctFile = xsct -------------------------------------------------------------------------------- /git_vivado.py: -------------------------------------------------------------------------------- 1 | # PYTHON 3.X.X REQUIRED!!! 2 | 3 | import os 4 | import sys 5 | import configparser 6 | import argparse 7 | import platform 8 | 9 | def accept_warning(s): 10 | c = '' 11 | d = {'Y': True, 'y': True, 'N': False, 'n': False} 12 | while c not in d: 13 | c = input('Warning: %s Y/N? ' % s) 14 | return d[c] 15 | 16 | def do_checkin(args): 17 | DEBUG_NO_VIVADO = args['DEBUG_NO_VIVADO'] 18 | DEBUG_VIVADO_TCL_TRACE = args['DEBUG_VIVADO_TCL_TRACE'] 19 | 20 | vivado_cmd = args['vivado_cmd'].replace('\\', '/') 21 | script_path = os.path.join(args['script_dir'], 'checkin.tcl').replace('\\', '/') 22 | xpr_path = args['xpr_path'].replace('\\', '/') 23 | repo_path = args['repo_path'].replace('\\', '/') 24 | version = args['version'].replace('\\', '/') 25 | 26 | if not args['force'] and not accept_warning('Files and directories contained in %s may be overwritten. Do you wish to continue?' % repo_path): 27 | sys.exit() 28 | 29 | print('Checking in project %s to repo %s' % (os.path.basename(xpr_path), os.path.basename(repo_path))) 30 | 31 | if DEBUG_NO_VIVADO: 32 | print ('vivado_cmd: %s' % vivado_cmd) 33 | print ('script_path: %s' % script_path) 34 | print ('xpr_path: %s' % xpr_path) 35 | print ('repo_path: %s' % repo_path) 36 | print ('version: %s' % version) 37 | else: 38 | notrace = '' if DEBUG_VIVADO_TCL_TRACE else ' -notrace' 39 | os.system("%s -mode batch -source %s%s -tclargs -x %s -r %s -v %s" % (vivado_cmd, script_path, notrace, xpr_path, repo_path, version)) 40 | 41 | def do_checkout(args): 42 | DEBUG_NO_VIVADO = args['DEBUG_NO_VIVADO'] 43 | DEBUG_VIVADO_TCL_TRACE = args['DEBUG_VIVADO_TCL_TRACE'] 44 | 45 | vivado_cmd = args['vivado_cmd'].replace('\\', '/') 46 | script_path = os.path.join(args['script_dir'], 'checkout.tcl').replace('\\', '/') 47 | xpr_path = args['xpr_path'].replace('\\', '/') 48 | repo_path = args['repo_path'].replace('\\', '/') 49 | version = args['version'].replace('\\', '/') 50 | build = args['build'] 51 | 52 | if not args['force'] and not accept_warning('Files and directories contained in %s may be overwritten. Do you wish to continue?' % os.path.dirname(xpr_path)): 53 | sys.exit() 54 | 55 | print('Checking out project %s from repo %s' % (os.path.basename(xpr_path), os.path.basename(repo_path))) 56 | notrace = '' if DEBUG_VIVADO_TCL_TRACE else ' -notrace' 57 | cmd = "%s -mode batch -source %s%s -tclargs -x %s -r %s -v %s%s" % ( 58 | vivado_cmd, 59 | script_path, 60 | notrace, 61 | # arguments 62 | xpr_path, 63 | repo_path, 64 | version, 65 | ' -b' if build else '' 66 | ) 67 | if DEBUG_NO_VIVADO: 68 | print ('vivado_cmd: %s' % vivado_cmd) 69 | print ('script_path: %s' % script_path) 70 | print ('xpr_path: %s' % xpr_path) 71 | print ('repo_path: %s' % repo_path) 72 | print ('version: %s' % version) 73 | print ('build: %s' % build) 74 | print(cmd) 75 | else: 76 | os.system(cmd) 77 | 78 | if __name__ == "__main__": 79 | # Parse CONFIG.INI 80 | script_dir = os.path.dirname(os.path.abspath(sys.argv[0])) 81 | project_name = os.path.basename(os.path.abspath(os.path.join(script_dir, '..'))) 82 | config = configparser.ConfigParser() 83 | config.read(os.path.join(script_dir, "config.ini")) 84 | operating_system = platform.system() 85 | config_settings = config[operating_system] 86 | 87 | # Default arguments assume that this script is contained in a submodule within the target repository 88 | default_repo_path = os.path.abspath(os.path.join(script_dir, '..')) 89 | default_xpr_path = os.path.abspath(os.path.join(script_dir, '..', 'proj', '%s.xpr' % project_name)) 90 | default_version = config_settings['VivadoVersion'] 91 | 92 | # Parse SYS.ARGV 93 | parser = argparse.ArgumentParser(description='Handles vivado project git repo operations') 94 | parser.add_argument( 95 | '-f', 96 | dest='force', 97 | default=False, 98 | action='store_true', 99 | help='Force overwrite of existing files and folders' 100 | ) 101 | subparsers = parser.add_subparsers(help='sub-command help') 102 | 103 | # Checkin Arguments 104 | parser_checkin = subparsers.add_parser( 105 | 'checkin', 106 | help='Checks in XPR to REPO', 107 | formatter_class=argparse.RawTextHelpFormatter 108 | ) 109 | parser_checkin.set_defaults(func=do_checkin) 110 | # Optional Args 111 | parser_checkin.add_argument( 112 | '-r', 113 | dest='repo_path', 114 | type=str, 115 | default=default_repo_path, 116 | help='Path to target repository from\nDefault = %s' % (default_repo_path) 117 | ) 118 | parser_checkin.add_argument( 119 | '-x', 120 | dest='xpr_path', 121 | type=str, 122 | default=default_xpr_path, 123 | help='Path to XPR file\nDefault = %s' % (default_xpr_path) 124 | ) 125 | parser_checkin.add_argument( 126 | '-v', 127 | dest='version', 128 | type=str, 129 | default=default_version, 130 | help='Vivado version number 20##.#\nDefault = %s' % (default_version) 131 | ) 132 | 133 | # Checkout Arguments 134 | parser_checkout = subparsers.add_parser( 135 | 'checkout', 136 | help='Checks out XPR from REPO', 137 | formatter_class=argparse.RawTextHelpFormatter 138 | ) 139 | parser_checkout.set_defaults(func=do_checkout) 140 | # Optional Args 141 | parser_checkout.add_argument( 142 | '-r', 143 | dest='repo_path', 144 | type=str, 145 | default=default_repo_path, 146 | help='Path to target repository from\nDefault = %s' % (default_repo_path) 147 | ) 148 | parser_checkout.add_argument( 149 | '-x', 150 | dest='xpr_path', 151 | type=str, 152 | default=default_xpr_path, 153 | help='Path to XPR file\nDefault = %s' % (default_xpr_path) 154 | ) 155 | parser_checkout.add_argument( 156 | '-v', 157 | dest='version', 158 | type=str, 159 | default=default_version, 160 | help='Vivado version number 20##.#\nDefault = %s' % (default_version) 161 | ) 162 | parser_checkout.add_argument( 163 | '-b', 164 | dest='build', 165 | default=False, 166 | action='store_true', 167 | help='Build the project after checkout\nDefault = false' 168 | ) 169 | 170 | # Parse Arguments 171 | args = parser.parse_args() 172 | 173 | funcargs = {'script_dir': script_dir} 174 | 175 | if not hasattr(args, 'func'): 176 | print("Please select a subcommand to execute. See this command's help page") 177 | sys.exit() 178 | 179 | if hasattr(args, 'force'): 180 | funcargs['force'] = args.force 181 | 182 | if hasattr(args, 'build'): 183 | funcargs['build'] = args.build 184 | 185 | if hasattr(args, 'repo_path'): 186 | funcargs['repo_path'] = os.path.abspath(os.path.join(os.getcwd(), args.repo_path)) 187 | 188 | if hasattr(args, 'xpr_path'): 189 | if args.xpr_path[-4:] != '.xpr': 190 | print('Error: xpr_path argument must end in .xpr') 191 | sys.exit() 192 | funcargs['xpr_path'] = os.path.abspath(os.path.join(os.getcwd(), args.xpr_path)) 193 | if args.func == do_checkout and os.path.isfile(funcargs['xpr_path']) or os.path.isdir(funcargs['xpr_path']): 194 | # TODO: add warning about overwriting existing project 195 | # TODO: add clean and overwrite process 196 | # TODO: move project_info.tcl to repo root 197 | print('Error: cannot check out repo when project exists; Please clean out the %s/proj directory' % (funcargs['repo_path'])) 198 | sys.exit() 199 | 200 | if hasattr(args, 'version'): 201 | funcargs['vivado_cmd'] = os.path.join(os.path.abspath(config_settings['VivadoInstallPath']), args.version, 'bin', 'vivado') 202 | funcargs['version'] = args.version 203 | if not os.path.isfile(funcargs['vivado_cmd']): 204 | print('Error: Vivado not installed at %s' % funcargs['vivado_cmd']) 205 | sys.exit() 206 | 207 | if hasattr(args, 'temp_directory'): 208 | funcargs['temp_directory'] = args.temp_directory 209 | 210 | DEBUG_NO_VIVADO = False 211 | DEBUG_VIVADO_TCL_TRACE = False 212 | funcargs['DEBUG_NO_VIVADO'] = DEBUG_NO_VIVADO 213 | funcargs['DEBUG_VIVADO_TCL_TRACE'] = DEBUG_VIVADO_TCL_TRACE 214 | 215 | args.func(funcargs) 216 | -------------------------------------------------------------------------------- /templates/hw.gitignore: -------------------------------------------------------------------------------- 1 | # This is a gitignore file automatically generated by digilent_vivado_checkin.tcl 2 | # The file will not be overwritten unless deleted 3 | 4 | # root 5 | /* 6 | !.gitignore 7 | !README.md 8 | !LICENSE 9 | !project_info.tcl 10 | !post_build.tcl 11 | !proj/ 12 | !repo/ 13 | !src/ 14 | !scripts/ 15 | !hw_handoff/ 16 | 17 | # vivado workspace 18 | proj/* 19 | 20 | # ip repository 21 | repo/** 22 | !repo/vivado-library 23 | repo/vivado-library/** 24 | !repo/local 25 | !repo/local/** 26 | !repo/cache 27 | repo/cache/** 28 | 29 | # version controlled sources 30 | src/** 31 | !src/bd 32 | src/bd/** 33 | !src/bd/*.tcl 34 | !src/constraints 35 | src/constraints/** 36 | !src/constraints/*.xdc 37 | !src/hdl 38 | src/hdl/** 39 | !src/hdl/*.v 40 | !src/hdl/*.sv 41 | !src/hdl/*.vhd 42 | !src/ip 43 | !src/ip/* 44 | src/ip/*/** 45 | !src/ip/**/*.xci 46 | !src/other 47 | !src/other/** 48 | !src/sim 49 | !src/sim/** 50 | 51 | # hardware handoff 52 | hw_handoff/* 53 | !hw_handoff/*.xsa 54 | 55 | # maintain required directories 56 | !**/.keep -------------------------------------------------------------------------------- /templates/post_build.tcl: -------------------------------------------------------------------------------- 1 | set script_dir [file dirname [file normalize [info script]]] 2 | 3 | # This script does nothing by default, edit it in your project repo to add functionality. 4 | # Several comment blocks with examples can be seen below. Customize them as needed. 5 | puts "INFO: Running [info script]" 6 | puts " This script is a stub. Nothing happened." 7 | 8 | 9 | # # Exporting a bitstream for a hw-only project: 10 | # puts "INFO: Running [info script]" 11 | # puts [get_property directory [current_run]]; # impl_1 12 | # set impl_dir [file join ${script_dir} proj *.runs impl_1] 13 | # set src [glob [file join ${impl_dir} *.bit]] 14 | # set release_dir [file join ${script_dir} release] 15 | # if {[file exists ${release_dir}] == 0} {file mkdir ${release_dir}} 16 | # set dst [file join ${release_dir} [file tail ${src}]] 17 | # file copy -force ${src} ${dst} 18 | # puts "INFO: Wrote out bitstream file ${dst}" 19 | 20 | 21 | # # Exporting an xsa for a project with sw: 22 | # puts "INFO: Running [info script]" 23 | # set top_module [get_property top [get_filesets sources_1]] 24 | # set handoff_dir [file join ${script_dir} hw_handoff] 25 | # if {[file exists ${handoff_dir}] == 0} {file mkdir ${handoff_dir}} 26 | # set xsa_file [file join ${handoff_dir} ${top_module}.xsa] 27 | # write_hw_platform -fixed -include_bit -force -file ${xsa_file} 28 | # puts "INFO: Wrote out xsa file ${xsa_file}" 29 | 30 | 31 | # # Generate a release ZIP file for any project: 32 | # set proj_name [get_property name [current_project]] 33 | # set release_dir [file join ${script_dir} release] 34 | # if {[file exists ${release_dir}] == 0} {file mkdir ${release_dir}} 35 | # set zip_file [file join ${release_dir} ${proj_name}.xpr.zip] 36 | # set temp_dir [file join ${script_dir} temp] 37 | # archive_project ${zip_file} -temp_dir ${temp_dir} -force -include_local_ip_cache 38 | # puts "INFO: Wrote out project release archive ${zip_file}" -------------------------------------------------------------------------------- /templates/project_info.tcl: -------------------------------------------------------------------------------- 1 | # This is an automatically generated file used by digilent_vivado_checkout.tcl to set project options 2 | proc set_project_properties_post_create_project {proj_name} { 3 | set project_obj [get_projects $proj_name] 4 | set_property "part" "" $project_obj 5 | set_property "board_part" "" $project_obj 6 | set_property "default_lib" "" $project_obj 7 | set_property "simulator_language" "" $project_obj 8 | set_property "target_language" "" $project_obj 9 | } 10 | 11 | proc set_project_properties_pre_add_repo {proj_name} { 12 | set project_obj [get_projects $proj_name] 13 | # default nothing 14 | } 15 | 16 | proc set_project_properties_post_create_runs {proj_name} { 17 | set project_obj [get_projects $proj_name] 18 | 19 | } 20 | --------------------------------------------------------------------------------