Module: Origen::Tester::VectorGenerator

Extended by:
ActiveSupport::Concern
Included in:
Origen::Tester
Defined in:
lib/origen/tester/vector_generator.rb

Instance Method Summary (collapse)

Instance Method Details

- (Object) _render(method)

:nodoc:



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/origen/tester/vector_generator.rb', line 142

def _render(method)  # :nodoc:
  if self.respond_to?(method)
    template = send(method)
    # Record the current file, this can be used to resolve any relative path
    # references in the file about to be compiled
    Origen.file_handler.current_file = template
    # Ran into crosstalk problems when rendering ERB templates recursively, setting eoutvar based
    # on the name of the file will causes each template to be rendered into its own 'bank'.
    # Not sure why the final gsub is needed but seems to fail to parse correctly otherwise.
    eoutvar = Pathname.new(template).basename('.*').basename('.*').to_s.gsub('-', '_')
    # Make the file name available to the template
    Origen.generator.compiler.options[:file] = template
    push_microcode Origen.generator.compiler.insert(ERB.new(File.read(template.to_s), 0, Origen.config.erb_trim_mode, eoutvar).result)
  end
end

- (Object) add_microcode_to_last_or_cycle(code)

Adds the given microcode to the last vector if possible. If not possible (meaning the vector already contains microcode) then a new cycle will be added with the given microcode.



244
245
246
247
# File 'lib/origen/tester/vector_generator.rb', line 244

def add_microcode_to_last_or_cycle(code)
  cycle if !stage.last_vector || stage.last_vector.has_microcode?
  stage.last_vector.update(microcode: code)
end

- (Object) before_write_pattern_line(line)

Tester models can overwrite this if they wish to inject any additional pattern lines at final pattern dump time



291
292
293
# File 'lib/origen/tester/vector_generator.rb', line 291

def before_write_pattern_line(line)
  [line]
end

- (Boolean) compressable_vector?(vec)

Returns:

  • (Boolean)


378
379
380
381
# File 'lib/origen/tester/vector_generator.rb', line 378

def compressable_vector?(vec)
  !!(compress && vec.is_a?(Vector) && !vec.has_microcode? &&
     vec.pin_vals && !vec.dont_compress)
end

- (Object) current_pin_vals



565
566
567
# File 'lib/origen/tester/vector_generator.rb', line 565

def current_pin_vals
  ordered_pins_cache.map(&:to_vector).join(' ')
end

- (Object) cycle_count

init cycle count when first accessed, otherwise return value



58
59
60
# File 'lib/origen/tester/vector_generator.rb', line 58

def cycle_count
  @cycle_count ||= 0
end

- (Object) dec_vec_count(num = 1)

decrement vector count



52
53
54
55
# File 'lib/origen/tester/vector_generator.rb', line 52

def dec_vec_count(num = 1)
  vec_count if @vec_count.nil?  # define if not already
  @vec_count = @vec_count - num
end

- (Object) dont_compress



363
364
365
366
367
368
369
370
371
372
# File 'lib/origen/tester/vector_generator.rb', line 363

def dont_compress
  if block_given?
    orig = @dont_compress
    @dont_compress = true
    yield
    @dont_compress = orig
  else
    @dont_compress
  end
end

- (Object) dont_compress=(val)



374
375
376
# File 'lib/origen/tester/vector_generator.rb', line 374

def dont_compress=(val)
  @dont_compress = val
end

- (Object) expand_vector(vec)

expands (uncompresses to pattern) vector if desired or leaves it as is allows for tracking and formatting of vector if comment then return without modification



386
387
388
389
390
391
392
393
394
395
396
397
398
399
# File 'lib/origen/tester/vector_generator.rb', line 386

def expand_vector(vec)
  if vec.is_a?(Vector)
    if expand_repeats
      vec.repeat.times do
        vec.repeat = 1
        yield track_and_format_vector(vec)
      end
    else
      yield track_and_format_vector(vec)
    end
  else
    yield vec  # Return comments without modification
  end
end

- (Object) format(vector_array, section)

Final pass of a generator vector array which returns lines suitable for writing to the output file. This gives the tester model a chance to concatenate repeats and any other last optimization/formatting changes it wishes to make.

At this point vector array contains a combination of non-vector lines and uncompressed Vector objects (vector lines)



256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'lib/origen/tester/vector_generator.rb', line 256

def format(vector_array, section)
  # Go through vector_array and print out both
  # vectors and non-vectors to pattern (via 'yield line')
  vector_array.each do |vec|
    # These may eventually be merged to the same method, but splitting for now
    # so that multi mode development can proceed without upsetting single mode
    if vector_group_size > 1
      multi_mode_optimize(vec, section: section) do |line|
        yield line
      end
    else
      optimize(vec, section: section) do |line|
        yield line
      end
    end
  end
  # now flush buffer if there is still a vector
  if vector_group_size > 1
    pipeline.empty do |vector|
      expand_vector(vector) do |line|
        yield line
      end
    end
  else
    if @buffered_vector
      expand_vector(@buffered_vector) do |line|
        yield line
      end
      @buffered_vector = nil
    end
  end
end

- (Object) format_pin_state(pin)



604
605
606
607
608
609
610
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/vector_generator.rb', line 604

def format_pin_state(pin)
  if pin.repeat_previous? && @support_repeat_previous
    @repeat_previous || '-'
  elsif pin.driving?
    if pin.value == 1
      if pin.high_voltage?
        @drive_very_hi_state || '2'
      else
        @drive_hi_state || '1'
      end
    else
      @drive_lo_state || '0'
    end
  elsif pin.comparing_midband?
    @expect_mid_state || 'M'
  elsif pin.comparing?
    if pin.value == 1
      @expect_hi_state || 'H'
    else
      @expect_lo_state || 'L'
    end
  elsif pin.driving_mem?
    @drive_mem_state || 'D'
  elsif pin.comparing_mem?
    @expect_mem_state || 'E'
  elsif pin.to_be_captured?
    @capture_state || 'C'
  else
    @dont_care_state || 'X'
  end
end

- (Object) format_vector(_vec)



425
426
# File 'lib/origen/tester/vector_generator.rb', line 425

def format_vector(_vec)
end

- (Object) get_pingroup(pin)



569
570
571
572
573
574
# File 'lib/origen/tester/vector_generator.rb', line 569

def get_pingroup(pin)
  pingroup_map.each do |id, pins|
    return id if pins.include? pin
  end
  nil
end

- (Object) inc_cycle_count(num = 1)

increment cycle count



63
64
65
66
# File 'lib/origen/tester/vector_generator.rb', line 63

def inc_cycle_count(num = 1)
  cycle_count if @cycle_count.nil? # define if not already
  @cycle_count = @cycle_count + num
end

- (Object) inc_vec_count(num = 1)

increment vector count



46
47
48
49
# File 'lib/origen/tester/vector_generator.rb', line 46

def inc_vec_count(num = 1)
  vec_count if @vec_count.nil?  # define if not already
  @vec_count = @vec_count + num
end

- (Object) inhibit_pin(*pins) Also known as: inhibit_pins

Call to prevent the given pins from appearing in the generated vectors.

This is a convenient way to inhibit something like a J750 mux pin from appearing in the patterns when generating the pattern for a different platform.

When used this method must be called before the first vector is generated - it will not be retrospectively applied to existing vectors.



83
84
85
86
87
88
89
90
# File 'lib/origen/tester/vector_generator.rb', line 83

def inhibit_pin(*pins)
  pins.each do |pin|
    inhibited_pins << pin
  end
  inhibited_pins.uniq!
  inhibited_pins.compact!
  inhibited_pins
end

- (Object) inhibited_pins

Returns an array of pin IDs that are currently inhibited (will not be included when vectors are generated)



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

def inhibited_pins
  @inhibited_pins ||= []
end

- (Object) last_object(offset = 0)



182
183
184
# File 'lib/origen/tester/vector_generator.rb', line 182

def last_object(offset = 0)
  stage.last_object(offset)
end

- (Object) last_vector(offset = 0)



178
179
180
# File 'lib/origen/tester/vector_generator.rb', line 178

def last_vector(offset = 0)
  stage.last_vector(offset)
end

- (Object) multi_mode_optimize(vec, _options = {})



299
300
301
302
303
304
305
306
# File 'lib/origen/tester/vector_generator.rb', line 299

def multi_mode_optimize(vec, _options = {})
  pipeline << vec
  pipeline.flush do |vector|
    expand_vector(vector) do |line|
      yield line
    end
  end
end

- (Object) optimize(vec, options = {}) Also known as: buffer



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
# File 'lib/origen/tester/vector_generator.rb', line 308

def optimize(vec, options = {})
  options = { section: false
          }.merge(options)

  # Flush the buffer if this vector is not compressible or if it doesn't
  # match the existing buffer (to get ready for new vector)
  if @buffered_vector && (!(compressable_vector?(vec) && vec == @buffered_vector) ||
    @buffered_vector.repeat == @max_repeat_loop)
    expand_vector(@buffered_vector) do |line|
      # if last vector in pattern then pad if insufficient vectors
      if options[:section] == :footer && (@min_pattern_vectors) && (vec_count < @min_pattern_vectors)
        yield "#{comment_char} PADDING VECTORS ADDED TO MEET MIN #{@min_pattern_vectors} FOR PATTERN"
        (@min_pattern_vectors - vec_count + 1).times do
          yield line
        end
        inc_vec_count(@min_pattern_vectors - vec_count)
      else
        yield line
      end
    end
    @buffered_vector = nil
  end
  if compressable_vector?(vec)
    # The new vector has already been identified as equal to the buffer
    # so just increment vector if buffered already, otherwise it is the
    # first encounter with this vector and create buffer with it
    if @buffered_vector
      # simply increment repeat count
      @buffered_vector.repeat += vec.repeat
      # decrement vector count only once with each added repeat
      dec_vec_count(1)
      # if new repeat exceeds @max_repeat_loop
      if @buffered_vector.repeat > @max_repeat_loop
        delay(@buffered_vector.repeat) do |options|
          @buffered_vector.repeat = options[:repeat]
          if options[:repeat] == @max_repeat_loop
            expand_vector(@buffered_vector) do |line|
              yield line
            end
          end
        end
      end
    else
      # not buffered vector, set buffer to vector
      @buffered_vector = vec
    end
  else
    # not compressible
    expand_vector(vec) do |line|
      yield line
    end
  end
end

- (Object) ordered_pins(options = {})



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
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
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
# File 'lib/origen/tester/vector_generator.rb', line 437

def ordered_pins(options = {})
  options = {
    include_inhibited_pins: false,
    include_pingroups:      true
  }.merge(options)

  result = nil

  Origen.profile 'Working out pin pattern order' do
    pinorder = Origen.app.pin_pattern_order.dup
    pinexclude = Origen.app.pin_pattern_exclude.dup

    if Origen.app.pin_pattern_order.last.is_a?(Hash)
      options.merge!(pinorder.pop)
    end
    if Origen.app.pin_pattern_exclude.last.is_a?(Hash)
      options.merge!(pinexclude.pop)
    end

    ordered_pins = []

    # Create a copy of all pins and groups to be output, pins/groups will be delete from here as
    # they are output, so that at the end of the user defined pin order what is left in here can
    # either be discarded or output at the end
    pins = Origen.pin_bank.pins.dup
    pingroups = Origen.pin_bank.pin_groups.dup

    if pinorder && pinorder.size > 0
      pinorder.each do |id|
        # If the ID refers to a pin group
        if group = Origen.pin_bank.pin_groups[id]
          # If the group has still to be output just do that now
          if pingroups.include? group.id
            ordered_pins << group
            # Now delete the group from the list of groups still to be output and all of its pins
            # from the list pins still to be output
            group.each do |pin|
              pins.delete(pin.id)
              pin.groups.each do |name, _group|
                pingroups.delete(name)
              end
            end
            pingroups.delete(group.id)
          # To get here the some of the pins in the group have already been output which is preventing
          # output of the complete group at this point, in that case output any of its pins that have
          # still to go
          else
            group.each do |pin|
              if pins.include? pin.id
                ordered_pins << pin
                pin.groups.each do |name, _group|
                  pingroups.delete(name)
                end
              end
            end
          end
        # this is a pin
        else
          pin = Origen.pin_bank.find(id)
          fail "Undefined pin (#{id}) added to pin_pattern_order" unless pin
          ordered_pins << pin
          pin.groups.each do |name, _group|
            pingroups.delete(name)
          end
          pin.name = id
          pins.delete(pin.id)
        end
      end
    end

    if pinexclude && pinexclude.size > 0
      pinexclude.each do |id|
        if group = Origen.pin_bank.pin_groups[id]
          # see if group is already in ordered_pins
          fail "Pin group #{id} is defined both in pin_pattern_order and pin_pattern_exclude" unless pingroups.include? id
          # this is a pin group, delete all pins in group
          pingroups.delete(id)
          group.each do |pin|
            fail "Pin (#{pin.name}) in group (#{group.id}) is defined both in pin_pattern_order and pin_pattern_exclude" unless pins.include? pin.id
            pins.delete(pin.id)
          end
        else # this is a pin, delete the pin
          pin = Origen.pin_bank.find(id)
          fail "Undefined pin (#{id}) added to pin_pattern_exclude" unless pin
          fail "Pin #{pin.name} is defined both in pin_pattern_order and pin_pattern_exclude" unless pins.include? pin.id
          pin.name = id
          pins.delete(pin.id)
          pin.groups.each do |name, _group|
            pingroups.delete(name)
          end
        end
      end
    end

    unless options[:only]
      # all the rest of the pins to the end of the pattern order
      pins.each do |_id, pin|
        # check for port
        if pin.belongs_to_a_pin_group?
          # Are any of this pin's groups still waiting to be output? pingroups at this point contains
          # those groups which have not been rendered yet
          group = pingroups.find do |_id, group|
            pin.groups.any? { |_pid, pgroup| group == pgroup }
          end
          if group
            ordered_pins << group[1]
            group[1].each { |pin| pins.delete(pin.id) }
          else
            ordered_pins << pin
          end
        else
          ordered_pins << pin
        end
      end
    end

    result = ordered_pins.map do |pin|
      if options[:include_inhibited_pins]
        pin
      else
        inhibited_pins.include?(pin) ? nil : pin
      end
    end
    result = result.compact
  end
  result
end

- (Object) ordered_pins_cache(options = {})

Cache the pin ordering for later use since all vectors should be formatted the same



433
434
435
# File 'lib/origen/tester/vector_generator.rb', line 433

def ordered_pins_cache(options = {})
  @ordered_pins_cache ||= ordered_pins(options)
end

- (Object) pingroup_map



428
429
430
# File 'lib/origen/tester/vector_generator.rb', line 428

def pingroup_map
  Origen.app.pingroup_map
end

- (Object) pipeline



295
296
297
# File 'lib/origen/tester/vector_generator.rb', line 295

def pipeline
  @pipeline ||= VectorPipeline.new(vector_group_size)
end

- (Object) preset_next_vector(attrs = {}, &block)

Allows the attributes for the next vector to be setup prior to generating it.

A block can be optionally supplied to act as a clean up method, that is the block will be saved and executed after the next cycle has been generated.

See the V93K store_next_cycle method for an example of using this.



195
196
197
198
# File 'lib/origen/tester/vector_generator.rb', line 195

def preset_next_vector(attrs = {}, &block)
  @preset_next_vector = attrs
  @preset_next_vector_cleanup = block
end

- (Object) push_comment(msg)



162
163
164
165
# File 'lib/origen/tester/vector_generator.rb', line 162

def push_comment(msg)
  # Comments are stored verbatim for now, can't see much use for a dedicated comment object
  stage.store msg unless @inhibit_comments
end

- (Object) push_microcode(code, options = {}) Also known as: microcode



167
168
169
170
171
172
173
174
175
# File 'lib/origen/tester/vector_generator.rb', line 167

def push_microcode(code, options = {})
  unless @inhibit_vectors
    if options[:offset] && options[:offset] != 0
      stage.insert_from_end code, options[:offset]
    else
      stage.store code
    end
  end
end

- (Object) push_vector(attrs = {}) Also known as: vector

Called by every $tester.cycle command to push a vector to the stage object



201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/origen/tester/vector_generator.rb', line 201

def push_vector(attrs = {})
  attrs = {
    dont_compress: @dont_compress
  }.merge(attrs)
  unless @inhibit_vectors
    if @preset_next_vector
      attrs = @preset_next_vector.merge(attrs) do |key, preset, current|
        if preset && current && current != ''
          fail "Value for #{key} set by preset_next_vector clashed with the next vector!"
        else
          preset || current
        end
      end
      @preset_next_vector = nil
    end
    stage.store Vector.new(attrs)
    inc_vec_count
    inc_cycle_count(attrs[:repeat] || 1)
    if @preset_next_vector_cleanup
      @preset_next_vector_cleanup.call
      @preset_next_vector_cleanup = nil
    end
  end
end

- (Object) render(template, options = {})

Render content directly into a pattern, any options will be passed to the template



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/origen/tester/vector_generator.rb', line 94

def render(template, options = {})
  # Record the current file, this can be used to resolve any relative path
  # references in the file about to be compiled
  Origen.file_handler.current_file = template
  # Ran into crosstalk problems when rendering ERB templates recursively, setting eoutvar based
  # on the name of the file will causes each template to be rendered into its own 'bank'.
  # Not sure why the final gsub is needed but seems to fail to parse correctly otherwise.
  eoutvar = Pathname.new(template).basename('.*').basename('.*').to_s.gsub('-', '_')
  # Make the file name available to the template
  Origen.generator.compiler.options[:file] = template
  options.each { |k, v| Origen.generator.compiler.options[k] = v }
  code = Origen.generator.compiler.insert(ERB.new(File.read(template.to_s), 0, Origen.config.erb_trim_mode, eoutvar).result)
  code.strip!
  push_microcode code
end

- (Object) render_body

Same as the render method, except the template method should be called body_template.



120
121
122
# File 'lib/origen/tester/vector_generator.rb', line 120

def render_body
  _render(:body_template)
end

If the tester defines a method named footer_template this method will compile whatever template file is returned by that method.

This method is called automatically during the footer section of a Pattern.create operation.



129
130
131
# File 'lib/origen/tester/vector_generator.rb', line 129

def render_footer
  _render(:footer_template)
end

- (Object) render_header

If the tester defines a method named header_template this method will compile whatever template file is returned by that method.

This method is called automatically during the header section of a Pattern.create operation.



138
139
140
# File 'lib/origen/tester/vector_generator.rb', line 138

def render_header
  _render(:header_template)
end

- (Object) render_template

If the tester defines a method named template this method will compile whatever template file is returned by that method.

This method is called automatically after the body section of a Pattern.create operation has completed.



115
116
117
# File 'lib/origen/tester/vector_generator.rb', line 115

def render_template
  _render(:template)
end

- (Object) reset_cycle_count(num = 0)

reset_cycle_count



69
70
71
72
# File 'lib/origen/tester/vector_generator.rb', line 69

def reset_cycle_count(num = 0)
  cycle_count if @cycle_count.nil? # define if not already
  @cycle_count = num
end

- (Object) stage



158
159
160
# File 'lib/origen/tester/vector_generator.rb', line 158

def stage
  Origen.generator.stage
end

- (Object) track_and_format_vector(vec)

Update tracking info (stats object) and allow for any additional formatting via format_vector method if overridden



404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
# File 'lib/origen/tester/vector_generator.rb', line 404

def track_and_format_vector(vec)
  unless vec.timeset
    puts 'No timeset defined!'
    puts 'Add one to your top level startup method or target like this:'
    puts '$tester.set_timeset("nvmbist", 40)   # Where 40 is the period in ns'
    exit 1
  end
  stats = Origen.app.stats
  stats.add_vector
  if vector_group_size > 1 && vec.repeat > 1
    stats.add_cycle(1)
    stats.add_cycle((vec.repeat - 1) * vector_group_size)
    stats.add_time_in_ns(vec.timeset.period_in_ns)
    stats.add_time_in_ns((vec.repeat - 1) * vector_group_size * vec.timeset.period_in_ns)
  else
    stats.add_cycle(vec.repeat)
    stats.add_time_in_ns(vec.repeat * vec.timeset.period_in_ns)
  end
  format_vector(vec)
end

- (Object) update_pin_from_formatted_state(pin, state)



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
# File 'lib/origen/tester/vector_generator.rb', line 576

def update_pin_from_formatted_state(pin, state)
  if state == @repeat_previous || state == '-'
    pin.repeat_previous = true
  elsif state == @drive_very_hi_state || state == '2'
    pin.drive_very_hi
  elsif state == @drive_hi_state || state == '1'
    pin.drive_hi
  elsif state == @drive_lo_state || state == '0'
    pin.drive_lo
  elsif state == @expect_hi_state || state == 'H'
    pin.expect_hi
  elsif state == @expect_lo_state || state == 'L'
    pin.expect_lo
  elsif state == @expect_mid_state || state == 'M'
    pin.expect_mid
  elsif state == @drive_mem_state || state == 'D'
    pin.drive_mem
  elsif state == @expect_mem_state || state == 'E'
    pin.expect_mem
  elsif state == @capture_state || state == 'C'
    pin.capture
  elsif state == @dont_care_state || state == 'X'
    pin.dont_care
  else
    fail "Unknown pin state: #{state}"
  end
end

- (Object) update_vector(attrs = {})



227
228
229
230
231
232
# File 'lib/origen/tester/vector_generator.rb', line 227

def update_vector(attrs = {})
  unless @inhibit_vectors
    offset = (attrs.delete(:offset) || 0).abs
    stage.last_vector(offset).update(attrs)
  end
end

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



234
235
236
237
238
239
# File 'lib/origen/tester/vector_generator.rb', line 234

def update_vector_pin_val(pin, options = {})
  unless @inhibit_vectors
    offset = (options.delete(:offset) || 0).abs
    stage.last_vector(offset).update_pin_val(pin)
  end
end

- (Object) vec_count

init vector count when first accessed, otherwise return value



41
42
43
# File 'lib/origen/tester/vector_generator.rb', line 41

def vec_count
  @vec_count ||= 0
end

- (Object) vector_group_size



14
15
16
# File 'lib/origen/tester/vector_generator.rb', line 14

def vector_group_size
  @vector_group_size || 1
end

- (Object) vector_group_size=(number)



18
19
20
21
22
23
24
25
# File 'lib/origen/tester/vector_generator.rb', line 18

def vector_group_size=(number)
  if number > 1 && number.odd?
    fail 'Only even numbers can be supplied for the vector_group_size!'
  end
  # Each pattern should run with its own tester instance, but just in case
  @pipeline = nil
  @vector_group_size = number
end

- (Object) with_vector_group_size(number)



27
28
29
30
31
32
# File 'lib/origen/tester/vector_generator.rb', line 27

def with_vector_group_size(number)
  orig = vector_group_size
  self.vector_group_size = number
  yield
  self.vector_group_size = orig
end