origen_link 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/start_link_server +4 -1
- data/config/version.rb +1 -1
- data/lib/origen_link/configuration_commands.rb +161 -9
- data/lib/origen_link/server/jtag.rb +15 -0
- data/lib/origen_link/server/pin.rb +115 -18
- data/lib/origen_link/server/sequencer.rb +214 -106
- data/lib/origen_link/server_com.rb +5 -1
- data/lib/origen_link/test/top_level.rb +5 -5
- data/lib/origen_link/test/top_level_controller.rb +2 -0
- data/lib/origen_link/vector_based.rb +153 -45
- data/pattern/jtag_comm_timing_api.rb +26 -0
- data/templates/web/index.md.erb +396 -9
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 14d0facfcb04447ab5238b62f38ee31b4332e212
|
4
|
+
data.tar.gz: f68f21592acc3eb1dd48301cac3e220a742b789a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e162fafd6a68753e03afb20a20cd6f779b7a25a5d50473711f83a9769955453c3e1259adfedd02a9b3c36f8077fc4d9823c68ed5f802b9a8ae8c049265070010
|
7
|
+
data.tar.gz: 8fd17ea6f4eb541a880e9c526d36d265ba3fdfc075e276bfd65b6f535f785a854b615b576df5f2467df791a23d57c27535eb912758bfec2c4e48ecf3930071ee
|
data/bin/start_link_server
CHANGED
@@ -1,15 +1,18 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
$LOAD_PATH.unshift(File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib'))
|
3
|
+
$LOAD_PATH.unshift(File.join(File.expand_path(File.dirname(__FILE__)), '..', 'config'))
|
3
4
|
require 'socket'
|
4
5
|
require 'origen_link/server/sequencer'
|
6
|
+
require 'version'
|
5
7
|
|
6
8
|
server = TCPServer.open('', 12_777)
|
7
|
-
puts 'server started'
|
8
9
|
pinsequencer = OrigenLink::Server::Sequencer.new
|
10
|
+
pinsequencer.version = OrigenLink::VERSION
|
9
11
|
remoteuser = ''
|
10
12
|
remotehost = ''
|
11
13
|
sessionactivity = Time.now
|
12
14
|
sessionactive = false
|
15
|
+
puts "server version #{pinsequencer.version} started"
|
13
16
|
|
14
17
|
loop do
|
15
18
|
client = server.accept
|
data/config/version.rb
CHANGED
@@ -11,6 +11,10 @@ module OrigenLink
|
|
11
11
|
@pinmap = pinmap.gsub(/\s+/, '')
|
12
12
|
response = send_cmd('pin_assign', @pinmap)
|
13
13
|
setup_cmd_response_logger('pin_assign', response)
|
14
|
+
# store pins to the pinmap hash, this is used to remove non-link pins
|
15
|
+
# from the pattern in cases where the app includes too many pins
|
16
|
+
pinmap_arr = @pinmap.split(',')
|
17
|
+
0.step(pinmap_arr.size - 1, 2) { |p| @pinmap_hash[pinmap_arr[p]] = true }
|
14
18
|
end
|
15
19
|
|
16
20
|
# pinorder=
|
@@ -24,9 +28,40 @@ module OrigenLink
|
|
24
28
|
# example:
|
25
29
|
# tester.pinorder = 'tclk,tms,tdi,tdo'
|
26
30
|
def pinorder=(pinorder)
|
27
|
-
|
28
|
-
|
29
|
-
|
31
|
+
cmd = []
|
32
|
+
cmd << 'pin_patternorder'
|
33
|
+
cmd << pinorder.gsub(/\s+/, '')
|
34
|
+
@pinorder = cmd[1]
|
35
|
+
if @pinmap.nil?
|
36
|
+
@batched_setup_cmds << cmd
|
37
|
+
else
|
38
|
+
response = send_cmd(cmd[0], @pinorder)
|
39
|
+
setup_cmd_response_logger(cmd[0], response)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# set_pinorder
|
44
|
+
# This method is called if the app has not explicitly set the pin order
|
45
|
+
# for the Link server using pinorder= (above)
|
46
|
+
#
|
47
|
+
# Origen.app.pin_pattern_order is read to get the pin pattern order
|
48
|
+
# and pass it to pinorder=
|
49
|
+
def set_pinorder
|
50
|
+
pinlist = ''
|
51
|
+
ordered_pins_cache.each do |pin|
|
52
|
+
unless pin.is_a?(Hash)
|
53
|
+
if pin.size == 1
|
54
|
+
pinlist = pinlist + ',' unless pinlist.length == 0
|
55
|
+
pinlist = pinlist + pin.name.to_s
|
56
|
+
else
|
57
|
+
dut.pins(pin.id).map.each do |sub_pin|
|
58
|
+
pinlist = pinlist + ',' unless pinlist.length == 0
|
59
|
+
pinlist = pinlist + sub_pin.name.to_s
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
self.pinorder = pinlist
|
30
65
|
end
|
31
66
|
|
32
67
|
# pinformat=
|
@@ -36,9 +71,16 @@ module OrigenLink
|
|
36
71
|
# example:
|
37
72
|
# tester.pinformat = 'func_25mhz,tclk,rl'
|
38
73
|
def pinformat=(pinformat)
|
39
|
-
|
40
|
-
|
41
|
-
|
74
|
+
cmd = []
|
75
|
+
cmd << 'pin_format'
|
76
|
+
cmd << replace_tset_name_w_number(pinformat.gsub(/\s+/, ''))
|
77
|
+
@pinformat = cmd[1]
|
78
|
+
if @pinmap.nil?
|
79
|
+
@batched_setup_cmds << cmd
|
80
|
+
else
|
81
|
+
response = send_cmd(cmd[0], @pinformat)
|
82
|
+
setup_cmd_response_logger(cmd[0], response)
|
83
|
+
end
|
42
84
|
end
|
43
85
|
|
44
86
|
# pintiming=
|
@@ -51,9 +93,119 @@ module OrigenLink
|
|
51
93
|
# example:
|
52
94
|
# tester.pintiming = 'func_25mhz,tms,0,tdi,0,tdo,1'
|
53
95
|
def pintiming=(pintiming)
|
54
|
-
|
55
|
-
|
56
|
-
|
96
|
+
cmd = []
|
97
|
+
cmd << 'pin_timing'
|
98
|
+
cmd << replace_tset_name_w_number(pintiming.gsub(/\s+/, ''))
|
99
|
+
@pintiming = cmd[1]
|
100
|
+
if @pinmap.nil?
|
101
|
+
@batched_setup_cmds << cmd
|
102
|
+
else
|
103
|
+
response = send_cmd(cmd[0], @pintiming)
|
104
|
+
setup_cmd_response_logger(cmd[0], response)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# process_timeset(tset)
|
109
|
+
# This method will check the pin timing api for the current timeset.
|
110
|
+
# If the timset is programmed, it will be processed into the Link
|
111
|
+
# timing format, registered, and sent to the server.
|
112
|
+
# Else, a warning message will be displayed
|
113
|
+
#
|
114
|
+
# example generated command:
|
115
|
+
# send_cmd('pin_timingv2', '2,drive,5,data,tck;10,data,tdi|compare,35,data,tck,tdo;5,data,tdi')
|
116
|
+
def process_timeset(tset)
|
117
|
+
# Check to see if this timeset has been programmed
|
118
|
+
if dut.timesets(tset.to_sym).nil?
|
119
|
+
# Timset has not been programmed through the pin timing api
|
120
|
+
tset_warning(tset)
|
121
|
+
'' # return empty string on failure
|
122
|
+
else
|
123
|
+
# Timeset has been programmed
|
124
|
+
# accumulate and sort drive events
|
125
|
+
drive_str = tset_argstr_from_events(dut.timesets(tset.to_sym).drive_waves)
|
126
|
+
|
127
|
+
# accumulate and sort compare events
|
128
|
+
compare_str = tset_argstr_from_events(dut.timesets(tset.to_sym).compare_waves)
|
129
|
+
|
130
|
+
# construct the command argument string
|
131
|
+
argstr = get_tset_number(tset).to_s
|
132
|
+
if drive_str.length > 0
|
133
|
+
argstr = argstr + ',drive,' + drive_str
|
134
|
+
argstr = argstr + '|compare,' + compare_str if compare_str.length > 0
|
135
|
+
elsif compare_str.length > 0
|
136
|
+
argstr = argstr + ',compare,' + compare_str
|
137
|
+
else
|
138
|
+
fail "#{tset} timeset is programmed with no drive or compare edges"
|
139
|
+
end
|
140
|
+
|
141
|
+
# send the timeset information to the server
|
142
|
+
cmd = []
|
143
|
+
cmd << 'pin_timingv2'
|
144
|
+
cmd << argstr
|
145
|
+
if @pinmap.nil?
|
146
|
+
@batched_setup_cmds << cmd
|
147
|
+
else
|
148
|
+
response = send_cmd('pin_timingv2', argstr)
|
149
|
+
setup_cmd_response_logger('pin_timingv2', response)
|
150
|
+
end
|
151
|
+
|
152
|
+
# return the tset number from the tset hash
|
153
|
+
"tset#{@tsets_programmed[tset]},"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# tset_argstr_from_events(timing_waves)
|
158
|
+
# consume timing wave info and return command argstr format
|
159
|
+
# output: 10,data,tdi,tms;15,data,tck;25,0,tck;35,data,tms
|
160
|
+
def tset_argstr_from_events(waves)
|
161
|
+
event_time = []
|
162
|
+
event_setting = {}
|
163
|
+
event_pins = {}
|
164
|
+
waves.each do |w|
|
165
|
+
# skip any events wave that does not have any associated pins
|
166
|
+
unless w.pins.size == 0
|
167
|
+
w.evaluated_events.each do |e|
|
168
|
+
event_key = e[0].to_f # time stamp for the event
|
169
|
+
event_time << event_key
|
170
|
+
event_setting[event_key] = [] unless event_setting.key?(event_key)
|
171
|
+
event_setting[event_key] << e[1].to_s
|
172
|
+
|
173
|
+
event_pins[event_key] = [] unless event_pins.key?(event_key)
|
174
|
+
event_pins[event_key] << []
|
175
|
+
w.pins.each do |p|
|
176
|
+
event_pins[event_key].last << p.id.to_s if @pinmap_hash[p.id.to_s]
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
# now sort the events into time order and build the tset argstr
|
182
|
+
event_time.uniq!
|
183
|
+
event_time.sort!
|
184
|
+
rtnstr = ''
|
185
|
+
event_time.each do |event_key|
|
186
|
+
rtnstr = rtnstr + ';' unless rtnstr.length == 0
|
187
|
+
event_setting[event_key].each_index do |i|
|
188
|
+
pins = event_pins[event_key][i].uniq.join(',')
|
189
|
+
rtnstr = rtnstr + ';' if i > 0
|
190
|
+
rtnstr = rtnstr + event_key.to_s + ',' + event_setting[event_key][i] + ',' + pins if pins.length > 0
|
191
|
+
end
|
192
|
+
end
|
193
|
+
rtnstr.gsub(/;+/, ';')
|
194
|
+
end
|
195
|
+
|
196
|
+
# tset_warning(tset)
|
197
|
+
# This method is used to display a no timing info warning.
|
198
|
+
# The warning is displayed only once per tset that is
|
199
|
+
# encountered
|
200
|
+
def tset_warning(tset)
|
201
|
+
unless @tsets_warned.key?(tset)
|
202
|
+
Origen.log.warn("No timing information provided for timeset :#{tset}")
|
203
|
+
Origen.log.warn('Default timing will be used (pin operations are in pattern order)')
|
204
|
+
Origen.log.warn('Specify timing through the timing api or by using:')
|
205
|
+
Origen.log.warn(" tester.pinformat = 'func_25mhz,tclk,rl'")
|
206
|
+
Origen.log.warn(" tester.pintiming = 'func_25mhz,tms,0,tdi,0,tdo,1'")
|
207
|
+
@tsets_warned[tset] = true
|
208
|
+
end
|
57
209
|
end
|
58
210
|
|
59
211
|
# replace_tset_name_w_number(csl)
|
@@ -2,11 +2,17 @@ require 'origen_link/server/pin'
|
|
2
2
|
|
3
3
|
module OrigenLink
|
4
4
|
module Server
|
5
|
+
# The Jtag class is not part of the OrigenLink plug-in/server ecosystem.
|
6
|
+
# It implements standard jtag protocol. It can be used to implement a
|
7
|
+
# Jtag protocol server (not included in this repository presently).
|
5
8
|
class Jtag
|
9
|
+
# The value read from TDO during the shift
|
6
10
|
attr_reader :tdoval
|
11
|
+
# Enable extra output
|
7
12
|
attr_accessor :verbose_enable
|
8
13
|
attr_accessor :anytdofail
|
9
14
|
|
15
|
+
# Create the jtag pin objects
|
10
16
|
def initialize(tdiio = 16, tdoio = 23, tmsio = 19, tckio = 26, tck_period = 0.000001)
|
11
17
|
@tdipin = Pin.new(tdiio, :out)
|
12
18
|
@tdopin = Pin.new(tdoio, :in)
|
@@ -19,10 +25,12 @@ module OrigenLink
|
|
19
25
|
@anytdofail = false
|
20
26
|
end
|
21
27
|
|
28
|
+
# not needed, no need for wait states between operations
|
22
29
|
def tck_period=(value)
|
23
30
|
@tck_half_period = value / 2
|
24
31
|
end
|
25
32
|
|
33
|
+
# close out file IO objects for the pins
|
26
34
|
def destroy
|
27
35
|
@tdipin.destroy
|
28
36
|
@tdopin.destroy
|
@@ -34,6 +42,7 @@ module OrigenLink
|
|
34
42
|
@tckpin = nil
|
35
43
|
end
|
36
44
|
|
45
|
+
# perform 1 jtag cycle
|
37
46
|
def do_cycle(tdival, tmsval, capturetdo = false)
|
38
47
|
@tdipin.out(tdival)
|
39
48
|
@tmspin.out(tmsval)
|
@@ -47,11 +56,13 @@ module OrigenLink
|
|
47
56
|
@tckpin.out(0)
|
48
57
|
end
|
49
58
|
|
59
|
+
# advance state machine to test logic reset, then return to run/test idle
|
50
60
|
def do_tlr
|
51
61
|
8.times { do_cycle(0, 1) }
|
52
62
|
do_cycle(0, 0)
|
53
63
|
end
|
54
64
|
|
65
|
+
# shift a value in on tdi, optionall capture tdo
|
55
66
|
def do_shift(numbits, value, capturetdo = false, suppresscomments = false, tdocompare = '')
|
56
67
|
@tdoval = 0
|
57
68
|
@tdostr = ''
|
@@ -98,6 +109,7 @@ module OrigenLink
|
|
98
109
|
end
|
99
110
|
end
|
100
111
|
|
112
|
+
# perform an ir-update
|
101
113
|
def do_ir(numbits, value, options = {})
|
102
114
|
defaults = {
|
103
115
|
capturetdo: false,
|
@@ -130,6 +142,7 @@ module OrigenLink
|
|
130
142
|
do_cycle(0, 0)
|
131
143
|
end
|
132
144
|
|
145
|
+
# perform a dr update
|
133
146
|
def do_dr(numbits, value, options = {})
|
134
147
|
defaults = {
|
135
148
|
capturetdo: true,
|
@@ -160,6 +173,7 @@ module OrigenLink
|
|
160
173
|
do_cycle(0, 0)
|
161
174
|
end
|
162
175
|
|
176
|
+
# traverse the pause dr state
|
163
177
|
def pause_dr
|
164
178
|
do_cycle(0, 1)
|
165
179
|
do_cycle(0, 0)
|
@@ -171,6 +185,7 @@ module OrigenLink
|
|
171
185
|
do_cycle(0, 0)
|
172
186
|
end
|
173
187
|
|
188
|
+
# traverse the pause ir state
|
174
189
|
def pause_ir
|
175
190
|
do_cycle(0, 1)
|
176
191
|
pause_dr
|
@@ -5,20 +5,31 @@
|
|
5
5
|
|
6
6
|
module OrigenLink
|
7
7
|
module Server
|
8
|
+
# The server pin class is used to perform IO using the UDOO pins
|
8
9
|
class Pin
|
9
10
|
@@pin_setup = {
|
10
11
|
in: 'in',
|
11
12
|
out: 'out'
|
12
13
|
}
|
13
14
|
|
15
|
+
# True if this pin exists in /sys/class/gpio after export. False otherwise.
|
14
16
|
attr_reader :gpio_valid
|
17
|
+
# This pin's vector data for the pattern cycle being executed
|
18
|
+
attr_accessor :pattern_data
|
19
|
+
# This pin's index in the vector data received from the plug-in app
|
20
|
+
attr_accessor :pattern_index
|
21
|
+
# This pin's response for the executing vector
|
22
|
+
attr_accessor :response
|
15
23
|
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
24
|
+
# Export the pin io files through the system and take control of the IO
|
25
|
+
#
|
26
|
+
# This method will execute system command
|
27
|
+
# "echo #{ionumber} > /sys/class/gpio/export"
|
28
|
+
# to create the IO file interface. It will
|
29
|
+
# set the direction, initial pin state and initialize
|
30
|
+
# instance variables
|
31
|
+
#
|
32
|
+
# Receives
|
22
33
|
# ionumber - required, value indicating the pin number (BCM IO number,
|
23
34
|
# not the header pin number)
|
24
35
|
# direction - optional, specifies the pin direction. A pin is
|
@@ -49,8 +60,94 @@ module OrigenLink
|
|
49
60
|
end
|
50
61
|
@pin_val_obj = File.open(@pin_val_name, 'r+') if @gpio_valid
|
51
62
|
end
|
63
|
+
@pattern_data = ''
|
64
|
+
@pattern_index = -1
|
65
|
+
@response = 'W'
|
66
|
+
@cycle_failure = false
|
67
|
+
@data_is_drive = false
|
68
|
+
end
|
69
|
+
|
70
|
+
# data_is_drive?
|
71
|
+
# returns whether the current pattern data is drive
|
72
|
+
def data_is_drive?
|
73
|
+
@data_is_drive
|
74
|
+
end
|
75
|
+
|
76
|
+
# data_is_compare?
|
77
|
+
# returns whether the current pattern data is compare
|
78
|
+
def data_is_compare?
|
79
|
+
!@data_is_drive
|
52
80
|
end
|
53
81
|
|
82
|
+
# cycle_failure
|
83
|
+
# returns a boolean indicating pass/fail status of this pin
|
84
|
+
def cycle_failure
|
85
|
+
if @response == 'W'
|
86
|
+
true # force failure if no operation performed
|
87
|
+
else
|
88
|
+
@cycle_failure
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# load_pattern_data
|
93
|
+
# Grab this pin's data character from the pattern data
|
94
|
+
def load_pattern_data(cycle)
|
95
|
+
if @pattern_index > -1
|
96
|
+
@pattern_data = cycle[@pattern_index]
|
97
|
+
@response = 'W'
|
98
|
+
@cycle_failure = false
|
99
|
+
if @pattern_data == '1' || @pattern_data == '0'
|
100
|
+
@data_is_drive = true
|
101
|
+
else
|
102
|
+
@data_is_drive = false
|
103
|
+
end
|
104
|
+
else
|
105
|
+
@gpio_valid = false
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# process_event(event)
|
110
|
+
# perform the requested pin operation and update the response (if required)
|
111
|
+
def process_event(operation, requested_action)
|
112
|
+
if operation == :drive
|
113
|
+
if data_is_drive?
|
114
|
+
if requested_action == 'data'
|
115
|
+
out(@pattern_data)
|
116
|
+
@response = @pattern_data
|
117
|
+
else
|
118
|
+
out(requested_action)
|
119
|
+
end # requested_action == 'data'
|
120
|
+
end # data_is_drive?
|
121
|
+
end # operation == :drive
|
122
|
+
if operation == :compare
|
123
|
+
if data_is_compare?
|
124
|
+
if requested_action == 'data'
|
125
|
+
case self.in
|
126
|
+
when '0'
|
127
|
+
@cycle_failure = true if @pattern_data == 'H'
|
128
|
+
if @pattern_data == 'X'
|
129
|
+
@response = '.'
|
130
|
+
else
|
131
|
+
@response = 'L'
|
132
|
+
end
|
133
|
+
# end of when '0'
|
134
|
+
when '1'
|
135
|
+
@cycle_failure = true if @pattern_data == 'L'
|
136
|
+
if @pattern_data == 'X'
|
137
|
+
@response = '`'
|
138
|
+
else
|
139
|
+
@response = 'H'
|
140
|
+
end
|
141
|
+
# end of when '1'
|
142
|
+
else
|
143
|
+
@response = 'W'
|
144
|
+
end # case
|
145
|
+
end # requested_action == 'data'
|
146
|
+
end # data_is_compare?
|
147
|
+
end # operation == :compare
|
148
|
+
end
|
149
|
+
|
150
|
+
# Close the file IO objects associated with this pin
|
54
151
|
def destroy
|
55
152
|
if @gpio_valid
|
56
153
|
@pin_dir_obj.close
|
@@ -60,10 +157,10 @@ module OrigenLink
|
|
60
157
|
end
|
61
158
|
end
|
62
159
|
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
160
|
+
# Sets the output state of the pin.
|
161
|
+
#
|
162
|
+
# If the pin is setup as an input,
|
163
|
+
# the direction will first be changed to output.
|
67
164
|
#
|
68
165
|
def out(value)
|
69
166
|
if @gpio_valid
|
@@ -75,10 +172,10 @@ module OrigenLink
|
|
75
172
|
end
|
76
173
|
end
|
77
174
|
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
175
|
+
# Reads and returns state of the pin.
|
176
|
+
#
|
177
|
+
# If the pin is setup as an output, the direction will first
|
178
|
+
# be changed to input.
|
82
179
|
#
|
83
180
|
def in
|
84
181
|
if @gpio_valid
|
@@ -95,11 +192,10 @@ module OrigenLink
|
|
95
192
|
end
|
96
193
|
end
|
97
194
|
|
98
|
-
#
|
99
|
-
# description - Sets the pin direction
|
195
|
+
# Sets the pin direction
|
100
196
|
#
|
101
|
-
#
|
102
|
-
#
|
197
|
+
# Receives:
|
198
|
+
# direction - specifies the pin direction. Input is default.
|
103
199
|
#
|
104
200
|
# Valid direction values:
|
105
201
|
# :in - input
|
@@ -113,6 +209,7 @@ module OrigenLink
|
|
113
209
|
end
|
114
210
|
end
|
115
211
|
|
212
|
+
# Returns 'OrigenLinPin' + io number
|
116
213
|
def to_s
|
117
214
|
'OrigenLinkPin' + @ionumber.to_s
|
118
215
|
end
|