origen 0.43.0 → 0.44.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +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
|