origen_link 0.2.0.pre0 → 0.2.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 +66 -66
- data/config/application.rb +109 -109
- data/config/commands.rb +74 -74
- data/config/shared_commands.rb +40 -40
- data/config/version.rb +8 -8
- data/lib/origen_link.rb +4 -4
- data/lib/origen_link/callback_handlers.rb +13 -13
- data/lib/origen_link/capture_support.rb +94 -94
- data/lib/origen_link/configuration_commands.rb +84 -84
- data/lib/origen_link/listener.rb +78 -78
- data/lib/origen_link/server/jtag.rb +180 -180
- data/lib/origen_link/server/pin.rb +121 -121
- data/lib/origen_link/server/sequencer.rb +361 -361
- data/lib/origen_link/server_com.rb +150 -150
- data/lib/origen_link/test/top_level.rb +48 -48
- data/lib/origen_link/test/top_level_controller.rb +44 -44
- data/lib/origen_link/test/vector_based.rb +25 -25
- data/lib/origen_link/vector_based.rb +366 -365
- data/lib/tasks/origen_link.rake +6 -6
- data/pattern/example.rb +4 -4
- data/pattern/jtag_capture_id.rb +22 -22
- data/pattern/transaction_test.rb +18 -18
- data/templates/web/index.md.erb +25 -25
- data/templates/web/layouts/_basic.html.erb +13 -13
- data/templates/web/partials/_navbar.html.erb +20 -20
- data/templates/web/release_notes.md.erb +5 -5
- metadata +3 -4
@@ -1,25 +1,25 @@
|
|
1
|
-
require 'origen_link/vector_based'
|
2
|
-
|
3
|
-
module OrigenLink
|
4
|
-
module Test
|
5
|
-
class VectorBased < ::OrigenLink::VectorBased
|
6
|
-
attr_accessor :message, :microcodestr, :test_response
|
7
|
-
|
8
|
-
def send_cmd(cmdstr, argstr)
|
9
|
-
@message = cmdstr + ':' + argstr
|
10
|
-
@test_response
|
11
|
-
end
|
12
|
-
|
13
|
-
def send_batch(vector_batch)
|
14
|
-
@test_response
|
15
|
-
end
|
16
|
-
|
17
|
-
def setup_cmd_response_logger(command, response)
|
18
|
-
end
|
19
|
-
|
20
|
-
def microcode(msg)
|
21
|
-
@microcodestr = @microcodestr + msg
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
1
|
+
require 'origen_link/vector_based'
|
2
|
+
|
3
|
+
module OrigenLink
|
4
|
+
module Test
|
5
|
+
class VectorBased < ::OrigenLink::VectorBased
|
6
|
+
attr_accessor :message, :microcodestr, :test_response
|
7
|
+
|
8
|
+
def send_cmd(cmdstr, argstr)
|
9
|
+
@message = cmdstr + ':' + argstr
|
10
|
+
@test_response
|
11
|
+
end
|
12
|
+
|
13
|
+
def send_batch(vector_batch)
|
14
|
+
@test_response
|
15
|
+
end
|
16
|
+
|
17
|
+
def setup_cmd_response_logger(command, response)
|
18
|
+
end
|
19
|
+
|
20
|
+
def microcode(msg)
|
21
|
+
@microcodestr = @microcodestr + msg
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -1,365 +1,366 @@
|
|
1
|
-
require 'etc'
|
2
|
-
require 'origen_testers'
|
3
|
-
require 'origen_link/server_com'
|
4
|
-
require 'origen_link/capture_support'
|
5
|
-
require 'origen_link/configuration_commands'
|
6
|
-
require 'origen_link/callback_handlers'
|
7
|
-
module OrigenLink
|
8
|
-
# OrigenLink::VectorBased
|
9
|
-
# This class is meant to be used for live silicon debug. Vector data that Origen
|
10
|
-
# generates is intercepted and sent to a debug device (typically will be a Udoo
|
11
|
-
# Neo - www.udoo.org). The debug device can be any device that is able to serve
|
12
|
-
# a TCP socket, recieve and interpret the command set used by this class and send
|
13
|
-
# the expected responses.
|
14
|
-
#
|
15
|
-
# Integration instructions
|
16
|
-
# Set the pin map (must be done first) and pin order
|
17
|
-
# if tester.link?
|
18
|
-
# tester.pinmap = 'tclk,26,tms,19,tdi,16,tdo,23'
|
19
|
-
# tester.pinorder = 'tclk,tms,tdi,tdo'
|
20
|
-
# end
|
21
|
-
#
|
22
|
-
# Set Origen to only generate vectors for pins in the pinmap (order should match)
|
23
|
-
# pin_pattern_order :tclk, :tms, :tdi, :tdo, only: true if tester.link?
|
24
|
-
#
|
25
|
-
# At the beginning of the Startup method add this line
|
26
|
-
# tester.initialize_pattern if tester.link?
|
27
|
-
#
|
28
|
-
# At the end of the Shutdown method add this line
|
29
|
-
# tester.finalize_pattern if tester.link?
|
30
|
-
#
|
31
|
-
# Create a link environment with the IP address and socket number of a link server
|
32
|
-
# $tester = OrigenLink::VectorBased.new('192.168.0.2', 12777)
|
33
|
-
class VectorBased
|
34
|
-
include OrigenTesters::VectorBasedTester
|
35
|
-
include ServerCom
|
36
|
-
include CaptureSupport
|
37
|
-
include ConfigurationCommands
|
38
|
-
|
39
|
-
# these attributes are exposed for testing purposes, a user would not need to read them
|
40
|
-
attr_reader :fail_count, :vector_count, :total_comm_time, :total_connect_time, :total_xmit_time
|
41
|
-
attr_reader :total_recv_time, :total_packets, :vector_repeatcount, :tsets_programmed, :captured_data
|
42
|
-
attr_reader :vector_batch, :store_pins_batch, :comment_batch
|
43
|
-
attr_reader :user_name, :initial_comm_sent
|
44
|
-
|
45
|
-
def initialize(address, port, options = {})
|
46
|
-
@address = address
|
47
|
-
@port = port
|
48
|
-
@fail_count = 0
|
49
|
-
@vector_count = 0
|
50
|
-
@previous_vectordata = ''
|
51
|
-
@previous_tset = ''
|
52
|
-
@vector_repeatcount = 0
|
53
|
-
@total_comm_time = 0
|
54
|
-
@total_connect_time = 0
|
55
|
-
@total_xmit_time = 0
|
56
|
-
@total_recv_time = 0
|
57
|
-
@total_packets = 0
|
58
|
-
@max_packet_time = 0
|
59
|
-
@max_receive_time = 0
|
60
|
-
@tsets_programmed = {}
|
61
|
-
@tset_count = 1
|
62
|
-
@store_pins = []
|
63
|
-
@captured_data = []
|
64
|
-
# A tester seems to be unable to register as a callback handler, so for now instantiating a
|
65
|
-
# dedicated object to implement the handlers related to this tester
|
66
|
-
CallbackHandlers.new
|
67
|
-
@vector_batch = []
|
68
|
-
@store_pins_batch = {}
|
69
|
-
@comment_batch = {}
|
70
|
-
@batch_vectors = true
|
71
|
-
@pattern_link_messages = []
|
72
|
-
@pattern_comments = {}
|
73
|
-
@user_name = Etc.getlogin
|
74
|
-
@initial_comm_sent = false
|
75
|
-
end
|
76
|
-
|
77
|
-
# push_comment
|
78
|
-
# This method intercepts comments so they can be correctly placed in the output file
|
79
|
-
# when vector batching is used
|
80
|
-
def push_comment(msg)
|
81
|
-
if @batch_vectors
|
82
|
-
key = @vector_batch.length
|
83
|
-
if @comment_batch.key?(key)
|
84
|
-
@comment_batch[key] = @comment_batch[key] + "\n" + msg
|
85
|
-
else
|
86
|
-
@comment_batch[key] = msg
|
87
|
-
end
|
88
|
-
pattern_key = @pattern_link_messages.length + key
|
89
|
-
@pattern_comments[pattern_key] = @comment_batch[key]
|
90
|
-
else
|
91
|
-
microcode msg
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
# push_vector
|
96
|
-
# This method intercepts vector data from Origen, removes white spaces and compresses repeats
|
97
|
-
def push_vector(options)
|
98
|
-
programmed_data = options[:pin_vals].gsub(/\s+/, '')
|
99
|
-
unless options[:timeset]
|
100
|
-
puts 'No timeset defined!'
|
101
|
-
puts 'Add one to your top level startup method or target like this:'
|
102
|
-
puts '$tester.set_timeset("nvmbist", 40) # Where 40 is the period in ns'
|
103
|
-
exit 1
|
104
|
-
end
|
105
|
-
tset = options[:timeset].name
|
106
|
-
if @vector_count > 0
|
107
|
-
# compressing repeats as we go
|
108
|
-
if (programmed_data == @previous_vectordata) && (@previous_tset == tset) && @store_pins.empty?
|
109
|
-
@vector_repeatcount += 1
|
110
|
-
else
|
111
|
-
# all repeats of the previous vector have been counted
|
112
|
-
# time to flush. Don't panic though! @previous_vectordata
|
113
|
-
# is what gets flushed. programmed_data is passed as an
|
114
|
-
# arg to be set as the new @previous_vectordata
|
115
|
-
flush_vector(programmed_data, tset)
|
116
|
-
end
|
117
|
-
else
|
118
|
-
# if this is the first vector of the pattern, insure variables are initialized
|
119
|
-
@previous_vectordata = programmed_data
|
120
|
-
@previous_tset = tset
|
121
|
-
@vector_repeatcount = 1
|
122
|
-
end # if vector_count > 0
|
123
|
-
@vector_count += 1
|
124
|
-
end
|
125
|
-
|
126
|
-
# flush_vector
|
127
|
-
# Just as the name suggests, this method "flushes" a vector. This is necessary because
|
128
|
-
# of repeat compression (a vector isn't sent until different vector data is encountered)
|
129
|
-
#
|
130
|
-
# Don't forget to flush when you're in debug mode. Otherwise, the last vector of a
|
131
|
-
# write command won't be sent to the server.
|
132
|
-
def flush_vector(programmed_data = '', tset = '')
|
133
|
-
# prevent server crash when vector_flush is used during debug
|
134
|
-
unless @previous_vectordata == ''
|
135
|
-
if @vector_repeatcount > 1
|
136
|
-
repeat_prefix = "repeat#{@vector_repeatcount},"
|
137
|
-
else
|
138
|
-
repeat_prefix = ''
|
139
|
-
end
|
140
|
-
if @tsets_programmed[@previous_tset]
|
141
|
-
tset_prefix = "tset#{@tsets_programmed[@previous_tset]},"
|
142
|
-
else
|
143
|
-
tset_prefix = ''
|
144
|
-
end
|
145
|
-
|
146
|
-
if @batch_vectors
|
147
|
-
@vector_batch << 'pin_cycle:' + tset_prefix + repeat_prefix + @previous_vectordata
|
148
|
-
# store capture pins for batch processing
|
149
|
-
unless @store_pins.empty?
|
150
|
-
@store_pins_batch[@vector_batch.length - 1] = @store_pins
|
151
|
-
end
|
152
|
-
else
|
153
|
-
process_vector_response(send_cmd('pin_cycle', tset_prefix + repeat_prefix + @previous_vectordata))
|
154
|
-
end
|
155
|
-
|
156
|
-
# make sure that only requested vectors are stored when batching is enabled
|
157
|
-
@store_pins = []
|
158
|
-
end
|
159
|
-
|
160
|
-
@vector_repeatcount = 1
|
161
|
-
@previous_vectordata = programmed_data
|
162
|
-
@previous_tset = tset
|
163
|
-
end
|
164
|
-
|
165
|
-
# synchronize
|
166
|
-
# This method will synchronize the DUT state with Origen. All generated
|
167
|
-
# vectors are sent to the DUT for execution and the responses are processed
|
168
|
-
def synchronize(output_file = '')
|
169
|
-
flush_vector
|
170
|
-
if @batch_vectors
|
171
|
-
process_response(send_batch(@vector_batch), output_file)
|
172
|
-
end
|
173
|
-
@vector_batch = []
|
174
|
-
@store_pins_batch.clear
|
175
|
-
@comment_batch.clear
|
176
|
-
end
|
177
|
-
|
178
|
-
# process_response
|
179
|
-
# This method will process a server response. Send log info to the output,
|
180
|
-
# keep track of fail count and captured data
|
181
|
-
def process_response(response, output_file = '')
|
182
|
-
if response.is_a?(Array)
|
183
|
-
# if called from finalize_pattern -> synchronize, open the output_file and store results
|
184
|
-
output_obj = nil
|
185
|
-
output_obj = File.open(output_file, 'a+') unless output_file == ''
|
186
|
-
|
187
|
-
# in case there were only comments and no vectors, place comments (if any)
|
188
|
-
microcode @comment_batch[0] if response.size == 0
|
189
|
-
|
190
|
-
response.each_index do |index|
|
191
|
-
# restore store pins state for processing
|
192
|
-
if @store_pins_batch.key?(index)
|
193
|
-
@store_pins = @store_pins_batch[index]
|
194
|
-
else
|
195
|
-
@store_pins = []
|
196
|
-
end
|
197
|
-
process_vector_response(response[index], output_obj)
|
198
|
-
if @comment_batch.key?(index)
|
199
|
-
if output_file == ''
|
200
|
-
microcode @comment_batch[index]
|
201
|
-
else
|
202
|
-
# get the header placed correctly, the below code doesn't work
|
203
|
-
# if index == response.length - 1
|
204
|
-
# output_obj.puts 'last comment'
|
205
|
-
# output_obj.lineno = 0
|
206
|
-
# end
|
207
|
-
output_obj.puts(@comment_batch[index])
|
208
|
-
end
|
209
|
-
end
|
210
|
-
end
|
211
|
-
output_obj.close unless output_file == ''
|
212
|
-
else
|
213
|
-
process_vector_response(response)
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
# process_vector_response
|
218
|
-
# This method exists to prevent code duplication when handling an array of
|
219
|
-
# batched responses versus a single response string.
|
220
|
-
def process_vector_response(vector_response, output_obj = nil)
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
vector_response
|
225
|
-
vector_response
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
expected_msg = '
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
thiscyclefail = true if (cycle[index] == '
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
#
|
260
|
-
@
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
#
|
266
|
-
#
|
267
|
-
|
268
|
-
|
269
|
-
@
|
270
|
-
@
|
271
|
-
@
|
272
|
-
@
|
273
|
-
@
|
274
|
-
@
|
275
|
-
|
276
|
-
|
277
|
-
@
|
278
|
-
@
|
279
|
-
@
|
280
|
-
@
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
#
|
291
|
-
#
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
Origen.log.debug("total
|
299
|
-
Origen.log.debug("total
|
300
|
-
Origen.log.debug("total
|
301
|
-
Origen.log.debug("total
|
302
|
-
Origen.log.debug("total
|
303
|
-
Origen.log.debug("
|
304
|
-
Origen.log.debug("
|
305
|
-
Origen.log.debug("
|
306
|
-
Origen.log.debug("
|
307
|
-
Origen.log.debug("max
|
308
|
-
Origen.log.debug("max
|
309
|
-
|
310
|
-
|
311
|
-
Origen.
|
312
|
-
|
313
|
-
|
314
|
-
Origen.
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
file.puts("
|
320
|
-
@
|
321
|
-
|
322
|
-
file.puts(@
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
#
|
330
|
-
#
|
331
|
-
#
|
332
|
-
#
|
333
|
-
#
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
#
|
340
|
-
# true
|
341
|
-
#
|
342
|
-
#
|
343
|
-
#
|
344
|
-
#
|
345
|
-
#
|
346
|
-
#
|
347
|
-
#
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
end
|
1
|
+
require 'etc'
|
2
|
+
require 'origen_testers'
|
3
|
+
require 'origen_link/server_com'
|
4
|
+
require 'origen_link/capture_support'
|
5
|
+
require 'origen_link/configuration_commands'
|
6
|
+
require 'origen_link/callback_handlers'
|
7
|
+
module OrigenLink
|
8
|
+
# OrigenLink::VectorBased
|
9
|
+
# This class is meant to be used for live silicon debug. Vector data that Origen
|
10
|
+
# generates is intercepted and sent to a debug device (typically will be a Udoo
|
11
|
+
# Neo - www.udoo.org). The debug device can be any device that is able to serve
|
12
|
+
# a TCP socket, recieve and interpret the command set used by this class and send
|
13
|
+
# the expected responses.
|
14
|
+
#
|
15
|
+
# Integration instructions
|
16
|
+
# Set the pin map (must be done first) and pin order
|
17
|
+
# if tester.link?
|
18
|
+
# tester.pinmap = 'tclk,26,tms,19,tdi,16,tdo,23'
|
19
|
+
# tester.pinorder = 'tclk,tms,tdi,tdo'
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# Set Origen to only generate vectors for pins in the pinmap (order should match)
|
23
|
+
# pin_pattern_order :tclk, :tms, :tdi, :tdo, only: true if tester.link?
|
24
|
+
#
|
25
|
+
# At the beginning of the Startup method add this line
|
26
|
+
# tester.initialize_pattern if tester.link?
|
27
|
+
#
|
28
|
+
# At the end of the Shutdown method add this line
|
29
|
+
# tester.finalize_pattern if tester.link?
|
30
|
+
#
|
31
|
+
# Create a link environment with the IP address and socket number of a link server
|
32
|
+
# $tester = OrigenLink::VectorBased.new('192.168.0.2', 12777)
|
33
|
+
class VectorBased
|
34
|
+
include OrigenTesters::VectorBasedTester
|
35
|
+
include ServerCom
|
36
|
+
include CaptureSupport
|
37
|
+
include ConfigurationCommands
|
38
|
+
|
39
|
+
# these attributes are exposed for testing purposes, a user would not need to read them
|
40
|
+
attr_reader :fail_count, :vector_count, :total_comm_time, :total_connect_time, :total_xmit_time
|
41
|
+
attr_reader :total_recv_time, :total_packets, :vector_repeatcount, :tsets_programmed, :captured_data
|
42
|
+
attr_reader :vector_batch, :store_pins_batch, :comment_batch
|
43
|
+
attr_reader :user_name, :initial_comm_sent
|
44
|
+
|
45
|
+
def initialize(address, port, options = {})
|
46
|
+
@address = address
|
47
|
+
@port = port
|
48
|
+
@fail_count = 0
|
49
|
+
@vector_count = 0
|
50
|
+
@previous_vectordata = ''
|
51
|
+
@previous_tset = ''
|
52
|
+
@vector_repeatcount = 0
|
53
|
+
@total_comm_time = 0
|
54
|
+
@total_connect_time = 0
|
55
|
+
@total_xmit_time = 0
|
56
|
+
@total_recv_time = 0
|
57
|
+
@total_packets = 0
|
58
|
+
@max_packet_time = 0
|
59
|
+
@max_receive_time = 0
|
60
|
+
@tsets_programmed = {}
|
61
|
+
@tset_count = 1
|
62
|
+
@store_pins = []
|
63
|
+
@captured_data = []
|
64
|
+
# A tester seems to be unable to register as a callback handler, so for now instantiating a
|
65
|
+
# dedicated object to implement the handlers related to this tester
|
66
|
+
CallbackHandlers.new
|
67
|
+
@vector_batch = []
|
68
|
+
@store_pins_batch = {}
|
69
|
+
@comment_batch = {}
|
70
|
+
@batch_vectors = true
|
71
|
+
@pattern_link_messages = []
|
72
|
+
@pattern_comments = {}
|
73
|
+
@user_name = Etc.getlogin
|
74
|
+
@initial_comm_sent = false
|
75
|
+
end
|
76
|
+
|
77
|
+
# push_comment
|
78
|
+
# This method intercepts comments so they can be correctly placed in the output file
|
79
|
+
# when vector batching is used
|
80
|
+
def push_comment(msg)
|
81
|
+
if @batch_vectors
|
82
|
+
key = @vector_batch.length
|
83
|
+
if @comment_batch.key?(key)
|
84
|
+
@comment_batch[key] = @comment_batch[key] + "\n" + msg
|
85
|
+
else
|
86
|
+
@comment_batch[key] = msg
|
87
|
+
end
|
88
|
+
pattern_key = @pattern_link_messages.length + key
|
89
|
+
@pattern_comments[pattern_key] = @comment_batch[key]
|
90
|
+
else
|
91
|
+
microcode msg
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# push_vector
|
96
|
+
# This method intercepts vector data from Origen, removes white spaces and compresses repeats
|
97
|
+
def push_vector(options)
|
98
|
+
programmed_data = options[:pin_vals].gsub(/\s+/, '')
|
99
|
+
unless options[:timeset]
|
100
|
+
puts 'No timeset defined!'
|
101
|
+
puts 'Add one to your top level startup method or target like this:'
|
102
|
+
puts '$tester.set_timeset("nvmbist", 40) # Where 40 is the period in ns'
|
103
|
+
exit 1
|
104
|
+
end
|
105
|
+
tset = options[:timeset].name
|
106
|
+
if @vector_count > 0
|
107
|
+
# compressing repeats as we go
|
108
|
+
if (programmed_data == @previous_vectordata) && (@previous_tset == tset) && @store_pins.empty?
|
109
|
+
@vector_repeatcount += 1
|
110
|
+
else
|
111
|
+
# all repeats of the previous vector have been counted
|
112
|
+
# time to flush. Don't panic though! @previous_vectordata
|
113
|
+
# is what gets flushed. programmed_data is passed as an
|
114
|
+
# arg to be set as the new @previous_vectordata
|
115
|
+
flush_vector(programmed_data, tset)
|
116
|
+
end
|
117
|
+
else
|
118
|
+
# if this is the first vector of the pattern, insure variables are initialized
|
119
|
+
@previous_vectordata = programmed_data
|
120
|
+
@previous_tset = tset
|
121
|
+
@vector_repeatcount = 1
|
122
|
+
end # if vector_count > 0
|
123
|
+
@vector_count += 1
|
124
|
+
end
|
125
|
+
|
126
|
+
# flush_vector
|
127
|
+
# Just as the name suggests, this method "flushes" a vector. This is necessary because
|
128
|
+
# of repeat compression (a vector isn't sent until different vector data is encountered)
|
129
|
+
#
|
130
|
+
# Don't forget to flush when you're in debug mode. Otherwise, the last vector of a
|
131
|
+
# write command won't be sent to the server.
|
132
|
+
def flush_vector(programmed_data = '', tset = '')
|
133
|
+
# prevent server crash when vector_flush is used during debug
|
134
|
+
unless @previous_vectordata == ''
|
135
|
+
if @vector_repeatcount > 1
|
136
|
+
repeat_prefix = "repeat#{@vector_repeatcount},"
|
137
|
+
else
|
138
|
+
repeat_prefix = ''
|
139
|
+
end
|
140
|
+
if @tsets_programmed[@previous_tset]
|
141
|
+
tset_prefix = "tset#{@tsets_programmed[@previous_tset]},"
|
142
|
+
else
|
143
|
+
tset_prefix = ''
|
144
|
+
end
|
145
|
+
|
146
|
+
if @batch_vectors
|
147
|
+
@vector_batch << 'pin_cycle:' + tset_prefix + repeat_prefix + @previous_vectordata
|
148
|
+
# store capture pins for batch processing
|
149
|
+
unless @store_pins.empty?
|
150
|
+
@store_pins_batch[@vector_batch.length - 1] = @store_pins
|
151
|
+
end
|
152
|
+
else
|
153
|
+
process_vector_response(send_cmd('pin_cycle', tset_prefix + repeat_prefix + @previous_vectordata))
|
154
|
+
end
|
155
|
+
|
156
|
+
# make sure that only requested vectors are stored when batching is enabled
|
157
|
+
@store_pins = []
|
158
|
+
end
|
159
|
+
|
160
|
+
@vector_repeatcount = 1
|
161
|
+
@previous_vectordata = programmed_data
|
162
|
+
@previous_tset = tset
|
163
|
+
end
|
164
|
+
|
165
|
+
# synchronize
|
166
|
+
# This method will synchronize the DUT state with Origen. All generated
|
167
|
+
# vectors are sent to the DUT for execution and the responses are processed
|
168
|
+
def synchronize(output_file = '')
|
169
|
+
flush_vector
|
170
|
+
if @batch_vectors
|
171
|
+
process_response(send_batch(@vector_batch), output_file)
|
172
|
+
end
|
173
|
+
@vector_batch = []
|
174
|
+
@store_pins_batch.clear
|
175
|
+
@comment_batch.clear
|
176
|
+
end
|
177
|
+
|
178
|
+
# process_response
|
179
|
+
# This method will process a server response. Send log info to the output,
|
180
|
+
# keep track of fail count and captured data
|
181
|
+
def process_response(response, output_file = '')
|
182
|
+
if response.is_a?(Array)
|
183
|
+
# if called from finalize_pattern -> synchronize, open the output_file and store results
|
184
|
+
output_obj = nil
|
185
|
+
output_obj = File.open(output_file, 'a+') unless output_file == ''
|
186
|
+
|
187
|
+
# in case there were only comments and no vectors, place comments (if any)
|
188
|
+
microcode @comment_batch[0] if response.size == 0
|
189
|
+
|
190
|
+
response.each_index do |index|
|
191
|
+
# restore store pins state for processing
|
192
|
+
if @store_pins_batch.key?(index)
|
193
|
+
@store_pins = @store_pins_batch[index]
|
194
|
+
else
|
195
|
+
@store_pins = []
|
196
|
+
end
|
197
|
+
process_vector_response(response[index], output_obj)
|
198
|
+
if @comment_batch.key?(index)
|
199
|
+
if output_file == ''
|
200
|
+
microcode @comment_batch[index]
|
201
|
+
else
|
202
|
+
# get the header placed correctly, the below code doesn't work
|
203
|
+
# if index == response.length - 1
|
204
|
+
# output_obj.puts 'last comment'
|
205
|
+
# output_obj.lineno = 0
|
206
|
+
# end
|
207
|
+
output_obj.puts(@comment_batch[index])
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
output_obj.close unless output_file == ''
|
212
|
+
else
|
213
|
+
process_vector_response(response)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
# process_vector_response
|
218
|
+
# This method exists to prevent code duplication when handling an array of
|
219
|
+
# batched responses versus a single response string.
|
220
|
+
def process_vector_response(vector_response, output_obj = nil)
|
221
|
+
msg = ''
|
222
|
+
unless @store_pins.empty?
|
223
|
+
msg = " (Captured #{@store_pins.map(&:name).join(', ')})\n"
|
224
|
+
capture_data(vector_response)
|
225
|
+
vector_response.strip!
|
226
|
+
# vector_response += msg
|
227
|
+
end
|
228
|
+
vector_cycles = vector_response.split(/\s+/)
|
229
|
+
expected_msg = ''
|
230
|
+
expected_msg = ' ' + vector_cycles.pop if vector_cycles[vector_cycles.length - 1] =~ /Expected/
|
231
|
+
pfstatus = vector_cycles[0].chr
|
232
|
+
vector_cycles[0] = vector_cycles[0].byteslice(2, vector_cycles[0].length - 2)
|
233
|
+
|
234
|
+
vector_cycles.each do |cycle|
|
235
|
+
thiscyclefail = false
|
236
|
+
if pfstatus == 'F'
|
237
|
+
# check to see if this cycle failed
|
238
|
+
0.upto(cycle.length - 1) do |index|
|
239
|
+
thiscyclefail = true if (cycle[index] == 'H') && (expected_msg[expected_msg.length - cycle.length + index] == 'L')
|
240
|
+
thiscyclefail = true if (cycle[index] == 'L') && (expected_msg[expected_msg.length - cycle.length + index] == 'H')
|
241
|
+
end
|
242
|
+
end
|
243
|
+
if thiscyclefail
|
244
|
+
expected_msg_prnt = expected_msg
|
245
|
+
prepend = 'F:'
|
246
|
+
else
|
247
|
+
expected_msg_prnt = ''
|
248
|
+
prepend = 'P:'
|
249
|
+
end
|
250
|
+
|
251
|
+
if output_obj.nil?
|
252
|
+
microcode prepend + cycle + expected_msg_prnt + msg
|
253
|
+
else
|
254
|
+
output_obj.puts(prepend + cycle + expected_msg_prnt + msg)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
unless vector_response.chr == 'P'
|
259
|
+
# TODO: Put this back with an option to disable, based on a serial or parallel interface being used
|
260
|
+
# microcode 'E:' + @previous_vectordata + ' //expected data for previous vector'
|
261
|
+
@fail_count += 1
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
# initialize_pattern
|
266
|
+
# This method sets initializes variables at the start of a pattern.
|
267
|
+
# it is called automatically when pattern generation starts.
|
268
|
+
def initialize_pattern
|
269
|
+
@fail_count = 0
|
270
|
+
@vector_count = 0
|
271
|
+
@vector_batch.delete_if { true }
|
272
|
+
@store_pins_batch.clear
|
273
|
+
@comment_batch.clear
|
274
|
+
@pattern_link_messages.delete_if { true }
|
275
|
+
@pattern_comments.clear
|
276
|
+
|
277
|
+
@total_packets = 0
|
278
|
+
@total_comm_time = 0
|
279
|
+
@total_connect_time = 0
|
280
|
+
@total_xmit_time = 0
|
281
|
+
@total_recv_time = 0
|
282
|
+
|
283
|
+
if @pinmap.nil?
|
284
|
+
Origen.log.error('pinmap has not been setup, use tester.pinmap= to initialize a pinmap')
|
285
|
+
else
|
286
|
+
Origen.log.debug('executing pattern with pinmap:' + @pinmap.to_s)
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
# finalize_pattern
|
291
|
+
# This method flushes the final vector. Then, it logs success or failure of the
|
292
|
+
# pattern execution along with execution time information.
|
293
|
+
def finalize_pattern(output_file)
|
294
|
+
Origen.log.debug('Pattern generation completed. Sending all stored vector data')
|
295
|
+
synchronize(output_file)
|
296
|
+
send_cmd('', 'session_end')
|
297
|
+
# for debug, report communication times
|
298
|
+
Origen.log.debug("total communication time: #{@total_comm_time}")
|
299
|
+
Origen.log.debug("total connect time: #{@total_connect_time}")
|
300
|
+
Origen.log.debug("total transmit time: #{@total_xmit_time}")
|
301
|
+
Origen.log.debug("total receive time: #{@total_recv_time}")
|
302
|
+
Origen.log.debug("total packets: #{@total_packets}")
|
303
|
+
Origen.log.debug("total time per packet: #{@total_comm_time / @total_packets}")
|
304
|
+
Origen.log.debug("connect time per packet: #{@total_connect_time / @total_packets}")
|
305
|
+
Origen.log.debug("transmit time per packet: #{@total_xmit_time / @total_packets}")
|
306
|
+
Origen.log.debug("receive time per packet: #{@total_recv_time / @total_packets}")
|
307
|
+
Origen.log.debug("max packet time: #{@max_packet_time}")
|
308
|
+
Origen.log.debug("max duration command - #{@longest_packet}")
|
309
|
+
Origen.log.debug("max receive time: #{@max_receive_time}")
|
310
|
+
if @fail_count == 0
|
311
|
+
# Origen.log.success("PASS - pattern execution passed (#{@vector_count} vectors pass)")
|
312
|
+
Origen.app.stats.report_pass
|
313
|
+
else
|
314
|
+
# Origen.log.error("FAIL - pattern execution failed (#{@fail_count} failures)")
|
315
|
+
Origen.app.stats.report_fail
|
316
|
+
end
|
317
|
+
commands_file = Origen.app.current_job.output_file.split('.')[0] + '_link_cmds.txt'
|
318
|
+
File.open(commands_file, 'w') do |file|
|
319
|
+
file.puts("pin_assign:#{@pinmap}")
|
320
|
+
file.puts("pin_patternorder:#{@pinorder}")
|
321
|
+
@pattern_link_messages.each_index do |index|
|
322
|
+
file.puts(@pattern_link_messages[index])
|
323
|
+
file.puts(@pattern_comments[index]) if @pattern_comments.key?(index)
|
324
|
+
end
|
325
|
+
file.puts(':session_end')
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
# to_s
|
330
|
+
# returns 'Origen::VectorBased'
|
331
|
+
#
|
332
|
+
# This method at the moment is used for implementing code that runs only if the
|
333
|
+
# environment is set to link vector based. tester.link? will be used once the testers
|
334
|
+
# plug in supports the method link?.
|
335
|
+
def to_s
|
336
|
+
'OrigenLink::VectorBased'
|
337
|
+
end
|
338
|
+
|
339
|
+
# transaction
|
340
|
+
# returns true/false indicating whether the transaction passed
|
341
|
+
# true = pass
|
342
|
+
# false = fail
|
343
|
+
#
|
344
|
+
# TODO: capture transaction vector data and response for use in debug
|
345
|
+
#
|
346
|
+
# if !tester.transaction {dut.reg blah blah}
|
347
|
+
# puts 'transaction failed'
|
348
|
+
# end
|
349
|
+
def transaction
|
350
|
+
if block_given?
|
351
|
+
synchronize
|
352
|
+
transaction_fail_count = @fail_count
|
353
|
+
yield
|
354
|
+
synchronize
|
355
|
+
transaction_fail_count = @fail_count - transaction_fail_count
|
356
|
+
if transaction_fail_count == 0
|
357
|
+
true
|
358
|
+
else
|
359
|
+
false
|
360
|
+
end
|
361
|
+
else
|
362
|
+
true
|
363
|
+
end
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|