origen 0.30.0 → 0.31.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 24fa93bb3395c5d472af5111b4cf2c7424ddb8fb
4
- data.tar.gz: 2115fdaa3ad10e8c5bad07e0693c1aea2f9484d6
3
+ metadata.gz: 437a40756e6194c3308c3044388d48c4c0b0c31c
4
+ data.tar.gz: d9341d81f27c7bbbf014fe26844d67f53bc1facf
5
5
  SHA512:
6
- metadata.gz: 8e2ced12f38f092dfbcc1ff1da469aca527de65decc950050d9b482b4059d1c5613ed8fb627c509519f6275f0c43db4c21d9c20c34012345654ef1006a45d2df
7
- data.tar.gz: 36270d0d55c0f772399a9afbf8380bdc535aa8ad0c047734ab032df1913101c82bb48845e2c56129e757b99c5782e31eca15f7583269a062ff9cc4fa9e8187b0
6
+ metadata.gz: 8ce734ee2bd0f466c05c38c7a9205ac7bfbee4165780bfdca9c57f4eb3390b49819882a43e0c24f512f4b65c866a2edf5c057b6c6eb4015d7bea48c1cbbfa3a5
7
+ data.tar.gz: 967eafac1a53b990d7b8b5f689278f27527ece71e76cfd6db63faecd7d8b4dbce5a8c87c96c037c1451925267b52d5216179f1108d06183c9dd21ad65188f996
data/config/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module Origen
2
2
  MAJOR = 0
3
- MINOR = 30
3
+ MINOR = 31
4
4
  BUGFIX = 0
5
5
  DEV = nil
6
6
 
data/lib/origen.rb CHANGED
@@ -27,6 +27,7 @@ unless defined? RGen::ORIGENTRANSITION
27
27
  require 'option_parser/optparse'
28
28
  require 'bundler'
29
29
  require 'origen/undefined'
30
+ require 'origen/componentable'
30
31
 
31
32
  module Origen
32
33
  autoload :Features, 'origen/features'
@@ -789,4 +790,6 @@ unless defined? RGen::ORIGENTRANSITION
789
790
  # outside the scope of an Origen command
790
791
  require 'origen/global_methods'
791
792
  include Origen::GlobalMethods
793
+
794
+ require 'origen/components'
792
795
  end
@@ -795,7 +795,18 @@ END
795
795
  end
796
796
  @target_instantiated = true
797
797
  Origen.mode = :debug if options[:force_debug]
798
- listeners_for(:on_create).each(&:on_create)
798
+ listeners_for(:on_create).each do |obj|
799
+ unless obj.is_a?(Origen::SubBlocks::Placeholder)
800
+ if obj.try(:is_a_model_and_controller?)
801
+ m = obj.model
802
+ c = obj.controller
803
+ m.on_create if m.respond_to_directly?(:on_create)
804
+ c.on_create if c.respond_to_directly?(:on_create)
805
+ else
806
+ obj.on_create
807
+ end
808
+ end
809
+ end
799
810
  @on_create_called = true
800
811
  # Keep this within the load_event to ensure any objects that are further instantiated objects
801
812
  # will be associated with (and cleared out upon reload of) the current target
@@ -0,0 +1,649 @@
1
+ module Origen
2
+ # Protologism taking after Enumerable, stating that this object can
3
+ # behave like an Origen Component
4
+ module Componentable
5
+ # Custom Componentable Errors
6
+
7
+ # Raised whenever a component name tries to be added but it already exists
8
+ class NameInUseError < StandardError
9
+ end
10
+
11
+ # Raised whenever a component name is used for something but does not exist.
12
+ class NameDoesNotExistError < StandardError
13
+ end
14
+
15
+ # Raised for everything else.
16
+ class Error < StandardError
17
+ end
18
+
19
+ # In order for Origen to bootstrap using a generic callback, we'll work a bit backwards.
20
+ # When this module is included by an 'includer', it will give
21
+ def self.included(othermod)
22
+ add_included_callback(othermod)
23
+ end
24
+
25
+ # These are split in case the included module actually has an :included method defined and the user wants
26
+ # to bootstrap setting up the add_included_callback manually.
27
+ # Note that someone making a module to house a Componentable class is very unlikely to do this, but it could
28
+ # still happen.
29
+ def self.add_included_callback(othermod)
30
+ othermod.define_singleton_method(:origen_model_init) do |klass, options = {}|
31
+ Origen::Componentable.init_parent_class(klass, self)
32
+ end
33
+ end
34
+
35
+ # When Origen's model initializer is included, all Componentable objects will be automatically booted.
36
+ def self.origen_model_init(klass, options = {})
37
+ Origen::Componentable.init_includer_class(klass)
38
+ end
39
+
40
+ # Initializes the class that included Componentable (the 'includer').
41
+ # All of the singleton methods will be added per Ruby, but the includer still needs to be booted by:
42
+ # 1) Creating and initializing the instance attribute (_componentable_container)
43
+ # 2) Defining a method to get the container directly.
44
+ # For example, the Component class will automatically have a :components method that references the
45
+ # _componentable_container.
46
+ def self.init_includer_class(klass_instance)
47
+ klass_instance.instance_variable_set(:@_componentable_container, {}.with_indifferent_access)
48
+ klass_instance.class.class_eval do
49
+ attr_reader :_componentable_container
50
+
51
+ define_method Origen::Componentable.componentable_names(klass_instance)[:plural] do
52
+ @_componentable_container
53
+ end
54
+ end
55
+ end
56
+
57
+ def self.parent_class_evaled?(parent_class, includer_singleton_name)
58
+ evaled = parent_class.instance_variable_get("@_#{includer_singleton_name}_evaled")
59
+ if evaled.nil?
60
+ # Check that this class isn't inheriting from another class that uses Componentable things.
61
+ # If so, the API is inherited and is fine, so set the evaled value for that class to true.
62
+ parent_class.ancestors.each do |ancestor|
63
+ if ancestor.instance_variable_get("@_#{includer_singleton_name}_evaled")
64
+ parent_class.instance_variable_set("@_#{includer_singleton_name}_evaled", true)
65
+ evaled = true
66
+ break
67
+ end
68
+ end
69
+ end
70
+ evaled
71
+ end
72
+
73
+ def self.init_parent_class(parent_class, includer_class)
74
+ # includer_single_name = begin
75
+ # if includer_class.name.include?('::')
76
+ # name = includer_class.name.split('::').last.underscore
77
+ # else
78
+ # name = includer_class.name.underscore
79
+ # end
80
+ # end
81
+ # includer_plural_name = Origen::Componentable.componentable_names(includer_class)[:plural]
82
+
83
+ names = Componentable.componentable_names(includer_class)
84
+ includer_single_name = names[:singleton]
85
+ includer_plural_name = names[:plural]
86
+
87
+ unless parent_class.is_a?(Class)
88
+ inc = parent_class.instance_variable_set("@_#{includer_single_name}".to_sym, includer_class.new)
89
+ inc.parent = parent_class
90
+ parent_class = parent_class.class
91
+ end
92
+
93
+ # If the includer's singleton name is taken (i.e., the parent already has a method <includer_single_name>),
94
+ # raise an error since the 'proper' way to interact with the includer directly is from this method.
95
+ if !Origen::Componentable.parent_class_evaled?(parent_class, includer_single_name) && parent_class.method_defined?(includer_single_name.to_sym)
96
+ fail Origen::Componentable::Error, "Class #{parent_class.name} provides a method :#{includer_single_name} already. Cannot include Componentable class #{includer_class.name} in this object!"
97
+ end
98
+
99
+ # for everything that's not the singleton name method or the @_<singleton_name> instance variable, having the method
100
+ # already exists is a warning, not an error.
101
+ methods_to_add = [
102
+ includer_plural_name.to_sym,
103
+
104
+ # Add methods
105
+ "add_#{includer_single_name}".to_sym,
106
+ "add_#{includer_plural_name}".to_sym,
107
+
108
+ # Listing/Querying methods
109
+ "list_#{includer_plural_name}".to_sym,
110
+ "#{includer_plural_name}_of_class".to_sym,
111
+ "#{includer_plural_name}_instances_of".to_sym,
112
+ "#{includer_plural_name}_of_type".to_sym,
113
+ "#{includer_single_name}?".to_sym,
114
+ "has_#{includer_single_name}?".to_sym,
115
+
116
+ # Enumeration methods
117
+ "each_#{includer_single_name}".to_sym,
118
+ "all_#{includer_plural_name}".to_sym,
119
+ "select_#{includer_plural_name}".to_sym,
120
+ "select_#{includer_single_name}".to_sym,
121
+
122
+ # Copying/Moving methods
123
+ "copy_#{includer_single_name}".to_sym,
124
+ "copy_#{includer_plural_name}".to_sym,
125
+ "move_#{includer_single_name}".to_sym,
126
+ "move_#{includer_plural_name}".to_sym,
127
+
128
+ # Deleting individual item methods
129
+ "delete_#{includer_single_name}".to_sym,
130
+ "delete_#{includer_plural_name}".to_sym,
131
+ "remove_#{includer_single_name}".to_sym,
132
+ "remove_#{includer_plural_name}".to_sym,
133
+ "delete_#{includer_single_name}!".to_sym,
134
+ "delete_#{includer_plural_name}!".to_sym,
135
+ "remove_#{includer_single_name}!".to_sym,
136
+ "remove_#{includer_plural_name}!".to_sym,
137
+
138
+ # Deleting all items methods
139
+ "delete_all_#{includer_plural_name}".to_sym,
140
+ "clear_#{includer_plural_name}".to_sym,
141
+ "remove_all_#{includer_plural_name}".to_sym
142
+ ]
143
+ unless Origen::Componentable.parent_class_evaled?(parent_class, includer_single_name)
144
+ methods_to_add.each do |m|
145
+ if parent_class.method_defined?(m)
146
+ Origen.log.warning "Componentable: Parent class #{parent_class.name} already defines a method #{m}. This method will not be used by Componentable"
147
+ end
148
+ end
149
+ parent_class.instance_variable_set("@_#{includer_single_name}_evaled".to_sym, true)
150
+ end
151
+
152
+ parent_class.class_eval do
153
+ # Note that all of these just trace back to the root method.
154
+
155
+ # Define the root method (singleton-named method)
156
+ # If any arguments are given, it behaves as an :add method.
157
+ # Otherwise, it returns the underlying object itself.
158
+ define_method includer_single_name.to_sym do |*args, &block|
159
+ if args.size == 0
160
+ # No arguments, so just return the class instance
161
+ instance_variable_get("@_#{includer_single_name}".to_sym)
162
+ else
163
+ # Arguments were provided, so treating this as an :add attempt
164
+ instance_variable_get("@_#{includer_single_name}".to_sym).add(*args, &block)
165
+ end
166
+ end
167
+
168
+ # Define the plural-named method.
169
+ # If arguments are given, then it behaves as an :add attempt, with or without a block.
170
+ # If a block is given without any arguments, it will behave as an :each operation and call the block.
171
+ # if no arguments are given, it will return the underlying HASH (not the object).
172
+ # This allows for plural_name[name] to
173
+ define_method "#{includer_plural_name}".to_sym do |*args, &block|
174
+ if block && args.size == 0
175
+ instance_variable_get("@_#{includer_single_name}".to_sym).each(&block)
176
+ elsif args.size == 0
177
+ instance_variable_get("@_#{includer_single_name}".to_sym)._componentable_container
178
+ else
179
+ instance_variable_get("@_#{includer_single_name}".to_sym).add(*args, &block)
180
+ end
181
+ end
182
+
183
+ # define the various 'add' methods
184
+ # what we'll actually do is just define one method then alias all the others together.
185
+ # Currently, this includes:
186
+ # <includer_plural_name>, add_<includer_single_name>, add_
187
+ define_method "add_#{includer_single_name}".to_sym do |name, options = {}, &block|
188
+ instance_variable_get("@_#{includer_single_name}".to_sym).add(name, options, &block)
189
+ end
190
+ alias_method "add_#{includer_plural_name}".to_sym, "add_#{includer_single_name}".to_sym
191
+
192
+ # define listing and getting methods
193
+ define_method "list_#{includer_plural_name}".to_sym do
194
+ instance_variable_get("@_#{includer_single_name}".to_sym).list
195
+ end
196
+
197
+ # define the querying object types
198
+ define_method "#{includer_plural_name}_of_class".to_sym do |klass, options = {}|
199
+ instance_variable_get("@_#{includer_single_name}".to_sym).instances_of(klass, options)
200
+ end
201
+ alias_method "#{includer_plural_name}_instances_of".to_sym, "#{includer_plural_name}_of_class".to_sym
202
+ alias_method "#{includer_plural_name}_of_type".to_sym, "#{includer_plural_name}_of_class".to_sym
203
+
204
+ # define the querying instance existance
205
+ define_method "#{includer_single_name}?".to_sym do |name|
206
+ instance_variable_get("@_#{includer_single_name}".to_sym).has?(name)
207
+ end
208
+ alias_method "has_#{includer_single_name}?".to_sym, "#{includer_single_name}?".to_sym
209
+
210
+ # define some of commonly used enumerate methods
211
+ define_method "each_#{includer_single_name}".to_sym do |&block|
212
+ instance_variable_get("@_#{includer_single_name}".to_sym).each(&block)
213
+ end
214
+ alias_method "all_#{includer_plural_name}".to_sym, "each_#{includer_single_name}".to_sym
215
+
216
+ define_method "select_#{includer_plural_name}".to_sym do |&block|
217
+ instance_variable_get("@_#{includer_single_name}".to_sym).select(&block)
218
+ end
219
+ alias_method "select_#{includer_single_name}".to_sym, "select_#{includer_plural_name}".to_sym
220
+
221
+ # define the copying/moving methods
222
+ define_method "copy_#{includer_single_name}".to_sym do |to_copy, to_location, options = {}|
223
+ instance_variable_get("@_#{includer_single_name}".to_sym).copy(to_copy, to_location, options)
224
+ end
225
+ alias_method "copy_#{includer_plural_name}".to_sym, "copy_#{includer_single_name}".to_sym
226
+
227
+ define_method "move_#{includer_single_name}".to_sym do |to_move, to_location|
228
+ instance_variable_get("@_#{includer_single_name}".to_sym).move(to_move, to_location)
229
+ end
230
+ alias_method "move_#{includer_plural_name}".to_sym, "move_#{includer_single_name}".to_sym
231
+
232
+ # define the deleting single instance methods
233
+ define_method "delete_#{includer_single_name}".to_sym do |name|
234
+ instance_variable_get("@_#{includer_single_name}".to_sym).delete(name)
235
+ end
236
+ alias_method "delete_#{includer_plural_name}".to_sym, "delete_#{includer_single_name}".to_sym
237
+ alias_method "remove_#{includer_single_name}".to_sym, "delete_#{includer_single_name}".to_sym
238
+ alias_method "remove_#{includer_plural_name}".to_sym, "delete_#{includer_single_name}".to_sym
239
+
240
+ define_method "delete_#{includer_single_name}!".to_sym do |name|
241
+ instance_variable_get("@_#{includer_single_name}".to_sym).delete!(name)
242
+ end
243
+ alias_method "delete_#{includer_plural_name}!".to_sym, "delete_#{includer_single_name}!".to_sym
244
+ alias_method "remove_#{includer_single_name}!".to_sym, "delete_#{includer_single_name}!".to_sym
245
+ alias_method "remove_#{includer_plural_name}!".to_sym, "delete_#{includer_single_name}!".to_sym
246
+
247
+ # define the deleting all instances methods
248
+ define_method "delete_all_#{includer_plural_name}".to_sym do
249
+ instance_variable_get("@_#{includer_single_name}".to_sym).delete_all
250
+ end
251
+ alias_method "clear_#{includer_plural_name}".to_sym, "delete_all_#{includer_plural_name}".to_sym
252
+ alias_method "remove_all_#{includer_plural_name}".to_sym, "delete_all_#{includer_plural_name}".to_sym
253
+ end
254
+ end
255
+
256
+ # All of these are generic names and the instantiation. When included, Componentable will add aliases to these
257
+ # methods onto the includer's parent. For example:
258
+ # <includer>.has? becomes $dut.has_<include>?
259
+ # <includer>.delete(name_to_delete) becomes $dut.delete_<includer>(name_to_delete)
260
+ # etc. etc.
261
+ # def self.parent_or_owner(includer)
262
+ # return includer.parent if includer.parent
263
+ # return includer.owner if includer.owner
264
+ # nil
265
+ # end
266
+
267
+ # Gets the plural name of the class.
268
+ def _plural_name
269
+ @plural_name || begin
270
+ @plural_name = Origen::Componentable.componentable_names(self)[:plural]
271
+ @singleton_name = Origen::Componentable.componentable_names(self)[:singleton]
272
+ end
273
+ end
274
+
275
+ # Gets the singleton name of the class.
276
+ def _singleton_name
277
+ @singleton_name || begin
278
+ @plural_name = Origen::Componentable.componentable_names(self)[:plural]
279
+ @singleton_name = Origen::Componentable.componentable_names(self)[:singleton]
280
+ end
281
+ end
282
+
283
+ # Gets the parent of the includer class.
284
+ def parent
285
+ @parent
286
+ end
287
+
288
+ # Sets the parent of the includer class
289
+ def parent=(p)
290
+ @parent = p
291
+ end
292
+
293
+ def self.componentable_names(klass)
294
+ unless klass.is_a?(Class)
295
+ # If we were given an instance of a class, get its actual class.
296
+ klass = klass.class
297
+ end
298
+ names = {}
299
+
300
+ # Evaluate the singleton name. This will be the class name or the class constant
301
+ # COMPONENTABLE_SINGLETON_NAME, if it's defined.
302
+ # The only corner case here is if the class is anonymous, then a COMPONENTABLE_SINGLETON_NAME is required.
303
+ if klass.const_defined?(:COMPONENTABLE_SINGLETON_NAME)
304
+ names[:singleton] = klass.const_get(:COMPONENTABLE_SINGLETON_NAME).downcase.to_sym
305
+ else
306
+ # Check if this is an anonymous class. If so, complain that COMPONENTABLE_SINGLETON_NAME is required
307
+ if !klass.respond_to?(:name) || klass.name.nil? # || klass.name.start_with?('#<Class:')
308
+ if klass.const_defined?(:COMPONENTABLE_PLURAL_NAME)
309
+ # Have a more specific error saying the plural name was found but isn't sufficient.
310
+ fail Origen::Componentable::Error, 'Anonymous classes that include the Componentable module must define COMPONENTABLE_SINGLETON_NAME, even if COMPONENTABLE_PLURAL_NAME is defined'
311
+ else
312
+ fail Origen::Componentable::Error, 'Anonymous classes that include the Componentable module must define COMPONENTABLE_SINGLETON_NAME'
313
+ end
314
+ else
315
+ if klass.name.include?('::')
316
+ names[:singleton] = klass.name.split('::').last.underscore.to_sym
317
+ else
318
+ names[:singleton] = klass.name.underscore.to_sym
319
+ end
320
+ end
321
+ end
322
+
323
+ if klass.const_defined?(:COMPONENTABLE_PLURAL_NAME)
324
+ name = klass.const_get(:COMPONENTABLE_PLURAL_NAME).downcase.to_sym
325
+
326
+ # do a quick check to make sure that the plural name and singleton name aren't set to the same thing
327
+ if name == names[:singleton]
328
+ fail Origen::Componentable::Error, "Componentable including class cannot define both COMPONENTABLE_SINGLETON_NAME and COMPONENTABLE_PLURAL_NAME to '#{name}'"
329
+ end
330
+ else
331
+ name = names[:singleton].to_s
332
+
333
+ # Only deal with a few cases here, I'm not interested in figuring out every
334
+ # english rule to pluralize everything. Examples:
335
+ # deer => deers (not deer, though technically I think deers is actually a word, but an odd one)
336
+ # goose => gooses (not geese)
337
+ # dwarf => dwarfs (not dwarves)
338
+ # If the user is concerned about this, they can supply their own
339
+ # name pluralizing their class name directly.
340
+ if name.match(/is$/)
341
+ # analysis => analyses
342
+ name.gsub!(/is$/, 'es')
343
+ elsif name.match(/[sxz]$|sh$|ch$/)
344
+ # if the names ends with s, h, ch, sh, x, z: append 'es'. Examples:
345
+ # bus => buses
346
+ # stress => stresses
347
+ # box => boxes
348
+ # branch => branches
349
+ # brush => brushes
350
+ # tax => taxes
351
+ # buzz => buzzes
352
+ name += 'es'
353
+ elsif name.match(/on$/)
354
+ # criterion => criteria
355
+ name.gsub!(/on$/, 'a')
356
+ else
357
+ # just append a single 's'. Examples:
358
+ # component => components
359
+ # sub_block => sub_blocks
360
+ # tool => tools
361
+ name += 's'
362
+ end
363
+ name = name.to_sym
364
+ end
365
+ names[:plural] = name
366
+
367
+ names
368
+ end
369
+
370
+ def add(name, options = {}, &block)
371
+ instances = _split_by_instances(name, options, &block)
372
+ return_instances = []
373
+ instances.each do |n, opts|
374
+ return_instances << _add(n, opts)
375
+ end
376
+
377
+ return_instances.size == 1 ? return_instances.first : return_instances
378
+ end
379
+
380
+ def _split_by_instances(name, options = {}, &block)
381
+ if !options[:instances].nil? && options[:instances] > 1
382
+ instances = {}
383
+ options[:instances].times do |i|
384
+ opts = {}
385
+
386
+ # merge the given options with any that are overriden with the block.
387
+ if block_given?
388
+ collector = Origen::Utility::Collector.new
389
+ yield collector
390
+ options.merge!(collector.store)
391
+ end
392
+
393
+ # go through the options one by one now and make sure that each element is either an array to be split
394
+ # by the instances, or is a single object. If not one of these two, complain.
395
+ options.each do |key, val|
396
+ if val.is_a?(Array)
397
+ if val.size == 1
398
+ # An array with a single element. This is fine. Just take that single element as the contents.
399
+ # Note: this is a workaround for the corner case of wanting to pass in an array as an option
400
+ # with a size that doesn't match the number of instances.
401
+ opts[key] = val.first
402
+ elsif val.size != options[:instances]
403
+ # The number of elements in the option doesn't match the number of instances, and it greater than
404
+ # a single element.
405
+ fail Origen::Componentable::Error, "Error when adding #{name}: size of given option :#{key} (#{val.size}) does not match the number of instances specified (#{options[:instances]})"
406
+ else
407
+ # use the index number to grab the correct value for this instance
408
+ opts[key] = val[i]
409
+ end
410
+ else
411
+ opts[key] = val
412
+ end
413
+ end
414
+
415
+ # set the instance's name and add it and its options to the list to be added
416
+ instances["#{name}#{i}".to_sym] = opts
417
+ end
418
+ instances
419
+ else
420
+ if block_given?
421
+ collector = Origen::Utility::Collector.new
422
+ yield collector
423
+ options.merge!(collector.store)
424
+ end
425
+ { name => options }
426
+ end
427
+ end
428
+
429
+ # Adds a new item to the componentable container.
430
+ # @note All options added will be passed to the subclasses instantiation.
431
+ # @note The options is only valid for the stock :add method.
432
+ # @note Any extra options provided are still passed to the subclasses instantiation.
433
+ # @param name [Symbol] Name to reference the new component object.
434
+ # @param options [Hash] Customizations for both the add method and for the class's instantiation.
435
+ # @option options [Class, String] class_name The class to instaniate the component at :name as.
436
+ # @return [ComponentableObject] The instantiated class at :name
437
+ # @raise [Origen::Componentable::NameInUseError] Raised if :name already points to a component.
438
+ def _add(name, options = {}, &block)
439
+ # Add the name and parent to the options if they aren't already given
440
+ # If the parent isn't available on the includer class, it will remain nil.
441
+ options = {
442
+ name: name,
443
+ parent: parent
444
+ }.merge(options)
445
+
446
+ if block_given?
447
+ collector = Origen::Utility::Collector.new
448
+ yield collector
449
+ options.merge!(collector.store)
450
+ end
451
+
452
+ # Instantiate the class. This will place the object in the @_componentable_container at the indicated name
453
+ _instantiate_class(name, options)
454
+
455
+ # Create an accessor for the new item, if indicated to do so.
456
+ _push_accessor(name, options)
457
+
458
+ @_componentable_container[name]
459
+ end
460
+
461
+ def _instantiate_class(name, options)
462
+ if @_componentable_container.key?(name)
463
+ fail Origen::Componentable::NameInUseError, "#{_singleton_name} name :#{name} is already in use."
464
+ end
465
+
466
+ if options[:class_name]
467
+ class_name = options.delete(:class_name)
468
+
469
+ unless Object.const_defined?(class_name.to_s)
470
+ fail Origen::Componentable::NameDoesNotExistError, "class_name option '#{class_name}' cannot be found"
471
+ end
472
+
473
+ # Instantiate the given class
474
+ if class_name.is_a?(String)
475
+ @_componentable_container[name] = eval(class_name).new(options)
476
+ else
477
+ @_componentable_container[name] = class_name.new(options)
478
+ end
479
+ else
480
+ # Instantiate a standard Component if no class given
481
+ @_componentable_container[name] = Origen::Component::Default.new(options)
482
+ end
483
+ @_componentable_container[name]
484
+ end
485
+
486
+ def _push_accessor(name, options)
487
+ if parent
488
+ def push_accessor(name)
489
+ if parent.respond_to?(name.to_sym)
490
+ Origen.log.warn("Componentable: #{_singleton_name} is trying to add an accessor for item :#{name} to parent #{parent.class.name} but that method already exist! No accessor will be added.")
491
+ else
492
+ parent.send(:eval, "define_singleton_method :#{name.to_sym} do; #{_singleton_name}[:#{name}]; end")
493
+ end
494
+ end
495
+
496
+ if self.class.const_defined?(:COMPONENTABLE_ADDS_ACCESSORS) && self.class.const_get(:COMPONENTABLE_ADDS_ACCESSORS)
497
+ if parent.respond_to?(:disable_componentable_accessors)
498
+ if parent.method(:disable_componentable_accessors).arity >= 1
499
+ unless parent.disable_componentable_accessors(self.class)
500
+ push_accessor(name)
501
+ end
502
+ else
503
+ unless parent.disable_componentable_accessors
504
+ push_accessor(name)
505
+ end
506
+ end
507
+ else
508
+ push_accessor(name)
509
+ end
510
+ end
511
+ end
512
+ end
513
+
514
+ # List the items in the componentable container
515
+ # @return [Array<Symbol>] Componentable container item names.
516
+ def list
517
+ @_componentable_container.keys
518
+ end
519
+
520
+ # Checks if a component exist in the componentable container.
521
+ # @param name [Symbol] Name to query existance of.
522
+ # @return [true, false] True if :name exists, False otherwise.
523
+ def has?(name)
524
+ @_componentable_container.include?(name)
525
+ end
526
+
527
+ def [](name)
528
+ @_componentable_container[name]
529
+ end
530
+
531
+ # Copies the component at :to_copy to :to_location. Default is to deep copy (i.e. clone)
532
+ # the to_copy, resulting in two independent components.
533
+ # @param to_copy [Symbol] Name of the component to copy.
534
+ # @param to_location [Symbol] Name to copy to.
535
+ # @param options [Hash] Customization options.
536
+ # @option options [true, false] :deep_copy (true) Indicates whether to deep copy (clone) the component or just copy the a reference to the component.
537
+ # @option options [true, false] :override (false) Indicates if the object at :to_location should be overridden if it already exists.
538
+ # @returns [Symbol] The new object (or reference to) at :to_location.
539
+ # @raise [Origen::Componentable::NameInUseError] Raised if :to_location is already in use and the :override option is not specified.
540
+ # @raise [Origen::Componentable::NameDoesNotExistsError] Raised if :to_copy name does not exists.
541
+ def copy(to_copy, to_location, options = {})
542
+ deep_copy = options.key?(:deep_copy) ? options[:deep_copy] : true
543
+ overwrite = options[:overwrite] || false
544
+
545
+ if @_componentable_container.key?(to_location) && !overwrite
546
+ # The copy location already exists and override was not specified
547
+ fail Origen::Componentable::NameInUseError, "#{_singleton_name} name :#{to_location} is already in use"
548
+ end
549
+
550
+ unless @_componentable_container.key?(to_copy)
551
+ # The to copy name doesn't exist
552
+ fail Origen::Componentable::NameDoesNotExistError, "#{_singleton_name} name :#{to_copy} does not exist"
553
+ end
554
+
555
+ if deep_copy
556
+ @_componentable_container[to_location] = @_componentable_container[to_copy].clone
557
+ else
558
+ @_componentable_container[to_location] = @_componentable_container[to_copy]
559
+ end
560
+ end
561
+
562
+ # Moves a component object from one name to another.
563
+ # @param to_move [Symbol] Component name to move elsewhere.
564
+ # @param new_name [Symbol] New name to give to the component from :to_move.
565
+ # @return [Symbol] The component moved.
566
+ # @raise [Origen::Componentable::NameInUseError] Raised if :new_name is already in use and the :override option is not specified.
567
+ # @raise [Origen::Componentable::NameDoesNotExistsError] Raised if :to_move name does not exists.
568
+ def move(to_move, new_name, options = {})
569
+ overwrite = options[:overwrite] || false
570
+
571
+ if @_componentable_container.key?(new_name) && !overwrite
572
+ # The move location already exists and override was not specified
573
+ fail Origen::Componentable::NameInUseError, "#{_singleton_name} name :#{new_name} is already in use"
574
+ end
575
+
576
+ unless @_componentable_container.key?(to_move)
577
+ # The to_move name doesn't exist
578
+ fail Origen::Componentable::NameDoesNotExistError, "#{_singleton_name} name :#{to_move} does not exist"
579
+ end
580
+
581
+ to_move_object = @_componentable_container.delete(to_move)
582
+ @_componentable_container[new_name] = to_move_object
583
+ end
584
+
585
+ # Deletes a component from the componentable container
586
+ # @param name [Symbol] Name of component to delete
587
+ # @return [Hash(Symbol, <ComponentableItem>)] containing the name of the component deleted and its component.
588
+ # @raise [Origen::Componentable::NameDoesNotExistsError] Raised if :to_copy name does not exists.
589
+ def delete(to_delete)
590
+ obj = delete!(to_delete)
591
+ fail Origen::Componentable::NameDoesNotExistError, "#{_singleton_name} name :#{to_delete} does not exist" if obj.nil?
592
+ obj
593
+ end
594
+ alias_method :remove, :delete
595
+
596
+ # Same as the :delete method but raises an error if :name doesn't exists.
597
+ # @param name [Symbol] Name oof the component to delete.
598
+ # @return [Hash(Symbol, <ComponentableItem>), nil] Hash containing the name of the component deleted and its component. Nil if the name doesn't exist.
599
+ def delete!(to_delete)
600
+ need_to_undef = parent && parent.respond_to?(to_delete) && parent.send(to_delete).eql?(@_componentable_container[to_delete])
601
+
602
+ obj = @_componentable_container.delete(to_delete)
603
+
604
+ if need_to_undef
605
+ parent.instance_eval "undef #{to_delete}"
606
+ end
607
+
608
+ obj
609
+ end
610
+ alias_method :remove!, :delete!
611
+
612
+ # Deletes all of the components in the container.
613
+ # @return [Hash(Symbol, <ComponentableItem>)] Hash containing all of the deleted items.
614
+ def delete_all
615
+ # delete individual objects one by one, making sure to delete all accessors as well
616
+ returns = {}
617
+ @_componentable_container.each do |key, val|
618
+ delete!(key)
619
+ returns[key] = val
620
+ end
621
+ returns
622
+ end
623
+ alias_method :clear, :delete_all
624
+ alias_method :remove_all, :delete_all
625
+
626
+ # Locates all names whose object is a :class_name object.
627
+ # @param class_name [Class, Instance of Class] Class to search componentable container for. This can either be the class name, or can be an instance of the class to search for.
628
+ # @return [Array <Strings>] An array listing all of the names in the componentable container which are a :class_name.
629
+ def instances_of(class_name, options = {})
630
+ unless class_name.is_a?(Class)
631
+ # class_name is actually an instance of the class to search for, not the class itself.
632
+ class_name = class_name.class
633
+ end
634
+ @_componentable_container.select do |name, component|
635
+ component.is_a?(class_name)
636
+ end.keys
637
+ end
638
+
639
+ # Implementation for an each method
640
+ def each(&block)
641
+ @_componentable_container.each(&block)
642
+ end
643
+
644
+ # Implementation for a select method
645
+ def select(&block)
646
+ @_componentable_container.select(&block)
647
+ end
648
+ end
649
+ end
@@ -0,0 +1,34 @@
1
+ module Origen
2
+ # API for dealing with instantiating and keeping track of components or
3
+ # 'component-like object' (e.g. sub blocks).
4
+ # This API can be included as a mixin and extended further extended by the includer
5
+ # to get the top-level component behavior while providing more refined usage at the same time.
6
+ module Component
7
+ # Componentable Component class. This is the general purpose container to just 'add a thing'
8
+ class Component
9
+ include Origen::Componentable
10
+
11
+ COMPONENTABLE_ADDS_ACCESSORS = true
12
+
13
+ # Kind of ironic really, but since we're auto-including this when Origen::Model is included,
14
+ # we can't include Origen::Model here or else we'll get a circular dependency.
15
+ # Note that the parent will still initialize correctly, but we need to initialize Components manually.
16
+ # I.e, the parent will get methods :component, :add_components, :components, etc., but the Component object
17
+ # won't be initialized so everything will fail.
18
+ def initialize
19
+ Origen::Componentable.init_includer_class(self)
20
+ end
21
+ end
22
+
23
+ # Default class instantiate if the class_name is not provided
24
+ class Default
25
+ include Origen::Model
26
+
27
+ attr_reader :options
28
+
29
+ def initialize(options = {})
30
+ @options = options
31
+ end
32
+ end
33
+ end
34
+ end
@@ -78,6 +78,20 @@ module Origen
78
78
  end
79
79
  end
80
80
 
81
+ # When compared to another object, a controller will consider itself equal if either the controller
82
+ # or its model match the given object
83
+ def ==(obj, options = {})
84
+ if obj.is_a?(Origen::SubBlocks::Placeholder)
85
+ obj = obj.materialize
86
+ end
87
+ if options[:called_from_model]
88
+ super(obj)
89
+ else
90
+ super(obj) || model == obj
91
+ end
92
+ end
93
+ alias_method :equal?, :==
94
+
81
95
  # Means that when dealing with a controller/model pair, you can
82
96
  # always call obj.model and obj.controller to get the one you want,
83
97
  # regardless of the one you currently have.
data/lib/origen/model.rb CHANGED
@@ -12,6 +12,7 @@ module Origen
12
12
  included do
13
13
  attr_writer :ip_name
14
14
  attr_accessor :version
15
+ attr_accessor :parent
15
16
  attr_reader :controller
16
17
 
17
18
  include Origen::ModelInitializer
@@ -32,6 +33,7 @@ module Origen
32
33
  include Origen::PowerDomains
33
34
  include Origen::Clocks
34
35
  include Origen::Model::Exporter
36
+ include Origen::Component
35
37
  end
36
38
 
37
39
  module ClassMethods
@@ -52,6 +54,12 @@ module Origen
52
54
  true
53
55
  end
54
56
 
57
+ # Returns true if the instance is an Origen::Model that is wrapped
58
+ # in a controller
59
+ def is_a_model_and_controller?
60
+ !!controller
61
+ end
62
+
55
63
  # Returns true if the model is the current DUT/top-level model
56
64
  def is_top_level?
57
65
  Origen.top_level == self
@@ -66,6 +74,18 @@ module Origen
66
74
  self
67
75
  end
68
76
 
77
+ def ==(obj)
78
+ if obj.is_a?(Origen::SubBlocks::Placeholder)
79
+ obj = obj.materialize
80
+ end
81
+ if controller
82
+ super(obj) || controller.send(:==, obj, called_from_model: true)
83
+ else
84
+ super(obj)
85
+ end
86
+ end
87
+ alias_method :equal?, :==
88
+
69
89
  def log
70
90
  Origen.log
71
91
  end
@@ -121,10 +141,13 @@ module Origen
121
141
  klass = self.class
122
142
  while klass != Object
123
143
  controller_class = "#{klass}Controller"
124
- if eval("defined? #{controller_class}")
125
- return eval(controller_class)
126
- elsif eval("defined? ::#{controller_class}")
127
- return eval("::#{controller_class}")
144
+ unless controller_class.start_with?('#<Class')
145
+ # klass is an anonymous class. Can't support automatic resolution with anonymous classes
146
+ if eval("defined? #{controller_class}")
147
+ return eval(controller_class)
148
+ elsif eval("defined? ::#{controller_class}")
149
+ return eval("::#{controller_class}")
150
+ end
128
151
  end
129
152
  klass = klass.superclass
130
153
  end
@@ -9,12 +9,13 @@ module Origen
9
9
  include_timestamp: true,
10
10
  file_path: nil
11
11
  }.merge(options)
12
+ # file_path is for internal use, don't pass it from the application, use the :dir option if you
13
+ # want to change where the exported files are
12
14
  if options[:file_path]
13
15
  file = File.join(options[:file_path], "#{name}.rb")
14
16
  else
15
- file = export_path(name)
17
+ file = export_path(name, options)
16
18
  end
17
- file += '.rb' unless file =~ /.rb$/
18
19
  file = Pathname.new(file)
19
20
  FileUtils.rm_rf(file.sub_ext('').to_s) if File.exist?(file.sub_ext('').to_s)
20
21
  FileUtils.rm_rf(file.to_s) if File.exist?(file.to_s)
@@ -73,9 +74,18 @@ module Origen
73
74
  end
74
75
 
75
76
  def import(name, options = {})
76
- path = export_path(name)
77
- require path
78
- extend "#{Origen.app.namespace.underscore.camelcase}::#{name.to_s.camelcase}".constantize
77
+ path = export_path(name, options)
78
+ if File.exist?(path)
79
+ require path
80
+ extend "#{Origen.app.namespace.underscore.camelcase}::#{name.to_s.camelcase}".constantize
81
+ true
82
+ else
83
+ if options[:allow_missing]
84
+ false
85
+ else
86
+ fail "The import for #{name} could not be found at #{path}"
87
+ end
88
+ end
79
89
  end
80
90
 
81
91
  private
@@ -115,20 +125,20 @@ module Origen
115
125
  end
116
126
  file.puts '# rubocop:disable all'
117
127
  indent = 0
118
- export_module_names_from_path(file.path).each do |name|
128
+ export_module_names_from_path(file.path, options).each do |name|
119
129
  file.puts((' ' * indent) + "module #{name}")
120
130
  indent += 2
121
131
  end
122
132
  yield indent
123
- export_module_names_from_path(file.path).each do |name|
133
+ export_module_names_from_path(file.path, options).each do |name|
124
134
  indent -= 2
125
135
  file.puts((' ' * indent) + 'end')
126
136
  end
127
137
  file.puts '# rubocop:enable all'
128
138
  end
129
139
 
130
- def export_module_names_from_path(name)
131
- name = name.sub("#{export_dir}/", '').sub('.rb', '')
140
+ def export_module_names_from_path(name, options = {})
141
+ name = name.sub("#{export_dir(options)}/", '').sub('.rb', '')
132
142
  name.split(/[\/\\]/).map do |n|
133
143
  if n == ''
134
144
  nil
@@ -138,12 +148,16 @@ module Origen
138
148
  end.compact
139
149
  end
140
150
 
141
- def export_path(name)
142
- File.join(export_dir, Origen.app.namespace.to_s.underscore, name.to_s.underscore)
151
+ def export_path(name, options = {})
152
+ if options.key?(:namespace) && !options[:namespace]
153
+ File.join(export_dir(options), "#{name.to_s.underscore}.rb")
154
+ else
155
+ File.join(export_dir(options), (options[:namespace] || Origen.app.namespace).to_s.underscore, "#{name.to_s.underscore}.rb")
156
+ end
143
157
  end
144
158
 
145
- def export_dir
146
- File.join(Origen.root, 'vendor', 'lib', 'models')
159
+ def export_dir(options = {})
160
+ options[:dir] || File.join(Origen.root, 'vendor', 'lib', 'models')
147
161
  end
148
162
 
149
163
  def export_pin(id, pin, options = {})
@@ -196,10 +210,19 @@ module Origen
196
210
  indent = ' ' * (options[:indent] || 0)
197
211
  file = File.join(options[:file_path].sub_ext(''), "#{id}.rb")
198
212
  local_file = file.to_s.sub("#{export_dir}/", '')
199
- line = indent + "model.sub_block :#{id}, file: '#{local_file}'"
213
+ line = indent + "model.sub_block :#{id}, file: '#{local_file}', lazy: true"
200
214
  unless block.base_address == 0
201
215
  line << ", base_address: #{block.base_address.to_hex}"
202
216
  end
217
+ block.custom_attrs.each do |key, value|
218
+ if value.is_a?(Symbol)
219
+ line << ", #{key}: :#{value}"
220
+ elsif value.is_a?(String)
221
+ line << ", #{key}: '#{value}'"
222
+ else
223
+ line << ", #{key}: #{value}"
224
+ end
225
+ end
203
226
  block.export(id, options.merge(file_path: options[:file_path].sub_ext('').to_s))
204
227
  line
205
228
  end
@@ -21,6 +21,16 @@ module Origen
21
21
  parent = options.delete(:parent)
22
22
  x.parent = parent if parent
23
23
  end
24
+
25
+ x.class.included_modules.each do |mod|
26
+ mod.send(:origen_model_init, x) if mod.respond_to?(:origen_model_init)
27
+ mod.constants.each do |constant|
28
+ if mod.const_defined?(constant)
29
+ mod.const_get(constant).send(:origen_model_init, x) if mod.const_get(constant).respond_to?(:origen_model_init)
30
+ end
31
+ end
32
+ end
33
+
24
34
  options.each do |k, v|
25
35
  x.send(:instance_variable_set, "@#{k}", v) if x.respond_to?(k)
26
36
  end
@@ -47,10 +57,17 @@ module Origen
47
57
  is_top_level = x.respond_to?(:includes_origen_top_level?)
48
58
  if x.respond_to?(:wrap_in_controller)
49
59
  x = x.wrap_in_controller
50
- # If this object has been instantiated after on_create has already been called,
51
- # then invoke it now
52
- if Origen.application_loaded? && Origen.app.on_create_called?
53
- x.controller.on_create if x.controller.respond_to?(:on_create)
60
+ end
61
+ # If this object has been instantiated after on_create has already been called,
62
+ # then invoke it now
63
+ if Origen.application_loaded? && Origen.app.on_create_called?
64
+ if x.try(:is_a_model_and_controller)
65
+ m = x.model
66
+ c = x.controller
67
+ m.on_create if m.respond_to_directly?(:on_create)
68
+ c.on_create if c.respond_to_directly?(:on_create)
69
+ else
70
+ x.on_create if x.respond_to?(:on_create)
54
71
  end
55
72
  end
56
73
  if is_top_level
@@ -3,10 +3,15 @@ module Origen
3
3
  module Interceptable
4
4
  def self.included(base)
5
5
  base.extend ClassMethods
6
+ end
6
7
 
7
- # Defers this executing until the whole class has loaded
8
- Origen.after_app_loaded do
9
- unless (base.instance_methods - Object.methods).include?(:global_path_to)
8
+ module ClassMethods
9
+ def new(*args, &block)
10
+ o = allocate
11
+ i = OrgFile::Interceptor.new(o)
12
+ o.__interceptor__ = i
13
+ i.send(:initialize, *args, &block)
14
+ unless o.respond_to?(:global_path_to)
10
15
  puts 'When adding the OrgFile::Interceptable module to a class, the class must define an instance method called "global_path_to", like this:'
11
16
  puts
12
17
  puts ' # Must return a string that contains a global path to access the given object,'
@@ -14,17 +19,8 @@ module Origen
14
19
  puts ' def global_path_to'
15
20
  puts ' "dut.pins(:#{id})"'
16
21
  puts ' end'
17
- fail "Incomplete integration of OrgFile::Interceptable in #{base}"
22
+ fail "Incomplete integration of OrgFile::Interceptable in #{o.class}"
18
23
  end
19
- end
20
- end
21
-
22
- module ClassMethods
23
- def new(*args, &block)
24
- o = allocate
25
- i = OrgFile::Interceptor.new(o)
26
- o.__interceptor__ = i
27
- i.send(:initialize, *args, &block)
28
24
  i
29
25
  end
30
26
  end
@@ -91,7 +91,7 @@ module Origen
91
91
  def default_reg_metadata
92
92
  Origen::Registers.reg_metadata[:global] ||= {}
93
93
  if block_given?
94
- collector = Collector.new
94
+ collector = Origen::Utility::Collector.new
95
95
  yield collector
96
96
  Origen::Registers.reg_metadata[:global].merge!(collector.store)
97
97
  end
@@ -107,7 +107,7 @@ module Origen
107
107
  def default_bit_metadata
108
108
  Origen::Registers.bit_metadata[:global] ||= {}
109
109
  if block_given?
110
- collector = Collector.new
110
+ collector = Origen::Utility::Collector.new
111
111
  yield collector
112
112
  Origen::Registers.bit_metadata[:global].merge!(collector.store)
113
113
  end
@@ -275,18 +275,6 @@ module Origen
275
275
  end
276
276
  end
277
277
 
278
- class Collector
279
- attr_reader :store
280
-
281
- def initialize
282
- @store = {}
283
- end
284
-
285
- def method_missing(method, *args, &_block)
286
- @store[method.to_s.sub('=', '').to_sym] = args.first
287
- end
288
- end
289
-
290
278
  # Returns true if the given object is one of the recognized Origen
291
279
  # bit containers (bit collection, reg or container).
292
280
  def contains_bits?(obj)
@@ -434,7 +422,7 @@ module Origen
434
422
  def default_reg_metadata
435
423
  Origen::Registers.reg_metadata[self.class] ||= {}
436
424
  if block_given?
437
- collector = Collector.new
425
+ collector = Origen::Utility::Collector.new
438
426
  yield collector
439
427
  Origen::Registers.reg_metadata[self.class].merge!(collector.store)
440
428
  end
@@ -445,7 +433,7 @@ module Origen
445
433
  def default_bit_metadata
446
434
  Origen::Registers.bit_metadata[self.class] ||= {}
447
435
  if block_given?
448
- collector = Collector.new
436
+ collector = Origen::Utility::Collector.new
449
437
  yield collector
450
438
  Origen::Registers.bit_metadata[self.class].merge!(collector.store)
451
439
  end
@@ -6,10 +6,16 @@ module Origen
6
6
  # @api private
7
7
  def init_sub_blocks(*args)
8
8
  options = args.find { |a| a.is_a?(Hash) }
9
+ @custom_attrs = (options ? options.dup : {}).with_indifferent_access
10
+ # Delete these keys which are either meta data added by Origen or are already covered by
11
+ # dedicated methods
12
+ %w(parent name base_address reg_base_address base).each do |key|
13
+ @custom_attrs.delete(key)
14
+ end
9
15
  if options
10
16
  # Using reg_base_address for storage to avoid class with the original Origen base
11
17
  # address API, but will accept any of these
12
- @reg_base_address = options.delete(:reg_base_address) || options.delete(:reg_base_address) ||
18
+ @reg_base_address = options.delete(:reg_base_address) ||
13
19
  options.delete(:base_address) || options.delete(:base) || 0
14
20
  if options[:_instance]
15
21
  if @reg_base_address.is_a?(Array)
@@ -30,6 +36,20 @@ module Origen
30
36
  end
31
37
  end
32
38
 
39
+ # Returns the default
40
+ def self.lazy?
41
+ @lazy || false
42
+ end
43
+
44
+ def self.lazy=(value)
45
+ @lazy = value
46
+ end
47
+
48
+ # Returns a hash containing all options that were passed to the sub_block definition
49
+ def custom_attrs
50
+ @custom_attrs
51
+ end
52
+
33
53
  module Domains
34
54
  def domain(name, options = {})
35
55
  domains[name] = Origen::Registers::Domain.new(name, options)
@@ -282,7 +302,12 @@ module Origen
282
302
  define_singleton_method name do
283
303
  get_sub_block(name)
284
304
  end
285
- block
305
+ if options.key?(:lazy)
306
+ lazy = options[:lazy]
307
+ else
308
+ lazy = Origen::SubBlocks.lazy?
309
+ end
310
+ lazy ? block : block.materialize
286
311
  end
287
312
  end
288
313
 
@@ -348,12 +373,13 @@ module Origen
348
373
  end
349
374
 
350
375
  def ==(obj)
351
- materialize == obj
352
- end
353
-
354
- def !=(obj)
355
- materialize != obj
376
+ if obj.is_a?(Placeholder)
377
+ materialize == obj.materialize
378
+ else
379
+ materialize == obj
380
+ end
356
381
  end
382
+ alias_method :equal?, :==
357
383
 
358
384
  def freeze
359
385
  materialize.freeze
@@ -7,6 +7,7 @@ module Origen
7
7
  autoload :InputCapture, 'origen/utility/input_capture'
8
8
  autoload :BlockArgs, 'origen/utility/block_args'
9
9
  autoload :FileDiff, 'origen/utility/file_diff.rb'
10
+ autoload :Collector, 'origen/utility/collector.rb'
10
11
 
11
12
  # Creates a hex-like representation of a register read value, where bits within
12
13
  # a nibble have different flags set the nibble will be expanded to bits
@@ -0,0 +1,15 @@
1
+ module Origen
2
+ module Utility
3
+ class Collector
4
+ attr_reader :store
5
+
6
+ def initialize
7
+ @store = {}
8
+ end
9
+
10
+ def method_missing(method, *args, &_block)
11
+ @store[method.to_s.sub('=', '').to_sym] = args.first
12
+ end
13
+ end
14
+ end
15
+ end
@@ -67,7 +67,7 @@ module Origen
67
67
  model.add_ground_pin :gnd3
68
68
  model.add_ground_pin_group :gnd, :gnd1, :gnd2, :gnd3
69
69
 
70
- model.sub_block :block1, file: 'origen/export1/block1.rb'
70
+ model.sub_block :block1, file: 'origen/export1/block1.rb', lazy: true
71
71
 
72
72
  end
73
73
  end
@@ -4,7 +4,7 @@ module Origen
4
4
  module Export1
5
5
  module Block1
6
6
  def self.extended(model)
7
- model.sub_block :x, file: 'origen/export1/block1/x.rb', base_address: 0x40000000
7
+ model.sub_block :x, file: 'origen/export1/block1/x.rb', lazy: true, base_address: 0x40000000
8
8
 
9
9
  end
10
10
  end
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.30.0
4
+ version: 0.31.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: 2018-01-24 00:00:00.000000000 Z
11
+ date: 2018-02-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -454,6 +454,8 @@ files:
454
454
  - lib/origen/commands/version.rb
455
455
  - lib/origen/commands/web.rb
456
456
  - lib/origen/commands_global.rb
457
+ - lib/origen/componentable.rb
458
+ - lib/origen/components.rb
457
459
  - lib/origen/controller.rb
458
460
  - lib/origen/core_ext.rb
459
461
  - lib/origen/core_ext/array.rb
@@ -577,6 +579,7 @@ files:
577
579
  - lib/origen/users/user.rb
578
580
  - lib/origen/utility.rb
579
581
  - lib/origen/utility/block_args.rb
582
+ - lib/origen/utility/collector.rb
580
583
  - lib/origen/utility/csv_data.rb
581
584
  - lib/origen/utility/diff.rb
582
585
  - lib/origen/utility/file_diff.rb