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 +4 -4
- data/config/version.rb +1 -1
- data/lib/origen.rb +3 -0
- data/lib/origen/application.rb +12 -1
- data/lib/origen/componentable.rb +649 -0
- data/lib/origen/components.rb +34 -0
- data/lib/origen/controller.rb +14 -0
- data/lib/origen/model.rb +27 -4
- data/lib/origen/model/exporter.rb +37 -14
- data/lib/origen/model_initializer.rb +21 -4
- data/lib/origen/org_file/interceptable.rb +9 -13
- data/lib/origen/registers.rb +4 -16
- data/lib/origen/sub_blocks.rb +33 -7
- data/lib/origen/utility.rb +1 -0
- data/lib/origen/utility/collector.rb +15 -0
- data/vendor/lib/models/origen/export1.rb +1 -1
- data/vendor/lib/models/origen/export1/block1.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 437a40756e6194c3308c3044388d48c4c0b0c31c
|
4
|
+
data.tar.gz: d9341d81f27c7bbbf014fe26844d67f53bc1facf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8ce734ee2bd0f466c05c38c7a9205ac7bfbee4165780bfdca9c57f4eb3390b49819882a43e0c24f512f4b65c866a2edf5c057b6c6eb4015d7bea48c1cbbfa3a5
|
7
|
+
data.tar.gz: 967eafac1a53b990d7b8b5f689278f27527ece71e76cfd6db63faecd7d8b4dbce5a8c87c96c037c1451925267b52d5216179f1108d06183c9dd21ad65188f996
|
data/config/version.rb
CHANGED
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
|
data/lib/origen/application.rb
CHANGED
@@ -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
|
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
|
data/lib/origen/controller.rb
CHANGED
@@ -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
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
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
|
-
|
78
|
-
|
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
|
-
|
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
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
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
|
-
|
8
|
-
|
9
|
-
|
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 #{
|
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
|
data/lib/origen/registers.rb
CHANGED
@@ -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
|
data/lib/origen/sub_blocks.rb
CHANGED
@@ -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) ||
|
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
|
-
|
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
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
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
|
data/lib/origen/utility.rb
CHANGED
@@ -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
|
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.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-
|
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
|