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

  # @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)

333
334
335
336
337
338
339
340
341
342
343
344
345
# File 'lib/origen_testers/stil_based_tester/base.rb', line 333

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


309
310
311
# File 'lib/origen_testers/stil_based_tester/base.rb', line 309

def called_subroutines
  @called_subroutines ||= []
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


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

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

277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
# File 'lib/origen_testers/stil_based_tester/base.rb', line 277

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


251
252
253
# File 'lib/origen_testers/stil_based_tester/base.rb', line 251

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


255
256
257
# File 'lib/origen_testers/stil_based_tester/base.rb', line 255

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

An internal method called by Origen to generate the pattern footer


301
302
303
304
305
306
# File 'lib/origen_testers/stil_based_tester/base.rb', line 301

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


34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
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
# File 'lib/origen_testers/stil_based_tester/base.rb', line 34

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

  @pattern_name = options[:pattern]

  unless pattern_only
    microcode 'STIL 1.0;'

    microcode ''
    microcode 'Signals {'
    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 {'
    line = "\"#{ordered_pins_name || 'ALL'}\" = '"
    ordered_pins.each_with_index do |pin, i|
      unless i == 0
        line << '+'
      end
      line << pin.name.to_s
    end
    microcode "  #{line}';"
    microcode '}'

    microcode ''
    microcode "Timing t_#{@pattern_name} {"
    (@wavesets || []).each_with_index do |w, i|
      microcode '' if i != 0
      microcode "  WaveformTable Waveset#{i + 1} {"
      microcode "    Period '#{w[:period]}ns';"
      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 "  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


347
348
349
350
351
352
353
# File 'lib/origen_testers/stil_based_tester/base.rb', line 347

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


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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/origen_testers/stil_based_tester/base.rb', line 108

def set_timeset(t, period_in_ns = nil)
  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
      end
    end
    unless wave_number
      lines = []
      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
          (wave ? wave.evaluated_events : []).each do |t, v|
            line << "'#{t}ns' "
            if v == 0
              line << 'D'
            elsif v == 0
              line << 'U'
            else
              line << 'D/U'
            end
            line << '; '
          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
          (wave ? wave.evaluated_events : []).each_with_index do |tv, i|
            t, v = *tv
            if i == 0 && t != 0
              line << "'0ns' X; "
            end
            line << "'#{t}ns' "
            if v == 0
              line << 'L'
            elsif v == 0
              line << 'H'
            else
              line << 'L/H/X'
            end
            line << '; '
          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)

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

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.


208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/origen_testers/stil_based_tester/base.rb', line 208

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

233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/origen_testers/stil_based_tester/base.rb', line 233

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