origen 0.43.0 → 0.44.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 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