origen_testers 0.31.0 → 0.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/config/application.rb +3 -1
- data/config/shared_commands.rb +4 -0
- data/config/version.rb +1 -1
- data/lib/origen_testers/api.rb +8 -0
- data/lib/origen_testers/atp/flow.rb +30 -9
- data/lib/origen_testers/flow.rb +36 -2
- data/lib/origen_testers/generator.rb +44 -5
- data/lib/origen_testers/interface.rb +22 -2
- data/lib/origen_testers/origen_ext/generator.rb +4 -3
- data/lib/origen_testers/origen_ext/generator/flow.rb +99 -5
- data/lib/origen_testers/program_generators.rb +5 -1
- data/lib/origen_testers/smartest_based_tester.rb +1 -0
- data/lib/origen_testers/smartest_based_tester/base.rb +177 -114
- data/lib/origen_testers/smartest_based_tester/base/flow.rb +329 -127
- data/lib/origen_testers/smartest_based_tester/base/generator.rb +25 -7
- data/lib/origen_testers/smartest_based_tester/base/limits_file.rb +186 -60
- data/lib/origen_testers/smartest_based_tester/base/pattern_compiler.rb +4 -0
- data/lib/origen_testers/smartest_based_tester/base/pattern_master.rb +4 -0
- data/lib/origen_testers/smartest_based_tester/base/processors/extract_bin_names.rb +5 -1
- data/lib/origen_testers/smartest_based_tester/base/processors/extract_flow_vars.rb +108 -0
- data/lib/origen_testers/smartest_based_tester/base/test_method.rb +8 -3
- data/lib/origen_testers/smartest_based_tester/base/test_suite.rb +9 -108
- data/lib/origen_testers/smartest_based_tester/base/test_suites.rb +17 -7
- data/lib/origen_testers/smartest_based_tester/base/variables_file.rb +29 -7
- data/lib/origen_testers/smartest_based_tester/smt7.rb +59 -0
- data/lib/origen_testers/smartest_based_tester/smt8.rb +218 -0
- data/lib/origen_testers/smartest_based_tester/v93k/flow.rb +32 -0
- data/lib/origen_testers/smartest_based_tester/v93k/templates/vars.tf.erb +2 -2
- data/lib/origen_testers/smartest_based_tester/v93k/test_suite.rb +109 -0
- data/lib/origen_testers/smartest_based_tester/v93k_smt8.rb +8 -0
- data/lib/origen_testers/smartest_based_tester/v93k_smt8/flow.rb +234 -0
- data/lib/origen_testers/smartest_based_tester/v93k_smt8/generator.rb +48 -0
- data/lib/origen_testers/smartest_based_tester/v93k_smt8/limits_file.rb +14 -0
- data/lib/origen_testers/smartest_based_tester/v93k_smt8/limits_workbook.rb +148 -0
- data/lib/origen_testers/smartest_based_tester/v93k_smt8/templates/limits.csv.erb +3 -0
- data/lib/origen_testers/smartest_based_tester/v93k_smt8/templates/template.flow.erb +41 -0
- data/lib/origen_testers/smartest_based_tester/v93k_smt8/test_suite.rb +66 -0
- data/lib/origen_testers/stil_based_tester/base.rb +4 -0
- data/lib/origen_testers/test/interface.rb +16 -2
- data/lib/origen_testers/vector_generator.rb +9 -4
- data/lib/origen_testers/vector_pipeline.rb +1 -1
- data/pattern/nvm/v93k/v93k_workout.rb +7 -0
- data/program/_erase_vfy.rb +2 -1
- data/program/components/_deep_nested.rb +3 -0
- data/program/components/_prb1_main.rb +1 -1
- data/program/components/_prb2_main.rb +6 -2
- data/program/flow_control.rb +3 -3
- data/program/prb1.rb +4 -0
- data/program/prb2.rb +7 -3
- data/templates/origen_guides/pattern/v93k.md.erb +24 -0
- data/templates/origen_guides/program/v93k.md.erb +6 -148
- data/templates/origen_guides/program/v93ksmt7.md.erb +165 -0
- data/templates/origen_guides/program/v93ksmt8.md.erb +112 -0
- metadata +30 -3
- data/lib/origen_testers/smartest_based_tester/base/test_methods/smart_calc_tml.rb +0 -23
@@ -45,7 +45,11 @@ module OrigenTesters
|
|
45
45
|
|
46
46
|
def _load_generator
|
47
47
|
if tester.v93k?
|
48
|
-
|
48
|
+
if tester.smt8?
|
49
|
+
class << self; include OrigenTesters::V93K_SMT8::Generator; end
|
50
|
+
else
|
51
|
+
class << self; include OrigenTesters::V93K::Generator; end
|
52
|
+
end
|
49
53
|
elsif tester.j750_hpt?
|
50
54
|
class << self; include OrigenTesters::J750_HPT::Generator; end
|
51
55
|
elsif tester.j750?
|
@@ -19,6 +19,9 @@ module OrigenTesters
|
|
19
19
|
# flow, the default value is :signature
|
20
20
|
attr_reader :unique_test_names
|
21
21
|
|
22
|
+
# Returns the SMT version, defaults to 7
|
23
|
+
attr_reader :smt_version
|
24
|
+
|
22
25
|
# permit modification of minimum repeat count
|
23
26
|
attr_accessor :min_repeat_loop
|
24
27
|
alias_method :min_repeat_count, :min_repeat_loop
|
@@ -55,6 +58,18 @@ module OrigenTesters
|
|
55
58
|
# delayed: false is supplied when defining the test
|
56
59
|
attr_accessor :delayed_binning
|
57
60
|
|
61
|
+
# Sets the package namespace that all generated test collateral should be placed under,
|
62
|
+
# defaults to the application's namespace if not defined (SMT8 only)
|
63
|
+
attr_writer :package_namespace
|
64
|
+
|
65
|
+
# When set to true, the bins and softbins sheets from the limits spreadsheet will
|
66
|
+
# be written out to a standalone (spreadsheet) file instead (SMT8 only)
|
67
|
+
attr_accessor :separate_bins_file
|
68
|
+
|
69
|
+
# When set to true (the default), patterns will be generated in ZIP format instead of ASCII
|
70
|
+
# format (SMT8 only)
|
71
|
+
attr_accessor :zip_patterns
|
72
|
+
|
58
73
|
def initialize(options = {})
|
59
74
|
options = {
|
60
75
|
# whether to use multiport bursts or not, if so this indicates the name of the port to use
|
@@ -62,9 +77,31 @@ module OrigenTesters
|
|
62
77
|
multiport_prefix: false,
|
63
78
|
multiport_postfix: false
|
64
79
|
}.merge(options)
|
80
|
+
|
81
|
+
@smt_version = options[:smt_version] || 7
|
82
|
+
|
83
|
+
@separate_bins_file = options[:separate_bins_file] || false
|
84
|
+
if options.key?(:zip_patterns)
|
85
|
+
@zip_patterns = options.delete(:zip_patterns)
|
86
|
+
else
|
87
|
+
@zip_patterns = true
|
88
|
+
end
|
89
|
+
|
90
|
+
if smt8?
|
91
|
+
require_relative 'smt8'
|
92
|
+
extend SMT8
|
93
|
+
else
|
94
|
+
require_relative 'smt7'
|
95
|
+
extend SMT7
|
96
|
+
end
|
97
|
+
|
65
98
|
@max_repeat_loop = 65_535
|
66
99
|
@min_repeat_loop = 33
|
67
|
-
|
100
|
+
if smt8?
|
101
|
+
@pat_extension = 'pat'
|
102
|
+
else
|
103
|
+
@pat_extension = 'avc'
|
104
|
+
end
|
68
105
|
@compress = true
|
69
106
|
# @support_repeat_previous = true
|
70
107
|
@match_entries = 10
|
@@ -85,18 +122,37 @@ module OrigenTesters
|
|
85
122
|
if options.key?(:unique_test_names)
|
86
123
|
@unique_test_names = options[:unique_test_names]
|
87
124
|
else
|
88
|
-
|
125
|
+
if smt8?
|
126
|
+
@unique_test_names = nil
|
127
|
+
else
|
128
|
+
@unique_test_names = :signature
|
129
|
+
end
|
89
130
|
end
|
90
|
-
if
|
91
|
-
@create_limits_file =
|
131
|
+
if smt8?
|
132
|
+
@create_limits_file = true
|
92
133
|
else
|
93
|
-
|
134
|
+
if options.key?(:create_limits_file)
|
135
|
+
@create_limits_file = options[:create_limits_file]
|
136
|
+
else
|
137
|
+
@create_limits_file = false
|
138
|
+
end
|
94
139
|
end
|
140
|
+
@package_namespace = options.delete(:package_namespace)
|
95
141
|
self.limitfile_test_modes = options[:limitfile_test_modes] || options[:limitsfile_test_modes]
|
96
142
|
self.force_pass_on_continue = options[:force_pass_on_continue]
|
97
143
|
self.delayed_binning = options[:delayed_binning]
|
98
144
|
end
|
99
145
|
|
146
|
+
def disable_pattern_diffs
|
147
|
+
smt8? && zip_patterns
|
148
|
+
end
|
149
|
+
|
150
|
+
# Returns the package namespace that all generated test collateral should be placed under,
|
151
|
+
# defaults to the application's namespace if not defined
|
152
|
+
def package_namespace
|
153
|
+
@package_namespace || Origen.app.namespace
|
154
|
+
end
|
155
|
+
|
100
156
|
# Set the test mode(s) that you want to see in the limits files, supply an array of mode names
|
101
157
|
# to set multiple.
|
102
158
|
def limitfile_test_modes=(val)
|
@@ -401,81 +457,142 @@ module OrigenTesters
|
|
401
457
|
pin.dont_care
|
402
458
|
options[:pin2].dont_care if options[:pin2]
|
403
459
|
|
404
|
-
# Single condition loops are simple
|
405
460
|
if !options[:pin2]
|
406
|
-
# Use the counted match loop (rather than timed) which is recommended in the V93K docs for new applications
|
407
|
-
# No pre-match failure handling is required here because the system will cleanly record failure info
|
408
|
-
# for this kind of match loop
|
409
461
|
cc "for the #{pin.name.upcase} pin to go #{state.to_s.upcase}"
|
462
|
+
match_block(timeout_in_cycles, options) do |match_or_conditions, fail_conditions|
|
463
|
+
match_or_conditions.add do
|
464
|
+
state == :low ? pin.expect_lo : pin.expect_hi
|
465
|
+
cycle
|
466
|
+
pin.dont_care
|
467
|
+
end
|
468
|
+
end
|
469
|
+
else
|
470
|
+
cc "for the #{pin.name.upcase} pin to go #{state.to_s.upcase}"
|
471
|
+
cc "or the #{options[:pin2].name.upcase} pin to go #{options[:state2].to_s.upcase}"
|
472
|
+
match_block(timeout_in_cycles, options) do |match_or_conditions, fail_conditions|
|
473
|
+
match_or_conditions.add do
|
474
|
+
state == :low ? pin.expect_lo : pin.expect_hi
|
475
|
+
cycle
|
476
|
+
pin.dont_care
|
477
|
+
end
|
478
|
+
match_or_conditions.add do
|
479
|
+
options[:state2] == :low ? options[:pin2].expect_lo : options[:pin2].expect_hi
|
480
|
+
cycle
|
481
|
+
options[:pin2].dont_care
|
482
|
+
end
|
483
|
+
fail_conditions.add do
|
484
|
+
cc 'To get here something has gone wrong, strobe again to force a pattern failure'
|
485
|
+
state == :low ? pin.expect_lo : pin.expect_hi
|
486
|
+
options[:state2] == :low ? options[:pin2].expect_lo : options[:pin2].expect_hi
|
487
|
+
cycle
|
488
|
+
pin.dont_care
|
489
|
+
options[:pin2].dont_care
|
490
|
+
end
|
491
|
+
end
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
495
|
+
def match_block(timeout_in_cycles, options = {}, &block)
|
496
|
+
unless block_given?
|
497
|
+
fail 'ERROR: block not passed to match_block!'
|
498
|
+
end
|
499
|
+
|
500
|
+
# Create BlockArgs objects in order to receive multiple blocks
|
501
|
+
match_conditions = Origen::Utility::BlockArgs.new
|
502
|
+
fail_conditions = Origen::Utility::BlockArgs.new
|
503
|
+
|
504
|
+
if block.arity > 0
|
505
|
+
yield match_conditions, fail_conditions
|
506
|
+
else
|
507
|
+
match_conditions.add(&block)
|
508
|
+
end
|
509
|
+
|
510
|
+
# Generate a conventional match loop when there is only one match condition block
|
511
|
+
if match_conditions.instance_variable_get(:@block_args).size == 1
|
410
512
|
# Need to ensure at least 8 cycles with no compares before entering
|
513
|
+
dut.pins.each do |name, pin|
|
514
|
+
pin.save
|
515
|
+
pin.dont_care if pin.comparing?
|
516
|
+
end
|
411
517
|
8.cycles
|
412
|
-
|
413
|
-
|
518
|
+
dut.pins.each { |name, pin| pin.restore }
|
519
|
+
|
520
|
+
# Placeholder, real number of loops required to implement the required timeout will be
|
521
|
+
# concatenated onto the end later once the length of the match loop is known
|
522
|
+
microcode 'SQPG MACT'
|
523
|
+
match_microcode = stage.current_bank.last
|
524
|
+
|
525
|
+
prematch_cycle_count = cycle_count
|
526
|
+
match_conditions.each(&:call)
|
527
|
+
|
528
|
+
match_loop_cycle_count = cycle_count - prematch_cycle_count
|
529
|
+
|
530
|
+
# Pad the compare vectors out to a multiple of 8 per the ADV documentation
|
531
|
+
until match_loop_cycle_count % 8 == 0
|
532
|
+
cycle
|
533
|
+
match_loop_cycle_count += 1
|
534
|
+
end
|
535
|
+
|
536
|
+
# Use 8 wait vectors by default to keep the overall number of cycles as a multiple of 8
|
537
|
+
mrpt = 8
|
538
|
+
|
539
|
+
number_of_loops = (timeout_in_cycles.to_f / (match_loop_cycle_count + mrpt)).ceil
|
540
|
+
|
541
|
+
# There seems to be a limit on the max MACT value, so account for longer times by expanding
|
414
542
|
# the wait loop
|
415
|
-
|
416
|
-
mrpt =
|
417
|
-
|
418
|
-
mrpt += (8 - (mrpt % 8)) # Keep to a multiple of 8, but round up to be safe
|
419
|
-
number_of_loops = 262_144
|
420
|
-
else
|
421
|
-
mrpt = 8
|
543
|
+
while number_of_loops > 262_144
|
544
|
+
mrpt = mrpt * 2 # Keep this as a multiple of 8
|
545
|
+
number_of_loops = (timeout_in_cycles.to_f / (match_loop_cycle_count + mrpt)).ceil
|
422
546
|
end
|
423
|
-
|
424
|
-
#
|
425
|
-
|
426
|
-
# Always do 8 vectors here as this allows reconstruction of test results if multiple loops
|
427
|
-
# are called in a pattern
|
428
|
-
8.cycles
|
429
|
-
pin.dont_care
|
547
|
+
|
548
|
+
match_microcode.concat(" #{number_of_loops};")
|
549
|
+
|
430
550
|
# Now do the wait loop, mrpt should always be a multiple of 8
|
431
551
|
microcode "SQPG MRPT #{mrpt};"
|
432
|
-
|
433
|
-
|
552
|
+
|
553
|
+
# Should be no compares in the wait cycles
|
554
|
+
dut.pins.each do |name, pin|
|
555
|
+
pin.save
|
556
|
+
pin.dont_care if pin.comparing?
|
434
557
|
end
|
558
|
+
mrpt.cycles
|
559
|
+
dut.pins.each { |name, pin| pin.restore }
|
560
|
+
|
561
|
+
# This is just used as a marker by the vector translator to indicate the end of the MRPT
|
562
|
+
# vectors, it does not end up in the final pattern binary.
|
563
|
+
# It is also used in a similar manner by Origen when generating SMT8 patterns.
|
435
564
|
microcode 'SQPG PADDING;'
|
436
|
-
8.cycles
|
437
565
|
|
566
|
+
# For multiple match conditions do something more like the J750 approach where branching based on
|
567
|
+
# miscompares is used to keep the loop going
|
438
568
|
else
|
439
|
-
|
440
|
-
# For two pins do something more like the J750 approach where branching based on miscompares is used
|
441
|
-
# to keep the loop going
|
442
|
-
cc "for the #{pin.name.upcase} pin to go #{state.to_s.upcase}"
|
443
|
-
cc "or the #{options[:pin2].name.upcase} pin to go #{options[:state2].to_s.upcase}"
|
444
|
-
|
445
569
|
if options[:check_for_fails]
|
446
570
|
cc 'Return preserving existing errors if the pattern has already failed before arriving here'
|
447
571
|
cycle(repeat: propagation_delay)
|
448
572
|
microcode 'SQPG RETC 1 1;'
|
449
573
|
end
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
options[:state2] == :low ? options[:pin2].expect_lo! : options[:pin2].expect_hi!
|
465
|
-
options[:pin2].dont_care
|
466
|
-
cc 'Wait for failure to propagate'
|
467
|
-
cycle(repeat: propagation_delay)
|
468
|
-
cc 'Exit match loop if pin has matched (no error), otherwise clear error and remain in loop'
|
469
|
-
microcode 'SQPG RETC 0 0;'
|
574
|
+
|
575
|
+
loop_microcode = ''
|
576
|
+
loop_cycles = 0
|
577
|
+
loop_vectors 2 do
|
578
|
+
loop_microcode = stage.current_bank.last
|
579
|
+
preloop_cycle_count = cycle_count
|
580
|
+
match_conditions.each do |condition|
|
581
|
+
condition.call
|
582
|
+
cc 'Wait for failure to propagate'
|
583
|
+
cycle(repeat: propagation_delay)
|
584
|
+
cc 'Exit match loop if pin has matched (no error), otherwise clear error and remain in loop'
|
585
|
+
microcode 'SQPG RETC 0 0;'
|
586
|
+
end
|
587
|
+
loop_cycles = cycle_count - preloop_cycle_count
|
470
588
|
end
|
471
589
|
|
590
|
+
number_of_loops = (timeout_in_cycles.to_f / loop_cycles).ceil
|
591
|
+
|
592
|
+
loop_microcode.sub!('2', number_of_loops.to_s)
|
593
|
+
|
472
594
|
if options[:force_fail_on_timeout]
|
473
|
-
|
474
|
-
state == :low ? pin.expect_lo : pin.expect_hi
|
475
|
-
options[:state2] == :low ? options[:pin2].expect_lo : options[:pin2].expect_hi if options[:pin2]
|
476
|
-
cycle
|
477
|
-
pin.dont_care
|
478
|
-
options[:pin2].dont_care if options[:pin2]
|
595
|
+
fail_conditions.each(&:call)
|
479
596
|
end
|
480
597
|
end
|
481
598
|
end
|
@@ -578,60 +695,6 @@ module OrigenTesters
|
|
578
695
|
@local_subroutines ||= []
|
579
696
|
end
|
580
697
|
|
581
|
-
# This is an internal method use by Origen which returns a fully formatted vector
|
582
|
-
# You can override this if you wish to change the output formatting at vector level
|
583
|
-
def format_vector(vec)
|
584
|
-
timeset = vec.timeset ? "#{vec.timeset.name}" : ''
|
585
|
-
pin_vals = vec.pin_vals ? "#{vec.pin_vals} " : ''
|
586
|
-
if vec.repeat # > 1
|
587
|
-
microcode = "R#{vec.repeat}"
|
588
|
-
else
|
589
|
-
microcode = vec.microcode ? vec.microcode : ''
|
590
|
-
end
|
591
|
-
|
592
|
-
if Origen.mode.simulation? || !inline_comments || $_testers_no_inline_comments
|
593
|
-
comment = ''
|
594
|
-
else
|
595
|
-
|
596
|
-
header_comments = []
|
597
|
-
repeat_comment = ''
|
598
|
-
vec.comments.each_with_index do |comment, i|
|
599
|
-
if comment =~ /^#/
|
600
|
-
if comment =~ /^#(R\d+)$/
|
601
|
-
repeat_comment = Regexp.last_match(1) + ' '
|
602
|
-
# Throw away the ############# headers and footers
|
603
|
-
elsif comment !~ /^# ####################/
|
604
|
-
comment = comment.strip.sub(/^# (## )?/, '')
|
605
|
-
if comment == ''
|
606
|
-
# Throw away empty lines at the start/end, but preserve them in the middle
|
607
|
-
unless header_comments.empty? || i == vec.comments.size - 1
|
608
|
-
header_comments << comment
|
609
|
-
end
|
610
|
-
else
|
611
|
-
header_comments << comment
|
612
|
-
end
|
613
|
-
end
|
614
|
-
end
|
615
|
-
end
|
616
|
-
|
617
|
-
if vec.pin_vals && ($_testers_enable_vector_comments || vector_comments)
|
618
|
-
comment = "#{vec.number}:#{vec.cycle}"
|
619
|
-
comment += ': ' if !header_comments.empty? || !vec.inline_comment.empty?
|
620
|
-
else
|
621
|
-
comment = ''
|
622
|
-
end
|
623
|
-
comment += header_comments.join("\cm") unless header_comments.empty?
|
624
|
-
unless vec.inline_comment.empty?
|
625
|
-
comment += "\cm" unless header_comments.empty?
|
626
|
-
comment += "(#{vec.inline_comment})"
|
627
|
-
end
|
628
|
-
comment = "#{repeat_comment}#{comment}"
|
629
|
-
end
|
630
|
-
|
631
|
-
# Max comment length 250 at the end
|
632
|
-
"#{microcode.ljust(25)}#{timeset.ljust(27)}#{pin_vals}# #{comment[0, 247]};"
|
633
|
-
end
|
634
|
-
|
635
698
|
# All vectors generated with the supplied block will have all pins set
|
636
699
|
# to the repeat previous state. Any pins that are changed state within
|
637
700
|
# the block will still update to the supplied value.
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'origen_testers/smartest_based_tester/base/processors/extract_flow_vars'
|
1
2
|
module OrigenTesters
|
2
3
|
module SmartestBasedTester
|
3
4
|
class Base
|
@@ -10,20 +11,67 @@ module OrigenTesters
|
|
10
11
|
|
11
12
|
attr_accessor :add_flow_enable, :flow_name, :flow_description
|
12
13
|
|
14
|
+
def self.generate_flag_name(flag)
|
15
|
+
case flag[0]
|
16
|
+
when '$'
|
17
|
+
flag[1..-1]
|
18
|
+
else
|
19
|
+
flag.upcase
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def smt8?
|
24
|
+
tester.smt8?
|
25
|
+
end
|
26
|
+
|
13
27
|
def var_filename
|
14
28
|
@var_filename || 'global'
|
15
29
|
end
|
16
30
|
|
17
31
|
def subdirectory
|
18
|
-
|
32
|
+
@subdirectory ||= begin
|
33
|
+
if smt8?
|
34
|
+
parents = []
|
35
|
+
f = parent
|
36
|
+
while f
|
37
|
+
parents.unshift(File.basename(f.filename, '.*').to_s.downcase)
|
38
|
+
f = f.parent
|
39
|
+
end
|
40
|
+
File.join tester.package_namespace, 'flows', *parents
|
41
|
+
else
|
42
|
+
'testflow/mfh.testflow.group'
|
43
|
+
end
|
44
|
+
end
|
19
45
|
end
|
20
46
|
|
21
47
|
def filename
|
22
|
-
super.gsub('_flow', '')
|
48
|
+
base = super.gsub('_flow', '')
|
49
|
+
if smt8?
|
50
|
+
flow_name(base) + '.flow'
|
51
|
+
else
|
52
|
+
base
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def flow_enable_var_name
|
57
|
+
var = filename.sub(/\..*/, '').upcase
|
58
|
+
if smt8?
|
59
|
+
'ENABLE'
|
60
|
+
else
|
61
|
+
generate_flag_name("#{var}_ENABLE")
|
62
|
+
end
|
23
63
|
end
|
24
64
|
|
25
|
-
def flow_name
|
26
|
-
@flow_name
|
65
|
+
def flow_name(filename = nil)
|
66
|
+
@flow_name_ = @flow_name unless smt8?
|
67
|
+
@flow_name_ ||= begin
|
68
|
+
flow_name = (filename || self.filename).sub(/\..*/, '').upcase
|
69
|
+
if smt8?
|
70
|
+
flow_name.gsub(' ', '_')
|
71
|
+
else
|
72
|
+
flow_name
|
73
|
+
end
|
74
|
+
end
|
27
75
|
end
|
28
76
|
|
29
77
|
def flow_description
|
@@ -34,95 +82,174 @@ module OrigenTesters
|
|
34
82
|
@hardware_bin_descriptions ||= {}
|
35
83
|
end
|
36
84
|
|
37
|
-
def
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
85
|
+
def flow_variables
|
86
|
+
@flow_variables ||= begin
|
87
|
+
vars = Processors::ExtractFlowVars.new.run(ast)
|
88
|
+
if !smt8? || (smt8? && top_level?)
|
89
|
+
if add_flow_enable
|
90
|
+
if add_flow_enable == :enabled
|
91
|
+
vars[:all][:referenced_enables] << [flow_enable_var_name, 1]
|
92
|
+
vars[:this_flow][:referenced_enables] << [flow_enable_var_name, 1]
|
93
|
+
else
|
94
|
+
vars[:all][:referenced_enables] << [flow_enable_var_name, 0]
|
95
|
+
vars[:this_flow][:referenced_enables] << [flow_enable_var_name, 0]
|
96
|
+
end
|
97
|
+
vars[:empty?] = false
|
98
|
+
end
|
99
|
+
end
|
100
|
+
vars
|
101
|
+
end
|
43
102
|
end
|
44
103
|
|
45
104
|
def at_flow_start
|
46
105
|
model # Call to ensure the signature gets populated
|
47
106
|
end
|
48
107
|
|
108
|
+
def on_top_level_set
|
109
|
+
if top_level?
|
110
|
+
if smt8?
|
111
|
+
@limits_file = platform::LimitsFile.new(self, manually_register: true, filename: filename.sub(/\..*/, ''), test_modes: @test_modes)
|
112
|
+
else
|
113
|
+
@limits_file = platform::LimitsFile.new(self, manually_register: true, filename: "#{name}_limits", test_modes: @test_modes)
|
114
|
+
end
|
115
|
+
else
|
116
|
+
@limits_file = top_level.limits_file
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def limits_file
|
121
|
+
@limits_file
|
122
|
+
end
|
123
|
+
|
49
124
|
def at_flow_end
|
50
125
|
# Take whatever the test modes are set to at the end of the flow as what we go with
|
51
126
|
@test_modes = tester.limitfile_test_modes
|
52
127
|
end
|
53
128
|
|
54
|
-
def
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
flow_control_variables << [var, 0]
|
63
|
-
end
|
64
|
-
h << " if @#{var} == 1 then"
|
65
|
-
h << ' {'
|
66
|
-
i = ' '
|
67
|
-
else
|
68
|
-
i = ''
|
129
|
+
def ast
|
130
|
+
@ast = nil unless @finalized
|
131
|
+
@ast ||= begin
|
132
|
+
unique_id = smt8? ? nil : sig
|
133
|
+
atp.ast(unique_id: unique_id, optimization: :smt,
|
134
|
+
implement_continue: !tester.force_pass_on_continue,
|
135
|
+
optimize_flags_when_continue: !tester.force_pass_on_continue
|
136
|
+
)
|
69
137
|
end
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
138
|
+
end
|
139
|
+
|
140
|
+
# Returns an array containing all sub-flow objects, not just the immediate children
|
141
|
+
def all_sub_flows
|
142
|
+
@all_sub_flows ||= begin
|
143
|
+
sub_flows = []
|
144
|
+
extract_sub_flows(self, sub_flows)
|
145
|
+
sub_flows
|
76
146
|
end
|
77
|
-
h
|
78
147
|
end
|
79
148
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
f << ' {'
|
86
|
-
f << ' }'
|
149
|
+
# @api private
|
150
|
+
def extract_sub_flows(flow, sub_flows)
|
151
|
+
flow.children.each do |id, sub_flow|
|
152
|
+
sub_flows << sub_flow
|
153
|
+
extract_sub_flows(sub_flow, sub_flows)
|
87
154
|
end
|
88
|
-
|
89
|
-
|
90
|
-
|
155
|
+
sub_flows
|
156
|
+
end
|
157
|
+
|
158
|
+
# Returns the sub_flow object corresponding to the given sub_flow AST
|
159
|
+
def sub_flow_from(sub_flow_ast)
|
160
|
+
path = sub_flow_ast.find(:path).value
|
161
|
+
sub_flow = all_sub_flows.find { |f| File.join(f.subdirectory, f.filename) == path }
|
91
162
|
end
|
92
163
|
|
164
|
+
# This is called by Origen on each flow after they have all been executed but before they
|
165
|
+
# are finally written/rendered
|
93
166
|
def finalize(options = {})
|
94
|
-
|
95
|
-
|
167
|
+
if smt8?
|
168
|
+
return unless top_level? || options[:called_by_top_level]
|
169
|
+
super
|
170
|
+
@finalized = true
|
171
|
+
# All flows have now been executed and the top-level contains the final AST.
|
172
|
+
# The AST contained in each child flow may not be complete since it has not been subject to the
|
173
|
+
# full-flow processing, e.g. to set flags in the event of a reference to a test being made from
|
174
|
+
# outside of a sub-flow.
|
175
|
+
# So here we substitute the AST in all sub-flows with the corresponding sub-flow node from the
|
176
|
+
# top-level AST, then we finalize the sub-flows with the final AST in place and then later final
|
177
|
+
# writing/rendering will be called as normal.
|
178
|
+
if top_level?
|
179
|
+
ast.find_all(:sub_flow, recursive: true).each do |sub_flow_ast|
|
180
|
+
sub_flow = sub_flow_from(sub_flow_ast)
|
181
|
+
unless sub_flow
|
182
|
+
fail "Something went wrong, couldn't find the sub-flow object for path #{path}"
|
183
|
+
end
|
184
|
+
# on_fail and on_pass nodes are removed because they will be rendered by the sub-flow's parent
|
185
|
+
sub_flow.instance_variable_set(:@ast, sub_flow_ast.remove(:on_fail, :on_pass).updated(:flow))
|
186
|
+
sub_flow.instance_variable_set(:@finalized, true) # To stop the AST being regenerated
|
187
|
+
end
|
188
|
+
options[:called_by_top_level] = true
|
189
|
+
all_sub_flows.each { |f| f.finalize(options) }
|
190
|
+
options.delete(:called_by_top_level)
|
191
|
+
end
|
192
|
+
else
|
193
|
+
super
|
194
|
+
@finalized = true
|
195
|
+
end
|
196
|
+
if smt8?
|
197
|
+
@indent = (add_flow_enable && top_level?) ? 3 : 2
|
198
|
+
else
|
199
|
+
@indent = add_flow_enable ? 2 : 1
|
200
|
+
end
|
96
201
|
@lines = []
|
202
|
+
@lines_buffer = []
|
97
203
|
@open_test_methods = []
|
204
|
+
@open_test_names = []
|
205
|
+
@post_test_lines = []
|
98
206
|
@stack = { on_fail: [], on_pass: [] }
|
99
|
-
|
100
|
-
implement_continue: !tester.force_pass_on_continue,
|
101
|
-
optimize_flags_when_continue: !tester.force_pass_on_continue
|
102
|
-
)
|
103
|
-
@set_runtime_variables = ast.set_flags
|
207
|
+
@set_runtime_variables = ast.excluding_sub_flows.set_flags
|
104
208
|
process(ast)
|
209
|
+
unless smt8?
|
210
|
+
unless flow_variables[:empty?]
|
211
|
+
Origen.interface.variables_file(self).add_variables(flow_variables)
|
212
|
+
end
|
213
|
+
end
|
105
214
|
test_suites.finalize
|
106
215
|
test_methods.finalize
|
107
|
-
|
216
|
+
if tester.create_limits_file && top_level?
|
217
|
+
render_limits_file
|
218
|
+
end
|
108
219
|
end
|
109
220
|
|
110
|
-
def render_limits_file
|
111
|
-
|
112
|
-
|
221
|
+
def render_limits_file
|
222
|
+
if limits_file
|
223
|
+
limits_file.test_modes = @test_modes
|
224
|
+
limits_file.generate(ast)
|
225
|
+
limits_file.write_to_file
|
226
|
+
end
|
113
227
|
end
|
114
228
|
|
115
|
-
def line(str)
|
116
|
-
|
229
|
+
def line(str, options = {})
|
230
|
+
if options[:already_indented]
|
231
|
+
line = str
|
232
|
+
else
|
233
|
+
if smt8?
|
234
|
+
line = (' ' * @indent) + str
|
235
|
+
else
|
236
|
+
line = ' ' + (' ' * (@indent - 1)) + str
|
237
|
+
end
|
238
|
+
end
|
239
|
+
if @lines_buffer.last
|
240
|
+
@lines_buffer.last << line
|
241
|
+
else
|
242
|
+
@lines << line
|
243
|
+
end
|
117
244
|
end
|
118
245
|
|
119
|
-
#
|
120
|
-
#
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
246
|
+
# Any calls to line made within the given block will be returned in an array, rather than
|
247
|
+
# immediately being put into the @lines array
|
248
|
+
def capture_lines
|
249
|
+
@lines_buffer << []
|
250
|
+
yield
|
251
|
+
@lines_buffer.pop
|
252
|
+
end
|
126
253
|
|
127
254
|
def on_test(node)
|
128
255
|
test_suite = node.find(:object).to_a[0]
|
@@ -139,7 +266,11 @@ module OrigenTesters
|
|
139
266
|
|
140
267
|
if node.children.any? { |n| t = n.try(:type); t == :on_fail || t == :on_pass } ||
|
141
268
|
!stack[:on_pass].empty? || !stack[:on_fail].empty?
|
142
|
-
|
269
|
+
if smt8?
|
270
|
+
line "#{name}.execute();"
|
271
|
+
else
|
272
|
+
line "run_and_branch(#{name})"
|
273
|
+
end
|
143
274
|
process_all(node.to_a.reject { |n| t = n.try(:type); t == :on_fail || t == :on_pass })
|
144
275
|
on_pass = node.find(:on_pass)
|
145
276
|
on_fail = node.find(:on_fail)
|
@@ -160,17 +291,25 @@ module OrigenTesters
|
|
160
291
|
@open_test_methods << nil
|
161
292
|
end
|
162
293
|
|
163
|
-
|
164
|
-
|
294
|
+
if smt8?
|
295
|
+
line "if (#{name}.pass) {"
|
296
|
+
else
|
297
|
+
line 'then'
|
298
|
+
line '{'
|
299
|
+
end
|
165
300
|
@indent += 1
|
166
301
|
pass_branch do
|
167
302
|
process_all(on_pass) if on_pass
|
168
303
|
stack[:on_pass].each { |n| process_all(n) }
|
169
304
|
end
|
170
305
|
@indent -= 1
|
171
|
-
|
172
|
-
|
173
|
-
|
306
|
+
if smt8?
|
307
|
+
line '} else {'
|
308
|
+
else
|
309
|
+
line '}'
|
310
|
+
line 'else'
|
311
|
+
line '{'
|
312
|
+
end
|
174
313
|
@indent += 1
|
175
314
|
fail_branch do
|
176
315
|
process_all(on_fail) if on_fail
|
@@ -181,7 +320,11 @@ module OrigenTesters
|
|
181
320
|
|
182
321
|
@open_test_methods.pop
|
183
322
|
else
|
184
|
-
|
323
|
+
if smt8?
|
324
|
+
line "#{name}.execute();"
|
325
|
+
else
|
326
|
+
line "run(#{name});"
|
327
|
+
end
|
185
328
|
end
|
186
329
|
end
|
187
330
|
|
@@ -195,16 +338,28 @@ module OrigenTesters
|
|
195
338
|
jobs, *nodes = *node
|
196
339
|
jobs = clean_job(jobs)
|
197
340
|
state = node.type == :if_job
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
341
|
+
if smt8?
|
342
|
+
if jobs.size == 1
|
343
|
+
condition = jobs.first
|
344
|
+
else
|
345
|
+
condition = jobs.map { |j| "(#{j})" }.join(' || ')
|
346
|
+
end
|
347
|
+
line "if (#{condition}) {"
|
348
|
+
else
|
349
|
+
condition = jobs.join(' or ')
|
350
|
+
line "if #{condition} then"
|
351
|
+
line '{'
|
352
|
+
end
|
202
353
|
@indent += 1
|
203
354
|
process_all(node) if state
|
204
355
|
@indent -= 1
|
205
|
-
|
206
|
-
|
207
|
-
|
356
|
+
if smt8?
|
357
|
+
line '} else {'
|
358
|
+
else
|
359
|
+
line '}'
|
360
|
+
line 'else'
|
361
|
+
line '{'
|
362
|
+
end
|
208
363
|
@indent += 1
|
209
364
|
process_all(node) unless state
|
210
365
|
@indent -= 1
|
@@ -215,13 +370,22 @@ module OrigenTesters
|
|
215
370
|
def on_condition_flag(node, state)
|
216
371
|
flag, *nodes = *node
|
217
372
|
else_node = node.find(:else)
|
218
|
-
if
|
219
|
-
|
373
|
+
if smt8?
|
374
|
+
if flag.is_a?(Array)
|
375
|
+
condition = flag.map { |f| "(#{generate_flag_name(f)} == 1)" }.join(' || ')
|
376
|
+
else
|
377
|
+
condition = "#{generate_flag_name(flag)} == 1"
|
378
|
+
end
|
379
|
+
line "if (#{condition}) {"
|
220
380
|
else
|
221
|
-
|
381
|
+
if flag.is_a?(Array)
|
382
|
+
condition = flag.map { |f| "@#{generate_flag_name(f)} == 1" }.join(' or ')
|
383
|
+
else
|
384
|
+
condition = "@#{generate_flag_name(flag)} == 1"
|
385
|
+
end
|
386
|
+
line "if #{condition} then"
|
387
|
+
line '{'
|
222
388
|
end
|
223
|
-
line "if #{condition} then"
|
224
|
-
line '{'
|
225
389
|
@indent += 1
|
226
390
|
if state
|
227
391
|
process_all(node.children - [else_node])
|
@@ -229,9 +393,13 @@ module OrigenTesters
|
|
229
393
|
process(else_node) if else_node
|
230
394
|
end
|
231
395
|
@indent -= 1
|
232
|
-
|
233
|
-
|
234
|
-
|
396
|
+
if smt8?
|
397
|
+
line '} else {'
|
398
|
+
else
|
399
|
+
line '}'
|
400
|
+
line 'else'
|
401
|
+
line '{'
|
402
|
+
end
|
235
403
|
@indent += 1
|
236
404
|
if state
|
237
405
|
process(else_node) if else_node
|
@@ -245,9 +413,6 @@ module OrigenTesters
|
|
245
413
|
def on_if_enabled(node)
|
246
414
|
flag, *nodes = *node
|
247
415
|
state = node.type == :if_enabled
|
248
|
-
[flag].flatten.each do |f|
|
249
|
-
flow_control_variables << generate_flag_name(f)
|
250
|
-
end
|
251
416
|
on_condition_flag(node, state)
|
252
417
|
end
|
253
418
|
alias_method :on_unless_enabled, :on_if_enabled
|
@@ -255,67 +420,90 @@ module OrigenTesters
|
|
255
420
|
def on_if_flag(node)
|
256
421
|
flag, *nodes = *node
|
257
422
|
state = node.type == :if_flag
|
258
|
-
[flag].flatten.each do |f|
|
259
|
-
runtime_control_variables << generate_flag_name(f)
|
260
|
-
end
|
261
423
|
on_condition_flag(node, state)
|
262
424
|
end
|
263
425
|
alias_method :on_unless_flag, :on_if_flag
|
264
426
|
|
265
427
|
def on_enable(node)
|
266
428
|
flag = node.value.upcase
|
267
|
-
|
268
|
-
|
429
|
+
if smt8?
|
430
|
+
line "#{flag} = 1;"
|
431
|
+
else
|
432
|
+
line "@#{flag} = 1;"
|
433
|
+
end
|
269
434
|
end
|
270
435
|
|
271
436
|
def on_disable(node)
|
272
437
|
flag = node.value.upcase
|
273
|
-
|
274
|
-
|
438
|
+
if smt8?
|
439
|
+
line "#{flag} = 0;"
|
440
|
+
else
|
441
|
+
line "@#{flag} = 0;"
|
442
|
+
end
|
275
443
|
end
|
276
444
|
|
277
445
|
def on_set_flag(node)
|
278
446
|
flag = generate_flag_name(node.value)
|
279
|
-
|
447
|
+
# This means if we are currently generating an on_test node and tester.force_pass_on_continue has been set
|
280
448
|
if @open_test_methods.last
|
281
449
|
if pass_branch?
|
282
|
-
if
|
283
|
-
|
284
|
-
|
450
|
+
if smt8?
|
451
|
+
@post_test_lines.last << "#{flag} = #{@open_test_names.last}.setOnPassFlags;"
|
452
|
+
else
|
453
|
+
if @open_test_methods.last.respond_to?(:on_pass_flag)
|
454
|
+
if @open_test_methods.last.on_pass_flag == ''
|
455
|
+
@open_test_methods.last.on_pass_flag = flag
|
456
|
+
else
|
457
|
+
Origen.log.error "The test method cannot set #{flag} on passing, because it already sets: #{@open_test_methods.last.on_pass_flag}"
|
458
|
+
Origen.log.error " #{node.source}"
|
459
|
+
exit 1
|
460
|
+
end
|
285
461
|
else
|
286
|
-
Origen.log.error
|
462
|
+
Origen.log.error 'Force pass on continue has been requested, but the test method does not have an :on_pass_flag attribute:'
|
287
463
|
Origen.log.error " #{node.source}"
|
288
464
|
exit 1
|
289
465
|
end
|
290
|
-
else
|
291
|
-
Origen.log.error 'Force pass on continue has been requested, but the test method does not have an :on_pass_flag attribute:'
|
292
|
-
Origen.log.error " #{node.source}"
|
293
|
-
exit 1
|
294
466
|
end
|
295
467
|
else
|
296
|
-
if
|
297
|
-
|
298
|
-
|
468
|
+
if smt8?
|
469
|
+
@post_test_lines.last << "#{flag} = #{@open_test_names.last}.setOnFailFlags;"
|
470
|
+
else
|
471
|
+
if @open_test_methods.last.respond_to?(:on_fail_flag)
|
472
|
+
if @open_test_methods.last.on_fail_flag == ''
|
473
|
+
@open_test_methods.last.on_fail_flag = flag
|
474
|
+
else
|
475
|
+
Origen.log.error "The test method cannot set #{flag} on failing, because it already sets: #{@open_test_methods.last.on_fail_flag}"
|
476
|
+
Origen.log.error " #{node.source}"
|
477
|
+
exit 1
|
478
|
+
end
|
299
479
|
else
|
300
|
-
Origen.log.error
|
480
|
+
Origen.log.error 'Force pass on continue has been requested, but the test method does not have an :on_fail_flag attribute:'
|
301
481
|
Origen.log.error " #{node.source}"
|
302
482
|
exit 1
|
303
483
|
end
|
304
|
-
else
|
305
|
-
Origen.log.error 'Force pass on continue has been requested, but the test method does not have an :on_fail_flag attribute:'
|
306
|
-
Origen.log.error " #{node.source}"
|
307
|
-
exit 1
|
308
484
|
end
|
309
485
|
end
|
310
486
|
else
|
311
|
-
|
487
|
+
if smt8?
|
488
|
+
line "#{flag} = 1;"
|
489
|
+
else
|
490
|
+
line "@#{flag} = 1;"
|
491
|
+
end
|
312
492
|
end
|
313
493
|
end
|
314
494
|
|
495
|
+
# Note that for smt8?, this should never be hit anymore since groups are now generated as sub-flows
|
315
496
|
def on_group(node)
|
316
497
|
on_fail = node.children.find { |n| n.try(:type) == :on_fail }
|
317
498
|
on_pass = node.children.find { |n| n.try(:type) == :on_pass }
|
318
|
-
|
499
|
+
group_name = unique_group_name(node.find(:name).value)
|
500
|
+
if smt8?
|
501
|
+
line '// *******************************************************'
|
502
|
+
line "// GROUP - #{group_name}"
|
503
|
+
line '// *******************************************************'
|
504
|
+
else
|
505
|
+
line '{'
|
506
|
+
end
|
319
507
|
@indent += 1
|
320
508
|
stack[:on_fail] << on_fail if on_fail
|
321
509
|
stack[:on_pass] << on_pass if on_pass
|
@@ -323,7 +511,13 @@ module OrigenTesters
|
|
323
511
|
stack[:on_fail].pop if on_fail
|
324
512
|
stack[:on_pass].pop if on_pass
|
325
513
|
@indent -= 1
|
326
|
-
|
514
|
+
if smt8?
|
515
|
+
line '// *******************************************************'
|
516
|
+
line "// /GROUP - #{group_name}"
|
517
|
+
line '// *******************************************************'
|
518
|
+
else
|
519
|
+
line "}, open,\"#{group_name}\", \"\""
|
520
|
+
end
|
327
521
|
end
|
328
522
|
|
329
523
|
def on_set_result(node)
|
@@ -336,19 +530,31 @@ module OrigenTesters
|
|
336
530
|
hardware_bin_descriptions[bin] ||= desc
|
337
531
|
end
|
338
532
|
|
339
|
-
if
|
340
|
-
|
533
|
+
if smt8?
|
534
|
+
# Currently only rendering pass bins or those not associated with a test (should come from the bin
|
535
|
+
# table if its associated with a test)
|
536
|
+
if node.to_a[0] == 'pass' || @open_test_methods.empty?
|
537
|
+
line "addBin(#{sbin || bin});"
|
538
|
+
end
|
341
539
|
else
|
342
|
-
if
|
343
|
-
line
|
540
|
+
if node.to_a[0] == 'pass'
|
541
|
+
line "stop_bin \"#{sbin}\", \"\", , good, noreprobe, green, #{bin}, over_on;"
|
344
542
|
else
|
345
|
-
|
543
|
+
if tester.create_limits_file
|
544
|
+
line 'multi_bin;'
|
545
|
+
else
|
546
|
+
line "stop_bin \"#{sbin}\", \"#{sdesc}\", , bad, noreprobe, red, #{bin}, #{overon};"
|
547
|
+
end
|
346
548
|
end
|
347
549
|
end
|
348
550
|
end
|
349
551
|
|
350
552
|
def on_log(node)
|
351
|
-
|
553
|
+
if smt8?
|
554
|
+
line "println(\"#{node.to_a[0]}\");"
|
555
|
+
else
|
556
|
+
line "print_dl(\"#{node.to_a[0]}\");"
|
557
|
+
end
|
352
558
|
end
|
353
559
|
|
354
560
|
def unique_group_name(name)
|
@@ -363,7 +569,8 @@ module OrigenTesters
|
|
363
569
|
end
|
364
570
|
|
365
571
|
def clean_job(job)
|
366
|
-
|
572
|
+
var = smt8? ? 'JOB' : '@JOB'
|
573
|
+
[job].flatten.map { |j| "#{var} == \"#{j.to_s.upcase}\"" }
|
367
574
|
end
|
368
575
|
|
369
576
|
private
|
@@ -393,12 +600,7 @@ module OrigenTesters
|
|
393
600
|
end
|
394
601
|
|
395
602
|
def generate_flag_name(flag)
|
396
|
-
|
397
|
-
when '$'
|
398
|
-
flag[1..-1]
|
399
|
-
else
|
400
|
-
flag.upcase
|
401
|
-
end
|
603
|
+
self.class.generate_flag_name(flag)
|
402
604
|
end
|
403
605
|
end
|
404
606
|
end
|