Skip to content

Instantly share code, notes, and snippets.

@abeln94
Last active June 26, 2023 17:55
Show Gist options
  • Save abeln94/153391e545934ed8cde2e796dd9bf7b5 to your computer and use it in GitHub Desktop.
Save abeln94/153391e545934ed8cde2e796dd9bf7b5 to your computer and use it in GitHub Desktop.
FPGA tools

Tools

These tools have been designed to work with pynq_z2 boards.

A (video) demo of them is available here.

FPGA Manager

A bat->powershell script to enable/disable the boards. Allows programming them too, but it's slow.

FPGA Programmer

A bat->powershell->tcl script to program all boards. No interface is available.

FPGA device tool

In https://github.com/abeln94/fpga-device-tool

A python app to enable/disable/program the boards.

@echo off
REM MIT License
REM Copyright (c) 2023 Abel Naya
REM Permission is hereby granted, free of charge, to any person obtaining a copy
REM of this software and associated documentation files (the "Software"), to deal
REM in the Software without restriction, including without limitation the rights
REM to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
REM copies of the Software, and to permit persons to whom the Software is
REM furnished to do so, subject to the following conditions:
REM The above copyright notice and this permission notice shall be included in all
REM copies or substantial portions of the Software.
REM THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
REM IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
REM FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
REM AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
REM LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
REM OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
REM SOFTWARE
START powershell -noprofile -command " Write-Host Asking for admin permissions...; Start-Process Powershell -Verb RunAs -ArgumentList ' cd ''%~dp0''; Invoke-Expression (Get-Content -Path ''%0'' -Delimiter ''START_OF_POWERSHELL_SCRIPT'')[2] ' "
goto:eof
The text above is bat(ch) that calls powershell to run as admin, the text below is powershell that will be run afterwards
START_OF_POWERSHELL_SCRIPT
Write-Host Initializing...
$pwd | Write-Host
# parameters
$padding = 5
$height = 25
$width = 500
$separation = 0
# init form
Add-Type -assembly System.Windows.Forms
$form = New-Object System.Windows.Forms.Form
$form.Text ='Device enabler tool'
$form.FormBorderStyle = 'FixedDialog'
$form.width=0
# init VIVADO
$Vivado = Get-ChildItem -Path "C:/Xilinx/Vivado/" | ForEach-Object { "C:/Xilinx/Vivado/$_/bin/vivado.bat" } | Where-Object { Test-Path $_ } | Select-Object -First 1
Write-Host "Vivado detected: $Vivado"
# init picker
$FileBrowser = New-Object System.Windows.Forms.OpenFileDialog
$FileBrowser.Title = "Choose bitstream"
$FileBrowser.Filter = 'Bitstream|*.bit|All|*.*'
$FileBrowser.RestoreDirectory = $false
# init console manager
Add-Type -Name Window -Namespace Console -MemberDefinition '
[DllImport("Kernel32.dll")]
public static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);
[DllImport("user32.dll")]
public static extern bool IsZoomed(IntPtr hWnd);
';
$PSConsole = [Console.Window]::GetConsoleWindow()
$PSConsole | Add-Member -NotePropertyName Visible -NotePropertyValue $false
$form.Add_Shown({
[Console.Window]::ShowWindow($PSConsole, 0)
$PSConsole.Visible = $false
}.GetNewClosure())
# main function
function UpdateForm { $xUpdateForm = Get-Item function:UpdateForm
# clear
$form.Controls.Clear()
# define function to add buttons
function AddButton ($text, $listener) {
$button = New-Object System.Windows.Forms.Button
$button.Location = New-Object System.Drawing.Size(
($padding + ($form.Controls.Count % 2)*($width/2+$padding)),
([int][Math]::Floor($form.Controls.Count/2)*($height + $padding)+ $separation)
)
$button.Size = New-Object System.Drawing.Size(($width/2), $height)
$button.Text = $text
$button.Add_Click({& $listener $button}.GetNewClosure())
$form.Controls.Add($button)
}
# get devices
$nl = [System.Environment]::NewLine
$ids = ((pnputil /enum-devices /class USB /connected | Out-String) -split $nl + $nl) | Select-Object -Skip 1 | ForEach-Object {
$lines = $_ -split $nl
[pscustomobject] @{
id = ($lines[0] -split ': *')[1]
deviceDescription = ($lines[1] -split ': *')[1]
status = ($lines[5] -split ': *')[1]
}
} | Where-Object {
$_.deviceDescription -eq 'USB Serial Converter A' #'USB Composite Device'
} | ForEach-Object {
if($_.status -eq 'started'){ $_.status = 'Enabled'}
if($_.status -eq 'Iniciado'){ $_.status = 'Enabled'}
$_ | Add-Member -NotePropertyName name -NotePropertyValue ($_.id -split '\\')[2]
$_
}
# define function to enable only a particular device
$enableOnly = { param($id, $button)
# enable that device
$button.Text = "Enabling... (1/$($ids.length))"
Write-Host "Enabling $id"
pnputil /enable-device $id
# disable the rest
$ids | ForEach-Object { $_.id } | Where-Object { $_ -ne $id } | ForEach-Object {$i=2} {
$button.Text = "Disabling... ($i/$($ids.length))"
Write-Host "Disabling $_"
pnputil /disable-device $_
$i++
}
}.GetNewClosure()
# define function to enable all devices
$enableAll = { param($button)
$ids | ForEach-Object { $_.id } | ForEach-Object {$i=1} {
$button.Text = "Enabling... ($i/$($ids.length))"
Write-Host "Enabling $_"
pnputil /enable-device $_
$i++
}
}.GetNewClosure()
#####################################
# button to refresh ui
AddButton 'Refresh' $xUpdateForm
# button to program all devices with bitfile
AddButton "Program bitstream" { param($button)
if($FileBrowser.ShowDialog() -ne "OK") { return }
Write-Host $FileBrowser.FileName
$button.Text = 'Running...'
# program each one
$ids | ForEach-Object { $_.id } | ForEach-Object {$i=1} {
& $enableOnly $_ $button
$button.Text = "Programming... ($i/$($ids.length))"
Write-Host "Starting FPGA_programmer"
(Get-Content -Path './FPGA_programmer.bat' -Delimiter 'START_OF_TCL_SCRIPT')[2] | & $Vivado -mode tcl -nolog -nojournal -verbose -tclargs $FileBrowser.FileName -only | ForEach-Object{ " > $_" } | Write-Host
Write-Host 'Done'
$i++
}
& $enableAll $button
& $xUpdateForm
}.GetNewClosure()
# add a button to enable all devices
AddButton "Enable all ($($ids.length))" { param($button)
& $enableAll $button
& $xUpdateForm
}.GetNewClosure()
# button to toggle console visibility
$GetVisibilityName = {
if ( $PSConsole.Visible ) {
return "Hide console"
} else {
return "Show console"
}
}.GetNewClosure()
AddButton (& $GetVisibilityName) { param($button)
if ( $PSConsole.Visible ) {
[Console.Window]::ShowWindow($PSConsole, 0)
} else {
[Console.Window]::ShowWindow($PSConsole, 5)
}
$PSConsole.Visible = !$PSConsole.Visible
$button.Text = (& $GetVisibilityName)
}.GetNewClosure()
# divider
$separation += ($padding*4)
# add a button for each device (to enable that one)
$ids | ForEach-Object {
$id = $_.id
AddButton "[$($_.status)] Enable $($_.name) only" { param($button)
& $enableOnly $id $button
& $xUpdateForm
}.GetNewClosure()
}
$form.height=0
$form.AutoSize = $true
$Form.StartPosition = 'CenterScreen'
}
UpdateForm
Write-Host Ready
$form.showdialog()
@echo off
REM MIT License
REM Copyright (c) 2023 Abel Naya
REM Permission is hereby granted, free of charge, to any person obtaining a copy
REM of this software and associated documentation files (the "Software"), to deal
REM in the Software without restriction, including without limitation the rights
REM to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
REM copies of the Software, and to permit persons to whom the Software is
REM furnished to do so, subject to the following conditions:
REM The above copyright notice and this permission notice shall be included in all
REM copies or substantial portions of the Software.
REM THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
REM IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
REM FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
REM AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
REM LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
REM OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
REM SOFTWARE
START powershell -noprofile -command " Write-Host Asking for admin permissions...; Start-Process Powershell -Verb RunAs -ArgumentList ' cd ''%~dp0''; $SCRIPT = ''%~f0''; $ARGUMENTS = ''%*''; Invoke-Expression (Get-Content -Path $SCRIPT -Delimiter ''POWERSHELL_SCRIPT_DELIMITER'')[2] ' "
goto:eof
The text above is bat(ch) that calls powershell to run as admin, the text below is powershell that will be run afterwards.
POWERSHELL_SCRIPT_DELIMITER
# Find Vivado
$Vivado = Get-ChildItem -Path "C:/Xilinx/Vivado/" | ForEach-Object { "C:/Xilinx/Vivado/$_/bin/vivado.bat" } | Where-Object { Test-Path $_ } | Select-Object -First 1
Write-Host "Vivado detected: $Vivado"
if (!$ARGUMENTS) {
# choose bitstream if not provided
Add-Type -assembly System.Windows.Forms
$FileBrowser = New-Object System.Windows.Forms.OpenFileDialog
$FileBrowser.Title = "Choose bitstream"
$FileBrowser.Filter = 'Bitstream|*.bit|All|*.*'
$FileBrowser.RestoreDirectory = $false
if($FileBrowser.ShowDialog() -ne "OK") { exit }
$ARGUMENTS = $FileBrowser.FileName
}
# launch
(Get-Content -Path $SCRIPT -Delimiter "START_OF_TCL_SCRIPT")[2] | & $Vivado -mode tcl -nolog -nojournal -verbose -tclargs $ARGUMENTS
# pause unless flag
if ($ARGUMENTS -inotmatch "-nowait") {pause}
#POWERSHELL_SCRIPT_DELIMITER
The text above is powershell, the text below is TCL that will be run in Vivado.
START_OF_TCL_SCRIPT
proc sleep {time_ms} {
global slep_vwait_var
set slep_vwait_var 0
after $time_ms set slep_vwait_var 1
vwait slep_vwait_var
}
# get bitstream file
set bitfile [lindex $argv 0]
if { [file exists $bitfile] == 1 } {
puts "Using bitfile $bitfile"
} else {
puts "No bitfile $bitfile"
puts ""
quit
}
proc getDevices {} {
set ids {}
# USB Serial Converter A
# USB Composite Device
foreach {full id} [regexp -all -inline { *[^:]+: *([^\n]+)\n *[^:]+: *USB Serial Converter A} [exec pnputil /enum-devices /class USB /connected]] {
lappend ids $id
}
return $ids
}
proc configureDevice {id state {retry 0}} {
if { [catch {exec pnputil [expr $state ? "{/enable-device}" : "{/disable-device}"] $id} error] } {
puts "Unable to switch the state of the device: $error"
if { $retry < 50 } {
sleep 1000
incr retry
puts "Retrying $retry/50"
configureDevice $id $state $retry
}
}
}
proc program {{retry 0}} {
global hw_device
if { [catch {program_hw_devices $hw_device} error] } {
puts "Unable to program the hw_device: $error"
if { $retry < 50 } {
sleep 1000
incr retry
puts "Retrying $retry/50"
program $retry
}
}
}
proc initialize {} {
global bitfile
global hw_device
if {[info exists hw_device]} { return }
# initialize hardware manager
load_features labtools
if { [catch {open_hw_manager} error] } { open_hw }
connect_hw_server -url TCP:localhost:3121
# connect to first available target
set targu [get_hw_targets *]
current_hw_target $targu
open_hw_target
set hw_device [lindex [get_hw_devices] 1]
current_hw_device $hw_device
# configure program
set_property PROGRAM.FILE $bitfile $hw_device
# if ila included: set_property PROBES.FILE {C:/design.ltx} $hw_device
}
if {[lsearch $argv "-only"] > 0} {
# program existing
puts "Programming existing board"
initialize
program
puts ""
quit
}
# program all
set devices [getDevices]
set devices_length [llength $devices]
puts "Programming $devices_length devices..."
set device_index 1
foreach {selected} $devices {
puts "Programming board $selected ($device_index / $devices_length)..."
puts "Enabling"
configureDevice $selected 1
foreach {other} $devices {
if {[string equal $selected $other] == 0} {
puts "Disabling $other"
configureDevice $other 0
}
}
sleep 500
puts "Programming..."
initialize
program
puts "...Done"
puts ""
}
foreach {selected} $devices {
puts "Enabling $selected"
configureDevice $selected 1
}
puts ""
quit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment