origen_testers 0.31.0 → 0.40.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|