origen 0.43.0 → 0.44.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 50ff914ed84d58eef72d7c1eee3919a420d0a4af50bd9fe01fbf4c79f334578b
4
- data.tar.gz: b51d183c27e9cb027f520a21f7bae2f8a21cd41d1158dfc8ec41feecb55409fd
3
+ metadata.gz: 9a8903e336caa8b0e7747f54f298178408b848f4203bfaccb4c7c2506c1df6c3
4
+ data.tar.gz: f3e398328927876c9ad9d7d46b04594f8ca7f33915be9b0d7956f0d86343c743
5
5
  SHA512:
6
- metadata.gz: 8b227567f13516ee3cb2aeef1ea5b423febcfb3cfe2443f61a0e79857032cd301df77753cede06d88bd2ce2d1eea9720b48e60fb3b235946cf1121ede63f3f22
7
- data.tar.gz: ef83425ec57f409158281bd045c9847dc5b97cbed7a89e99feb18a7037581309cfd7f7e3ae846e2b5626991f07cb310ade1cf4c2ce479337e38b80db576d6921
6
+ metadata.gz: fc638f7063bc0fa0ae993532d19360ed6d3191710d41d4cda3f31c72f86a165ac90854b4305335d49e64f67b2941bad5a456ebbf00e740238c8e1c3b6ef635e4
7
+ data.tar.gz: 8094048eb20dc9c3319fc5c5f629ba40a0c928915cf3c21ad3174119f2bad267fddcf9e4c2880d91abd1f3316bedaa963a60e6c2dec53a3c4bba3c52f681da8d
@@ -6,3 +6,5 @@ require "c99/ate_interface"
6
6
  require_relative "../lib/c99/nvm"
7
7
 
8
8
  require_relative "../helpers/guides"
9
+
10
+ require "#{Origen.root(:origen_sim)}/config/boot"
@@ -1,6 +1,6 @@
1
1
  module Origen
2
2
  MAJOR = 0
3
- MINOR = 43
3
+ MINOR = 44
4
4
  BUGFIX = 0
5
5
  DEV = nil
6
6
 
@@ -30,6 +30,8 @@ unless defined? RGen::ORIGENTRANSITION
30
30
  require 'origen/undefined'
31
31
  require 'origen/componentable'
32
32
 
33
+ autoload :PatSeq, 'origen/generator/pattern_sequencer'
34
+
33
35
  module Origen
34
36
  autoload :Features, 'origen/features'
35
37
  autoload :Bugs, 'origen/bugs'
@@ -75,17 +77,14 @@ unless defined? RGen::ORIGENTRANSITION
75
77
 
76
78
  APP_CONFIG = File.join('config', 'application.rb')
77
79
 
78
- class OrigenError < StandardError
79
- def self.status_code(code)
80
- define_method(:status_code) { code }
81
- end
82
- end
83
-
84
- class PerforceError < OrigenError; status_code(11); end
85
- class GitError < OrigenError; status_code(11); end
86
- class DesignSyncError < OrigenError; status_code(12); end
87
- class RevisionControlUninitializedError < OrigenError; status_code(13); end
88
- class SyntaxError < OrigenError; status_code(14); end
80
+ class OrigenError < StandardError; end
81
+ class PerforceError < OrigenError; end
82
+ class GitError < OrigenError; end
83
+ class DesignSyncError < OrigenError; end
84
+ class RevisionControlUninitializedError < OrigenError; end
85
+ class SyntaxError < OrigenError; end
86
+ class BinStrValError < OrigenError; end
87
+ class HexStrValError < OrigenError; end
89
88
 
90
89
  class << self
91
90
  include Origen::Utility::TimeAndDate
@@ -84,23 +84,29 @@ module Origen
84
84
  Origen.app.listeners_for(:program_generated).each(&:program_generated)
85
85
  else
86
86
  temporary_plugin_from_options = options[:current_plugin]
87
- expand_lists_and_directories(options[:files], options).each do |file|
88
- if temporary_plugin_from_options
89
- Origen.app.plugins.temporary = temporary_plugin_from_options
90
- end
91
- case options[:action]
92
- when :compile
93
- Origen.generator.compile_file_or_directory(file, options)
94
- when :merge
95
- Origen.generator.merge_file_or_directory(file, options)
96
- when :import_test_time
97
- Origen.time.import_test_time(file, options)
98
- when :import_test_flow
99
- Origen.time.import_test_flow(file, options)
100
- else
101
- Origen.generator.generate_pattern(file, options)
102
- end
87
+ if options[:action] == :pattern && options[:sequence]
88
+ patterns = expand_lists_and_directories(options[:files], options.merge(preserve_duplicates: true))
89
+ Origen.generator.generate_pattern(patterns, options)
103
90
  Origen.app.plugins.temporary = nil if temporary_plugin_from_options
91
+ else
92
+ expand_lists_and_directories(options[:files], options).each do |file|
93
+ if temporary_plugin_from_options
94
+ Origen.app.plugins.temporary = temporary_plugin_from_options
95
+ end
96
+ case options[:action]
97
+ when :compile
98
+ Origen.generator.compile_file_or_directory(file, options)
99
+ when :merge
100
+ Origen.generator.merge_file_or_directory(file, options)
101
+ when :import_test_time
102
+ Origen.time.import_test_time(file, options)
103
+ when :import_test_flow
104
+ Origen.time.import_test_flow(file, options)
105
+ else
106
+ Origen.generator.generate_pattern(file, options)
107
+ end
108
+ Origen.app.plugins.temporary = nil if temporary_plugin_from_options
109
+ end
104
110
  end
105
111
  end
106
112
  end
@@ -21,6 +21,7 @@ opt_parser = OptionParser.new do |opts|
21
21
  opts.on('--doc', 'Generate into doc format') { options[:doc] = true }
22
22
  opts.on('--html', 'Generate into html format') { options[:html] = true }
23
23
  opts.on('--nocom', 'No comments in the generated pattern') { options[:no_comments] = true }
24
+ opts.on('-seq', '--sequence NAME', String, 'Generate multiple patterns into a single concurrent pattern sequence') { |o| options[:sequence] = o }
24
25
  opts.on('-d', '--debugger', 'Enable the debugger') { options[:debugger] = true }
25
26
  opts.on('-m', '--mode MODE', Origen::Mode::MODES, 'Force the Origen operating mode:', ' ' + Origen::Mode::MODES.join(', ')) { |_m| }
26
27
  # Apply any application option extensions to the OptionParser
@@ -1,15 +1,18 @@
1
1
  module Origen
2
2
  class Generator
3
- autoload :Pattern, 'origen/generator/pattern'
4
- autoload :Flow, 'origen/generator/flow'
5
- autoload :Resources, 'origen/generator/resources'
6
- autoload :Job, 'origen/generator/job'
7
- autoload :PatternFinder, 'origen/generator/pattern_finder'
8
- autoload :PatternIterator, 'origen/generator/pattern_iterator'
9
- autoload :Stage, 'origen/generator/stage'
10
- autoload :Compiler, 'origen/generator/compiler'
11
- autoload :Comparator, 'origen/generator/comparator'
12
- autoload :Renderer, 'origen/generator/renderer'
3
+ autoload :Pattern, 'origen/generator/pattern'
4
+ autoload :Flow, 'origen/generator/flow'
5
+ autoload :Resources, 'origen/generator/resources'
6
+ autoload :Job, 'origen/generator/job'
7
+ autoload :PatternFinder, 'origen/generator/pattern_finder'
8
+ autoload :PatternIterator, 'origen/generator/pattern_iterator'
9
+ autoload :PatternSequencer, 'origen/generator/pattern_sequencer'
10
+ autoload :PatternSequence, 'origen/generator/pattern_sequence'
11
+ autoload :PatternThread, 'origen/generator/pattern_thread'
12
+ autoload :Stage, 'origen/generator/stage'
13
+ autoload :Compiler, 'origen/generator/compiler'
14
+ autoload :Comparator, 'origen/generator/comparator'
15
+ autoload :Renderer, 'origen/generator/renderer'
13
16
 
14
17
  class AbortError < StandardError; end
15
18
 
@@ -30,6 +33,10 @@ module Origen
30
33
  end
31
34
 
32
35
  def generate_pattern(file, options)
36
+ if options[:sequence]
37
+ options[:patterns] = file
38
+ file = options[:sequence]
39
+ end
33
40
  Job.new(file, options).run
34
41
  end
35
42
 
@@ -156,12 +156,36 @@ module Origen
156
156
  skip ||= !listener.before_pattern_lookup(@requested_pattern)
157
157
  end
158
158
  unless skip
159
- @pattern = Origen.generator.pattern_finder.find(@requested_pattern, @options)
160
- if @pattern.is_a?(Hash)
161
- @output_file_body = @pattern[:output]
162
- @pattern = @pattern[:pattern]
159
+ if @options[:sequence]
160
+ @pattern = @requested_pattern
161
+ Origen.pattern.sequence do |seq|
162
+ # This splits the pattern name by "_" then removes all values that are common to all patterns
163
+ # and then rejoins what is left.
164
+ # The goal is to keep the thread ID concise for the log and rather than using the whole pattern
165
+ # name only focussing on what is different.
166
+ # e.g. if you combined patterns flash_read_ckbd_ip1_max.rb and flash_read_ckbd_ip2_max.rb into
167
+ # a concurrent sequence then the two threads would be called 'ip1' and 'ip2'.
168
+ ids = @options[:patterns].map do |pat|
169
+ Pathname.new(pat).basename('.*').to_s.split('_')
170
+ end
171
+ ids = ids.map { |id| id.reject { |i| ids.all? { |id| id.include?(i) } }.join('_') }
172
+
173
+ @options[:patterns].each_with_index do |pat, i|
174
+ id = ids[i]
175
+ id = i.to_s if id.empty?
176
+ seq.in_parallel id do
177
+ seq.run pat
178
+ end
179
+ end
180
+ end
181
+ else
182
+ @pattern = Origen.generator.pattern_finder.find(@requested_pattern, @options)
183
+ if @pattern.is_a?(Hash)
184
+ @output_file_body = @pattern[:output]
185
+ @pattern = @pattern[:pattern]
186
+ end
187
+ load @pattern unless @pattern == :skip # Run the pattern
163
188
  end
164
- load @pattern unless @pattern == :skip # Run the pattern
165
189
  end
166
190
  end
167
191
  rescue Exception => e
@@ -59,96 +59,144 @@ module Origen
59
59
  pattern_close(options)
60
60
  end
61
61
 
62
- def create(options = {})
62
+ def sequence(options = {}, &block)
63
63
  @create_options = options
64
64
  unless Origen.tester
65
65
  puts 'The current target has not instantiated a tester and pattern generation cannot run.'
66
- puts 'Add something like this to your target file:'
67
- puts ''
68
- puts ' $tester = OrigenTesters::J750.new'
69
- puts ''
66
+ puts 'Add something like this to an environment file:'
67
+ puts
68
+ puts ' Origen::Tester::J750.new'
69
+ puts
70
+ puts
71
+ puts 'Then select it by running: origen e <environment name>'
70
72
  exit 1
71
73
  end
72
74
  Origen.tester.generating = :pattern
73
75
 
74
76
  job.output_file_body = options.delete(:name).to_s if options[:name]
75
77
 
76
- # Order the iterators by the order that their enable keys appear in the options, pad
77
- # any missing iterators with a dummy function...
78
- iterators = options.map do |key, _val|
79
- Origen.app.pattern_iterators.find { |iterator| iterator.key == key }
80
- end.compact
81
- iterators << DummyIterator.new while iterators.size < 10
82
-
83
- args = []
84
-
85
- # Couldn't get this to work fully dynamically, so hard-coded for 10 custom
86
- # iterators for now, should be plenty for any application in the meantime.
87
- # Should revisit this when time allows and remove this limitation by changing
88
- # this to a recursive structure.
89
- iterators[0].invoke(options) do |arg0|
90
- args[0] = arg0
91
- iterators[1].invoke(options) do |arg1|
92
- args[1] = arg1
93
- iterators[2].invoke(options) do |arg2|
94
- args[2] = arg2
95
- iterators[3].invoke(options) do |arg3|
96
- args[3] = arg3
97
- iterators[4].invoke(options) do |arg4|
98
- args[4] = arg4
99
- iterators[5].invoke(options) do |arg5|
100
- args[5] = arg5
101
- iterators[6].invoke(options) do |arg6|
102
- args[6] = arg6
103
- iterators[7].invoke(options) do |arg7|
104
- args[7] = arg7
105
- iterators[8].invoke(options) do |arg8|
106
- args[8] = arg8
107
- iterators[9].invoke(options) do |arg9|
108
- args[9] = arg9
109
- # Refresh the target to start all settings from scratch each time
110
- # This is an easy way to reset all registered values
111
- Origen.app.reload_target!(skip_first_time: true)
112
-
113
- # Final call back to the project to allow it to make any pattern name specific
114
- # configuration changes
115
- Origen.app.listeners_for(:before_pattern).each do |listener|
116
- listener.before_pattern(job.output_pattern_filename)
117
- end
78
+ # Refresh the target to start all settings from scratch each time
79
+ # This is an easy way to reset all registered values
80
+ Origen.app.reload_target!(skip_first_time: true)
118
81
 
119
- # Work out the final pattern name based on the current iteration
120
- job.reset_output_pattern_filename
121
- iterators.each_with_index do |iterator, i|
122
- if iterator.enabled?(options)
123
- job.output_pattern_filename =
124
- iterator.pattern_name.call(job.output_pattern_filename, args[i])
125
- end
126
- end
82
+ # Final call back to the project to allow it to make any pattern name specific
83
+ # configuration changes
84
+ Origen.app.listeners_for(:before_pattern).each do |listener|
85
+ listener.before_pattern(job.output_pattern_filename)
86
+ end
127
87
 
128
- # Allow custom pattern prefix
129
- unless options[:pat_prefix].to_s.empty?
130
- if job.output_prefix.empty?
131
- job.output_pattern_filename = "#{options[:pat_prefix]}_" + job.output_pattern_filename
132
- else
133
- job.output_pattern_filename = job.output_pattern_filename.sub(job.output_prefix, job.output_prefix + "#{options[:pat_prefix]}_")
134
- end
135
- end
88
+ ## Allow custom pattern postfix
89
+ # unless options[:pat_postfix].to_s.empty?
90
+ # job.output_pattern_filename = job.output_pattern_filename.sub(job.output_postfix + job.output_extension, "_#{options[:pat_postfix]}" + job.output_postfix + job.output_extension)
91
+ # end
92
+
93
+ @pattern_sequence = true
94
+ pattern_wrapper([], [], options) do
95
+ PatternSequencer.send(:active=, true)
96
+ @pattern_sequence = PatternSequence.new(job.output_pattern_filename, block)
97
+ @pattern_sequence.send(:execute)
98
+ PatternSequencer.send(:active=, false)
99
+ end
100
+ @pattern_sequence = false
101
+ @create_options = nil
102
+ end
136
103
 
137
- # Allow custom pattern postfix
138
- unless options[:pat_postfix].to_s.empty?
139
- job.output_pattern_filename = job.output_pattern_filename.sub(job.output_postfix + job.output_extension, "_#{options[:pat_postfix]}" + job.output_postfix + job.output_extension)
140
- end
104
+ def create(options = {})
105
+ if @pattern_sequence
106
+ yield
107
+ else
108
+ @create_options = options
109
+ unless Origen.tester
110
+ puts 'The current target has not instantiated a tester and pattern generation cannot run.'
111
+ puts 'Add something like this to an environment file:'
112
+ puts
113
+ puts ' Origen::Tester::J750.new'
114
+ puts
115
+ puts
116
+ puts 'Then select it by running: origen e <environment name>'
117
+ exit 1
118
+ end
119
+ Origen.tester.generating = :pattern
120
+
121
+ job.output_file_body = options.delete(:name).to_s if options[:name]
141
122
 
142
- pattern_wrapper(iterators, args, options) do
143
- # Call iterator setups, whatever these return are passed to the pattern
144
- yield_items = []
123
+ # Order the iterators by the order that their enable keys appear in the options, pad
124
+ # any missing iterators with a dummy function...
125
+ iterators = options.map do |key, _val|
126
+ Origen.app.pattern_iterators.find { |iterator| iterator.key == key }
127
+ end.compact
128
+ iterators << DummyIterator.new while iterators.size < 10
129
+
130
+ args = []
131
+
132
+ # Couldn't get this to work fully dynamically, so hard-coded for 10 custom
133
+ # iterators for now, should be plenty for any application in the meantime.
134
+ # Should revisit this when time allows and remove this limitation by changing
135
+ # this to a recursive structure.
136
+ iterators[0].invoke(options) do |arg0|
137
+ args[0] = arg0
138
+ iterators[1].invoke(options) do |arg1|
139
+ args[1] = arg1
140
+ iterators[2].invoke(options) do |arg2|
141
+ args[2] = arg2
142
+ iterators[3].invoke(options) do |arg3|
143
+ args[3] = arg3
144
+ iterators[4].invoke(options) do |arg4|
145
+ args[4] = arg4
146
+ iterators[5].invoke(options) do |arg5|
147
+ args[5] = arg5
148
+ iterators[6].invoke(options) do |arg6|
149
+ args[6] = arg6
150
+ iterators[7].invoke(options) do |arg7|
151
+ args[7] = arg7
152
+ iterators[8].invoke(options) do |arg8|
153
+ args[8] = arg8
154
+ iterators[9].invoke(options) do |arg9|
155
+ args[9] = arg9
156
+ # Refresh the target to start all settings from scratch each time
157
+ # This is an easy way to reset all registered values
158
+ Origen.app.reload_target!(skip_first_time: true)
159
+
160
+ # Final call back to the project to allow it to make any pattern name specific
161
+ # configuration changes
162
+ Origen.app.listeners_for(:before_pattern).each do |listener|
163
+ listener.before_pattern(job.output_pattern_filename)
164
+ end
165
+
166
+ # Work out the final pattern name based on the current iteration
167
+ job.reset_output_pattern_filename
145
168
  iterators.each_with_index do |iterator, i|
146
169
  if iterator.enabled?(options)
147
- yield_items << iterator.setup.call(args[i])
170
+ job.output_pattern_filename =
171
+ iterator.pattern_name.call(job.output_pattern_filename, args[i])
172
+ end
173
+ end
174
+
175
+ # Allow custom pattern prefix
176
+ unless options[:pat_prefix].to_s.empty?
177
+ if job.output_prefix.empty?
178
+ job.output_pattern_filename = "#{options[:pat_prefix]}_" + job.output_pattern_filename
179
+ else
180
+ job.output_pattern_filename = job.output_pattern_filename.sub(job.output_prefix, job.output_prefix + "#{options[:pat_prefix]}_")
148
181
  end
149
182
  end
150
183
 
151
- yield(*yield_items)
184
+ # Allow custom pattern postfix
185
+ unless options[:pat_postfix].to_s.empty?
186
+ job.output_pattern_filename = job.output_pattern_filename.sub(job.output_postfix + job.output_extension, "_#{options[:pat_postfix]}" + job.output_postfix + job.output_extension)
187
+ end
188
+
189
+ pattern_wrapper(iterators, args, options) do
190
+ # Call iterator setups, whatever these return are passed to the pattern
191
+ yield_items = []
192
+ iterators.each_with_index do |iterator, i|
193
+ if iterator.enabled?(options)
194
+ yield_items << iterator.setup.call(args[i])
195
+ end
196
+ end
197
+
198
+ yield(*yield_items)
199
+ end
152
200
  end
153
201
  end
154
202
  end
@@ -473,6 +521,9 @@ module Origen
473
521
  log.info '----------------------------------------------------------------------'
474
522
  check_for_changes(job.output_pattern, job.reference_pattern) unless tester.try(:disable_pattern_diffs)
475
523
  end
524
+ if @pattern_sequence
525
+ @pattern_sequence.send(:log_execution_profile)
526
+ end
476
527
  stats.record_pattern_completion(job.output_pattern)
477
528
  end
478
529
 
@@ -0,0 +1,201 @@
1
+ require 'io/console'
2
+
3
+ module Origen
4
+ class Generator
5
+ # Manages a single pattern sequence, i.e. an instance of PatternSequence is
6
+ # created for every Pattern.sequence do ... end block
7
+ class PatternSequence
8
+ def initialize(name, block)
9
+ @number_of_threads = 1
10
+ @name = name
11
+ @running_thread_ids = { main: true }
12
+ # The contents of the main Pattern.sequence block will be executed as a thread and treated
13
+ # like any other parallel block
14
+ thread = PatternThread.new(:main, self, block, true)
15
+ threads << thread
16
+ active_threads << thread
17
+ end
18
+
19
+ # Execute the given pattern
20
+ def run(pattern_name)
21
+ pattern = Origen.generator.pattern_finder.find(pattern_name.to_s, {})
22
+ pattern = pattern[:pattern] if pattern.is_a?(Hash)
23
+ load pattern
24
+ end
25
+ alias_method :call, :run
26
+
27
+ # Execute the given block in a new concurrent thread
28
+ def thread(id = nil, &block)
29
+ @number_of_threads += 1
30
+ id ||= "thread#{@number_of_threads}".to_sym
31
+ # Just stage the request for now, it will be started at the end of the current execute loop
32
+ @parallel_blocks_waiting_to_start ||= []
33
+ @parallel_blocks_waiting_to_start << [id, block]
34
+ @running_thread_ids[id] = true
35
+ end
36
+ alias_method :in_parallel, :thread
37
+
38
+ def wait_for_threads(*ids)
39
+ completed = false
40
+ blocked = false
41
+ ids = ids.map(&:to_sym)
42
+ all = ids.empty? || ids.include?(:all)
43
+ until completed
44
+ if all
45
+ limit = current_thread.id == :main ? 1 : 2
46
+ if @running_thread_ids.size > limit
47
+ current_thread.waiting_for_thread(blocked)
48
+ blocked = true
49
+ else
50
+ current_thread.record_active if blocked
51
+ completed = true
52
+ end
53
+ else
54
+ if ids.any? { |id| @running_thread_ids[id] }
55
+ current_thread.waiting_for_thread(blocked)
56
+ blocked = true
57
+ else
58
+ current_thread.record_active if blocked
59
+ completed = true
60
+ end
61
+ end
62
+ end
63
+ end
64
+ alias_method :wait_for_thread, :wait_for_threads
65
+
66
+ private
67
+
68
+ def thread_running?(id)
69
+ @running_thread_ids[id]
70
+ end
71
+
72
+ def current_thread
73
+ PatSeq.thread
74
+ end
75
+
76
+ def log_execution_profile
77
+ if threads.size > 1
78
+ thread_id_size = threads.map { |t| t.id.to_s.size }.max
79
+ line_size = IO.console.winsize[1] - 35 - thread_id_size
80
+ line_size -= 16 if tester.try(:sim?)
81
+ cycles_per_tick = (@cycle_count_stop / (line_size * 1.0)).ceil
82
+ if tester.try(:sim?)
83
+ execution_time = tester.execution_time_in_ns / 1_000_000_000.0
84
+ else
85
+ execution_time = Origen.app.stats.execution_time_for(Origen.app.current_job.output_pattern)
86
+ end
87
+ Origen.log.info ''
88
+ tick_time = execution_time / line_size
89
+
90
+ Origen.log.info "Concurrent execution profile (#{pretty_time(tick_time)}/increment):"
91
+ Origen.log.info
92
+
93
+ number_of_ticks = @cycle_count_stop / cycles_per_tick
94
+
95
+ ticks_per_step = 0
96
+ step_size = 0.1.us
97
+
98
+ while ticks_per_step < 10
99
+ step_size = step_size * 10
100
+ ticks_per_step = step_size / tick_time
101
+ end
102
+
103
+ ticks_per_step = ticks_per_step.ceil
104
+ step_size = tick_time * ticks_per_step
105
+
106
+ if tester.try(:sim?)
107
+ padding = '.' + (' ' * (thread_id_size + 1))
108
+ else
109
+ padding = ' ' * (thread_id_size + 2)
110
+ end
111
+ scale_step = '|' + ('-' * (ticks_per_step - 1))
112
+ number_of_steps = (number_of_ticks / ticks_per_step) + 1
113
+ scale = scale_step * number_of_steps
114
+ scale = scale[0, number_of_ticks]
115
+ Origen.log.info padding + scale
116
+
117
+ scale = ''
118
+ number_of_steps.times do |i|
119
+ scale += pretty_time(i * step_size, 1).ljust(ticks_per_step)
120
+ end
121
+ scale = scale[0, number_of_ticks]
122
+ Origen.log.info padding + scale
123
+
124
+ threads.each do |thread|
125
+ line = thread.execution_profile(0, @cycle_count_stop, cycles_per_tick)
126
+ Origen.log.info ''
127
+ Origen.log.info "#{thread.id}: ".ljust(thread_id_size + 2) + line
128
+ end
129
+ Origen.log.info ''
130
+ end
131
+ end
132
+
133
+ def pretty_time(time, number_decimal_places = 0)
134
+ return '0' if time == 0
135
+ if time < 1.us
136
+ "%.#{number_decimal_places}fns" % (time * 1_000_000_000)
137
+ elsif time < 1.ms
138
+ "%.#{number_decimal_places}fus" % (time * 1_000_000)
139
+ elsif time < 1.s
140
+ "%.#{number_decimal_places}fms" % (time * 1_000)
141
+ else
142
+ "%.#{number_decimal_places}fs" % tick_time
143
+ end
144
+ end
145
+
146
+ def thread_completed(thread)
147
+ @running_thread_ids.delete(thread.id)
148
+ active_threads.delete(thread)
149
+ end
150
+
151
+ def threads
152
+ @threads ||= []
153
+ end
154
+
155
+ def active_threads
156
+ @active_threads ||= []
157
+ end
158
+
159
+ def threads_waiting_to_start?
160
+ @parallel_blocks_waiting_to_start
161
+ end
162
+
163
+ def execute
164
+ active_threads.first.start
165
+ until active_threads.empty?
166
+ # Advance all threads to their next cycle point in sequential order. Keeping tight control of
167
+ # when threads are running in this way ensures that the output is deterministic no matter what
168
+ # computer it is running on, and ensures that the application code does not have to worry about
169
+ # race conditions.
170
+ cycs = active_threads.map do |t|
171
+ t.advance
172
+ t.pending_cycles
173
+ end.compact.min
174
+
175
+ if cycs
176
+ # Now generate the required number of cycles which is defined by the thread that has the least
177
+ # amount of cycles ready to go.
178
+ # Since tester.cycle is being called by the master process here it will generate as normal (as
179
+ # opposed to when called from a thread in which case it causes the thread to wait).
180
+ cycs.cycles
181
+
182
+ # Now let each thread know how many cycles we just generated, so they can decide whether they
183
+ # need to wait for more cycles or if they can start preparing the next one
184
+ active_threads.each { |t| t.executed_cycles(cycs) }
185
+ end
186
+
187
+ if @parallel_blocks_waiting_to_start
188
+ @parallel_blocks_waiting_to_start.each do |id, block|
189
+ thread = PatternThread.new(id, self, block)
190
+ threads << thread
191
+ active_threads << thread
192
+ thread.start
193
+ end
194
+ @parallel_blocks_waiting_to_start = nil
195
+ end
196
+ end
197
+ @cycle_count_stop = threads.first.current_cycle_count
198
+ end
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,99 @@
1
+ require 'concurrent'
2
+ module Origen
3
+ class Generator
4
+ # Provides APIs to enable applications to support concurrency
5
+ class PatternSequencer
6
+ class << self
7
+ def serialize(id = nil)
8
+ if active?
9
+ s = nil
10
+ id ||= caller[0]
11
+ @semaphores ||= {}
12
+ @semaphores[id] ||= Concurrent::Semaphore.new(1)
13
+ s = @semaphores[id]
14
+ completed = false
15
+ blocked = false
16
+ until completed
17
+ # If already acquired or available
18
+ if (thread.reservations[id] && thread.reservations[id][:semaphore]) || s.try_acquire
19
+ thread.record_active if blocked
20
+ yield
21
+ completed = true
22
+ else
23
+ thread.waiting_for_serialize(id, blocked)
24
+ blocked = true
25
+ end
26
+ end
27
+ # If the thread has reserved access to this serialized resource then don't release it now, but
28
+ # store a reference to the semaphore and it will be released at the end of the reserve block
29
+ if thread.reservations[id]
30
+ thread.reservations[id][:semaphore] = s
31
+ else
32
+ s.release
33
+ end
34
+ else
35
+ yield
36
+ end
37
+ end
38
+
39
+ # Once a lock is acquired on a serialize block with the given ID, it won't be released to
40
+ # other parallel threads until the end of this block
41
+ def reserve(id)
42
+ if active?
43
+ if thread.reservations[id]
44
+ thread.reservations[id][:count] += 1
45
+ else
46
+ thread.reservations[id] = { count: 1, semaphore: nil }
47
+ end
48
+ yield
49
+ if thread.reservations[id][:count] == 1
50
+ # May not be set if the application reserved the resource but never hit it
51
+ if s = thread.reservations[id][:semaphore]
52
+ s.release
53
+ end
54
+ thread.reservations[id] = nil
55
+ else
56
+ thread.reservations[id][:count] -= 1
57
+ end
58
+ else
59
+ yield
60
+ end
61
+ end
62
+
63
+ # Returns true if a pattern sequence is currently open/active
64
+ def active?
65
+ !!@active
66
+ end
67
+ alias_method :open?, :active?
68
+ alias_method :runnng?, :active?
69
+
70
+ # Returns the PatternThread object for the current thread
71
+ def thread
72
+ @thread.value
73
+ end
74
+
75
+ # Prepends the given string with "[<current thread ID>] " unless it already contains it
76
+ def add_thread(str)
77
+ if active? && thread
78
+ id = "[#{thread.id}] "
79
+ str.prepend(id) unless str =~ /#{id}/
80
+ end
81
+ str
82
+ end
83
+
84
+ private
85
+
86
+ def active=(val)
87
+ @active = val
88
+ end
89
+
90
+ def thread=(t)
91
+ @thread ||= Concurrent::ThreadLocalVar.new(nil)
92
+ @thread.value = t
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+ PatSeq = Origen::Generator::PatternSequencer
99
+ PatSeq.send(:thread=, nil)
@@ -0,0 +1,175 @@
1
+ module Origen
2
+ class Generator
3
+ # An instance of PatternThread is created for each parallel thread of execution
4
+ # in a pattern sequence. One instance of this class is also created to represent
5
+ # the original main thread in addition to those created by calling seq.in_parallel
6
+ class PatternThread
7
+ # Returns the parent pattern sequence object
8
+ attr_reader :sequence
9
+ attr_reader :pending_cycles
10
+ attr_reader :id
11
+ attr_reader :reservations
12
+ attr_reader :cycle_count_start
13
+ attr_reader :cycle_count_stop
14
+ # A record of when the thread is active to construct the execution profile
15
+ attr_reader :events
16
+
17
+ def initialize(id, sequence, block, primary = false)
18
+ if primary
19
+ @cycle_count_start = 0
20
+ else
21
+ @cycle_count_start = current_cycle_count
22
+ end
23
+ @events = [[:active, cycle_count_start]]
24
+ @id = id.to_sym
25
+ @sequence = sequence
26
+ @block = block
27
+ @primary = primary
28
+ @running = Concurrent::Event.new
29
+ @waiting = Concurrent::Event.new
30
+ @pending_cycles = nil
31
+ @completed = false
32
+ @reservations = {}
33
+ end
34
+
35
+ # Returns true if this is main thread (the one from which all in_parallel threads
36
+ # have been branched from)
37
+ def primary?
38
+ @primary
39
+ end
40
+
41
+ # @api private
42
+ #
43
+ # This method is called once by the pattern sequence to start a new thread. It will block until
44
+ # the thread is in the waiting state.
45
+ def start
46
+ @thread = Thread.new do
47
+ PatSeq.send(:thread=, self)
48
+ wait
49
+ @block.call(sequence)
50
+ sequence.send(:thread_completed, self)
51
+ record_cycle_count_stop
52
+ @completed = true
53
+ wait
54
+ end
55
+ @waiting.wait
56
+ end
57
+
58
+ def record_cycle_count_stop
59
+ @cycle_count_stop = current_cycle_count
60
+ events << [:stopped, cycle_count_stop]
61
+ events.freeze
62
+ end
63
+
64
+ def record_active
65
+ events << [:active, current_cycle_count]
66
+ end
67
+
68
+ def current_cycle_count
69
+ tester.try(:cycle_count) || 0
70
+ end
71
+
72
+ def execution_profile(start, stop, step)
73
+ events = @events.dup
74
+ cycles = start
75
+ state = :inactive
76
+ line = ''
77
+ ((stop - start) / step).times do |i|
78
+ active_cycles = 0
79
+ while events.first && events.first[1] >= cycles && events.first[1] < cycles + step
80
+ event = events.shift
81
+ # Bring the current cycles up to this event point applying the current state
82
+ if state == :active
83
+ active_cycles += event[1] - cycles
84
+ end
85
+ state = event[0] == :active ? :active : :inactive
86
+ cycles = event[1]
87
+ end
88
+
89
+ # Bring the current cycles up to the end of this profile tick
90
+ if state == :active
91
+ active_cycles += ((i + 1) * step) - cycles
92
+ end
93
+ cycles = ((i + 1) * step)
94
+
95
+ if active_cycles == 0
96
+ line += '_'
97
+ elsif active_cycles > (step * 0.5)
98
+ line += '█'
99
+ else
100
+ line += '▄'
101
+ end
102
+ end
103
+ line
104
+ end
105
+
106
+ # Will be called when the thread can't execute its next cycle because it is waiting to obtain a
107
+ # lock on a serialized block
108
+ def waiting_for_serialize(serialize_id, skip_event = false)
109
+ # puts "Thread #{id} is blocked waiting for #{serialize_id}"
110
+ events << [:waiting, current_cycle_count] unless skip_event
111
+ wait
112
+ end
113
+
114
+ # Will be called when the thread can't execute its next cycle because it is waiting for another
115
+ # thread to complete
116
+ def waiting_for_thread(skip_event = false)
117
+ events << [:waiting, current_cycle_count] unless skip_event
118
+ wait
119
+ end
120
+
121
+ # Will be called when the thread is ready for the next cycle
122
+ def cycle(options)
123
+ @pending_cycles = options[:repeat] || 1
124
+ # If there are threads pending start and we are about to enter a long delay, block for only
125
+ # one cycle to give them a change to get underway and make use of this delay
126
+ if @pending_cycles > 1 && sequence.send(:threads_waiting_to_start?)
127
+ remainder = @pending_cycles - 1
128
+ @pending_cycles = 1
129
+ end
130
+ wait
131
+ @pending_cycles = remainder if remainder
132
+ # If the sequence did not do enough cycles in that round to satisfy this thread, then go back
133
+ # around to complete the remainder before continuing with the rest of the pattern
134
+ if @pending_cycles == 0
135
+ @pending_cycles = nil
136
+ elsif @pending_cycles > 0
137
+ @pending_cycles.cycles
138
+ else
139
+ fail "Something has gone wrong @pending_cycles is #{@pending_cycles}"
140
+ end
141
+ end
142
+
143
+ # @api private
144
+ def executed_cycles(cycles)
145
+ @pending_cycles -= cycles if @pending_cycles
146
+ end
147
+
148
+ def completed?
149
+ @completed
150
+ end
151
+
152
+ # Returns true if the thread is currently waiting for the pattern sequence to advance it
153
+ def waiting?
154
+ @waiting.set?
155
+ end
156
+
157
+ # This should be called only by the pattern thread itself, and will block it until it is told to
158
+ # advance by the pattern sequence running in the main thread
159
+ def wait
160
+ @running.reset
161
+ @waiting.set
162
+ @running.wait
163
+ end
164
+
165
+ # This should be called only by the pattern sequence running in the main thread, it will un-block the
166
+ # pattern thread which is currently waiting, and it will block the main thread until the pattern thread
167
+ # reaches the next wait point (or completes)
168
+ def advance(completed_cycles = nil)
169
+ @waiting.reset
170
+ @running.set # Release the pattern thread
171
+ @waiting.wait # And wait for it to reach the next wait point
172
+ end
173
+ end
174
+ end
175
+ end
@@ -107,6 +107,7 @@ module Origen
107
107
 
108
108
  def debug(string = '', options = {})
109
109
  string, options = sanitize_args(string, options)
110
+ PatSeq.add_thread(string) unless options[:no_thread_id]
110
111
  intercept(string, :debug, options) do |msg, type, options|
111
112
  msg = format_msg('DEBUG', msg)
112
113
  log_files(:debug, msg) unless console_only?(options)
@@ -117,6 +118,7 @@ module Origen
117
118
 
118
119
  def info(string = '', options = {})
119
120
  string, options = sanitize_args(string, options)
121
+ PatSeq.add_thread(string) unless options[:no_thread_id]
120
122
  intercept(string, :info, options) do |msg, type, options|
121
123
  msg = format_msg('INFO', msg)
122
124
  log_files(:info, msg) unless console_only?(options)
@@ -130,6 +132,7 @@ module Origen
130
132
 
131
133
  def success(string = '', options = {})
132
134
  string, options = sanitize_args(string, options)
135
+ PatSeq.add_thread(string) unless options[:no_thread_id]
133
136
  intercept(string, :success, options) do |msg, type, options|
134
137
  msg = format_msg('SUCCESS', msg)
135
138
  log_files(:info, msg) unless console_only?(options)
@@ -140,6 +143,7 @@ module Origen
140
143
 
141
144
  def deprecate(string = '', options = {})
142
145
  string, options = sanitize_args(string, options)
146
+ PatSeq.add_thread(string) unless options[:no_thread_id]
143
147
  intercept(string, :deprecate, options) do |msg, type, options|
144
148
  msg = format_msg('DEPRECATED', msg)
145
149
  log_files(:warn, msg) unless console_only?(options)
@@ -151,6 +155,7 @@ module Origen
151
155
 
152
156
  def warn(string = '', options = {})
153
157
  string, options = sanitize_args(string, options)
158
+ PatSeq.add_thread(string) unless options[:no_thread_id]
154
159
  intercept(string, :warn, options) do |msg, type, options|
155
160
  msg = format_msg('WARNING', msg)
156
161
  log_files(:warn, msg) unless console_only?(options)
@@ -162,6 +167,7 @@ module Origen
162
167
 
163
168
  def error(string = '', options = {})
164
169
  string, options = sanitize_args(string, options)
170
+ PatSeq.add_thread(string) unless options[:no_thread_id]
165
171
  intercept(string, :error, options) do |msg, type, options|
166
172
  msg = format_msg('ERROR', msg)
167
173
  log_files(:error, msg) unless console_only?(options)
@@ -97,6 +97,8 @@ module Origen
97
97
  # Returns the basic access string for a given access method. Possible values: read-write, read-only,
98
98
  # write-only, writeOnce, read-writeOnce. Used primarily by CrossOrigen IP-XACT import/export.
99
99
  attr_reader :base_access
100
+ # Can be set to indicate that the current state of the bit is unknown, e.g. after reading X from a simulation
101
+ attr_accessor :unknown
100
102
 
101
103
  def initialize(owner, position, options = {}) # rubocop:disable MethodLength
102
104
  options = {
@@ -290,7 +292,7 @@ module Origen
290
292
  # unknown in cases where the reset value is undefined or determined by a memory location
291
293
  # and where the bit has not been written or read to a specific value yet.
292
294
  def has_known_value?
293
- !@reset_val.is_a?(Symbol) || @updated_post_reset
295
+ !@unknown && (!@reset_val.is_a?(Symbol) || @updated_post_reset)
294
296
  end
295
297
 
296
298
  # Set the data value of the bit to the given value (1 or 0)
@@ -15,6 +15,7 @@ module Origen
15
15
  DONT_CARE_CHAR = 'X'
16
16
  OVERLAY_CHAR = 'V'
17
17
  STORE_CHAR = 'S'
18
+ UNKNOWN_CHAR = '?'
18
19
 
19
20
  attr_accessor :name
20
21
  alias_method :id, :name
@@ -389,6 +390,11 @@ module Origen
389
390
  alias_method :value=, :write
390
391
  alias_method :val=, :write
391
392
 
393
+ # Sets the unknown attribute on all contained bits
394
+ def unknown=(val)
395
+ each { |bit| bit.unknown = val }
396
+ end
397
+
392
398
  # Will tag all bits for read and if a data value is supplied it
393
399
  # will update the expected data for when the read is performed.
394
400
  def read(value = nil, options = {}) # :nodoc:
@@ -902,7 +908,11 @@ module Origen
902
908
  if bit.has_overlay? && options[:mark_overlays]
903
909
  str += OVERLAY_CHAR
904
910
  else
905
- str += bit.data.to_s
911
+ if bit.has_known_value?
912
+ str += bit.data.to_s
913
+ else
914
+ str += UNKNOWN_CHAR
915
+ end
906
916
  end
907
917
  else
908
918
  str += DONT_CARE_CHAR
@@ -913,7 +923,11 @@ module Origen
913
923
  if bit.has_overlay? && options[:mark_overlays]
914
924
  str += OVERLAY_CHAR
915
925
  else
916
- str += bit.data.to_s
926
+ if bit.has_known_value?
927
+ str += bit.data.to_s
928
+ else
929
+ str += UNKNOWN_CHAR
930
+ end
917
931
  end
918
932
  end
919
933
  else
@@ -987,7 +1001,7 @@ module Origen
987
1001
 
988
1002
  nibbles.each_with_index do |nibble, i|
989
1003
  # If contains any special chars...
990
- if nibble =~ /[#{DONT_CARE_CHAR}#{STORE_CHAR}#{OVERLAY_CHAR}]/
1004
+ if nibble =~ /[#{UNKNOWN_CHAR}#{DONT_CARE_CHAR}#{STORE_CHAR}#{OVERLAY_CHAR}]/
991
1005
  # If all the same...
992
1006
  if nibble[0] == nibble[1] && nibble[1] == nibble[2] && nibble[2] == nibble[3]
993
1007
  outstr += nibble[0, 1] # .to_s
@@ -64,7 +64,7 @@ module Origen
64
64
  if val =~ /^[01_xXzZ]+$/
65
65
  true
66
66
  else
67
- fail Origen::SyntaxError, 'Binary string values can only contain: 0, 1, _, x, X, z, Z'
67
+ fail Origen::BinStrValError, "Binary string values can only contain: 0, 1, _, x, X, z, Z, this is invalid: #{val}"
68
68
  end
69
69
  end
70
70
  end
@@ -92,7 +92,7 @@ module Origen
92
92
  if val =~ /^[0-9a-fA-F_xXzZ]+$/
93
93
  true
94
94
  else
95
- fail Origen::SyntaxError, 'Hex string values can only contain: 0-9, a-f, A-F, _, x, X, z, Z'
95
+ fail Origen::HexStrValError, "Hex string values can only contain: 0-9, a-f, A-F, _, x, X, z, Z, this is invalid: #{val}"
96
96
  end
97
97
  end
98
98
  end
@@ -8,16 +8,16 @@ Gem::Specification.new do |s|
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 1.8.11".freeze) if s.respond_to? :required_rubygems_version=
9
9
  s.require_paths = ["lib".freeze]
10
10
  s.authors = ["Stephen McGinty".freeze]
11
- s.date = "2018-12-19"
11
+ s.date = "2019-05-16"
12
12
  s.email = ["stephen.f.mcginty@gmail.com".freeze]
13
13
  s.files = ["bin/boot.rb".freeze, "bin/fix_my_workspace".freeze, "config/application.rb".freeze, "config/boot.rb".freeze, "config/commands.rb".freeze, "config/shared_commands.rb".freeze, "config/version.rb".freeze, "lib/origen_app_generators.rb".freeze, "lib/origen_app_generators/application.rb".freeze, "lib/origen_app_generators/base.rb".freeze, "lib/origen_app_generators/empty_application.rb".freeze, "lib/origen_app_generators/empty_plugin.rb".freeze, "lib/origen_app_generators/new.rb".freeze, "lib/origen_app_generators/origen_infrastructure/app_generator_plugin.rb".freeze, "lib/origen_app_generators/plugin.rb".freeze, "lib/origen_app_generators/sub_block_parser.rb".freeze, "lib/origen_app_generators/test_engineering/stand_alone_application.rb".freeze, "lib/origen_app_generators/test_engineering/test_block.rb".freeze, "lib/tasks/app_generators.rake".freeze, "lib/tasks/new_app_tests.rake".freeze, "templates/app_generators".freeze, "templates/app_generators/application".freeze, "templates/app_generators/application/.gitignore".freeze, "templates/app_generators/application/.irbrc".freeze, "templates/app_generators/application/.rspec".freeze, "templates/app_generators/application/.travis.yml".freeze, "templates/app_generators/application/Gemfile".freeze, "templates/app_generators/application/Rakefile".freeze, "templates/app_generators/application/config".freeze, "templates/app_generators/application/config/application.rb".freeze, "templates/app_generators/application/config/boot.rb".freeze, "templates/app_generators/application/config/commands.rb".freeze, "templates/app_generators/application/config/maillist_dev.txt".freeze, "templates/app_generators/application/config/maillist_prod.txt".freeze, "templates/app_generators/application/config/version.rb".freeze, "templates/app_generators/application/doc".freeze, "templates/app_generators/application/doc/history".freeze, "templates/app_generators/application/dot_keep".freeze, "templates/app_generators/application/lib".freeze, "templates/app_generators/application/lib/app.rake".freeze, "templates/app_generators/application/lib/module.rb".freeze, "templates/app_generators/application/lib/top_level.rb".freeze, "templates/app_generators/application/origen_core_session".freeze, "templates/app_generators/application/spec".freeze, "templates/app_generators/application/spec/spec_helper.rb".freeze, "templates/app_generators/application/target".freeze, "templates/app_generators/application/target/debug.rb".freeze, "templates/app_generators/application/target/default.rb".freeze, "templates/app_generators/application/target/production.rb".freeze, "templates/app_generators/application/templates".freeze, "templates/app_generators/application/templates/web".freeze, "templates/app_generators/application/templates/web/index.md.erb".freeze, "templates/app_generators/application/templates/web/layouts".freeze, "templates/app_generators/application/templates/web/layouts/_basic.html.erb".freeze, "templates/app_generators/application/templates/web/partials".freeze, "templates/app_generators/application/templates/web/partials/_navbar.html.erb".freeze, "templates/app_generators/application/templates/web/release_notes.md.erb".freeze, "templates/app_generators/new".freeze, "templates/app_generators/new/generator.rb".freeze, "templates/app_generators/new/info.md.erb".freeze, "templates/app_generators/origen_infrastructure".freeze, "templates/app_generators/origen_infrastructure/app_generator_plugin".freeze, "templates/app_generators/origen_infrastructure/app_generator_plugin/config".freeze, "templates/app_generators/origen_infrastructure/app_generator_plugin/config/load_generators.rb".freeze, "templates/app_generators/origen_infrastructure/app_generator_plugin/lib".freeze, "templates/app_generators/origen_infrastructure/app_generator_plugin/lib/application.rb".freeze, "templates/app_generators/origen_infrastructure/app_generator_plugin/lib/base.rb".freeze, "templates/app_generators/origen_infrastructure/app_generator_plugin/lib/module.rb".freeze, "templates/app_generators/origen_infrastructure/app_generator_plugin/lib/plugin.rb".freeze, "templates/app_generators/plugin".freeze, "templates/app_generators/plugin/Gemfile".freeze, "templates/app_generators/plugin/Rakefile".freeze, "templates/app_generators/plugin/config".freeze, "templates/app_generators/plugin/config/boot.rb".freeze, "templates/app_generators/plugin/gemspec.rb".freeze, "templates/app_generators/plugin/lib".freeze, "templates/app_generators/plugin/lib/README".freeze, "templates/app_generators/plugin/lib_dev".freeze, "templates/app_generators/plugin/lib_dev/README".freeze, "templates/app_generators/plugin/templates".freeze, "templates/app_generators/plugin/templates/web".freeze, "templates/app_generators/plugin/templates/web/index.md.erb".freeze, "templates/app_generators/plugin/templates/web/partials".freeze, "templates/app_generators/plugin/templates/web/partials/_navbar_external.html.erb".freeze, "templates/app_generators/plugin/templates/web/partials/_navbar_internal.html.erb".freeze, "templates/app_generators/test_engineering".freeze, "templates/app_generators/test_engineering/stand_alone_application".freeze, "templates/app_generators/test_engineering/stand_alone_application/Gemfile".freeze, "templates/app_generators/test_engineering/stand_alone_application/environment".freeze, "templates/app_generators/test_engineering/stand_alone_application/environment/j750.rb".freeze, "templates/app_generators/test_engineering/stand_alone_application/environment/jlink.rb".freeze, "templates/app_generators/test_engineering/stand_alone_application/environment/uflex.rb".freeze, "templates/app_generators/test_engineering/stand_alone_application/environment/v93k.rb".freeze, "templates/app_generators/test_engineering/stand_alone_application/lib".freeze, "templates/app_generators/test_engineering/stand_alone_application/lib/ip_block.rb".freeze, "templates/app_generators/test_engineering/stand_alone_application/lib/ip_block_controller.rb".freeze, "templates/app_generators/test_engineering/stand_alone_application/lib/top_level.rb".freeze, "templates/app_generators/test_engineering/stand_alone_application/lib/top_level_controller.rb".freeze, "templates/app_generators/test_engineering/stand_alone_application/pattern".freeze, "templates/app_generators/test_engineering/stand_alone_application/pattern/example.rb".freeze, "templates/app_generators/test_engineering/stand_alone_application/target".freeze, "templates/app_generators/test_engineering/stand_alone_application/target/top_level.rb".freeze, "templates/app_generators/test_engineering/test_block".freeze, "templates/app_generators/test_engineering/test_block/environment".freeze, "templates/app_generators/test_engineering/test_block/environment/j750.rb".freeze, "templates/app_generators/test_engineering/test_block/environment/ultraflex.rb".freeze, "templates/app_generators/test_engineering/test_block/environment/v93k.rb".freeze, "templates/app_generators/test_engineering/test_block/lib".freeze, "templates/app_generators/test_engineering/test_block/lib/controller.rb".freeze, "templates/app_generators/test_engineering/test_block/lib/interface.rb".freeze, "templates/app_generators/test_engineering/test_block/lib/model.rb".freeze, "templates/app_generators/test_engineering/test_block/lib_dev".freeze, "templates/app_generators/test_engineering/test_block/lib_dev/dut.rb".freeze, "templates/app_generators/test_engineering/test_block/lib_dev/dut_controller.rb".freeze, "templates/app_generators/test_engineering/test_block/pattern".freeze, "templates/app_generators/test_engineering/test_block/pattern/example.rb".freeze, "templates/app_generators/test_engineering/test_block/program".freeze, "templates/app_generators/test_engineering/test_block/program/prb1.rb".freeze, "templates/app_generators/test_engineering/test_block/target".freeze, "templates/app_generators/test_engineering/test_block/target/default.rb".freeze]
14
14
  s.homepage = "http://origen-sdk.org/origen_app_generators".freeze
15
15
  s.licenses = ["MIT".freeze]
16
16
  s.required_ruby_version = Gem::Requirement.new(">= 1.9.3".freeze)
17
- s.rubygems_version = "2.7.7".freeze
17
+ s.rubygems_version = "2.7.6".freeze
18
18
  s.summary = "Origen application generators".freeze
19
19
 
20
- s.installed_by_version = "2.7.7" if s.respond_to? :installed_by_version
20
+ s.installed_by_version = "2.7.6" if s.respond_to? :installed_by_version
21
21
 
22
22
  if s.respond_to? :specification_version then
23
23
  s.specification_version = 4
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: origen
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.43.0
4
+ version: 0.44.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen McGinty
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-03-08 00:00:00.000000000 Z
11
+ date: 2019-05-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -374,6 +374,20 @@ dependencies:
374
374
  - - ">="
375
375
  - !ruby/object:Gem::Version
376
376
  version: 1.3.2
377
+ - !ruby/object:Gem::Dependency
378
+ name: concurrent-ruby
379
+ requirement: !ruby/object:Gem::Requirement
380
+ requirements:
381
+ - - ">="
382
+ - !ruby/object:Gem::Version
383
+ version: '0'
384
+ type: :runtime
385
+ prerelease: false
386
+ version_requirements: !ruby/object:Gem::Requirement
387
+ requirements:
388
+ - - ">="
389
+ - !ruby/object:Gem::Version
390
+ version: '0'
377
391
  description:
378
392
  email:
379
393
  - stephen.f.mcginty@gmail.com
@@ -502,6 +516,9 @@ files:
502
516
  - lib/origen/generator/pattern.rb
503
517
  - lib/origen/generator/pattern_finder.rb
504
518
  - lib/origen/generator/pattern_iterator.rb
519
+ - lib/origen/generator/pattern_sequence.rb
520
+ - lib/origen/generator/pattern_sequencer.rb
521
+ - lib/origen/generator/pattern_thread.rb
505
522
  - lib/origen/generator/renderer.rb
506
523
  - lib/origen/generator/resources.rb
507
524
  - lib/origen/generator/stage.rb
@@ -752,7 +769,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
752
769
  version: 1.8.11
753
770
  requirements: []
754
771
  rubyforge_project:
755
- rubygems_version: 2.7.7
772
+ rubygems_version: 2.7.6
756
773
  signing_key:
757
774
  specification_version: 4
758
775
  summary: The Semiconductor Developer's Kit