Class: Origen::Tester::J750

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

Overview

Tester model to generate .atp patterns for the Teradyne J750

Basic Usage

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

Many more methods exist to generate J750 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.

Direct Known Subclasses

J750_HPT

Defined Under Namespace

Modules: Files, Generator Classes: Parser

Instance Attribute Summary (collapse)

Attributes included from API

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

Class Method Summary (collapse)

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

- (J750) 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


43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/origen/tester/j750/j750.rb', line 43

def initialize
  @unique_counter = 0
  @max_repeat_loop = 65_535
  @min_repeat_loop = 2
  @pat_extension = 'atp'
  @active_loads = true
  @pipeline_depth = 34  # for extended mode is vectors, for normal mode is vector pairs (54 for J750Ex)
  @use_hv_pin = false   # allows to use high voltage for a pin for all patterns
  @software_version = '3.50.40'
  @compress = true
  @support_repeat_previous = true
  @match_entries = 10
  @name = 'j750'
  @program_comment_char = ['logprint', "'"]
  @@hpt_mode = false
end

Instance Attribute Details

- (Object) software_version

Returns the value of attribute software_version



31
32
33
# File 'lib/origen/tester/j750/j750.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/j750/j750.rb', line 30

def use_hv_pin
  @use_hv_pin
end

Class Method Details

+ (Object) hpt_mode



33
34
35
# File 'lib/origen/tester/j750/j750.rb', line 33

def self.hpt_mode
  @@hpt_mode
end

+ (Boolean) hpt_mode?

Returns:

  • (Boolean)


36
37
38
# File 'lib/origen/tester/j750/j750.rb', line 36

def self.hpt_mode?
  @@hpt_mode
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")


669
670
671
# File 'lib/origen/tester/j750/j750.rb', line 669

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 J750 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


628
629
630
631
632
# File 'lib/origen/tester/j750/j750.rb', line 628

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)


138
139
140
141
142
143
144
# File 'lib/origen/tester/j750/j750.rb', line 138

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



782
783
784
# File 'lib/origen/tester/j750/j750.rb', line 782

def called_subroutines
  @called_subroutines ||= []
end

- (Object) enable_flag(options = {})

  • J750 Specific *



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/origen/tester/j750/j750.rb', line 163

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

  case options[:flagnum]
    when 1
      flagname = 'cpuA'
    when 2
      flagname = 'cpuB'
    when 3
      flagname = 'cpuC'
    when 4
      flagname = 'cpuD'
    else
      abort "ERROR! Invalid flag name passed to 'enable_flag' method!\n"
  end
  update_vector(microcode: "enable(#{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)



213
214
215
216
217
218
219
# File 'lib/origen/tester/j750/j750.rb', line 213

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

- (Object) flows



60
61
62
# File 'lib/origen/tester/j750/j750.rb', line 60

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



793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
# File 'lib/origen/tester/j750/j750.rb', line 793

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)


257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
# File 'lib/origen/tester/j750/j750.rb', line 257

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


229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/origen/tester/j750/j750.rb', line 229

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)



834
835
836
837
838
# File 'lib/origen/tester/j750/j750.rb', line 834

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

- (Boolean) j750?

Returns:

  • (Boolean)


840
841
842
# File 'lib/origen/tester/j750/j750.rb', line 840

def j750?
  true
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


644
645
646
647
# File 'lib/origen/tester/j750/j750.rb', line 644

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



787
788
789
# File 'lib/origen/tester/j750/j750.rb', line 787

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


687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
# File 'lib/origen/tester/j750/j750.rb', line 687

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)


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
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
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
# File 'lib/origen/tester/j750/j750.rb', line 381

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} ign ifc icc")
  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} ign ifc icc")
  pin.dont_care
  cc ' Wait for the result to propagate through the pipeline'
  cycle(microcode: 'pipe_minus 1 ign ifc icc')
  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 ign ifc icc')
    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)


523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
# File 'lib/origen/tester/j750/j750.rb', line 523

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} ign ifc icc")
  microcode "#{global_opt}match_inner_loop_#{@unique_counter}:"
  cycle(microcode: "loopA #{inner_loop_count} ign ifc icc")
  cc 'Check if block condition met'
  yield
  cc ' Wait for the result to propagate through the pipeline'
  cycle(microcode: 'pipe_minus 1 ign ifc icc')
  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) memory_test(options = {})

  • J750 Specific *

Generates a single MTO opcode line for J750

Codes implemented: xa load_preset, xa inc, ya load_preset, ya inc, stv_m0, stv_m1, stv_c



282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
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
# File 'lib/origen/tester/j750/j750.rb', line 282

def memory_test(options = {})
  options = {
    gen_vector:          true,                 # Default generate vector not just MTO opcode
    init_counter_x:      false,            # initialize counter X
    inc_counter_x:       false,             # increment counter X
    init_counter_y:      false,            # initialize counter X
    inc_counter_y:       false,             # increment counter X
    capture_vector:      false,            # capture vector to memory using all mem types
    capture_vector_mem0: false,       # capture vector to memory type 0, here for J750 will be stv_m0
    capture_vector_mem1: false,       # capture vector to memory type 1, here for J750 will be stv_m1
    capture_vector_mem2: false,       # capture vector to memory type 2, here for J750 will be stv_c
    pin:                 false,                       # pin on which to drive or expect data, pass pin object here!
    pin_data:            false,                  # pin data (:none, :drive, :expect)
  }.merge(options)

  mto_opcode = ''

  if options[:init_counter_x]
    mto_opcode += ' xa load_preset'
  end
  if options[:inc_counter_x]
    mto_opcode += ' xa inc'
  end
  if options[:init_counter_y]
    mto_opcode += ' ya load_preset'
  end
  if options[:inc_counter_y]
    mto_opcode += ' ya inc'
  end
  if options[:capture_vector]
    mto_opcode += ' stv_m0 stv_m1 stv_c'
  end
  if options[:capture_vector_mem0]
    mto_opcode += ' stv_m0'
  end
  if options[:capture_vector_mem1]
    mto_opcode += ' stv_m1'
  end
  if options[:capture_vector_mem2]
    mto_opcode += ' stv_c'
  end

  unless mto_opcode.eql?('')
    mto_opcode = '(mto:' + mto_opcode + ')'
  end

  if options[:gen_vector]
    if options[:pin]
      case options[:pin_data]
        when :drive
          # store current pin state
          cur_pin_state = options[:pin].state.to_sym
          options[:pin].drive_mem
        when :expect
          # store current pin state
          cur_pin_state = options[:pin].state.to_sym
          options[:pin].expect_mem
      end
    end
    cycle(microcode: "#{mto_opcode}")
    if options[:pin]
      # restore previous pin state
      case options[:pin_data]
        when :drive
          options[:pin].state = cur_pin_state
        when :expect
          options[:pin].state = cur_pin_state
      end
    end
  else
    microcode "#{mto_opcode}"
  end
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



66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/origen/tester/j750/j750.rb', line 66

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 ||= J750::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



762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
# File 'lib/origen/tester/j750/j750.rb', line 762

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 microcode: 'end_module' unless options[:subroutine_pat]
    end
  end
  microcode '}'
end

- (Object) pattern_header(options = {})

An internal method called by Origen to create the pattern header



714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
# File 'lib/origen/tester/j750/j750.rb', line 714

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
    memory_test:    false,      # If true, define 2-bit MTO DGEN as instrument
  }.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...
  if options[:memory_test]
    microcode 'instruments = {'
    microcode '               mto:dgen_2bit;'
    microcode '}'
  end
  microcode "svm_only_file = #{options[:subroutine_pat] ? 'yes' : 'no'};"
  microcode 'opcode_mode = extended;'
  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 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 "vector ($tset, #{pin_list})"
  microcode '{'
  unless options[:subroutine_pat]
    microcode 'start_label pattern_st:'
  end
end

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

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



810
811
812
# File 'lib/origen/tester/j750/j750.rb', line 810

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


827
828
829
830
831
832
# File 'lib/origen/tester/j750/j750.rb', line 827

def repeat_previous
  pinmap = Origen.pin_bank.pins
  pinmap.each { |_id, pin| pin.repeat_previous = true }
  yield
  pinmap.each { |_id, pin| pin.repeat_previous = false }
end

- (Object) set_code(code)

  • J750 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)


658
659
660
# File 'lib/origen/tester/j750/j750.rb', line 658

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

- (Object) set_flag(options = {})

  • J750 Specific *



185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/origen/tester/j750/j750.rb', line 185

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

  case options[:flagnum]
    when 1
      flagname = 'cpuA'
    when 2
      flagname = 'cpuB'
    when 3
      flagname = 'cpuC'
    when 4
      flagname = 'cpuD'
    else
      abort "ERROR! Invalid flag name passed to 'set_flag' method!\n"
  end
  update_vector(microcode: "set_cpu(#{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


155
156
157
158
# File 'lib/origen/tester/j750/j750.rb', line 155

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 J750 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


98
99
100
101
102
103
# File 'lib/origen/tester/j750/j750.rb', line 98

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 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


117
118
119
120
121
122
# File 'lib/origen/tester/j750/j750.rb', line 117

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