Class: Origen::Tester::V93K

Inherits:
Object show all
Includes:
Origen::Tester
Defined in:
lib/origen/tester/v93k/v93k.rb,
lib/origen/tester/v93k/generator.rb,
lib/origen/tester/v93k/generator/flow.rb,
lib/origen/tester/v93k/generator/pattern.rb,
lib/origen/tester/v93k/generator/flow_node.rb,
lib/origen/tester/v93k/generator/test_suite.rb,
lib/origen/tester/v93k/generator/test_suites.rb,
lib/origen/tester/v93k/generator/test_method.rb,
lib/origen/tester/v93k/generator/test_methods.rb,
lib/origen/tester/v93k/generator/test_function.rb,
lib/origen/tester/v93k/generator/pattern_master.rb,
lib/origen/tester/v93k/generator/test_functions.rb,
lib/origen/tester/v93k/generator/flow_node/print.rb

Overview

Tester model to generate .avc patterns for the Verigy 930000

Basic Usage

$tester = Origen::Tester::V93K.new
$tester.cycle       # Generate a vector

Many more methods exist to generate V93K specific micro-code, see below for details.

Also note that this class includes the base Tester module and so all methods described there are also available.

Defined Under Namespace

Modules: Generator

Instance Attribute Summary

Attributes included from API

#comment_level, #generating, #includes, #inhibit_comments, #inhibit_vectors

Instance Method Summary (collapse)

Methods included from Origen::Tester

#register_tester

Methods included from API

#annotate, #any_clocks_running?, #c1, #c2, #clocks_running, #comment_char, #cycle, #doc?, #generate?, #generating_pattern?, #generating_program?, #ignore_fails, #import_test_time, #inhibit_vectors_and_comments, #is_command_based?, #is_vector_based?, #j750?, #j750_hpt?, #name, #pat_extension, #pattern_section, #pins_need_toggling, #pop_running_clock, #program_comment_char, #push_running_clock, #slice_repeats, #snip, #ss, #step_comment_prefix, #ultraflex?, #update_running_clocks

Methods included from Timing

#called_timesets, #count, #current_period_in_ns, #current_timeset, #cycles_to_ms, #cycles_to_time, #cycles_to_ts, #cycles_to_us, #delay, #max_repeat_loop, #ms_to_cycles, #ns_to_cycles, #s_to_cycles, #set_timeset, #timeset_changed, #us_to_cycles, #wait

Methods included from VectorGenerator

#_render, #add_microcode_to_last_or_cycle, #before_write_pattern_line, #compressable_vector?, #current_pin_vals, #cycle_count, #dec_vec_count, #dont_compress, #dont_compress=, #expand_vector, #format, #format_pin_state, #get_pingroup, #inc_cycle_count, #inc_vec_count, #inhibit_pin, #inhibited_pins, #last_object, #last_vector, #multi_mode_optimize, #optimize, #ordered_pins, #ordered_pins_cache, #pingroup_map, #pipeline, #preset_next_vector, #push_comment, #push_microcode, #push_vector, #render, #render_body, #render_footer, #render_header, #render_template, #reset_cycle_count, #stage, #track_and_format_vector, #update_pin_from_formatted_state, #update_vector, #update_vector_pin_val, #vec_count, #vector_group_size, #vector_group_size=, #with_vector_group_size

Constructor Details

- (V93K) initialize

Returns a new J750 instance, normally there would only ever be one of these assigned to the global variable such as $tester by your target:

$tester = J750.new


27
28
29
30
31
32
33
34
35
# File 'lib/origen/tester/v93k/v93k.rb', line 27

def initialize
  @max_repeat_loop = 65_535
  @pat_extension = 'avc'
  @compress = true
  # @support_repeat_previous = true
  @match_entries = 10
  @name = 'v93k'
  @comment_char = '#'
end

Instance Method Details

- (Object) before_timeset_change(options = {})



411
412
413
# File 'lib/origen/tester/v93k/v93k.rb', line 411

def before_timeset_change(options = {})
  microcode "SQPG CTIM #{options[:new].name};"
end

- (Object) call_subroutine(name, options = {})

Call a subroutine.

This calls a subroutine immediately following previous vector, it does not generate a new vector.

Subroutines should always be called through this method as it ensures a running log of called subroutines is maintained and which then gets output in the pattern header to import the right dependencies.

An offset option is available to make the call on earlier vectors.

Repeated calls to the same subroutine will automatically be compressed unless option :suppress_repeated_calls is supplied and set to false. This means that for the common use case of calling a subroutine to implement an overlay the subroutine can be called for every bit that has the overlay and the pattern will automatically generate correctly.

Examples

$tester.call_subroutine("mysub")
$tester.call_subroutine("my_other_sub", :offset => -1)


159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/origen/tester/v93k/v93k.rb', line 159

def call_subroutine(name, options = {})
  options = {
    offset:                  0,
    suppress_repeated_calls: true
  }.merge(options)
  called_subroutines << name.to_s.chomp unless called_subroutines.include?(name.to_s.chomp) || @inhibit_vectors

  code = "SQPG JSUB #{name};"
  if !options[:suppress_repeated_calls] ||
     last_object != code
    microcode code, offset: (options[:offset] * -1)
  end
end

- (Object) called_subroutines

Returns an array of subroutines called while generating the current pattern



366
367
368
# File 'lib/origen/tester/v93k/v93k.rb', line 366

def called_subroutines
  @called_subroutines ||= []
end

- (Object) end_subroutine(_cond = false)

Ends the current subroutine that was started with a previous call to start_subroutine



135
136
137
# File 'lib/origen/tester/v93k/v93k.rb', line 135

def end_subroutine(_cond = false)
  Pattern.close call_shutdown_callbacks: false
end

- (Object) format_vector(vec)

This is an internal method use by Origen which returns a fully formatted vector You can override this if you wish to change the output formatting at vector level



377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
# File 'lib/origen/tester/v93k/v93k.rb', line 377

def format_vector(vec)
  timeset = vec.timeset ? "#{vec.timeset.name}" : ''
  pin_vals = vec.pin_vals ? "#{vec.pin_vals} ;" : ''
  if vec.repeat # > 1
    microcode = "R#{vec.repeat}"
  else
    microcode = vec.microcode ? vec.microcode : ''
  end
  # if vec.pin_vals && vec.number && vec.cycle_number
  #  comment = " // Vector #{@pattern_vectors}, Cycle #{@pattern_cycles}"
  # else
  comment = ''
  # end
  "#{microcode.ljust(25)} #{timeset.ljust(25)} #{pin_vals} #{comment}"
end

- (Object) freq_count(_pin, options = {})

Do a frequency measure.

Examples

$tester.freq_count($top.pin(:d_out))                 # Freq measure on pin "d_out"


187
188
189
190
191
# File 'lib/origen/tester/v93k/v93k.rb', line 187

def freq_count(_pin, options = {})
  options = {
  }.merge(options)
  Pattern.split(options)
end

- (Object) handshake(options = {})

Handshake with the tester.

Examples

$tester.handshake                   # Pass control to the tester for a measurement


177
178
179
180
181
# File 'lib/origen/tester/v93k/v93k.rb', line 177

def handshake(options = {})
  options = {
  }.merge(options)
  Pattern.split(options)
end

- (Object) local_subroutines

Returns an array of subroutines created by the current pattern



371
372
373
# File 'lib/origen/tester/v93k/v93k.rb', line 371

def local_subroutines # :nodoc:
  @local_subroutines ||= []
end

- (Object) loop_vectors(name = nil, number_of_loops = 1, _global = false) Also known as: loop_vector

Add a loop to the pattern.

Pass in the number of times to execute it, all vectors generated by the given block will be captured in the loop.

Examples

$tester.loop_vectors 3 do   # Do this 3 times...
    $tester.cycle
    some_other_method_to_generate_vectors
end

For compatibility with the J750 you can supply a name as the first argument and that will simply be ignored when generated for the V93K tester…

$tester.loop_vectors "my_loop", 3 do   # Do this 3 times...
    $tester.cycle
    some_other_method_to_generate_vectors
end


325
326
327
328
329
330
331
332
333
334
335
336
337
# File 'lib/origen/tester/v93k/v93k.rb', line 325

def loop_vectors(name = nil, number_of_loops = 1, _global = false)
  # The name argument is present to maych J750 API, sort out the
  unless name.is_a?(String)
    name, number_of_loops, global = nil, name, number_of_loops
  end
  if number_of_loops > 1
    microcode "SQPG LBGN #{number_of_loops};"
    yield
    microcode 'SQPG LEND;'
  else
    yield
  end
end

- (Object) match(pin, state, timeout, options = {})

Generates a match loop on up to two pins.

This method is not really intended to be called directly, rather you should call via Tester#wait e.g. $tester.wait(:match => true).

The timeout should be provided in cycles, however when called via the wait method the time-based helpers (time_in_us, etc) will be converted to cycles for you. The following options are available to tailor the match loop behavior, defaults in parenthesis:

  • :pin - The pin object to match on (required)

  • :state - The pin state to match on, :low or :high (required)

  • :check_for_fails (false) - Flushes the pipeline and checks for fails prior to the match (to allow binout of fails encountered before the match)

  • :pin2 (nil) - Optionally supply a second pin to match on

  • :state2 (nil) - State for the second pin (required if :pin2 is supplied)

  • :force_fail_on_timeout (true) - Force a vector mis-compare if the match loop times out

Examples

$tester.wait(:match => true, :time_in_us => 5000, :pin => $top.pin(:done), :state => :high)


212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
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
# File 'lib/origen/tester/v93k/v93k.rb', line 212

def match(pin, state, timeout, options = {})
  options = {
    check_for_fails:       false,
    pin2:                  false,
    state2:                false,
    force_fail_on_timeout: true,
    global_loops:          false,
    generate_subroutine:   false,
    force_fail_on_timeout: true
  }.merge(options)

  # Ensure the match pins are don't care by default
  pin.dont_care
  options[:pin2].dont_care if options[:pin2]

  # Single condition loops are simple
  if !options[:pin2]
    # Use the counted match loop (rather than timed) which is recommended in the V93K docs for new applications
    # No pre-match failure handling is required here because the system will cleanly record failure info
    # for this kind of match loop

    cc "for the #{pin.name.upcase} pin to go #{state.to_s.upcase}"
    number_of_loops = (timeout.to_f / 8).ceil
    microcode "SQPG MACT #{number_of_loops};"
    # Strobe the pin for the required state
    state == :low ? pin.expect_lo! : pin.expect_hi!
    pin.dont_care
    # Wait for 7 vectors before re-checking, this keeps the loop to 8 vectors which allows the test results
    # to be reconstructed cleanly if multiple loops are called in a pattern
    microcode 'SQPG MRPT 7;'
    # Not sure if no compression is really required here...
    7.times do
      cycle(dont_compress: true)
    end
    microcode 'SQPG PADDING;'

  else

    # For two pins do something more like the J750 approach where branching based on miscompares is used
    # to keep the loop going
    cc "for the #{pin.name.upcase} pin to go #{state.to_s.upcase}"
    cc "or the #{options[:pin2].name.upcase} pin to go #{options[:state2].to_s.upcase}"

    if options[:check_for_fails]
      cc 'Return preserving existing errors if the pattern has already failed before arriving here'
      cycle(repeat: propagation_delay)
      microcode 'SQPG RETC 1 1;'
    end
    number_of_loops = (timeout.to_f / ((propagation_delay * 2) + 2)).ceil

    loop_vectors number_of_loops do
      # Check pin 1
      cc "Check if #{pin.name.upcase} is #{state.to_s.upcase} yet"
      state == :low ? pin.expect_lo! : pin.expect_hi!
      pin.dont_care
      cc 'Wait for failure to propagate'
      cycle(repeat: propagation_delay)
      cc 'Exit match loop if pin has matched (no error), otherwise clear error and remain in loop'
      microcode 'SQPG RETC 0 0;'

      # Check pin 2
      cc "Check if #{options[:pin2].name.upcase} is #{options[:state2].to_s.upcase} yet"
      options[:state2] == :low ? options[:pin2].expect_lo! : options[:pin2].expect_hi!
      options[:pin2].dont_care
      cc 'Wait for failure to propagate'
      cycle(repeat: propagation_delay)
      cc 'Exit match loop if pin has matched (no error), otherwise clear error and remain in loop'
      microcode 'SQPG RETC 0 0;'
    end

    if options[:force_fail_on_timeout]
      cc 'To get here something has gone wrong, strobe again to force a pattern failure'
      state == :low ? pin.expect_lo : pin.expect_hi
      options[:state2] == :low ? options[:pin2].expect_lo : options[:pin2].expect_hi if options[:pin2]
      cycle
      pin.dont_care
      options[:pin2].dont_care if options[:pin2]
    end
    microcode 'SQPG RSUB;'

  end
end

An internal method called by Origen to generate the pattern footer



361
362
363
# File 'lib/origen/tester/v93k/v93k.rb', line 361

def pattern_footer(_options = {})
  microcode 'SQPG STOP;'
end

- (Object) pattern_header(options = {})

An internal method called by Origen to create the pattern header



341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
# File 'lib/origen/tester/v93k/v93k.rb', line 341

def pattern_header(options = {})
  options = {
  }.merge(options)
  pin_list = ordered_pins.map do |p|
    if Origen.app.pin_pattern_order.include?(p.id)
      p.id # specified name overrides pin name
    else
      p.name
    end
  end.join(' ')
  microcode "FORMAT #{pin_list};"
  max_pin_name_length = ordered_pins.map(&:name).max { |a, b| a.length <=> b.length }.length
  pin_widths = ordered_pins.map { |p| p.size - 1 }

  max_pin_name_length.times do |i|
    cc((' ' * 50) + ordered_pins.map.with_index { |p, x| ((p.name[i] || ' ') + ' ' * pin_widths[x]).gsub('_', '-') }.join(' '))
  end
end

- (Object) propagation_delay

Returns the number of cycles to wait for any fails to propagate through the pipeline based on the current timeset



297
298
299
300
301
302
303
304
305
# File 'lib/origen/tester/v93k/v93k.rb', line 297

def propagation_delay
  # From 'Calculating the buffer cycles for JMPE and RETC (and match loops)' in SmarTest docs
  data_queue_buffer = (([105, 64 + ((125 + current_period_in_ns - 1) / current_period_in_ns).ceil].min + 3) * 8) + 72
  # Don't know how to calculate at runtime, hardcoding these to some default values for now
  number_of_sites = 128
  sclk_period = 40
  prop_delay_buffer = 195 + ((2 * number_of_sites + 3) * (sclk_period / 2))
  data_queue_buffer + prop_delay_buffer
end

- (Object) repeat_previous

All vectors generated with the supplied block will have all pins set to the repeat previous state. Any pins that are changed state within the block will still update to the supplied value.

Example

# All pins except invoke will be assigned the repeat previous code
# in the generated vector. On completion of the block they will
# return to their previous state, except for invoke which will
# retain the value assigned within the block.
$tester.repeat_previous do
    $top.pin(:invoke).drive(1)
    $tester.cycle
end


405
406
407
408
409
# File 'lib/origen/tester/v93k/v93k.rb', line 405

def repeat_previous
  Origen.app.pin_map.each { |_id, pin| pin.repeat_previous = true }
  yield
  Origen.app.pin_map.each { |_id, pin| pin.repeat_previous = false }
end

- (Object) start_subroutine(name)

Start a subroutine.

Generates a global subroutine label. Global is used to adhere to the best practice of containing all subroutines in dedicated patterns, e.g. global_subs.atp

Examples

$tester.start_subroutine("wait_for_done")
< generate your subroutine vectors here >
$tester.end_subroutine


128
129
130
131
132
# File 'lib/origen/tester/v93k/v93k.rb', line 128

def start_subroutine(name)
  local_subroutines << name.to_s.chomp unless local_subroutines.include?(name.to_s.chomp) || @inhibit_vectors
  # name += "_subr" unless name =~ /sub/
  Pattern.open name: name, call_startup_callbacks: false
end

- (Object) store(*pins) Also known as: capture

Capture the pin data from a vector to the tester.

This method uses the Digital Capture feature (Selective mode) of the V93000 to capture the data from the given pins on the previous vector. Note that is does not actually generate a new vector.

Note also that any drive cycles on the target pins can also be captured, to avoid this the wavetable should be set up like this to infer a 'D' (Don't Capture) on vectors where the target pin is being used to drive data:

PINS nvm_fail
0  d1:0  r1:D  0
1  d1:1  r1:D  1
2  r1:C  Capt
3  r1:D  NoCapt

Sometimes when generating vectors within a loop you may want to apply a capture retrospectively to a previous vector, passing in an offset option will allow you to do this.

Examples

$tester.cycle                     # This is the vector you want to capture
$tester.store :pin => pin(:fail)  # This applys the required opcode to the given pins

$tester.cycle                     # This one gets captured
$tester.cycle
$tester.cycle
$tester.store(:pin => pin(:fail), :offset => -2) # Just realized I need to capture that earlier vector

# Capturing multiple pins:
$tester.cycle
$tester.store :pins => [pin(:fail), pin(:done)]

Since the V93K store operates on a pin level (rather than vector level as on the J750) equivalent functionality can also be achieved by setting the store attribute of the pin itself prior to calling $tester.cycle. However it is recommended to use the tester API to do the store if cross-compatiblity with other platforms, such as the J750, is required.



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/origen/tester/v93k/v93k.rb', line 75

def store(*pins)
  options = pins.last.is_a?(Hash) ? pins.pop : {}
  options = { offset: 0
            }.merge(options)
  pins = pins.flatten.compact
  if pins.empty?
    fail 'For the V93K you must supply the pins to store/capture'
  end
  pins.each do |pin|
    pin.restore_state do
      pin.capture
      update_vector_pin_val pin, offset: options[:offset]
      last_vector(options[:offset]).dont_compress = true
    end
  end
end

- (Object) store_next_cycle(*pins)

Capture the next vector generated to HRAM

This method applys a store vector (stv) opcode to the next vector to be generated, note that is does not actually generate a new vector.

On J750 the pins argument is ignored since the tester only supports whole vector capture.

Examples:

$tester.store_next_cycle
$tester.cycle                # This is the vector that will be captured


103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/origen/tester/v93k/v93k.rb', line 103

def store_next_cycle(*pins)
  options = pins.last.is_a?(Hash) ? pins.pop : {}
  options = {
  }.merge(options)
  pins = pins.flatten.compact
  if pins.empty?
    fail 'For the V93K you must supply the pins to store/capture'
  end
  pins.each { |pin| pin.save; pin.capture }
  # Register this clean up function to be run after the next vector
  # is generated, cool or what!
  preset_next_vector do
    pins.each(&:restore)
  end
end

- (Boolean) v93k?

Returns:

  • (Boolean)


415
416
417
# File 'lib/origen/tester/v93k/v93k.rb', line 415

def v93k?
  true
end