Class: Origen::Tester::Ultraflex

Inherits:
Object
  • Object
show all
Includes:
Origen::Tester, Parser, Files
Defined in:
lib/origen/tester/ultraflex/ultraflex.rb,
lib/origen/tester/ultraflex/files.rb,
lib/origen/tester/ultraflex/parser.rb,
lib/origen/tester/ultraflex/generator.rb,
lib/origen/tester/ultraflex/parser/flow.rb,
lib/origen/tester/ultraflex/parser/flows.rb,
lib/origen/tester/ultraflex/parser/dc_spec.rb,
lib/origen/tester/ultraflex/parser/ac_spec.rb,
lib/origen/tester/ultraflex/generator/flow.rb,
lib/origen/tester/ultraflex/parser/timeset.rb,
lib/origen/tester/ultraflex/parser/dc_specs.rb,
lib/origen/tester/ultraflex/parser/flow_line.rb,
lib/origen/tester/ultraflex/generator/patset.rb,
lib/origen/tester/ultraflex/generator/patsets.rb,
lib/origen/tester/ultraflex/parser/pattern_set.rb,
lib/origen/tester/ultraflex/generator/patgroup.rb,
lib/origen/tester/ultraflex/parser/pattern_sets.rb,
lib/origen/tester/ultraflex/generator/patgroups.rb,
lib/origen/tester/ultraflex/parser/descriptions.rb,
lib/origen/tester/ultraflex/generator/flow_line.rb,
lib/origen/tester/ultraflex/parser/test_instance.rb,
lib/origen/tester/ultraflex/parser/test_instances.rb,
lib/origen/tester/ultraflex/generator/test_instance.rb,
lib/origen/tester/ultraflex/generator/test_instances.rb,
lib/origen/tester/ultraflex/generator/test_instance_group.rb

Overview

Tester model to generate .atp patterns for the Teradyne Ultraflex

Basic Usage

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

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

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

Defined Under Namespace

Modules: Files, Generator Classes: Parser

Instance Attribute Summary (collapse)

Attributes included from API

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

Instance Method Summary (collapse)

Methods included from Files

#read_test_times

Methods included from Parser

#parse, #tests

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?, #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, #update_running_clocks, #v93k?

Methods included from Timing

#before_timeset_change, #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_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

- (Ultraflex) initialize

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

$tester = Ultraflex.new

NOTE: Ultraflex features not yet supported;

- dual mode (assumes single mode)
- multiple modules per pattern (only one per for now)


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 40

def initialize
  @unique_counter = 0
  @max_repeat_loop = 65_535
  @min_repeat_loop = 2
  @pat_extension = 'atp'
  @active_loads = true
  @pipeline_depth = 255  # for single mode on UP1600
  @use_hv_pin = false   # allows to use high voltage for a pin for all patterns
  @software_version = '8.10.10'
  @compress = true
  @support_repeat_previous = true
  @match_entries = 10
  @name = 'ultraflex'
  @program_comment_char = ['logprint', "'"]
  @min_module_size = 64                   # min number of vectors in a module for single
end

Instance Attribute Details

- (Object) software_version

Returns the value of attribute software_version



31
32
33
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 31

def software_version
  @software_version
end

- (Object) use_hv_pin

Returns the value of attribute use_hv_pin



30
31
32
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 30

def use_hv_pin
  @use_hv_pin
end

Instance Method Details

- (Object) branch_to(label) Also known as: branch

Branch execution to the given point.

This generates a new vector with a jump instruction to a given label. This method will generate an additional vector.

Examples

$tester.branch_to("something_significant")


593
594
595
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 593

def branch_to(label)
  cycle(microcode: "jump #{label}")
end

- (Object) call_match

Call a match loop.

Normally you would put your match loop in a global subs pattern, then you can call it via this method. This method automatically syncs match loop naming with the match generation flow, no arguments required.

This is a Ultraflex specific API.

Examples

$tester.cycle
$tester.call_match  # Calls the match loop, or the first entry point if you have multiple
$tester.cycle
$tester.call_match  # Calls the match loop, or the second entry point if you have multiple


552
553
554
555
556
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 552

def call_match
  @match_counter = @match_counter || 0
  call_subroutine("match_done_#{@match_counter}")
  @match_counter += 1 unless @match_counter == (@match_entries || 1) - 1
end

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

Call a subroutine.

This method applies a call subroutine opcode to the 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.

Examples

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


135
136
137
138
139
140
141
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 135

def call_subroutine(name, options = {})
  options = {
    offset: 0
  }.merge(options)
  called_subroutines << name.to_s.chomp unless called_subroutines.include?(name.to_s.chomp) || @inhibit_vectors
  update_vector microcode: "call #{name}", offset: options[:offset]
end

- (Object) called_subroutines

Returns an array of subroutines called while generating the current pattern



697
698
699
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 697

def called_subroutines
  @called_subroutines ||= []
end

- (Object) enable_flag(options = {})

  • Ultraflex Specific *



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 160

def enable_flag(options = {})
  options = { flagnum: 4,      # which flag to enable for later checking
          }.merge(options)

  case options[:flagnum]
    when 1
      flagname = 'cpuA_cond'
    when 2
      flagname = 'cpuB_cond'
    when 3
      flagname = 'cpuC_cond'
    when 4
      flagname = 'cpuD_cond'
    else
      abort "ERROR! Invalid flag name passed to 'enable_flag' method!\n"
  end
  update_vector(microcode: "branch_expr(#{flagname})")
end

- (Object) end_subroutine(cond = false)

End a subroutine.

Generates a return opcode on the last vector.

Examples

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

cond: whether return is conditional on a flag (to permit to mix subrs together)



210
211
212
213
214
215
216
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 210

def end_subroutine(cond = false)
  if cond
    update_vector microcode: 'if (flag) return'
  else
    update_vector microcode: 'return'
  end
end

- (Object) flows



57
58
59
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 57

def flows
  parser.flows
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



708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 708

def format_vector(vec)
  timeset = vec.timeset ? "> #{vec.timeset.name}" : ''
  pin_vals = vec.pin_vals ? "#{vec.pin_vals} ;" : ''
  if vec.repeat > 1
    microcode = "repeat #{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(65)}#{timeset.ljust(31)}#{pin_vals}#{comment}"
end

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

Do a frequency measure.

Write the necessary micro code to do a frequency measure on the given pin, optionally supply a read code to pass information to the tester.

Examples

$tester.freq_count($top.pin(:d_out))                 # Freq measure on pin "d_out"
$tester.freq_count($top.pin(:d_out):readcode => 10)


254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 254

def freq_count(pin, options = {})
  options = { readcode: false
            }.merge(options)

  cycle(microcode: "set_code #{options[:readcode]}") if options[:readcode]
  cycle(microcode: 'set_cpu (cpuA)')
  cycle(microcode: 'set_cpu (cpuA)')
  cycle(microcode: 'set_cpu (cpuB)')
  cycle(microcode: 'set_cpu (cpuC)')
  cycle(microcode: 'freq_loop_1:')
  cycle(microcode: 'if (cpuA) jump freq_loop_1')
  pin.drive_lo
  delay(2000)
  pin.dont_care
  cycle(microcode: 'freq_loop_2: enable (cpuB)')
  cycle(microcode: 'if (flag) jump freq_loop_2')
  cycle(microcode: 'enable (cpuC)')
  cycle(microcode: 'if (flag) jump freq_loop_1')
end

- (Object) handshake(options = {})

Handshake with the tester.

Will set a cpu flag (A) and wait for it to be cleared by the tester, optionally pass in a read code to pass information to the tester.

Examples

$tester.handshake                   # Pass control to the tester for a measurement
$tester.handshake(:readcode => 10)  # Trigger a specific action by the tester


226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 226

def handshake(options = {})
  options = {
    readcode:    false,
    manual_stop: false,    # set a 2nd CPU flag in case 1st flag is automatically cleared
  }.merge(options)
  if options[:readcode]
    cycle(microcode: "set_code #{options[:readcode]}")
  end
  if options[:manual_stop]
    cycle(microcode: 'enable (cpuB)')
    cycle(microcode: 'set_cpu (cpuA cpuB)')
    cycle(microcode: "loop_here_#{@unique_counter}: if (flag) jump loop_here_#{@unique_counter}")
  else
    cycle(microcode: 'set_cpu (cpuA)')
    cycle(microcode: "loop_here_#{@unique_counter}: if (cpuA) jump loop_here_#{@unique_counter}")
  end
  @unique_counter += 1  # Increment so a different label will be applied if another
  # handshake is called in the same pattern
end

- (Object) ignore_fails(*pins)



748
749
750
751
752
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 748

def ignore_fails(*pins)
  pins.each(&:suspend)
  yield
  pins.each(&:resume)
end

- (Object) label(name, global = false)

Apply a label to the pattern.

No additional vector is generated. Arguments:

  name : label name
global : (optional) whether to apply global label, default=false

Examples

$tester.label("something_significant")
$tester.label("something_significant",true) # apply global label


568
569
570
571
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 568

def label(name, global = false)
  global_opt = (global) ? 'global ' : ''
  microcode global_opt + name + ':'
end

- (Object) local_subroutines

Returns an array of subroutines created by the current pattern



702
703
704
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 702

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

- (Object) loop_vectors(name, number_of_loops, global = false, label_first = false) Also known as: loop_vector

Add loop to the pattern.

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

Optional arguments: global - whether to apply global label (default=false)

label_first - whether to apply loop label before loop vector or not

Examples

$tester.loop_vectors("pulse_loop", 3) do   # Do this 3 times...
    $tester.cycle
    some_other_method_to_generate_vectors
end


611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 611

def loop_vectors(name, number_of_loops, global = false, label_first = false)
  if number_of_loops > 1
    @loop_counters ||= {}
    if @loop_counters[name]
      @loop_counters[name] += 1
    else
      @loop_counters[name] = 0
    end
    loop_name = @loop_counters[name] == 0 ? name : "#{name}_#{@loop_counters[name]}"
    if label_first
      global_opt = (global) ? 'global ' : ''
      microcode "#{global_opt}#{loop_name}: "
    end
    cycle(microcode: "loopA #{number_of_loops}")
    unless label_first
      global_opt = (global) ? 'global ' : ''
      cycle(microcode: "#{global_opt}#{loop_name}: ")
    end
    yield
    cycle(microcode: "end_loopA #{loop_name}")
  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)

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

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

  • :check_for_fails (false) - Flushes the pipeline and handshakes with the tester (passing readcode 100) prior to the match (to allow binout of fails encountered before the match)

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

  • :on_timeout_goto (“”) - Optionally supply a label to branch to on timeout, by default will continue from the end of the match loop

  • :on_pin_match_goto (“”) - Optionally supply a label to branch to when pin 1 matches, by default will continue from the end of the match loop

  • :on_pin2_match_goto (“”) - Optionally supply a label to branch to when pin 2 matches, by default will continue from the end of the match loop

  • :multiple_entries (false) - Supply an integer to generate multiple entries into the match (each with a unique readcode), this can be useful when debugging patterns with multiple matches

  • :force_fail_on_timeout (true) - force pattern to fail if timeout occurs

  • :global_loops (false) - whether match loop loops should use global labels

  • :manual_stop (false) - whether to use extra cpuB flag to resolve IG-XL v.3.50.xx bug where VBT clears cpuA immediately

    at start of PatFlagFunc instead of at end.  Use will have to manually clear cpuB to resume this pattern.

Examples

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


305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
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
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 305

def match(pin, state, timeout, options = {})
  options = {
    check_for_fails:       false,
    on_timeout_goto:       false,
    pin2:                  false,
    state2:                false,
    on_pin_match_goto:     false,
    on_pin2_match_goto:    false,
    multiple_entries:      false,
    force_fail_on_timeout: true,
    global_loops:          false,
    manual_stop:           false,
    clr_fail_post_match:   false
  }.merge(options)

  # Flush the pipeline first and then pass control to the program to bin out any failures
  # prior to entering the match loop
  if options[:check_for_fails]
    if options[:multiple_entries]
      @match_entries.times do |i|
        microcode "global subr match_done_#{i}:"
        cycle(microcode: "set_code #{i + 100}")
        cycle(microcode: 'jump call_tester') unless i == @match_entries - 1
      end
      microcode 'call_tester:'
    else
      cycle(microcode: 'set_code 100')
    end
    cc 'Wait for any prior failures to propagate through the pipeline'
    cycle(microcode: 'pipe_minus 1')
    cc 'Now handshake with the tester to bin out and parts that have failed before they got here'
    handshake(manual_stop: options[:manual_stop])
  end

  # Now do the main match loop
  cc 'Start the match loop'

  # Calculate the loop counts for the 2 loops to appropriately hit the timeout requested
  inner_loop_vectors = (@pipeline_depth - 1) + 4  # num vectors in inner loop
  if timeout.to_f < @max_repeat_loop * inner_loop_vectors * @min_repeat_loop
    # Handle case for smaller timeouts (that would force small outer loop count)
    inner_loop_count = (timeout.to_f / (inner_loop_vectors * @min_repeat_loop)).ceil
    outer_loop_count = @min_repeat_loop
  else
    # Handle longer delays
    inner_loop_count = @max_repeat_loop
    outer_loop_count = (timeout.to_f / (@max_repeat_loop * inner_loop_vectors)).ceil  # Will do a minimum of 1 * max_repeat_loop * (pipeline_depth-1)
  end

  global_opt = (options[:global_loops]) ? 'global ' : ''
  microcode "#{global_opt}match_outer_loop_#{@unique_counter}:"
  cycle(microcode: "loopB #{outer_loop_count}")
  microcode "#{global_opt}match_inner_loop_#{@unique_counter}:"
  state == :low ? pin.expect_lo : pin.expect_hi
  cc "Check if #{pin.name} is #{state == :low ? 'low' : 'high'} yet"
  cycle(microcode: "loopA #{inner_loop_count}")
  pin.dont_care
  cc ' Wait for the result to propagate through the pipeline'
  cycle(microcode: 'pipe_minus 1')
  cc "Branch if #{pin.name} was #{state == :low ? 'low' : 'high'}"
  cycle(microcode: "if (pass) jump #{pin.name}_matched_#{@unique_counter} icc ifc")
  cycle(microcode: 'clr_flag (fail) icc')
  if options[:pin2]
    cc "Check if #{options[:pin2].name} is #{options[:state2] == :low ? 'low' : 'high'} yet"
    options[:state2] == :low ? options[:pin2].expect_lo : options[:pin2].expect_hi
    state == :low ? pin.expect_hi : pin.expect_lo   # Give priority to pin 1, don't match pin 2 on this cycle
    # if it is really a pin 1 match
    cycle  # Read for pin 2 and !pin 1
    options[:pin2].dont_care
    pin.dont_care
    cc 'Again wait for the result to propagate through the pipeline'
    cycle(microcode: 'pipe_minus 1')
    cc "Branch if #{options[:pin2].name} was #{options[:state2] == :low ? 'low' : 'high'}"
    cycle(microcode: "if (pass) jump #{options[:pin2].name}_matched_#{@unique_counter} icc ifc")
    cycle(microcode: 'clr_flag (fail) icc')
  end
  cc 'Loop back around if time remaining'
  cycle(microcode: "end_loopA match_inner_loop_#{@unique_counter} icc")
  cycle(microcode: "end_loopB match_outer_loop_#{@unique_counter} icc")
  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
  if options[:on_timeout_goto]
    cycle(microcode: "jump #{options[:on_timeout_goto]} icc")
  else
    cycle(microcode: "jump match_loop_end_#{@unique_counter} icc")
    # cycle(:microcode => 'halt')
  end
  microcode "#{pin.name}_matched_#{@unique_counter}:"
  cycle(microcode: 'pop_loop icc')
  unless options[:clr_fail_post_match]
    cycle(microcode: 'clr_fail')
  end
  if options[:on_pin_match_goto]
    cycle(microcode: "jump #{options[:on_pin_match_goto]}")
  end
  if options[:pin2]
    microcode "#{options[:pin2].name}_matched_#{@unique_counter}:"
    cycle(microcode: 'pop_loop icc')
    cycle(microcode: 'clr_fail')
    if options[:on_pin2_match_goto]
      cycle(microcode: "jump #{options[:on_pin2_match_goto]}")
    end
  end
  microcode "match_loop_end_#{@unique_counter}:"
  if options[:clr_fail_post_match]
    cycle(microcode: 'clr_fail')
  end

  @unique_counter += 1  # Increment so a different label will be applied if another
  # handshake is called in the same pattern
end

- (Object) match_block(timeout, options = {})

Generates a match loop based on vector condition passed in via block

This method is not really intended to be called directly, rather you should call via Tester#wait:

e.g. $tester.wait(:match => true) do
       reg(:status_reg).bit(:done).read(1)!  # vector condition that you want to match
     end

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:

  • :check_for_fails (false) - Flushes the pipeline and handshakes with the tester (passing readcode 100) prior to the match (to allow binout of fails encountered before the match)

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

  • :on_timeout_goto (“”) - Optionally supply a label to branch to on timeout, by default will continue from the end of the match loop

  • :on_block_match_goto (“”) - Optionally supply a label to branch to when block condition is met, by default will continue from the end of the match loop

  • :multiple_entries (false) - Supply an integer to generate multiple entries into the match (each with a unique readcode), this can be useful when debugging patterns with multiple matches

  • :force_fail_on_timeout (true) - force pattern to fail if timeout occurs

  • :global_loops (false) - whether match loop loops should use global labels

  • :manual_stop (false) - whether to use extra cpuB flag to resolve IG-XL v.3.50.xx bug where VBT clears cpuA immediately

    at start of PatFlagFunc instead of at end.  Use will have to manually clear cpuB to resume this pattern.

Examples

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


447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 447

def match_block(timeout, options = {})
  options = {
    check_for_fails:       false,
    on_timeout_goto:       false,
    on_block_match_goto:   false,
    multiple_entries:      false,
    force_fail_on_timeout: true,
    global_loops:          false,
    manual_stop:           false,
    clr_fail_post_match:   false
  }.merge(options)

  unless block_given?
    fail 'ERROR: block not passed to match_block!'
  end

  # Flush the pipeline first and then pass control to the program to bin out any failures
  # prior to entering the match loop
  if options[:check_for_fails]
    if options[:multiple_entries]
      @match_entries.times do |i|
        microcode "global subr match_done_#{i}:"
        cycle(microcode: "set_code #{i + 100}")
        cycle(microcode: 'jump call_tester') unless i == @match_entries - 1
      end
      microcode 'call_tester:'
    else
      cycle(microcode: 'set_code 100')
    end
    cc 'Wait for any prior failures to propagate through the pipeline'
    cycle(microcode: 'pipe_minus 1')
    cc 'Now handshake with the tester to bin out and parts that have failed before they got here'
    handshake(manual_stop: options[:manual_stop])
  end

  # Now do the main match loop
  cc 'Start the match loop'

  # Calculate the loop counts for the 2 loops to appropriately hit the timeout requested
  inner_loop_vectors = (@pipeline_depth - 1) + 4  # num vectors in inner loop
  if timeout.to_f < @max_repeat_loop * inner_loop_vectors * @min_repeat_loop
    # Handle case for smaller timeouts (that would force small outer loop count)
    inner_loop_count = (timeout.to_f / (inner_loop_vectors * @min_repeat_loop)).ceil
    outer_loop_count = @min_repeat_loop
  else
    # Handle longer delays
    inner_loop_count = @max_repeat_loop
    outer_loop_count = (timeout.to_f / (@max_repeat_loop * inner_loop_vectors)).ceil  # Will do a minimum of 1 * max_repeat_loop * (pipeline_depth-1)
  end

  global_opt = (options[:global_loops]) ? 'global ' : ''
  microcode "#{global_opt}match_outer_loop_#{@unique_counter}:"
  cycle(microcode: "loopB #{outer_loop_count}")
  microcode "#{global_opt}match_inner_loop_#{@unique_counter}:"
  cycle(microcode: "loopA #{inner_loop_count}")
  cc 'Check if block condition met'
  yield
  cc ' Wait for the result to propagate through the pipeline'
  cycle(microcode: 'pipe_minus 1')
  cc 'Branch if block condition met'
  cycle(microcode: "if (pass) jump block_matched_#{@unique_counter} icc ifc")
  cycle(microcode: 'clr_flag (fail) icc')
  cc 'Loop back around if time remaining'
  cycle(microcode: "end_loopA match_inner_loop_#{@unique_counter} icc")
  cycle(microcode: "end_loopB match_outer_loop_#{@unique_counter} icc")
  if options[:force_fail_on_timeout]
    cc 'To get here something has gone wrong, check block again to force a pattern failure'
    yield
  end
  if options[:on_timeout_goto]
    cycle(microcode: "jump #{options[:on_timeout_goto]} icc")
  else
    cycle(microcode: "jump match_loop_end_#{@unique_counter} icc")
    # cycle(:microcode => 'halt')
  end
  microcode "block_matched_#{@unique_counter}:"
  cycle(microcode: 'pop_loop icc')
  unless options[:clr_fail_post_match]
    cycle(microcode: 'clr_fail')
  end
  if options[:on_block_match_goto]
    cycle(microcode: "jump #{options[:on_block_match_goto]}")
  end
  microcode "match_loop_end_#{@unique_counter}:"
  if options[:clr_fail_post_match]
    cycle(microcode: 'clr_fail')
  end

  @unique_counter += 1  # Increment so a different label will be applied if another
  # handshake is called in the same pattern
end

- (Object) parser(prog_dir = Origen.config.test_program_output_directory)

Main accessor to all content parsed from existing test program sheets found in the supplied directory or in Origen.config.test_program_output_directory



63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 63

def parser(prog_dir = Origen.config.test_program_output_directory)
  unless prog_dir
    fail 'You must supply the directory containing the test program sheets, or define it via Origen.config.test_program_output_directory'
  end
  @parser ||= ULTRAFLEX::Parser.new
  @parsed_dir ||= false
  if @parsed_dir != prog_dir
    @parser.parse(prog_dir)
    @parsed_dir = prog_dir
  end
  @parser
end

An internal method called by Origen to generate the pattern footer



677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 677

def pattern_footer(options = {})
  options = {
    subroutine_pat: false,
    end_in_ka:      false,
    end_with_halt:  false
  }.merge(options)
  # cycle(:microcode => "#{$soc.end_of_pattern_label}:") if $soc.end_of_pattern_label
  if options[:end_in_ka]
    $tester.cycle microcode: 'keep_alive'
  else
    if options[:end_with_halt]
      $tester.cycle microcode: 'halt'
    else
      $tester.cycle
    end
  end
  microcode '}'
end

- (Object) pattern_header(options = {})

An internal method called by Origen to create the pattern header



638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 638

def pattern_header(options = {})
  options = {
    subroutine_pat: false,
    group:          false,            # If true the end pattern is intended to run within a pattern group
    high_voltage:   false,     # Supply a pin name here to declare it as an HV instrument
    freq_counter:   false,     # Supply a pin name here to declare it as a frequency counter
  }.merge(options)

  called_timesets.each do |timeset|
    microcode "import tset #{timeset.name};"
  end
  unless options[:group]    # Withhold imports for pattern groups, is this correct?
    called_subroutines.each do |sub_name|
      # Don't import any called subroutines that are declared in the current pattern
      microcode "import svm_subr #{sub_name};" unless local_subroutines.include?(sub_name)
    end
  end
  # Should implement this more like @instruments.each...
  microcode 'opcode_mode = single;'
  microcode 'digital_inst = hsdm;'
  microcode 'compressed = yes;' # if $soc.gzip_patterns
  options[:high_voltage] = @use_hv_pin
  microcode "pin_setup = {#{options[:high_voltage]} high_voltage;}" if options[:high_voltage]
  microcode "pin_setup = {#{options[:freq_counter]} freq_count;}" if options[:freq_counter]
  microcode ''

  pin_list = ordered_pins.map(&:name).join(', ')

  microcode "#{options[:subroutine_pat] ? 'srm_vector' : 'vm_vector'}"
  microcode "#{options[:pattern]} ($tset, #{pin_list})"
  microcode '{'
  unless options[:subroutine_pat]
    microcode "start_label #{options[:pattern]}_st:"
  end
end

- (Object) push_microcode(code) Also known as: microcode

Override this to force the formatting to match the v1 Ultraflex model (easier diffs)



725
726
727
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 725

def push_microcode(code) # :nodoc:
  stage.store(code.ljust(65) + ''.ljust(31))
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


742
743
744
745
746
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 742

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) set_code(code)

  • Ultraflex Specific *

Set a readcode.

Use the set an explicit readcode for communicating with the tester. This method will generate an additional vector.

Examples

$tester.set_code(55)


582
583
584
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 582

def set_code(code)
  cycle(microcode: "set_code #{code}")
end

- (Object) set_flag(options = {})

  • Ultraflex Specific *



182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 182

def set_flag(options = {})
  options = { flagnum: 4,      # which flag to set
          }.merge(options)

  case options[:flagnum]
    when 1
      flagname = 'cpuA_cond'
    when 2
      flagname = 'cpuB_cond'
    when 3
      flagname = 'cpuC_cond'
    when 4
      flagname = 'cpuD_cond'
    else
      abort "ERROR! Invalid flag name passed to 'set_flag' method!\n"
  end
  update_vector(microcode: "set_cpu_cond(#{flagname})")
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


152
153
154
155
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 152

def start_subroutine(name)
  local_subroutines << name.to_s.chomp unless local_subroutines.include?(name.to_s.chomp) || @inhibit_vectors
  microcode "global subr #{name}:"
end

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

Capture a vector to the tester HRAM.

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

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

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

Examples:

$tester.cycle                # This is the vector you want to capture
$tester.store                # This applys the STV opcode

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


95
96
97
98
99
100
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 95

def store(*pins)
  options = pins.last.is_a?(Hash) ? pins.pop : {}
  options = { offset: 0
            }.merge(options)
  update_vector microcode: 'stv', offset: options[:offset]
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 Ultraflex 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


114
115
116
117
118
119
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 114

def store_next_cycle(*pins)
  options = pins.last.is_a?(Hash) ? pins.pop : {}
  options = {
  }.merge(options)
  preset_next_vector microcode: 'stv'
end

- (Boolean) ultraflex?

Returns:

  • (Boolean)


754
755
756
# File 'lib/origen/tester/ultraflex/ultraflex.rb', line 754

def ultraflex?
  true
end