origen_link 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
@@ -34,6 +34,11 @@ require 'origen_link/server/pin'
|
|
34
34
|
# timing is stored in a timeset hash
|
35
35
|
# first argument is the timeset key
|
36
36
|
# ex: "pin_timing:1,tdi,0,tdo,1,tms,0
|
37
|
+
#
|
38
|
+
# version (check version of app server is
|
39
|
+
# running)
|
40
|
+
# ex: "version:"
|
41
|
+
# response ex: "P:0.2.0.pre0"
|
37
42
|
##################################################
|
38
43
|
module OrigenLink
|
39
44
|
module Server
|
@@ -45,10 +50,50 @@ module OrigenLink
|
|
45
50
|
@gpio_dir || '/sys/class/gpio'
|
46
51
|
end
|
47
52
|
|
53
|
+
##################################################
|
54
|
+
# OrigenLink::Server::Sequencer Class
|
55
|
+
#
|
56
|
+
# This class processes messages targeted for
|
57
|
+
# pin sequencer interface (vector pattern
|
58
|
+
# execution).
|
59
|
+
#
|
60
|
+
# Supported messages:
|
61
|
+
# pin_assign (create pin mapping)
|
62
|
+
# ex: "pin_assign:tck,3,extal,23,tdo,5"
|
63
|
+
#
|
64
|
+
# pin_patternorder (define vector pin order)
|
65
|
+
# ex: "pin_patternorder:tdo,extal,tck"
|
66
|
+
#
|
67
|
+
# pin_cycle (execute vector data)
|
68
|
+
# ex: "pin_cycle:H11"
|
69
|
+
#
|
70
|
+
# pin_clear (clear all setup information)
|
71
|
+
# ex: "pin_clear:"
|
72
|
+
#
|
73
|
+
# pin_format (setup a pin with return format)
|
74
|
+
# first argument is the timeset
|
75
|
+
# ex: "pin_format:1,tck,rl"
|
76
|
+
#
|
77
|
+
# pin_timing (define when pin events happen)
|
78
|
+
# timing is stored in a timeset hash
|
79
|
+
# first argument is the timeset key
|
80
|
+
# ex: "pin_timing:1,tdi,0,tdo,1,tms,0
|
81
|
+
#
|
82
|
+
# version (check version of app server is
|
83
|
+
# running)
|
84
|
+
# ex: "version:"
|
85
|
+
# response ex: "P:0.2.0.pre0"
|
86
|
+
##################################################
|
48
87
|
class Sequencer
|
88
|
+
# code version of the server (populated by start_link_server)
|
89
|
+
attr_accessor :version
|
90
|
+
# hash holding the pinmap ('name' => pin object)
|
49
91
|
attr_reader :pinmap
|
92
|
+
# array of pin names in pattern order
|
50
93
|
attr_reader :patternorder
|
94
|
+
# hash holding programmed time set information
|
51
95
|
attr_reader :cycletiming
|
96
|
+
# hash holding pin pattern order ('name' => index)
|
52
97
|
attr_reader :patternpinindex
|
53
98
|
|
54
99
|
##################################################
|
@@ -61,6 +106,7 @@ module OrigenLink
|
|
61
106
|
@patternpinindex = Hash.new(-1)
|
62
107
|
@patternorder = []
|
63
108
|
@cycletiming = Hash.new(-1)
|
109
|
+
@version = ''
|
64
110
|
end
|
65
111
|
|
66
112
|
##################################################
|
@@ -90,6 +136,10 @@ module OrigenLink
|
|
90
136
|
pin_format(command[1])
|
91
137
|
when 'pin_timing'
|
92
138
|
pin_timing(command[1])
|
139
|
+
when 'pin_timingv2'
|
140
|
+
pin_timingv2(command[1])
|
141
|
+
when 'version'
|
142
|
+
"P:#{@version}"
|
93
143
|
else
|
94
144
|
'Error Invalid command: ' + command[0].to_s
|
95
145
|
end
|
@@ -126,13 +176,89 @@ module OrigenLink
|
|
126
176
|
end
|
127
177
|
end
|
128
178
|
|
179
|
+
########################################################
|
180
|
+
# pin_timingv2 method
|
181
|
+
# arguments: <args> from the message request
|
182
|
+
# Should be '1,drive,5,pin,10,pin2,|compare,0,pin3'
|
183
|
+
# First integer is timeset number
|
184
|
+
#
|
185
|
+
# returns "P:" or error message
|
186
|
+
#
|
187
|
+
# This method sets up a time set. Any arbitrary
|
188
|
+
# waveform can be generated
|
189
|
+
#
|
190
|
+
########################################################
|
191
|
+
def pin_timingv2(args)
|
192
|
+
# get the tset number
|
193
|
+
argarr = args.split(',')
|
194
|
+
tset_key = argarr.delete_at(0).to_i
|
195
|
+
new_timeset(tset_key)
|
196
|
+
args = argarr.join(',')
|
197
|
+
|
198
|
+
invalid_pins = []
|
199
|
+
|
200
|
+
# process and load the timeset
|
201
|
+
waves = args.split('|')
|
202
|
+
waves.each do |w|
|
203
|
+
argarr = w.split(',')
|
204
|
+
wave_type = argarr.delete_at(0)
|
205
|
+
event_data_key = wave_type + '_event_data'
|
206
|
+
event_pins_key = wave_type + '_event_pins'
|
207
|
+
w = argarr.join(',')
|
208
|
+
events = w.split(';')
|
209
|
+
events.each do |e|
|
210
|
+
argarr = e.split(',')
|
211
|
+
event_key = argarr.delete_at(0).to_f
|
212
|
+
@cycletiming[tset_key]['events'] << event_key
|
213
|
+
@cycletiming[tset_key][event_data_key][event_key] = [] unless @cycletiming[tset_key][event_data_key].key?(event_key)
|
214
|
+
@cycletiming[tset_key][event_data_key][event_key] << argarr.delete_at(0)
|
215
|
+
# now load the pins for this event
|
216
|
+
@cycletiming[tset_key][event_pins_key][event_key] = [] unless @cycletiming[tset_key][event_pins_key].key?(event_key)
|
217
|
+
@cycletiming[tset_key][event_pins_key][event_key] << []
|
218
|
+
argarr.each do |pin|
|
219
|
+
if @pinmap.key?(pin)
|
220
|
+
@cycletiming[tset_key][event_pins_key][event_key].last << @pinmap[pin]
|
221
|
+
else
|
222
|
+
invalid_pins << pin
|
223
|
+
end
|
224
|
+
end # of argarr.each
|
225
|
+
end # of events.each
|
226
|
+
end # of waves.each
|
227
|
+
@cycletiming[tset_key]['events'].uniq!
|
228
|
+
@cycletiming[tset_key]['events'].sort!
|
229
|
+
|
230
|
+
# return result
|
231
|
+
if invalid_pins.size > 0
|
232
|
+
'F:Invalid pins (not in pinmap): ' + invalid_pins.join(', ')
|
233
|
+
else
|
234
|
+
'P:'
|
235
|
+
end
|
236
|
+
end # of def pin_timingv2
|
237
|
+
|
129
238
|
##################################################
|
130
239
|
# new_timeset(tset)
|
131
240
|
# creates a new empty timeset hash
|
241
|
+
#
|
242
|
+
# timing format:
|
243
|
+
# ['events'] = [0, 5, 10, 35]
|
244
|
+
# ['drive_event_data'] = {
|
245
|
+
# 0: ['data']
|
246
|
+
# 10: ['data','0']
|
247
|
+
# 35: ['0']
|
248
|
+
# }
|
249
|
+
# ['drive_event_pins'] = {
|
250
|
+
# 0: [[pin_obj1, pin_obj2]]
|
251
|
+
# 10: [[pin1,pin2], [pin3]]
|
252
|
+
# etc.
|
253
|
+
# }
|
132
254
|
##################################################
|
133
255
|
def new_timeset(tset)
|
134
256
|
@cycletiming[tset] = {}
|
135
|
-
@cycletiming[tset]['
|
257
|
+
@cycletiming[tset]['events'] = []
|
258
|
+
@cycletiming[tset]['drive_event_data'] = {}
|
259
|
+
@cycletiming[tset]['drive_event_pins'] = {}
|
260
|
+
@cycletiming[tset]['compare_event_data'] = {}
|
261
|
+
@cycletiming[tset]['compare_event_pins'] = {}
|
136
262
|
end
|
137
263
|
|
138
264
|
##################################################
|
@@ -146,11 +272,24 @@ module OrigenLink
|
|
146
272
|
argarr = args.split(',')
|
147
273
|
tset_key = argarr.delete_at(0).to_i
|
148
274
|
new_timeset(tset_key) unless @cycletiming.key?(tset_key)
|
149
|
-
@cycletiming[tset_key]
|
150
|
-
@cycletiming[tset_key]
|
275
|
+
@cycletiming[tset_key]['events'] += [1, 3]
|
276
|
+
@cycletiming[tset_key]['events'].sort!
|
277
|
+
[1, 3].each do |event|
|
278
|
+
@cycletiming[tset_key]['drive_event_pins'][event] = [[]]
|
279
|
+
end
|
280
|
+
@cycletiming[tset_key]['compare_event_data'][1] = ['data']
|
151
281
|
0.step(argarr.length - 2, 2) do |index|
|
152
|
-
|
153
|
-
|
282
|
+
drive_type = argarr[index + 1]
|
283
|
+
pin_name = argarr[index]
|
284
|
+
@cycletiming[tset_key]['drive_event_data'][1] = ['data']
|
285
|
+
@cycletiming[tset_key]['drive_event_pins'][1][0] << @pinmap[pin_name]
|
286
|
+
@cycletiming[tset_key]['drive_event_pins'][3][0] << @pinmap[pin_name]
|
287
|
+
@cycletiming[tset_key]['compare_event_pins'][1] = [[@pinmap[pin_name]]]
|
288
|
+
if drive_type == 'rl'
|
289
|
+
@cycletiming[tset_key]['drive_event_data'][3] = ['0']
|
290
|
+
else
|
291
|
+
@cycletiming[tset_key]['drive_event_data'][3] = ['1']
|
292
|
+
end
|
154
293
|
end
|
155
294
|
'P:'
|
156
295
|
end
|
@@ -173,16 +312,41 @@ module OrigenLink
|
|
173
312
|
# format pins are driven between 0 and 1 and
|
174
313
|
# return between 1 and 2. Non-return pins are
|
175
314
|
# acted upon during the 0, 1 or 2 time period.
|
315
|
+
#
|
176
316
|
##################################################
|
177
317
|
def pin_timing(args)
|
178
318
|
argarr = args.split(',')
|
179
319
|
tset_key = argarr.delete_at(0).to_i
|
180
320
|
new_timeset(tset_key) unless @cycletiming.key?(tset_key)
|
181
|
-
|
182
|
-
|
321
|
+
[0, 2, 4].each do |event|
|
322
|
+
@cycletiming[tset_key]['drive_event_pins'][event] = [[]]
|
323
|
+
@cycletiming[tset_key]['compare_event_pins'][event] = [[]]
|
183
324
|
end
|
325
|
+
|
326
|
+
# process the information received
|
184
327
|
0.step(argarr.length - 2, 2) do |index|
|
185
|
-
|
328
|
+
event = argarr[index + 1].to_i
|
329
|
+
# reorder event number to allow rising/falling edges
|
330
|
+
event *= 2
|
331
|
+
pin_name = argarr[index]
|
332
|
+
@cycletiming[tset_key]['events'] << event
|
333
|
+
@cycletiming[tset_key]['drive_event_data'][event] = ['data']
|
334
|
+
@cycletiming[tset_key]['drive_event_pins'][event][0] << @pinmap[pin_name]
|
335
|
+
@cycletiming[tset_key]['compare_event_data'][event] = ['data']
|
336
|
+
@cycletiming[tset_key]['compare_event_pins'][event][0] << @pinmap[pin_name]
|
337
|
+
end
|
338
|
+
|
339
|
+
# remove events with no associated pins
|
340
|
+
@cycletiming[tset_key]['events'].uniq!
|
341
|
+
@cycletiming[tset_key]['events'].sort!
|
342
|
+
[0, 2, 4].each do |event|
|
343
|
+
if @cycletiming[tset_key]['drive_event_pins'][event][0].size == 0
|
344
|
+
@cycletiming[tset_key]['events'] -= [event]
|
345
|
+
@cycletiming[tset_key]['drive_event_data'].delete(event)
|
346
|
+
@cycletiming[tset_key]['drive_event_pins'].delete(event)
|
347
|
+
@cycletiming[tset_key]['compare_event_data'].delete(event)
|
348
|
+
@cycletiming[tset_key]['compare_event_pins'].delete(event)
|
349
|
+
end
|
186
350
|
end
|
187
351
|
'P:'
|
188
352
|
end
|
@@ -198,15 +362,18 @@ module OrigenLink
|
|
198
362
|
def pin_patternorder(args)
|
199
363
|
argarr = args.split(',')
|
200
364
|
index = 0
|
201
|
-
|
202
|
-
@cycletiming[0]['timing'][0].delete_if { true }
|
203
|
-
else
|
204
|
-
new_timeset(0)
|
205
|
-
end
|
365
|
+
new_timeset(0)
|
206
366
|
argarr.each do |pin|
|
207
367
|
@patternorder << pin
|
208
|
-
@
|
209
|
-
@
|
368
|
+
@pinmap[pin].pattern_index = index # pattern index stored in pin object now
|
369
|
+
@patternpinindex[pin] = index # to be removed
|
370
|
+
|
371
|
+
# define default timing
|
372
|
+
@cycletiming[0]['events'] << index
|
373
|
+
@cycletiming[0]['drive_event_data'][index] = ['data']
|
374
|
+
@cycletiming[0]['drive_event_pins'][index] = [[@pinmap[pin]]]
|
375
|
+
@cycletiming[0]['compare_event_data'][index] = ['data']
|
376
|
+
@cycletiming[0]['compare_event_pins'][index] = [[@pinmap[pin]]]
|
210
377
|
index += 1
|
211
378
|
end
|
212
379
|
'P:'
|
@@ -222,6 +389,7 @@ module OrigenLink
|
|
222
389
|
# sequenced. Each pin object and pin data
|
223
390
|
# is passed to the "process_pindata" method
|
224
391
|
# for decoding and execution
|
392
|
+
#
|
225
393
|
##################################################
|
226
394
|
def pin_cycle(args)
|
227
395
|
# set default repeats and timeset
|
@@ -240,108 +408,48 @@ module OrigenLink
|
|
240
408
|
end
|
241
409
|
|
242
410
|
message = ''
|
243
|
-
|
244
|
-
@
|
411
|
+
# load pattern cycle data into pin objects
|
412
|
+
@pinmap.each_value { |p| p.load_pattern_data(args) }
|
413
|
+
cycle_failure = false
|
414
|
+
|
245
415
|
0.upto(repeat_count - 1) do |count|
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
unless @cycletiming[tset]['rl'].nil?
|
256
|
-
@cycletiming[tset]['rl'].each do |pin|
|
257
|
-
process_pindata(@pinmap[pin], '0')
|
416
|
+
# process timing events
|
417
|
+
@cycletiming[tset]['events'].each do |event|
|
418
|
+
# process drive events
|
419
|
+
if @cycletiming[tset]['drive_event_pins'].key?(event)
|
420
|
+
@cycletiming[tset]['drive_event_pins'][event].each_index do |i|
|
421
|
+
@cycletiming[tset]['drive_event_pins'][event][i].each do |p|
|
422
|
+
p.process_event(:drive, @cycletiming[tset]['drive_event_data'][event][i])
|
423
|
+
end
|
424
|
+
end
|
258
425
|
end
|
259
|
-
|
260
|
-
|
261
|
-
@cycletiming[tset]['
|
262
|
-
|
426
|
+
|
427
|
+
# process compare events
|
428
|
+
if @cycletiming[tset]['compare_event_pins'].key?(event)
|
429
|
+
@cycletiming[tset]['compare_event_pins'][event].each_index do |i|
|
430
|
+
@cycletiming[tset]['compare_event_pins'][event][i].each do |p|
|
431
|
+
p.process_event(:compare, @cycletiming[tset]['compare_event_data'][event][i])
|
432
|
+
end
|
433
|
+
end
|
263
434
|
end
|
435
|
+
end # event
|
436
|
+
|
437
|
+
# build response message
|
438
|
+
message += ' ' unless count == 0
|
439
|
+
|
440
|
+
@patternorder.each do |p|
|
441
|
+
message += @pinmap[p].response
|
442
|
+
cycle_failure = true if @pinmap[p].cycle_failure
|
264
443
|
end
|
265
|
-
|
266
|
-
|
267
|
-
# changing response format to return all data for easier debug, below is original method
|
268
|
-
# TODO: remove the commented code once return format and delay handling is finalized
|
269
|
-
# if (count == 0) || (@cycle_failure)
|
270
|
-
# message = ''
|
271
|
-
# @patternorder.each do |pin|
|
272
|
-
# message += response[pin]
|
273
|
-
# end
|
274
|
-
# end
|
275
|
-
message = message + ' ' unless count == 0
|
276
|
-
@patternorder.each do |pin|
|
277
|
-
message += response[pin]
|
278
|
-
end
|
279
|
-
end # end cycle through repeats
|
280
|
-
if @cycle_failure
|
444
|
+
end # count
|
445
|
+
if cycle_failure
|
281
446
|
rtnmsg = 'F:' + message + ' Expected:' + args
|
282
447
|
else
|
283
448
|
rtnmsg = 'P:' + message
|
284
449
|
end
|
285
|
-
# no need to return repeat count since all data is returned
|
286
|
-
# TODO: remove the commented code once return format and delay handling is finalized
|
287
|
-
# rtnmsg += ' Repeat ' + repeat_count.to_s if repeat_count > 1
|
288
450
|
rtnmsg
|
289
451
|
end
|
290
452
|
|
291
|
-
##################################################
|
292
|
-
# process_events
|
293
|
-
# used by pin_cycle to avoid duplicating code
|
294
|
-
##################################################
|
295
|
-
def process_events(events, pindata)
|
296
|
-
response = {}
|
297
|
-
unless events.nil?
|
298
|
-
events.each do |pin|
|
299
|
-
response[pin] = process_pindata(@pinmap[pin], pindata[@patternpinindex[pin]])
|
300
|
-
end
|
301
|
-
end
|
302
|
-
response
|
303
|
-
end
|
304
|
-
|
305
|
-
##################################################
|
306
|
-
# process_pindata method
|
307
|
-
# arguments:
|
308
|
-
# pin: the pin object to be operated on
|
309
|
-
# data: the pin data to be executed
|
310
|
-
# returns: the drive data or read data
|
311
|
-
#
|
312
|
-
# This method translates pin data into one
|
313
|
-
# of three possible events. Drive 0, drive 1
|
314
|
-
# or read. Supported character decode:
|
315
|
-
# drive 0: '0'
|
316
|
-
# drive 1: '1'
|
317
|
-
# read: anything else
|
318
|
-
##################################################
|
319
|
-
def process_pindata(pin, data)
|
320
|
-
if data == '0' || data == '1'
|
321
|
-
pin.out(data)
|
322
|
-
data
|
323
|
-
else
|
324
|
-
case pin.in
|
325
|
-
when '0'
|
326
|
-
@cycle_failure = true if data == 'H'
|
327
|
-
if data == 'X'
|
328
|
-
'.'
|
329
|
-
else
|
330
|
-
'L'
|
331
|
-
end
|
332
|
-
when '1'
|
333
|
-
@cycle_failure = true if data == 'L'
|
334
|
-
if data == 'X'
|
335
|
-
'`'
|
336
|
-
else
|
337
|
-
'H'
|
338
|
-
end
|
339
|
-
else
|
340
|
-
'W'
|
341
|
-
end
|
342
|
-
end
|
343
|
-
end
|
344
|
-
|
345
453
|
##################################################
|
346
454
|
# pin_clear method
|
347
455
|
#
|
@@ -1,5 +1,7 @@
|
|
1
1
|
module OrigenLink
|
2
2
|
module ServerCom
|
3
|
+
# send a single command to the server
|
4
|
+
#
|
3
5
|
# send_cmd(cmdstr, argstr)
|
4
6
|
# cmdstr is a valid command. <category>_<command>
|
5
7
|
# Ex: 'pin_assign'
|
@@ -72,6 +74,7 @@ module OrigenLink
|
|
72
74
|
response # ensure the response is passed along
|
73
75
|
end
|
74
76
|
|
77
|
+
# Send the stored batch of vectors to the server
|
75
78
|
def send_batch(vector_batch)
|
76
79
|
vector_batch_str = @user_name + "\n" + vector_batch.join("\n") + "\n\n"
|
77
80
|
user_status = ''
|
@@ -124,7 +127,8 @@ module OrigenLink
|
|
124
127
|
response
|
125
128
|
end
|
126
129
|
|
127
|
-
#
|
130
|
+
# Handle a server response (inform of Failures)
|
131
|
+
#
|
128
132
|
# There are several setup commands that initialize the debugger device with
|
129
133
|
# information about how to interact with the dut. All of the setup commands
|
130
134
|
# return pass or fail. This method exists so that the code doesn't have to
|
@@ -15,10 +15,10 @@ module OrigenLink
|
|
15
15
|
invalid_pin_number_test: false,
|
16
16
|
missing_pinmap_test: false
|
17
17
|
}.merge(options)
|
18
|
-
add_pin :tclk
|
19
|
-
add_pin :tdi
|
20
|
-
add_pin :tdo
|
21
|
-
add_pin :tms
|
18
|
+
add_pin :tclk, meta: { link_io: 119 }
|
19
|
+
add_pin :tdi, meta: { link_io: 116 }
|
20
|
+
add_pin :tdo, meta: { link_io: 124 }
|
21
|
+
add_pin :tms, meta: { link_io: 6 }
|
22
22
|
add_pin :resetb
|
23
23
|
add_pins :port_a, size: 8
|
24
24
|
|
@@ -31,7 +31,7 @@ module OrigenLink
|
|
31
31
|
else
|
32
32
|
tester.pinmap = 'tclk,119,tms,6,tdi,116,tdo,124' unless options[:missing_pinmap_test]
|
33
33
|
end
|
34
|
-
tester.pinorder = 'tclk,tms,tdi,tdo'
|
34
|
+
# tester.pinorder = 'tclk,tms,tdi,tdo'
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|