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 +4 -4
- data/config/boot.rb +2 -0
- data/config/version.rb +1 -1
- data/lib/origen.rb +10 -11
- data/lib/origen/application/runner.rb +22 -16
- data/lib/origen/commands/generate.rb +1 -0
- data/lib/origen/generator.rb +17 -10
- data/lib/origen/generator/job.rb +29 -5
- data/lib/origen/generator/pattern.rb +123 -72
- data/lib/origen/generator/pattern_sequence.rb +201 -0
- data/lib/origen/generator/pattern_sequencer.rb +99 -0
- data/lib/origen/generator/pattern_thread.rb +175 -0
- data/lib/origen/log.rb +6 -0
- data/lib/origen/registers/bit.rb +3 -1
- data/lib/origen/registers/bit_collection.rb +17 -3
- data/lib/origen/value/bin_str_val.rb +1 -1
- data/lib/origen/value/hex_str_val.rb +1 -1
- data/origen_app_generators/origen_app_generators.gemspec +3 -3
- metadata +20 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9a8903e336caa8b0e7747f54f298178408b848f4203bfaccb4c7c2506c1df6c3
|
4
|
+
data.tar.gz: f3e398328927876c9ad9d7d46b04594f8ca7f33915be9b0d7956f0d86343c743
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fc638f7063bc0fa0ae993532d19360ed6d3191710d41d4cda3f31c72f86a165ac90854b4305335d49e64f67b2941bad5a456ebbf00e740238c8e1c3b6ef635e4
|
7
|
+
data.tar.gz: 8094048eb20dc9c3319fc5c5f629ba40a0c928915cf3c21ad3174119f2bad267fddcf9e4c2880d91abd1f3316bedaa963a60e6c2dec53a3c4bba3c52f681da8d
|
data/config/boot.rb
CHANGED
data/config/version.rb
CHANGED
data/lib/origen.rb
CHANGED
@@ -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
|
-
|
80
|
-
|
81
|
-
|
82
|
-
end
|
83
|
-
|
84
|
-
class
|
85
|
-
class
|
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
|
-
|
88
|
-
|
89
|
-
|
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
|
data/lib/origen/generator.rb
CHANGED
@@ -1,15 +1,18 @@
|
|
1
1
|
module Origen
|
2
2
|
class Generator
|
3
|
-
autoload :Pattern,
|
4
|
-
autoload :Flow,
|
5
|
-
autoload :Resources,
|
6
|
-
autoload :Job,
|
7
|
-
autoload :PatternFinder,
|
8
|
-
autoload :PatternIterator,
|
9
|
-
autoload :
|
10
|
-
autoload :
|
11
|
-
autoload :
|
12
|
-
autoload :
|
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
|
|
data/lib/origen/generator/job.rb
CHANGED
@@ -156,12 +156,36 @@ module Origen
|
|
156
156
|
skip ||= !listener.before_pattern_lookup(@requested_pattern)
|
157
157
|
end
|
158
158
|
unless skip
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
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
|
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
|
67
|
-
puts
|
68
|
-
puts '
|
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
|
-
#
|
77
|
-
#
|
78
|
-
|
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
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
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
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
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
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
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
|
-
|
143
|
-
|
144
|
-
|
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
|
-
|
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
|
-
|
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
|
data/lib/origen/log.rb
CHANGED
@@ -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)
|
data/lib/origen/registers/bit.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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::
|
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::
|
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 = "
|
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.
|
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.
|
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.
|
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-
|
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.
|
772
|
+
rubygems_version: 2.7.6
|
756
773
|
signing_key:
|
757
774
|
specification_version: 4
|
758
775
|
summary: The Semiconductor Developer's Kit
|