-
Notifications
You must be signed in to change notification settings - Fork 24
/
parameters.rb
245 lines (221 loc) · 7.72 KB
/
parameters.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
require 'active_support/concern'
require 'set'
module Origen
module Parameters
extend ActiveSupport::Concern
autoload :Set, 'origen/parameters/set'
autoload :Live, 'origen/parameters/live'
autoload :Missing, 'origen/parameters/missing'
attr_accessor :current
# @api private
#
# Any define_params blocks contained within the given block will be allowed to be re-opened later
# in the block to override existing parameter settings or to add new ones.
#
# This is not allowed normally since already-defined child parameter sets could have referenced the
# original parameter and they would not reflect the final value after re-opening the parent parameter
# set.
#
# By defining the parameters within this block, Origen will keep track of relationships between parameter
# sets and any time a parent is changed the definitions of existing children will be re-executed to ensure
# that they reflect the new values.
#
# This is initially intended to support the concept of a app/parameters/application.rb being
# used to define baseline parameter sets, and then target-specific files can then override them.
def self.transaction
start_transaction
yield
stop_transaction
end
# @api private
def self.start_transaction
@transaction_data = {}
@transaction_open = true
@transaction_counter ||= 0
@transaction_counter += 1
end
# @api private
def self.stop_transaction
@transaction_counter -= 1
if @transaction_counter == 0
# Now finalize (freeze) all parameter sets we have just defined, this was deferred at define time due
# to running within a transaction
@transaction_data.each do |model, parameter_sets|
parameter_sets.keys.each do |name|
model._parameter_sets[name].finalize
end
end
@transaction_data = nil
@transaction_open = false
end
end
# @api private
def self.transaction_data
@transaction_data
end
# @api private
def self.transaction_open
@transaction_open
end
# @api private
def self.transaction_redefine
@transaction_redefine
end
# @api private
def self.redefine(model, name)
@transaction_redefine = true
model._parameter_sets.delete(name)
@transaction_data[model][name][:definitions].each { |options, block| model.define_params(name, options, &block) }
@transaction_data[model][name][:children].each { |model, name| redefine(model, name) }
@transaction_redefine = false
end
module ClassMethods
def parameters_context(obj = nil)
if obj
if obj.is_a?(Symbol)
valid = [:top, :dut].include?(obj)
end
valid ||= obj.is_a?(String)
unless valid
fail 'Invalid parameters context, must be :top or a string path to a model object'
end
@parameters_context = obj
else
@parameters_context
end
end
end
# @api private
def define_params_transaction
Origen::Parameters.transaction_data
end
def define_params(name, options = {}, &block)
name = name.to_sym
if _parameter_sets[name] && !Origen::Parameters.transaction_open
fail "Parameter set '#{name}' cannot be re-opened once originally defined!"
else
if Origen::Parameters.transaction_open && !Origen::Parameters.transaction_redefine
define_params_transaction[self] ||= {}
define_params_transaction[self][name] ||= { children: ::Set[], definitions: [] }
define_params_transaction[self][name][:definitions] << [options.dup, block]
redefine_children = define_params_transaction[self][name][:children] if _parameter_sets[name]
end
if _parameter_sets[name]
defaults_already_set = true
else
_parameter_sets[name] = Origen::Parameters::Set.new(top_level: true, owner: self)
end
if options[:inherit]
parents = {}
Array(options[:inherit]).each do |inherit|
kontext = _validate_parameter_set_name(inherit)
parent = kontext[:obj]._parameter_sets[kontext[:context]]
parents[inherit] = parent
if Origen::Parameters.transaction_open && !Origen::Parameters.transaction_redefine
define_params_transaction[kontext[:obj]][kontext[:context]][:children] << [self, name]
end
_parameter_sets[name].copy_defaults_from(parent) unless defaults_already_set
end
parents = parents.values.first if parents.size == 1
_parameter_sets[name].define(parents, &block)
else
_parameter_sets[name].define(&block)
end
if redefine_children
redefine_children.each { |model, set_name| Origen::Parameters.redefine(model, set_name) }
end
end
_parameter_sets[name]
end
alias_method :define_parameters, :define_params
def with_params(name, _options = {})
orig = _parameter_current
self.params = name
yield
self.params = orig
end
def params(context = nil)
@_live_parameter_requested = false
context ||= _parameter_current
_parameter_sets[context] || Missing.new(owner: self)
end
alias_method :parameters, :params
def params=(name)
# Don't validate on setting this as this object could be used to set
# the context on some other object, therefore validate later if someone tries
# to access the params on this object
# _validate_parameter_set_name(name)
@_parameter_current = name
end
alias_method :parameters=, :params=
def has_params?
_parameter_sets.empty? ? false : true
end
# Return value of param if it exists, nil otherwise.
def param?(name)
_param = name.to_s =~ /^params./ ? name.to_s : 'params.' + name.to_s
begin
val = eval("self.#{_param}")
rescue
nil
else
val
end
end
# @api private
def _parameter_current
if path = self.class.parameters_context
case path
when :top, :dut
Origen.top_level._parameter_current
else
eval(path)._parameter_current
end
else
@_parameter_current || :default
end
end
# @api private
def _parameter_sets
@_parameter_sets ||= {}
end
# @api private
def _request_live_parameter
@_live_parameter_requested = true
end
# @api private
def _live_parameter_requested?
@_live_parameter_requested
end
private
def _validate_parameter_set_name(expr)
# Check if the user specified to inherit from another object
# or just passed in a param context
param_context = {}.tap do |context_hash|
case expr
when Symbol
# user specified a local context
context_hash[:obj] = self
context_hash[:context] = expr
when String
# user specified a DUT path
path = expr.split('.')[0..-2].join('.')
kontext = expr.split('.')[-1].to_sym
context_hash[:obj] = eval(path)
context_hash[:context] = kontext
else
Origen.log.error('Parameter context must be a Symbol (local to self) or a String (reference to another object)!')
fail
end
end
if param_context[:obj]._parameter_sets.key?(param_context[:context])
param_context
else
puts "Unknown parameter set :#{param_context[:context]} requested for #{param_context[:obj].class}, these are the valid sets:"
param_context[:obj]._parameter_sets.keys.each { |k| puts " :#{k}" }
puts ''
fail 'Unknown parameter set!'
end
end
end
end