xilinx-provision 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.project ADDED
@@ -0,0 +1,17 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <projectDescription>
3
+ <name>xilinx-provision</name>
4
+ <comment></comment>
5
+ <projects>
6
+ </projects>
7
+ <buildSpec>
8
+ <buildCommand>
9
+ <name>com.aptana.ide.core.unifiedBuilder</name>
10
+ <arguments>
11
+ </arguments>
12
+ </buildCommand>
13
+ </buildSpec>
14
+ <natures>
15
+ <nature>com.aptana.ruby.core.rubynature</nature>
16
+ </natures>
17
+ </projectDescription>
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source 'http://rubygems.org'
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem 'activesupport', '>= 2.3.5'
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem 'rdoc', '>= 3.6.1'
10
+ gem 'rspec', '~> 2.6.0'
11
+ gem 'bundler', '~> 1.0.14'
12
+ gem 'jeweler', '~> 1.6.1'
13
+ gem 'rcov', '>= 0', :platform => :mri
14
+
15
+ gem 'ether_ping', '~> 0.3.1'
16
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,36 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.1.2)
5
+ ether_ping (0.3.1)
6
+ ethernet (>= 0.1.0)
7
+ ethernet (0.1.3)
8
+ ffi (>= 1.0.0)
9
+ ffi (1.0.9)
10
+ git (1.2.5)
11
+ jeweler (1.6.2)
12
+ bundler (~> 1.0)
13
+ git (>= 1.2.5)
14
+ rake
15
+ rake (0.9.1)
16
+ rcov (0.9.9)
17
+ rdoc (3.6.1)
18
+ rspec (2.6.0)
19
+ rspec-core (~> 2.6.0)
20
+ rspec-expectations (~> 2.6.0)
21
+ rspec-mocks (~> 2.6.0)
22
+ rspec-core (2.6.3)
23
+ rspec-expectations (2.6.0)
24
+ diff-lcs (~> 1.1.2)
25
+ rspec-mocks (2.6.0)
26
+
27
+ PLATFORMS
28
+ ruby
29
+
30
+ DEPENDENCIES
31
+ bundler (~> 1.0.14)
32
+ ether_ping (~> 0.3.1)
33
+ jeweler (~> 1.6.1)
34
+ rcov
35
+ rdoc (>= 3.6.1)
36
+ rspec (~> 2.6.0)
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Massachusetts Institute of Technology
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,57 @@
1
+ = xilinx-provision
2
+
3
+ Automates the tasks involved in uploading a bitfile to a Xilinx FPGA board.
4
+
5
+ == Disclaimer
6
+
7
+ The authors are not affiliated in any way with Xilinx, Inc. We are sharing this code so that other researches won't have to duplicate the effort.
8
+
9
+ == Features
10
+
11
+ The gem automates the following tasks:
12
+ * builds a recent version of the USB cable driver
13
+ * writes udev rules for the USB cable driver
14
+ * writes udev rules for uploading firmware to the cable
15
+ * uploads a bitfile to a FPGA
16
+
17
+ == Usage
18
+
19
+ After installing the ruby gem, perform a one-time setup to get the USB cable set up.
20
+
21
+ sudo xilinx-provision-setup
22
+
23
+ Then upload a bitfile to your FPGA using
24
+
25
+ xilinx-provision path/to/bitfile
26
+
27
+ Notice that the setup command requires root access, but normal operation does not.
28
+
29
+ To program FPGAs automatically, use the following Ruby code.
30
+
31
+ require 'xilinx/provision'
32
+ Xilinx::Provision.fpga 'path/to/bitfile'
33
+
34
+ For advanced usage, see the examples in the bin/ and spec/ directories.
35
+
36
+ == Dependencies
37
+
38
+ Right now, the gem works in Debian-based Linux distributions. It should be easy to extend it to other Linux distributions.
39
+
40
+ I have no interest in making the gem work on Windows, but I would welcome patches that do so.
41
+
42
+ The gem assumes Xilinx ISE is installed. Any edition will work, including the WebPACK free edition. Download the software from:
43
+ http://www.xilinx.com/support/download/index.htm
44
+
45
+ == Contributing to xilinx-provision
46
+
47
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
48
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
49
+ * Fork the project
50
+ * Start a feature/bugfix branch
51
+ * Commit and push until you are happy with your contribution
52
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
53
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
54
+
55
+ == Copyright
56
+
57
+ Copyright (c) 2011 Massachusetts Institute of Technology. See LICENSE.txt for further details.
data/Rakefile ADDED
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "xilinx-provision"
18
+ gem.homepage = "http://github.com/csail/xilinx-provision"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Deploys bitfiles to Xilinx FPGAs}
21
+ gem.description = %Q{Wraps the impact CLI tool in the Xilinx ISE}
22
+ gem.email = "victor@costan.us"
23
+ gem.authors = ["Victor Costan"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rspec/core'
29
+ require 'rspec/core/rake_task'
30
+ RSpec::Core::RakeTask.new(:spec) do |spec|
31
+ spec.pattern = FileList['spec/**/*_spec.rb']
32
+ end
33
+
34
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
35
+ spec.pattern = 'spec/**/*_spec.rb'
36
+ spec.rcov = true
37
+ end
38
+
39
+ task :default => :spec
40
+
41
+ require 'rdoc/task'
42
+ Rake::RDocTask.new do |rdoc|
43
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
44
+
45
+ rdoc.rdoc_dir = 'rdoc'
46
+ rdoc.title = "xilinx-provision #{version}"
47
+ rdoc.rdoc_files.include('README*')
48
+ rdoc.rdoc_files.include('lib/**/*.rb')
49
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'xilinx/provision'
4
+
5
+ if ARGV.length != 1
6
+ puts "Usage: #{$0} path_to_bitfile"
7
+ exit 1
8
+ end
9
+
10
+ Xilinx::Provision.fpga ARGV[0]
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'xilinx/provision'
4
+
5
+ if output = Xilinx::Provision::CableDriver.setup ||
6
+ Xilinx::Provision::CableFirmware.setup
7
+ print output
8
+ exit 1
9
+ else
10
+ exit 0
11
+ end
@@ -0,0 +1,25 @@
1
+ # :nodoc: namespace
2
+ module Xilinx
3
+
4
+ # Documentation here.
5
+ module Provision
6
+ # Programs an FPGA chip on a JTAG chain.
7
+ #
8
+ # The options argument accepts the following keys:
9
+ # :cable_port:: set to :auto by default
10
+ #
11
+ # Raises an exception if programming fails, returns true otherwise.
12
+ def self.fpga(bitfile, options = {})
13
+ if output = Xilinx::Provision::Impact.program_fpga(bitfile, options)
14
+ raise "Failed to program device!\nCommand output:\n#{output}"
15
+ end
16
+ true
17
+ end
18
+ end # namespace Xilinx::Provision
19
+
20
+ end # namespace Xilinx
21
+
22
+ require 'xilinx/provision/cable_driver.rb'
23
+ require 'xilinx/provision/cable_firmware.rb'
24
+ require 'xilinx/provision/impact.rb'
25
+ require 'xilinx/provision/udev.rb'
@@ -0,0 +1,95 @@
1
+ require 'English'
2
+ require 'fileutils'
3
+ require 'tmpdir'
4
+
5
+ # :nodoc namespace
6
+ module Xilinx
7
+
8
+ # :nodoc namespace
9
+ module Provision
10
+
11
+ # Drives the setup of the USB cable driver needed to talk to Xilinx boards.
12
+ module CableDriver
13
+ # Performs all the setup needed for the USB cable driver.
14
+ #
15
+ # Returns a false value in case of success, or a string with error information
16
+ # if something goes wrong.
17
+ def self.setup
18
+ if output = build_prerequisites
19
+ return "Error while obtaining driver prerequisites:\n#{output}"
20
+ elsif output = build(path)
21
+ return "Error while building driver:\n#{output}"
22
+ elsif output = configure_udev
23
+ return "Error while configuring cable driver udev rules\n#{output}"
24
+ elsif output = Xilinx::Provision::Udev.reload_rules
25
+ return "Error while loading cable driver udev rules\n#{output}"
26
+ end
27
+ nil
28
+ end
29
+
30
+ # Installs the packages needed to build the cable driver.
31
+ #
32
+ # Returns a false value for success, and a string containing error output if
33
+ # the build goes wrong.
34
+ def self.build_prerequisites
35
+ if File.exist?(`which apt-get`.strip)
36
+ # The literal `apt-get ...` doesn't use Kernel.` and can't be stubbed.
37
+ output = Kernel.`(
38
+ 'apt-get install -y git-core libusb-dev build-essential fxload 2>&1')
39
+ $CHILD_STATUS.to_i == 0 ? nil : output
40
+ else
41
+ "Unsupported OS / distribution\n"
42
+ end
43
+ end
44
+
45
+ # Builds the cable driver.
46
+ #
47
+ # Assumes the build requirements have been installed by build_prerequisites.
48
+ #
49
+ # Args:
50
+ # target_path:: directory that will contain the driver
51
+ #
52
+ # Returns the command's output.
53
+ def self.build(target_path)
54
+ target_path = File.expand_path target_path
55
+ Dir.mktmpdir do |temp_dir|
56
+ Dir.chdir temp_dir do
57
+ output = `git clone -q #{git_url} 2>&1`
58
+ return output if $CHILD_STATUS.to_i != 0
59
+ Dir.chdir 'usb-driver' do
60
+ output = `make all 2>&1`
61
+ return output if $CHILD_STATUS.to_i != 0
62
+ FileUtils.cp 'libusb-driver.so', target_path
63
+ end
64
+ end
65
+ end
66
+ nil
67
+ end
68
+
69
+ # Sets up the udev daemon to allow non-root access to the USB cable.
70
+ def self.configure_udev
71
+ Xilinx::Provision::Udev.add_rules udev_rules, '71-xilinx-usb-cable'
72
+ nil
73
+ end
74
+
75
+ # Rules for the udev daemon to allow non-root access to the USB cable.
76
+ #
77
+ # Returns an array of rules to be written to a udev file.
78
+ def self.udev_rules
79
+ ['ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="03fd", MODE="666"']
80
+ end
81
+
82
+ # The path to the driver file.
83
+ def self.path
84
+ File.expand_path '../libusb-driver.so', Xilinx::Provision::Impact.path
85
+ end
86
+
87
+ # The URL printed when no ISE installation is found.
88
+ def self.git_url
89
+ 'git://git.zerfleddert.de/usb-driver'
90
+ end
91
+ end # namespace Xilinx::Provision::CableDriver
92
+
93
+ end # namespace Xilinx::Provision
94
+
95
+ end # namespace Xilinx
@@ -0,0 +1,88 @@
1
+ # :nodoc namespace
2
+ module Xilinx
3
+
4
+ # :nodoc namespace
5
+ module Provision
6
+
7
+ # Finds firmware files for the Xilinx USB cable and sets up automatic uploading.
8
+ #
9
+ # The USB cables are weird beasts. A cable contains a small FPGA that must be
10
+ # programmed every time the cable is powered up, which happens on every
11
+ # connection to the computer.
12
+ #
13
+ # Xilinx ISE ships with the firmware for all cable types, but it doesn't
14
+ # automatically upload the firmware when needed. Udev to the rescue!
15
+ module CableFirmware
16
+ # Performs all the setup needed for automated firmware upload.
17
+ #
18
+ # Returns a false value in case of success, or a string with error information
19
+ # if something goes wrong.
20
+ def self.setup
21
+ if output = configure_udev
22
+ return "Error while configuring firmware upload udev rules\n#{output}"
23
+ elsif output = Xilinx::Provision::Udev.reload_rules
24
+ return "Error while loading firmware upload udev rules\n#{output}"
25
+ end
26
+ nil
27
+ end
28
+
29
+ # Sets up the udev daemon to allow non-root access to the USB cable.
30
+ def self.configure_udev
31
+ Xilinx::Provision::Udev.add_rules udev_rules,
32
+ '71-xilinx-usb-firmware-upload'
33
+ nil
34
+ end
35
+
36
+ # Rules for the udev daemon to allow non-root access to the USB cable.
37
+ #
38
+ # Returns an array of rules to be written to a udev file.
39
+ def self.udev_rules
40
+ return nil unless path = rules_path
41
+ old_rules = File.read(rules_path).split("\n")
42
+ upgrade_rules old_rules, path
43
+ end
44
+
45
+ # Returns a
46
+ def self.upgrade_rules(old_rules, rules_path)
47
+ rules_dir = File.dirname rules_path
48
+ old_rules.map do |old_rule|
49
+ rule = old_rule.dup
50
+ # Update old udev syntax.
51
+ [['TEMPNODE', 'tempnode'], ['SYSFS', 'ATTRS'],
52
+ ['BUS', 'SUBSYSTEMS']].each { |from, to| rule.gsub! from, to }
53
+
54
+ # Change firmware file references to point inside Xilinx ISE. It's very
55
+ # rude to copy crap straigt into /usr/share, Xilinx!
56
+ rule.gsub!(/ \S+\.hex /) do |filepath|
57
+ firmware_name = File.basename filepath.strip
58
+ " #{File.join(rules_dir, firmware_name)} "
59
+ end
60
+
61
+ rule
62
+ end
63
+ end
64
+
65
+ # The path to the firmware upload rules file that ships with ISE.
66
+ #
67
+ # This file is written in old-style udev, so it needs to be converted.
68
+ #
69
+ # Returns a path to the rules file, or nil if the file cannot be found.
70
+ def self.rules_path
71
+ dir_path = Xilinx::Provision::Impact.path
72
+ until dir_path == '/' || dir_path.empty?
73
+ dir_path = File.dirname dir_path
74
+ matches = Dir[File.join(dir_path, '**', '*.rules')]
75
+ next if matches.empty?
76
+ if matches.length > 1
77
+ better_matches = Dir[File.join(dir_path, '**', 'xusbdfwu.rules')]
78
+ matches = better_matches unless better_matches.empty?
79
+ end
80
+ return matches.sort.last
81
+ end
82
+ nil
83
+ end
84
+ end # namespace Xilinx::Provision::CableFirmware
85
+
86
+ end # namespace Xilinx::Provision
87
+
88
+ end # namespace Xilinx
@@ -0,0 +1,157 @@
1
+ require 'tmpdir'
2
+
3
+ # :nodoc namespace
4
+ module Xilinx
5
+
6
+ # :nodoc namespace
7
+ module Provision
8
+
9
+ # Runs the impact tool.
10
+ module Impact
11
+ # Programs an FPGA chip on a JTAG chain.
12
+ #
13
+ # The options argument accepts the following keys:
14
+ # :cable_port:: set to :auto by default
15
+ #
16
+ # Returns a false value for success, or a string containing error output if
17
+ # something goes wrong.
18
+ def self.program_fpga(bitfile, options = {})
19
+ options = { :mode => :bscan }.merge options
20
+ options[:cable_port] ||= :auto
21
+ devices = identify_chain(options)
22
+
23
+ bitfile = File.expand_path bitfile
24
+ batch = [
25
+ 'identify',
26
+ "assignFile -position #{devices.length} -file #{bitfile}",
27
+ "program -position #{devices.length}",
28
+ 'cleanCableLock',
29
+ 'closeCable'
30
+ ]
31
+ options.merge! :batch => batch
32
+ output = run options
33
+ $CHILD_STATUS.to_i == 0 ? nil : output
34
+ end
35
+
36
+ # Scans the JTAG chain and returns the devices on it.
37
+ #
38
+ # The options argument accepts the following keys:
39
+ # :cable_port:: set to :auto by default
40
+ #
41
+ # Returns the command's output.
42
+ def self.identify_chain(options = {})
43
+ batch = ['identify', 'cleanCableLock', 'closeCable']
44
+ options = {:mode => :bscan, :cable_port => :auto, :batch => batch}
45
+ parse_identify run(options)
46
+ end
47
+
48
+ # Extracts a JTAG chain from an impact identify command.
49
+ #
50
+ # Args:
51
+ # output:: the impact command output, obtained from Impact#run
52
+ #
53
+ # Returns an array of hashes with the following keys:
54
+ # name:: the device name, e.g. "Xilinx xc5vlx110t"
55
+ # version:: number reported by impact
56
+ def self.parse_identify(output)
57
+ lines = output.split("\n").each(&:strip!)
58
+ lines.each_with_index do |line, index|
59
+ if /ident.*chain/i =~ line
60
+ lines = lines[index..-1]
61
+ break
62
+ end
63
+ end
64
+
65
+ device_id_regexp = /'(\d+)':.*manufacturer.* id.*=([^,]+),.*version.*(\d+)/i
66
+ devices = []
67
+ device = {}
68
+ lines.each do |line|
69
+ if match = device_id_regexp.match(line)
70
+ device[:index] = match[1].to_i
71
+ device[:name] = match[2].strip
72
+ device[:version] = match[3].to_i
73
+ end
74
+ if /^\-+$/ =~ line && !device.empty?
75
+ devices << device
76
+ device = {}
77
+ end
78
+ end
79
+ devices
80
+ end
81
+
82
+ # Runs the impact tool and returns the status.
83
+ #
84
+ # The options argument accepts the following keys:
85
+ # :batch:: array of commands to be written to a batch file and executed
86
+ # :mode:: device configuration mode (try :bscan for JTAG boundary scan)
87
+ # :cable_port:: (try :auto)
88
+ #
89
+ # Returns the command's output.
90
+ def self.run(options = {})
91
+ unless command_line =
92
+ "LD_PRELOAD=#{Xilinx::Provision::CableDriver.path} " + path
93
+ raise "Xilinx ISE not found\nPlease download from #{download_url}"
94
+ end
95
+
96
+ batch = options[:batch] && options[:batch].dup
97
+
98
+ if options[:cable_port]
99
+ command_line << " -port #{options[:cable_port]}"
100
+ batch.unshift "setCable -port #{options[:cable_port]}" if batch
101
+ end
102
+ if options[:mode]
103
+ command_line << " -mode #{options[:mode]}"
104
+ batch.unshift "setMode -#{options[:mode]}" if batch
105
+ end
106
+ batch.push 'quit' if batch && batch.last != 'quit'
107
+
108
+ output = nil
109
+ Dir.mktmpdir do |temp_dir|
110
+ Dir.chdir temp_dir do
111
+ if options[:batch]
112
+ File.open('impact_batch', 'wb') do |f|
113
+ f.write batch.map { |line| line + "\n" }.join
114
+ end
115
+ command_line << ' -batch impact_batch'
116
+ end
117
+ command_line << ' 2>&1'
118
+ output = Kernel.`(command_line)
119
+ end
120
+ end
121
+ output
122
+ end
123
+
124
+ # Path to the impact binary.
125
+ def self.path
126
+ @path ||= path!
127
+ end
128
+
129
+ # Cached path.
130
+ @path = nil
131
+
132
+ # Path to the impact binary.
133
+ #
134
+ # This method does not cache its result and is really slow.
135
+ def self.path!
136
+ paths = Dir['/opt/**/impact']
137
+ paths = Dir['/usr/**/impact'] if paths.empty?
138
+
139
+ # 1 is a Fixnum which is a pointer, so its size shows 32/64-bit
140
+ if 1.size == 8
141
+ paths = paths.select { |path| path.index '64' }
142
+ else
143
+ paths = paths.reject { |path| path.index '64' }
144
+ end
145
+
146
+ paths.sort.last
147
+ end
148
+
149
+ # The URL printed when no ISE installation is found.
150
+ def self.download_url
151
+ 'http://www.xilinx.com/support/download/index.htm'
152
+ end
153
+ end # namespace Xilinx::Provision::Impact
154
+
155
+ end # namespace Xilinx::Provision
156
+
157
+ end # namespace Xilinx
@@ -0,0 +1,46 @@
1
+ require 'English'
2
+
3
+ # :nodoc namespace
4
+ module Xilinx
5
+
6
+ # :nodoc namespace
7
+ module Provision
8
+
9
+ # Runs the impact tool.
10
+ module Udev
11
+ # Installs a group of udev rules.
12
+ def self.add_rules(rules, group_name)
13
+ file = File.join rules_path, group_name + '.rules'
14
+ File.open file, 'w' do |f|
15
+ f.write rules.map { |rule| rule + "\n" }.join
16
+ end
17
+ end
18
+
19
+ # Removes a group of udev rules.
20
+ def self.remove_rules(group_name)
21
+ file = File.join rules_path, group_name + '.rules'
22
+ File.unlink file if File.exist?(file)
23
+ end
24
+
25
+ # Asks udev to reload its rules to reflect updates done by add_rules.
26
+ #
27
+ # Returns a false value for success, or a string containing error output if
28
+ # something goes wrong.
29
+ def self.reload_rules
30
+ output = `/etc/init.d/udev restart 2>&1`
31
+ $CHILD_STATUS.to_i == 0 ? nil : output
32
+ end
33
+
34
+ # Directory or file containing the udev rules.
35
+ def self.rules_path
36
+ if File.exist? '/etc/udev/rules.d'
37
+ return '/etc/udev/rules.d'
38
+ else
39
+ raise "Unsupported OS or distribution."
40
+ end
41
+ end
42
+ end # module Xilinx::Provision::Udev
43
+
44
+ end # module Xilinx::Provision
45
+
46
+ end # module Xilinx
Binary file
@@ -0,0 +1,75 @@
1
+ Release 13.1 - iMPACT O.40d (lin64)
2
+ Copyright (c) 1995-2011 Xilinx, Inc. All rights reserved.
3
+ Preference Table
4
+ Name Setting
5
+ StartupClock Auto_Correction
6
+ AutoSignature False
7
+ KeepSVF False
8
+ ConcurrentMode False
9
+ UseHighz False
10
+ ConfigOnFailure Stop
11
+ UserLevel Novice
12
+ MessageLevel Detailed
13
+ svfUseTime false
14
+ SpiByteSwap Auto_Correction
15
+ AutoInfer false
16
+ SvfPlayDisplayComments false
17
+ AutoDetecting cable. Please wait.
18
+ Using windrvr6 driver.
19
+ Connecting to cable (Usb Port - USB21).
20
+ Checking cable driver.
21
+ File version of /opt/Xilinx/13.1/ISE_DS/ISE/bin/lin64/xusbdfwu.hex = 1030.
22
+ File version of /etc/hotplug/usb/xusbdfwu.fw/xusbdfwu.hex = 1030.
23
+ libusb-driver.so version: 2011-03-25 19:15:17.
24
+ Cable PID = 0008.
25
+ Max current requested during enumeration is 150 mA.
26
+ Type = 0x0005.
27
+ Cable Type = 3, Revision = 0.
28
+ Setting cable speed to 6 MHz.
29
+ Cable connection established.
30
+ Firmware version = 2401.
31
+ File version of /opt/Xilinx/13.1/ISE_DS/ISE/data/xusb_xp2.hex = 2401.
32
+ Firmware hex file version = 2401.
33
+ PLD file version = 200Dh.
34
+ PLD version = 200Dh.
35
+ Type = 0x0005.
36
+ ESN option: 0000149C444901.
37
+ Identifying chain contents...'0': : Manufacturer's ID = Xilinx xc5vlx110t, Version : 10
38
+ INFO:iMPACT:1777 -
39
+ Reading /opt/Xilinx/13.1/ISE_DS/ISE/virtex5/data/xc5vlx110t.bsd...
40
+ INFO:iMPACT:501 - '1': Added Device xc5vlx110t successfully.
41
+ ----------------------------------------------------------------------
42
+ ----------------------------------------------------------------------
43
+ '1': : Manufacturer's ID = Xilinx xccace, Version : 0
44
+ INFO:iMPACT:1777 -
45
+ Reading /opt/Xilinx/13.1/ISE_DS/ISE/acecf/data/xccace.bsd...
46
+ INFO:iMPACT:501 - '1': Added Device xccace successfully.
47
+ ----------------------------------------------------------------------
48
+ ----------------------------------------------------------------------
49
+ '2': : Manufacturer's ID = Xilinx xc95144xl, Version : 5
50
+ INFO:iMPACT:1777 -
51
+ Reading /opt/Xilinx/13.1/ISE_DS/ISE/xc9500xl/data/xc95144xl.bsd...
52
+ INFO:iMPACT:501 - '1': Added Device xc95144xl successfully.
53
+ ----------------------------------------------------------------------
54
+ ----------------------------------------------------------------------
55
+ '3': : Manufacturer's ID = Xilinx xcf32p, Version : 15
56
+ INFO:iMPACT:1777 -
57
+ Reading /opt/Xilinx/13.1/ISE_DS/ISE/xcfp/data/xcf32p.bsd...
58
+ INFO:iMPACT:501 - '1': Added Device xcf32p successfully.
59
+ ----------------------------------------------------------------------
60
+ ----------------------------------------------------------------------
61
+ '4': : Manufacturer's ID = Xilinx xcf32p, Version : 15
62
+ INFO:iMPACT:501 - '1': Added Device xcf32p successfully.
63
+ ----------------------------------------------------------------------
64
+ ----------------------------------------------------------------------
65
+ done.
66
+ Elapsed time = 0 sec.
67
+ Elapsed time = 0 sec.
68
+ ----------------------------------------------------------------------
69
+ ----------------------------------------------------------------------
70
+ ----------------------------------------------------------------------
71
+ ----------------------------------------------------------------------
72
+ ----------------------------------------------------------------------
73
+ ----------------------------------------------------------------------
74
+ ----------------------------------------------------------------------
75
+ ----------------------------------------------------------------------
@@ -0,0 +1,3 @@
1
+ # version 0003
2
+ SYSFS{idVendor}=="03fd", SYSFS{idProduct}=="0008", MODE="666"
3
+ BUS=="usb", ACTION=="add", SYSFS{idVendor}=="03fd", SYSFS{idProduct}=="0007", RUN+="/sbin/fxload -v -t fx2 -I /usr/share/xusbdfwu.hex -D $TEMPNODE"
@@ -0,0 +1,13 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+ require 'xilinx/provision'
5
+ require 'ether_ping'
6
+
7
+ # Requires supporting files with custom matchers and macros, etc,
8
+ # in ./support/ and its subdirectories.
9
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
10
+
11
+ RSpec.configure do |config|
12
+
13
+ end
@@ -0,0 +1,54 @@
1
+ require File.expand_path('../../spec_helper', File.dirname(__FILE__))
2
+
3
+ describe Xilinx::Provision::CableDriver do
4
+ describe 'build_prerequisites' do
5
+ before do
6
+ # Remove one a package without deps to validate that it reinstalls.
7
+ if File.exist? `which apt-get`.strip
8
+ `apt-get remove -y fxload 2>&1`
9
+ end
10
+ end
11
+
12
+ it 'should install the fxload binary' do
13
+ Xilinx::Provision::CableDriver.build_prerequisites.should be_nil
14
+ File.exist?(`which fxload`.strip).should be_true
15
+ end
16
+
17
+ it 'should forward build output if an error happens' do
18
+ Kernel.stub(:`) do
19
+ Kernel.system 'false'
20
+ 'Error 42'
21
+ end
22
+ Xilinx::Provision::CableDriver.build_prerequisites.
23
+ should match(/Error 42/)
24
+ end
25
+ end
26
+
27
+ describe 'build' do
28
+ before { Xilinx::Provision::CableDriver.build_prerequisites }
29
+
30
+ before { @temp_dir = Dir.mktmpdir }
31
+ after { FileUtils.rm_rf @temp_dir }
32
+
33
+ it 'should copy the USB driver to the given target' do
34
+ Xilinx::Provision::CableDriver.build(@temp_dir).should be_nil
35
+ Dir[File.join(@temp_dir, '*.so')].map { |entry| File.basename(entry) }.
36
+ should include('libusb-driver.so')
37
+ end
38
+
39
+ it 'should forward build output if an error happens' do
40
+ Xilinx::Provision::CableDriver.should_receive(:git_url).and_return '::'
41
+ Xilinx::Provision::CableDriver.build(@temp_dir).
42
+ should match(/No such file or directory/i)
43
+ end
44
+ end
45
+
46
+ describe 'path' do
47
+ let(:path) { Xilinx::Provision::CableDriver.path }
48
+
49
+ it 'should point to a valid directory' do
50
+ File.exist?(File.dirname(path)).should be_true
51
+ File.directory?(File.dirname(path)).should be_true
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,55 @@
1
+ require File.expand_path('../../spec_helper', File.dirname(__FILE__))
2
+
3
+ describe Xilinx::Provision::CableFirmware do
4
+ describe 'rules_path' do
5
+ describe 'on the real system' do
6
+ let(:path) { Xilinx::Provision::CableFirmware.rules_path }
7
+
8
+ it 'should point to a valid file' do
9
+ File.exist?(path).should be_true
10
+ File.directory?(path).should be_false
11
+ end
12
+ end
13
+
14
+ describe 'on the mock system' do
15
+ before { Xilinx::Provision::Impact.stub!(:path).and_return(__FILE__) }
16
+
17
+ it 'should find the mock rules file' do
18
+ Xilinx::Provision::CableFirmware.rules_path.
19
+ should match(/snippet.rules$/)
20
+ end
21
+ end
22
+ end
23
+
24
+ describe 'udev rules' do
25
+ describe 'on the real system' do
26
+ let(:rules) { Xilinx::Provision::CableFirmware.udev_rules }
27
+
28
+ it 'should output a non-empty array' do
29
+ rules.should have_at_least(1).rule
30
+ end
31
+
32
+ it 'should only have strings in the array' do
33
+ rules.all? { |rule| rule.respond_to? :to_str }.should be_true
34
+ end
35
+ end
36
+
37
+ describe 'on the mock system' do
38
+ before { Xilinx::Provision::Impact.stub!(:path).and_return(__FILE__) }
39
+
40
+ it 'should match the golden output' do
41
+ Xilinx::Provision::CableFirmware.udev_rules.should == [
42
+ '# version 0003',
43
+ 'ATTRS{idVendor}=="03fd", ATTRS{idProduct}=="0008", MODE="666"',
44
+ %Q|SUBSYSTEMS=="usb", ACTION=="add", ATTRS{idVendor}=="03fd", ATTRS{idProduct}=="0007", RUN+="/sbin/fxload -v -t fx2 -I #{File.expand_path('../../../fixtures', __FILE__)}/xusbdfwu.hex -D $tempnode"|
45
+ ]
46
+ end
47
+ end
48
+ end
49
+
50
+ describe 'configure_udev' do
51
+ it 'should run happily' do
52
+ Xilinx::Provision::CableFirmware.configure_udev.should be_nil
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,85 @@
1
+ require File.expand_path('../../spec_helper', File.dirname(__FILE__))
2
+
3
+ describe Xilinx::Provision::Impact do
4
+ describe 'path' do
5
+ let(:path) { Xilinx::Provision::Impact.path }
6
+
7
+ it 'is a non-empty string' do
8
+ path.should be_kind_of String
9
+ path.should_not be_empty
10
+ end
11
+
12
+ it 'can be executed, and outputs a Xilinx banner' do
13
+ Kernel.`(path + ' -help').should include('Xilinx')
14
+ end
15
+ end
16
+
17
+ describe 'run' do
18
+ it 'should piece the impact command-line correctly' do
19
+ Xilinx::Provision::Impact.stub(:path).and_return('/path/to/impact')
20
+ Kernel.should_receive(:`).with 'LD_PRELOAD=/path/to/libusb-driver.so ' +
21
+ '/path/to/impact -port auto -mode bscan -batch impact_batch 2>&1'
22
+ lambda {
23
+ Xilinx::Provision::Impact.run :batch => ['identify'], :mode => :bscan,
24
+ :cable_port => :auto
25
+ }.should_not raise_error
26
+ end
27
+
28
+ it 'should run an identify correctly' do
29
+ Xilinx::Provision::Impact.run(:batch => ['identify'], :mode => :bscan,
30
+ :cable_port => :auto).should match(/identifying chain/i)
31
+ end
32
+ end
33
+
34
+ describe 'parse_identify' do
35
+ describe 'on mock input' do
36
+ let(:output) do
37
+ Xilinx::Provision::Impact.parse_identify(File.read(
38
+ File.expand_path('../../../fixtures/impact_detect', __FILE__)))
39
+ end
40
+
41
+ it 'should find 5 devices' do
42
+ output.should have(5).devices
43
+ end
44
+
45
+ it 'should show the FPGA as device 0' do
46
+ output[0][:name].should == 'Xilinx xc5vlx110t'
47
+ end
48
+
49
+ it 'should identify the FPGA version' do
50
+ output[0][:name].should == 'Xilinx xc5vlx110t'
51
+ end
52
+ end
53
+ end
54
+
55
+ describe 'identify_chain' do
56
+ it 'should find at least one device' do
57
+ Xilinx::Provision::Impact.identify_chain.should have_at_least(1).device
58
+ end
59
+ end
60
+
61
+ describe 'program_fpga' do
62
+ describe 'with the ethernet bitfile' do
63
+ let(:bitfile) do
64
+ File.expand_path('../../../fixtures/ethernet_ping.bit', __FILE__)
65
+ end
66
+
67
+ let(:return_value) do
68
+ Xilinx::Provision::Impact.program_fpga bitfile
69
+ end
70
+
71
+ let(:ethernet_device) do
72
+ 'eth0'
73
+ end
74
+
75
+ it 'should return nil for success' do
76
+ return_value.should be_nil
77
+ end
78
+
79
+ it 'should make the FPGA respond to pings' do
80
+ client = EtherPing::Client.new ethernet_device, 0x88B5, '001122334455'
81
+ client.ping("abcd", 3).should be_kind_of(Numeric)
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,41 @@
1
+ require File.expand_path('../../spec_helper', File.dirname(__FILE__))
2
+
3
+ describe Xilinx::Provision::Impact do
4
+ let(:path) { Xilinx::Provision::Udev.rules_path }
5
+
6
+ describe 'rules_path' do
7
+ it 'should point to a directory' do
8
+ File.directory?(path).should be_true
9
+ end
10
+ end
11
+
12
+ describe 'add_rules' do
13
+ before { Xilinx::Provision::Udev.add_rules ['ab', 'cd'], '99-spec-group' }
14
+ after { Xilinx::Provision::Udev.remove_rules '99-spec-group' }
15
+
16
+ let(:file_matches) { Dir[File.join(path, '99-spec-group*')] }
17
+
18
+ it 'should create a file' do
19
+ file_matches.should have(1).file
20
+ end
21
+
22
+ it 'should write the rules in the file' do
23
+ File.read(file_matches.first).should == "ab\ncd\n"
24
+ end
25
+
26
+ describe 'remove_rules' do
27
+ before { Xilinx::Provision::Udev.remove_rules '99-spec-group' }
28
+
29
+ it 'should remove the previously added file' do
30
+ Dir[File.join(path, '99-spec-group*')].should be_empty
31
+ end
32
+ end
33
+ end
34
+
35
+ describe 'reload_rules' do
36
+ it 'should execute happily' do
37
+ Xilinx::Provision::Udev.reload_rules
38
+ $CHILD_STATUS.to_i.should == 0
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,26 @@
1
+ require File.expand_path('../spec_helper', File.dirname(__FILE__))
2
+
3
+ describe Xilinx::Provision do
4
+ describe 'fpga' do
5
+ it 'delegates to Impact.program_fpga' do
6
+ Xilinx::Provision::Impact.should_receive(:program_fpga).
7
+ with('/path/to/bitfile', {}).and_return(nil)
8
+ Xilinx::Provision.fpga('/path/to/bitfile').should be_true
9
+ end
10
+
11
+ it 'raises an exception if programming fails' do
12
+ Xilinx::Provision::Impact.should_receive(:program_fpga).
13
+ with('/path/to/bitfile', {}).and_return("42")
14
+ lambda {
15
+ Xilinx::Provision.fpga '/path/to/bitfile'
16
+ }.should raise_error
17
+ end
18
+
19
+ it 'works with a real bitfile' do
20
+ lambda {
21
+ bitfile = File.expand_path '../../fixtures/ethernet_ping.bit', __FILE__
22
+ Xilinx::Provision.fpga bitfile
23
+ }.should_not raise_error
24
+ end
25
+ end
26
+ end
metadata ADDED
@@ -0,0 +1,184 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: xilinx-provision
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
11
+ platform: ruby
12
+ authors:
13
+ - Victor Costan
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-06-01 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ type: :development
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ hash: 29
28
+ segments:
29
+ - 3
30
+ - 6
31
+ - 1
32
+ version: 3.6.1
33
+ prerelease: false
34
+ version_requirements: *id001
35
+ name: rdoc
36
+ - !ruby/object:Gem::Dependency
37
+ type: :development
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ hash: 23
44
+ segments:
45
+ - 2
46
+ - 6
47
+ - 0
48
+ version: 2.6.0
49
+ prerelease: false
50
+ version_requirements: *id002
51
+ name: rspec
52
+ - !ruby/object:Gem::Dependency
53
+ type: :development
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ~>
58
+ - !ruby/object:Gem::Version
59
+ hash: 11
60
+ segments:
61
+ - 1
62
+ - 0
63
+ - 14
64
+ version: 1.0.14
65
+ prerelease: false
66
+ version_requirements: *id003
67
+ name: bundler
68
+ - !ruby/object:Gem::Dependency
69
+ type: :development
70
+ requirement: &id004 !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ hash: 13
76
+ segments:
77
+ - 1
78
+ - 6
79
+ - 1
80
+ version: 1.6.1
81
+ prerelease: false
82
+ version_requirements: *id004
83
+ name: jeweler
84
+ - !ruby/object:Gem::Dependency
85
+ type: :development
86
+ requirement: &id005 !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ hash: 3
92
+ segments:
93
+ - 0
94
+ version: "0"
95
+ prerelease: false
96
+ version_requirements: *id005
97
+ name: rcov
98
+ - !ruby/object:Gem::Dependency
99
+ type: :development
100
+ requirement: &id006 !ruby/object:Gem::Requirement
101
+ none: false
102
+ requirements:
103
+ - - ~>
104
+ - !ruby/object:Gem::Version
105
+ hash: 17
106
+ segments:
107
+ - 0
108
+ - 3
109
+ - 1
110
+ version: 0.3.1
111
+ prerelease: false
112
+ version_requirements: *id006
113
+ name: ether_ping
114
+ description: Wraps the impact CLI tool in the Xilinx ISE
115
+ email: victor@costan.us
116
+ executables:
117
+ - xilinx-provision
118
+ - xilinx-provision-setup
119
+ extensions: []
120
+
121
+ extra_rdoc_files:
122
+ - LICENSE.txt
123
+ - README.rdoc
124
+ files:
125
+ - .document
126
+ - .project
127
+ - .rspec
128
+ - Gemfile
129
+ - Gemfile.lock
130
+ - LICENSE.txt
131
+ - README.rdoc
132
+ - Rakefile
133
+ - VERSION
134
+ - bin/xilinx-provision
135
+ - bin/xilinx-provision-setup
136
+ - lib/xilinx/provision.rb
137
+ - lib/xilinx/provision/cable_driver.rb
138
+ - lib/xilinx/provision/cable_firmware.rb
139
+ - lib/xilinx/provision/impact.rb
140
+ - lib/xilinx/provision/udev.rb
141
+ - spec/fixtures/ethernet_ping.bit
142
+ - spec/fixtures/impact_detect
143
+ - spec/fixtures/snippet.rules
144
+ - spec/spec_helper.rb
145
+ - spec/xilinx/provision/cable_driver_spec.rb
146
+ - spec/xilinx/provision/cable_firmware_spec.rb
147
+ - spec/xilinx/provision/impact_spec.rb
148
+ - spec/xilinx/provision/udev_spec.rb
149
+ - spec/xilinx/provision_spec.rb
150
+ homepage: http://github.com/csail/xilinx-provision
151
+ licenses:
152
+ - MIT
153
+ post_install_message:
154
+ rdoc_options: []
155
+
156
+ require_paths:
157
+ - lib
158
+ required_ruby_version: !ruby/object:Gem::Requirement
159
+ none: false
160
+ requirements:
161
+ - - ">="
162
+ - !ruby/object:Gem::Version
163
+ hash: 3
164
+ segments:
165
+ - 0
166
+ version: "0"
167
+ required_rubygems_version: !ruby/object:Gem::Requirement
168
+ none: false
169
+ requirements:
170
+ - - ">="
171
+ - !ruby/object:Gem::Version
172
+ hash: 3
173
+ segments:
174
+ - 0
175
+ version: "0"
176
+ requirements: []
177
+
178
+ rubyforge_project:
179
+ rubygems_version: 1.8.4
180
+ signing_key:
181
+ specification_version: 3
182
+ summary: Deploys bitfiles to Xilinx FPGAs
183
+ test_files: []
184
+