origen 0.30.0 → 0.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/config/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
|