Class: OrigenTesters::StilBasedTester::Base

Inherits:
Object
  • Object
show all
Includes:
VectorBasedTester
Defined in:
lib/origen_testers/stil_based_tester/base.rb

Direct Known Subclasses

D10, STIL

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from VectorBasedTester

#register_tester

Constructor Details

#initialize(options = {}) ⇒ Base

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


12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/origen_testers/stil_based_tester/base.rb', line 12

def initialize(options = {})
  self.pattern_only = options.delete(:pattern_only)
  @max_repeat_loop = 65_535
  @min_repeat_loop = 2
  @pat_extension = 'stil'
  @compress = true
  @use_timing_equations = options[:use_timing_equations]

  # @support_repeat_previous = true
  @match_entries = 10
  @name = 'stil'
  @comment_char = '//'
  @level_period = true
  @inline_comments = true
  @header_done = false
  @footer_done = false
end

Instance Attribute Details

#pattern_onlyObject

When set to true generated patterns will only contain Pattern blocks, i.e. only vectors



7
8
9
# File 'lib/origen_testers/stil_based_tester/base.rb', line 7

def pattern_only
  @pattern_only
end

Instance Method Details

#call_subroutine(name, options = {}) ⇒ Object

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)


411
412
413
414
415
416
417
418
419
420
421
422
423
# File 'lib/origen_testers/stil_based_tester/base.rb', line 411

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 = "Call #{name};"
  if !options[:suppress_repeated_calls] ||
     last_object != code
    microcode code, offset: (options[:offset] * -1)
  end
end

#called_subroutinesObject

Returns an array of subroutines called while generating the current pattern



387
388
389
# File 'lib/origen_testers/stil_based_tester/base.rb', line 387

def called_subroutines
  @called_subroutines ||= []
end

#flattened_ordered_pinsObject

returns the orderd pins with groups decomposed into individual pins



35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/origen_testers/stil_based_tester/base.rb', line 35

def flattened_ordered_pins
  if @flattened_ordered_pins.nil?
    @flattened_ordered_pins = []
    ordered_pins.each do |p|
      if p.is_a?(Origen::Pins::PinCollection)
        p.each { |ip| @flattened_ordered_pins << ip }
      else
        @flattened_ordered_pins << p
      end
    end
  end
  @flattened_ordered_pins
end

#format_vector(vec) ⇒ Object

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



435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
# File 'lib/origen_testers/stil_based_tester/base.rb', line 435

def format_vector(vec)
  timeset = vec.timeset ? "#{vec.timeset.name}" : ''
  pin_vals = vec.pin_vals ? "#{vec.pin_vals};".gsub(' ', '') : ''
  sig_name = tester.ordered_pins_name || 'ALL'
  if sig_name.nil?
    Origen.log.warn "WARN: SigName must be defined for STIL format.  Use pin_pattern_order(*pins, name: <sigName>).  Default to 'ALL'"
    sig_name = 'ALL'
  end
  if vec.repeat > 1
    microcode = "Loop #{vec.repeat} {\n"
  else
    microcode = vec.microcode ? vec.microcode : ''
  end
  if vec.pin_vals && ($_testers_enable_vector_comments || vector_comments)
    comment = "// V:#{vec.number} C:#{vec.cycle} #{vec.inline_comment}"
  else
    comment = vec.inline_comment.empty? ? '' : "Ann {*// #{vec.inline_comment}*}"
  end

  microcode_post = vec.repeat > 1 ? "\n}" : ''
  "#{microcode}  V { \"#{sig_name}\" = #{pin_vals} }#{comment}#{microcode_post}"
end

#loop_vectors(name = nil, number_of_loops = 1, _global = false) ⇒ Object 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


355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
# File 'lib/origen_testers/stil_based_tester/base.rb', line 355

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.is_a?(Symbol)
    name, number_of_loops, global = 'loop', name, number_of_loops
  end
  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]}"
    loop_name = loop_name.symbolize
    microcode "#{loop_name}: Loop #{number_of_loops} {"
    yield
    microcode '}'
  else
    yield
  end
end

#match(pin, state, timeout_in_cycles, options = {}) ⇒ Object



329
330
331
# File 'lib/origen_testers/stil_based_tester/base.rb', line 329

def match(pin, state, timeout_in_cycles, options = {})
  Origen.log.warning "Call to match loop on pin #{pin.id} is not supported by the STIL generator and has been ignored"
end

#match_block(timeout_in_cycles, options = {}, &block) ⇒ Object



333
334
335
# File 'lib/origen_testers/stil_based_tester/base.rb', line 333

def match_block(timeout_in_cycles, options = {}, &block)
  Origen.log.warning 'Call to match loop block is not supported by the STIL generator and has been ignored'
end

#output_group_definition(grp, grp_name) ⇒ Object



49
50
51
52
53
54
55
56
57
58
# File 'lib/origen_testers/stil_based_tester/base.rb', line 49

def output_group_definition(grp, grp_name)
  line = "\"#{grp_name}\" = '"
  grp.each_with_index do |pin, i|
    unless i == 0
      line << '+'
    end
    line << pin.name.to_s
  end
  microcode "  #{line}';"
end

An internal method called by Origen to generate the pattern footer



379
380
381
382
383
384
# File 'lib/origen_testers/stil_based_tester/base.rb', line 379

def pattern_footer(options = {})
  cycle dont_compress: true     # one extra single vector before stop microcode
  microcode 'Stop;' unless options[:subroutine]
  microcode '}'
  @footer_done = true
end

#pattern_header(options = {}) ⇒ Object

An internal method called by Origen to create the pattern header



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/origen_testers/stil_based_tester/base.rb', line 61

def pattern_header(options = {})
  options = {
  }.merge(options)

  @pattern_name = options[:pattern]

  unless pattern_only
    microcode 'STIL 1.0;'

    microcode ''
    microcode 'Signals {'
    flattened_ordered_pins.each do |pin|
      line = ''
      line << "#{pin.name} "
      if pin.direction == :input
        line << 'In;'
      elsif pin.direction == :output
        line << 'Out;'
      else
        line << 'InOut;'
      end
      microcode "  #{line}"
    end
    microcode '}'

    microcode ''
    microcode 'SignalGroups {'
    # output pin group definitions used in this pattern
    ordered_pins.each do |p|
      output_group_definition(p, p.name.to_s) if p.is_a?(Origen::Pins::PinCollection)
    end

    # output the all pin group
    output_group_definition(flattened_ordered_pins, "#{ordered_pins_name || 'ALL'}")
    microcode '}'

    # output the period category specs
    if @use_timing_equations
      microcode ''
      microcode 'Spec {'
      microcode "  Category c_#{@pattern_name} {"
      (@wavesets || []).each_with_index do |w, i|
        microcode "    period_#{w[:name]} = '#{w[:period]}ns';"
      end
      microcode '  }'
      microcode '}'
    end

    microcode ''
    microcode "Timing t_#{@pattern_name} {"
    (@wavesets || []).each_with_index do |w, i|
      microcode '' if i != 0
      microcode "  WaveformTable Waveset#{i + 1} {"
      period_var = "period_#{w[:name]}"
      if @use_timing_equations
        microcode "    Period '#{period_var}';"
      else
        microcode "    Period '#{w[:period]}ns';"
      end
      microcode '    Waveforms {'
      w[:lines].each do |line|
        microcode "      #{line}"
      end
      microcode '    }'
      microcode '  }'
    end
    microcode '}'

    microcode ''
    microcode "PatternBurst b_#{@pattern_name} {"
    microcode "  PatList { #{@pattern_name}; }"
    microcode '}'

    microcode ''
    microcode "PatternExec e_#{@pattern_name} {"
    microcode "  Category c_#{@pattern_name};" if @use_timing_equations
    microcode "  Timing t_#{@pattern_name};"
    microcode "  PatternBurst b_#{@pattern_name};"
    microcode '}'
    microcode ''
  end

  microcode "Pattern \"#{@pattern_name}\" {"
  microcode "#{@pattern_name}:"
  @header_done = true

  if tester.ordered_pins_name.nil? && pattern_only
    Origen.log.warn "WARN: SigName must be defined for STIL format.  Use pin_pattern_order(*pins, name: <sigName>).  Defaulting to use 'ALL'"
  end
end

#push_comment(msg) ⇒ Object



425
426
427
428
429
430
431
# File 'lib/origen_testers/stil_based_tester/base.rb', line 425

def push_comment(msg)
  if @footer_done
    stage.store msg unless @inhibit_comments
  else
    stage.store "Ann {*#{msg}*}" unless @inhibit_comments
  end
end

#set_timeset(t, period_in_ns = nil) ⇒ Object



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
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
# File 'lib/origen_testers/stil_based_tester/base.rb', line 152

def set_timeset(t, period_in_ns = nil)
  # check for period size override from the app if performing convert command
  if Origen.current_command == 'convert'
    listeners = Origen.listeners_for(:convert_command_set_period_in_ns)
    if listeners.empty?
      unless @call_back_message_displayed
        Origen.log.warn 'STIL output is generated using "origen convert" with no timeset period callback method defined. Default period size will be used.'
        Origen.log.info 'stil tester implements a callback for setting the timeset period size when converting a pattern to stil format'
        Origen.log.info 'to use the callback feature add the following define to your app in config/application.rb'
        Origen.log.info '  def convert_command_set_period_in_ns(timeset_name)'
        Origen.log.info '    return 25 if timeset_name == "timeset0"'
        Origen.log.info '    return 30 if timeset_name == "timeset1"'
        Origen.log.info '    40'
        Origen.log.info '  end'
        @call_back_message_displayed = true
      end
    else
      listeners.each do |listener|
        period_in_ns = listener.convert_command_set_period_in_ns(t)
      end
    end
  end
  super
  if pattern_only
    # Why does D10 not include this?
    # microcode "W #{t};"
  else
    @wavesets ||= []
    wave_number = nil
    @wavesets.each_with_index do |w, i|
      if w[:name] == timeset.name && w[:period] = timeset.period_in_ns
        wave_number = i + 1               # bug fix wave numbers are 1 more than their index #
      end
    end
    unless wave_number
      lines = []
      period_var = "period_#{timeset.name}"
      flattened_ordered_pins.each do |pin|
        if pin.direction == :input || pin.direction == :io
          line = "#{pin.name} { 01 { "
          wave = pin.drive_wave if tester.timeset.dut_timeset
          if wave
            (@use_timing_equations ? wave.events : wave.evaluated_events).each do |t, v|
              if @use_timing_equations
                line << "'#{t.to_s.gsub('period', period_var)}' "
              else
                line << "'#{t}ns' "
              end
              if v == 0
                line << 'D'
              elsif v == 1
                line << 'U'
              else
                line << 'D/U'
              end
              line << '; '
            end
          end
          line << '}}'
          lines << line
        end
        if pin.direction == :output || pin.direction == :io
          line = "#{pin.name} { LHX { "
          wave = pin.compare_wave if tester.timeset.dut_timeset
          if wave
            (@use_timing_equations ? wave.events : wave.evaluated_events).each_with_index do |tv, i|
              t, v = *tv
              if i == 0 && t != 0
                line << "'0ns' X; "
              end
              if @use_timing_equations
                line << "'#{t.to_s.gsub('period', period_var)}' "
              else
                line << "'#{t}ns' "
              end
              if v == 0
                line << 'L'
              elsif v == 0
                line << 'H'
              else
                line << 'L/H/X'
              end
              line << '; '
            end
          end
          line << '}}'
          lines << line
        end
      end
      @wavesets << { name: timeset.name, period: timeset.period_in_ns, lines: lines }
      wave_number = @wavesets.size
    end
    microcode "W Waveset#{wave_number};"
  end
end

#stil_based?Boolean

Returns:

  • (Boolean)


30
31
32
# File 'lib/origen_testers/stil_based_tester/base.rb', line 30

def stil_based?
  true
end

#store(*pins) ⇒ Object 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 STIL 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-compatibility with other platforms, such as the J750, is required.



286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
# File 'lib/origen_testers/stil_based_tester/base.rb', line 286

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 STIL generation 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
      last_vector(options[:offset]).contains_capture = true
    end
  end
end

#store_next_cycle(*pins) ⇒ Object Also known as: store!

Same as the store method, except that the capture will be applied to the next vector to be generated.

Examples:

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


311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
# File 'lib/origen_testers/stil_based_tester/base.rb', line 311

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 STIL generation 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 |vector|
    vector.contains_capture = true
    pins.each(&:restore)
  end
end