Module: Xilinx::Provision::Impact

Defined in:
lib/xilinx/provision/impact.rb

Overview

Runs the impact tool.

Class Method Summary collapse

Class Method Details

.download_urlObject

The URL printed when no ISE installation is found.



150
151
152
# File 'lib/xilinx/provision/impact.rb', line 150

def self.download_url
  'http://www.xilinx.com/support/download/index.htm'
end

.identify_chain(options = {}) ⇒ Object

Scans the JTAG chain and returns the devices on it.

The options argument accepts the following keys:

:cable_port:: set to :auto by default

Returns the command’s output.



42
43
44
45
46
# File 'lib/xilinx/provision/impact.rb', line 42

def self.identify_chain(options = {})
  batch = ['identify', 'cleanCableLock', 'closeCable']
  options = {:mode => :bscan, :cable_port => :auto, :batch => batch}
  parse_identify run(options)
end

.parse_identify(output) ⇒ Object

Extracts a JTAG chain from an impact identify command.

Args:

output:: the impact command output, obtained from Impact#run

Returns an array of hashes with the following keys:

name:: the device name, e.g. "Xilinx xc5vlx110t"
version:: number reported by impact


56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/xilinx/provision/impact.rb', line 56

def self.parse_identify(output)
  lines = output.split("\n").each(&:strip!)
  lines.each_with_index do |line, index|
    if /ident.*chain/i =~ line
      lines = lines[index..-1]
      break
    end
  end
  
  device_id_regexp = /'(\d+)':.*manufacturer.* id.*=([^,]+),.*version.*(\d+)/i
  devices = []
  device = {}
  lines.each do |line|
    if match = device_id_regexp.match(line)
      device[:index] = match[1].to_i
      device[:name] = match[2].strip
      device[:version] = match[3].to_i
    end
    if /^\-+$/ =~ line && !device.empty?
      devices << device
      device = {}
    end
  end
  devices
end

.pathObject

Path to the impact binary.



125
126
127
# File 'lib/xilinx/provision/impact.rb', line 125

def self.path
  @path ||= path!
end

.path!Object

Path to the impact binary.

This method does not cache its result and is really slow.



135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/xilinx/provision/impact.rb', line 135

def self.path!
  paths = Dir['/opt/**/impact']
  paths = Dir['/usr/**/impact'] if paths.empty?
  
  # 1 is a Fixnum which is a pointer, so its size shows 32/64-bit
  if 1.size == 8
    paths = paths.select { |path| path.index '64' }
  else
    paths = paths.reject { |path| path.index '64' }
  end
  
  paths.sort.last
end

.program_fpga(bitfile, options = {}) ⇒ Object

Programs an FPGA chip on a JTAG chain.

The options argument accepts the following keys:

:cable_port:: set to :auto by default

Returns a false value for success, or a string containing error output if something goes wrong.



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/xilinx/provision/impact.rb', line 18

def self.program_fpga(bitfile, options = {})
  options = { :mode => :bscan }.merge options
  options[:cable_port] ||= :auto
  devices = identify_chain(options)
  
  bitfile = File.expand_path bitfile
  batch = [
    'identify',
    "assignFile -position #{devices.length} -file #{bitfile}",
    "program -position #{devices.length}",
    'cleanCableLock',
    'closeCable'
  ]
  options.merge! :batch => batch
  output = run options
  $CHILD_STATUS.to_i == 0 ? nil : output
end

.run(options = {}) ⇒ Object

Runs the impact tool and returns the status.

The options argument accepts the following keys:

:batch:: array of commands to be written to a batch file and executed
:mode:: device configuration mode (try :bscan for JTAG boundary scan)
:cable_port:: (try :auto)

Returns the command’s output.



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/xilinx/provision/impact.rb', line 90

def self.run(options = {})
  unless command_line =
      "LD_PRELOAD=#{Xilinx::Provision::CableDriver.path} " + path
    raise "Xilinx ISE not found\nPlease download from #{download_url}"
  end
  
  batch = options[:batch] && options[:batch].dup
  
  if options[:cable_port]
    command_line << " -port #{options[:cable_port]}"
    batch.unshift "setCable -port #{options[:cable_port]}" if batch
  end
  if options[:mode]
    command_line << " -mode #{options[:mode]}"
    batch.unshift "setMode -#{options[:mode]}" if batch
  end
  batch.push 'quit' if batch && batch.last != 'quit'
  
  output = nil
  Dir.mktmpdir do |temp_dir|
    Dir.chdir temp_dir do
      if options[:batch]
        File.open('impact_batch', 'wb') do |f|
          f.write batch.map { |line| line + "\n" }.join
        end
        command_line << ' -batch impact_batch'
      end
      command_line << ' 2>&1'
      output = Kernel.`(command_line)
    end 
  end
  output
end